]> git.sur5r.net Git - i3/i3status/blob - src/print_ddate.c
de9a7be468e71d4232bc560963e19d438671784f
[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                                 if (dt->season_day > 9 && dt->season_day < 13) {
99                                         outwalk += sprintf(outwalk, "th");
100                                         break;
101                                 }
102
103                                 switch (dt->season_day % 10) {
104                                         case 0:
105                                                 outwalk += sprintf(outwalk, "st");
106                                                 break;
107                                         case 1:
108                                                 outwalk += sprintf(outwalk, "nd");
109                                                 break;
110                                         case 2:
111                                                 outwalk += sprintf(outwalk, "rd");
112                                                 break;
113                                         default:
114                                                 outwalk += sprintf(outwalk, "th");
115                                                 break;
116                                 }
117                                 break;
118                         /* YOLD */
119                         case 'Y':
120                                 outwalk += sprintf(outwalk, "%d", dt->year);
121                                 break;
122                         /* Holidays */
123                         case 'H':
124                                 if (dt->season_day == 4) {
125                                         outwalk += sprintf(outwalk, "%s", holidays[dt->season]);
126                                 }
127                                 if (dt->season_day == 49) {
128                                         outwalk += sprintf(outwalk, "%s", holidays[dt->season + 5]);
129                                 }
130                                 break;
131                         /* Stop parsing the format string, except on Holidays */
132                         case 'N':
133                                 if (dt->season_day != 4 && dt->season_day != 49) {
134                                         return (outwalk - orig_outwalk);
135                                 }
136                                 break;
137                         /* Newline- and Tabbing-characters */
138                         case 'n':
139                                 outwalk += sprintf(outwalk, "\n");
140                                 break;
141                         case 't':
142                                 outwalk += sprintf(outwalk, "\t");
143                                 break;
144                         /* The St. Tib's Day replacement */
145                         case '{':
146                                 tibs_end = strstr(i, "%}");
147                                 if (tibs_end == NULL) {
148                                         i++;
149                                         break;
150                                 }
151                                 if (dt->st_tibs_day) {
152                                         /* We outpt "St. Tib's Day... */
153                                         outwalk += sprintf(outwalk, "St. Tib's Day");
154                                 } else {
155                                         /* ...or parse the substring between %{ and %} ... */
156                                         *tibs_end = '\0';
157                                         outwalk += format_output(outwalk, i + 2, dt);
158                                         *tibs_end = '%';
159                                 }
160                                 /* ...and continue with the rest */
161                                 i = tibs_end;
162                                 break;
163                         case '}':
164                                 i++;
165                                 break;
166                         default:
167                                 /* No escape-sequence, so we just skip */
168                                 outwalk += sprintf(outwalk, "%%%c", *(i+1));
169                                 break;
170                 }
171                 i++;
172         }
173         return (outwalk - orig_outwalk);
174 }
175
176 /* Get the current date and convert it to discordian */
177 struct disc_time *get_ddate(struct tm *current_tm) {
178         static struct disc_time dt;
179
180         if (current_tm == NULL)
181                 return NULL;
182
183         /* We have to know, whether we have to insert St. Tib's Day, so whether it's a leap
184            year in gregorian calendar */
185         int is_leap_year = !(current_tm->tm_year % 4) &&
186                             (!(current_tm->tm_year % 400) || current_tm->tm_year % 100);
187
188         /* If St. Tib's Day has passed, it will be necessary to skip a day. */
189         int yday = current_tm->tm_yday;
190
191         if (is_leap_year && yday == 59) {
192                 /* On St. Tibs Day we don't have to define a date */
193                 dt.st_tibs_day = 1;
194         } else {
195                 dt.st_tibs_day = 0;
196                 if (is_leap_year && yday > 59)
197                         yday -= 1;
198
199                 dt.season_day = yday % 73;
200                 dt.week_day = yday % 5;
201         }
202         dt.year = current_tm->tm_year + 3066;
203         dt.season = yday / 73;
204         return &dt;
205 }
206
207 void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t) {
208         char *outwalk = buffer;
209         static char *form = NULL;
210         struct tm current_tm;
211         struct disc_time *dt;
212         set_timezone(NULL);  /* Use local time. */
213         localtime_r(&t, &current_tm);
214         if ((dt = get_ddate(&current_tm)) == NULL)
215                 return;
216         if (form == NULL)
217                 if ((form = malloc(strlen(format) + 1)) == NULL)
218                         return;
219         strcpy(form, format);
220         outwalk += format_output(outwalk, form, dt);
221         OUTPUT_FULL_TEXT(buffer);
222 }