]> git.sur5r.net Git - i3/i3status/blob - src/print_ddate.c
Skip a day in the Discordian calendar when St. Tib's Day has passed
[i3/i3status] / src / print_ddate.c
1 // vim:ts=8:expandtab
2 #include <time.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <yajl/yajl_gen.h>
7 #include <yajl/yajl_version.h>
8
9 #include "i3status.h"
10
11 /* define fixed output-Strings */
12 char *season_long[5] = {
13         "Chaos",
14         "Discord",
15         "Confusion",
16         "Bureaucracy",
17         "The Aftermath"
18 };
19
20 char *season_short[5] = {
21         "Chs",
22         "Dsc",
23         "Cfn",
24         "Bcy",
25         "Afm"
26 };
27
28 char *day_long[5] = {
29         "Sweetmorn",
30         "Boomtime",
31         "Pungenday",
32         "Prickle-Prickle",
33         "Setting Orange"
34 };
35
36 char *day_short[5] = {
37         "SM",
38         "BT",
39         "PD",
40         "PP",
41         "SO"
42 };
43
44 char *holidays[10] = {
45         "Mungday",
46         "Mojoday",
47         "Syaday",
48         "Zaraday",
49         "Maladay",
50         "Chaoflux",
51         "Discoflux",
52         "Confuflux",
53         "Bureflux",
54         "Afflux"
55 };
56
57 /* A helper-struct, taking the discordian date */
58 struct disc_time {
59         int year;
60         int season;
61         int week_day;
62         int season_day;
63         int st_tibs_day;
64 };
65
66 /* Print the date *dt in format *format */
67 static int format_output(char *outwalk, char *format, struct disc_time *dt) {
68         char *orig_outwalk = outwalk;
69         char *i;
70         char *tibs_end = 0;
71
72         for (i = format; *i != '\0'; i++) {
73                 if (*i != '%') {
74                         *(outwalk++) = *i;
75                         continue;
76                 }
77                 switch (*(i+1)) {
78                         /* Weekday in long and abbreviation */
79                         case 'A':
80                                 outwalk += sprintf(outwalk, "%s", day_long[dt->week_day]);
81                                 break;
82                         case 'a':
83                                 outwalk += sprintf(outwalk, "%s", day_short[dt->week_day]);
84                                 break;
85                         /* Season in long and abbreviation */
86                         case 'B':
87                                 outwalk += sprintf(outwalk, "%s", season_long[dt->season]);
88                                 break;
89                         case 'b':
90                                 outwalk += sprintf(outwalk, "%s", season_short[dt->season]);
91                                 break;
92                         /* Day of the season (ordinal and cardinal) */
93                         case 'd':
94                                 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
95                                 break;
96                         case 'e':
97                                 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
98                                 switch (dt->season_day) {
99                                         case 0:
100                                                 outwalk += sprintf(outwalk, "st");
101                                                 break;
102                                         case 1:
103                                                 outwalk += sprintf(outwalk, "nd");
104                                                 break;
105                                         case 2:
106                                                 outwalk += sprintf(outwalk, "rd");
107                                                 break;
108                                         default:
109                                                 outwalk += sprintf(outwalk, "th");
110                                                 break;
111                                 }
112                                 break;
113                         /* YOLD */
114                         case 'Y':
115                                 outwalk += sprintf(outwalk, "%d", dt->year);
116                                 break;
117                         /* Holidays */
118                         case 'H':
119                                 if (dt->season_day == 4) {
120                                         outwalk += sprintf(outwalk, "%s", holidays[dt->season]);
121                                 }
122                                 if (dt->season_day == 49) {
123                                         outwalk += sprintf(outwalk, "%s", holidays[dt->season + 5]);
124                                 }
125                                 break;
126                         /* Stop parsing the format string, except on Holidays */
127                         case 'N':
128                                 if (dt->season_day != 4 && dt->season_day != 49) {
129                                         return (outwalk - orig_outwalk);
130                                 }
131                                 break;
132                         /* Newline- and Tabbing-characters */
133                         case 'n':
134                                 outwalk += sprintf(outwalk, "\n");
135                                 break;
136                         case 't':
137                                 outwalk += sprintf(outwalk, "\t");
138                                 break;
139                         /* The St. Tib's Day replacement */
140                         case '{':
141                                 tibs_end = strstr(i, "%}");
142                                 if (tibs_end == NULL) {
143                                         i++;
144                                         break;
145                                 }
146                                 if (dt->st_tibs_day) {
147                                         /* We outpt "St. Tib's Day... */
148                                         outwalk += sprintf(outwalk, "St. Tib's Day");
149                                 } else {
150                                         /* ...or parse the substring between %{ and %} ... */
151                                         *tibs_end = '\0';
152                                         outwalk += format_output(outwalk, i + 2, dt);
153                                         *tibs_end = '%';
154                                 }
155                                 /* ...and continue with the rest */
156                                 i = tibs_end;
157                                 break;
158                         case '}':
159                                 i++;
160                                 break;
161                         default:
162                                 /* No escape-sequence, so we just skip */
163                                 outwalk += sprintf(outwalk, "%%%c", *(i+1));
164                                 break;
165                 }
166                 i++;
167         }
168         return (outwalk - orig_outwalk);
169 }
170
171 /* Get the current date and convert it to discordian */
172 struct disc_time *get_ddate(struct tm *current_tm) {
173         static struct disc_time dt;
174
175         if (current_tm == NULL)
176                 return NULL;
177
178         /* We have to know, whether we have to insert St. Tib's Day, so whether it's a leap
179            year in gregorian calendar */
180         int is_leap_year = !(current_tm->tm_year % 4) &&
181                             (!(current_tm->tm_year % 400) || current_tm->tm_year % 100);
182
183         /* If St. Tib's Day has passed, it will be necessary to skip a day. */
184         int yday = current_tm->tm_yday;
185
186         if (is_leap_year && yday == 59) {
187                 /* On St. Tibs Day we don't have to define a date */
188                 dt.st_tibs_day = 1;
189         } else {
190                 dt.st_tibs_day = 0;
191                 if (is_leap_year && yday > 59)
192                         yday -= 1;
193
194                 dt.season_day = yday % 73;
195                 dt.week_day = yday % 5;
196         }
197         dt.year = current_tm->tm_year + 3066;
198         dt.season = yday / 73;
199         return &dt;
200 }
201
202 void print_ddate(yajl_gen json_gen, char *buffer, const char *format, struct tm *current_tm) {
203         char *outwalk = buffer;
204         static char *form = NULL;
205         struct disc_time *dt;
206         if ((dt = get_ddate(current_tm)) == NULL)
207                 return;
208         if (form == NULL)
209                 if ((form = malloc(strlen(format) + 1)) == NULL)
210                         return;
211         strcpy(form, format);
212         outwalk += format_output(outwalk, form, dt);
213         OUTPUT_FULL_TEXT(buffer);
214 }