]> git.sur5r.net Git - i3/i3status/blob - src/print_ddate.c
clang-format-3.5 -i **/*.[ch], update modeline
[i3/i3status] / src / print_ddate.c
1 // vim:ts=4:sw=4: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 char *season_short[5] = {
20     "Chs",
21     "Dsc",
22     "Cfn",
23     "Bcy",
24     "Afm"};
25
26 char *day_long[5] = {
27     "Sweetmorn",
28     "Boomtime",
29     "Pungenday",
30     "Prickle-Prickle",
31     "Setting Orange"};
32
33 char *day_short[5] = {
34     "SM",
35     "BT",
36     "PD",
37     "PP",
38     "SO"};
39
40 char *holidays[10] = {
41     "Mungday",
42     "Mojoday",
43     "Syaday",
44     "Zaraday",
45     "Maladay",
46     "Chaoflux",
47     "Discoflux",
48     "Confuflux",
49     "Bureflux",
50     "Afflux"};
51
52 /* A helper-struct, taking the discordian date */
53 struct disc_time {
54     int year;
55     int season;
56     int week_day;
57     int season_day;
58     int st_tibs_day;
59 };
60
61 /* Print the date *dt in format *format */
62 static int format_output(char *outwalk, char *format, struct disc_time *dt) {
63     char *orig_outwalk = outwalk;
64     char *i;
65     char *tibs_end = 0;
66
67     for (i = format; *i != '\0'; i++) {
68         if (*i != '%') {
69             *(outwalk++) = *i;
70             continue;
71         }
72         switch (*(i + 1)) {
73             /* Weekday in long and abbreviation */
74             case 'A':
75                 outwalk += sprintf(outwalk, "%s", day_long[dt->week_day]);
76                 break;
77             case 'a':
78                 outwalk += sprintf(outwalk, "%s", day_short[dt->week_day]);
79                 break;
80             /* Season in long and abbreviation */
81             case 'B':
82                 outwalk += sprintf(outwalk, "%s", season_long[dt->season]);
83                 break;
84             case 'b':
85                 outwalk += sprintf(outwalk, "%s", season_short[dt->season]);
86                 break;
87             /* Day of the season (ordinal and cardinal) */
88             case 'd':
89                 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
90                 break;
91             case 'e':
92                 outwalk += sprintf(outwalk, "%d", dt->season_day + 1);
93                 if (dt->season_day > 9 && dt->season_day < 13) {
94                     outwalk += sprintf(outwalk, "th");
95                     break;
96                 }
97
98                 switch (dt->season_day % 10) {
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, time_t t) {
203     char *outwalk = buffer;
204     static char *form = NULL;
205     struct tm current_tm;
206     struct disc_time *dt;
207     set_timezone(NULL); /* Use local time. */
208     localtime_r(&t, &current_tm);
209     if ((dt = get_ddate(&current_tm)) == NULL)
210         return;
211     if (form == NULL)
212         if ((form = malloc(strlen(format) + 1)) == NULL)
213             return;
214     strcpy(form, format);
215     outwalk += format_output(outwalk, form, dt);
216     OUTPUT_FULL_TEXT(buffer);
217 }