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