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