11 static struct trans trans_mon[] = {
12 { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
13 { 6, "june" }, { 7, "july" }, { 8, "august" }, { 9, "september" },
14 { 10, "october" }, { 11, "november" }, { 12, "december" },
18 static struct trans trans_wday[] = {
19 { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
20 { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
24 static char digits[] = "0123456789";
27 trans(const struct trans t[], const char *arg)
31 for (f = 0; t[f].val != -1; f++)
32 if (!strncasecmp(t[f].str, arg, 3) ||
33 !strncasecmp(t[f].str, arg, strlen(t[f].str)))
40 vary_append(struct vary *v, char *arg)
42 struct vary *result, **nextp;
52 *nextp = (struct vary *)malloc(sizeof(struct vary));
54 (*nextp)->next = NULL;
58 static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
61 daysinmonth(const struct tm *t)
65 year = t->tm_year + 1900;
70 else if (!(year % 100))
76 else if (t->tm_mon >= 0 && t->tm_mon < 12)
77 return mdays[t->tm_mon];
84 adjyear(struct tm *t, char type, int val)
96 t->tm_year += 100; /* as per date.c */
97 else if (t->tm_year > 1900)
98 t->tm_year -= 1900; /* struct tm holds years since 1900 */
101 return mktime(t) != -1;
105 adjmon(struct tm *t, char type, int val, int istext)
113 if (val <= t->tm_mon)
114 val += 11 - t->tm_mon; /* early next year */
116 val -= t->tm_mon + 1; /* later this year */
117 if (!adjyear(t, '+', (t->tm_mon + val) / 12))
127 if (val-1 > t->tm_mon)
128 val = 13 - val + t->tm_mon; /* later last year */
130 val = t->tm_mon - val + 1; /* early this year */
131 if (!adjyear(t, '-', val / 12))
134 if (val > t->tm_mon) {
135 if (!adjyear(t, '-', 1))
143 if (val > 12 || val < 1)
148 return mktime(t) != -1;
152 adjday(struct tm *t, char type, int val)
158 mdays = daysinmonth(t);
159 if (val > mdays - t->tm_mday) {
160 val -= mdays - t->tm_mday + 1;
162 if (!adjmon(t, '+', 1, 0))
172 if (val >= t->tm_mday) {
175 if (!adjmon(t, '-', 1, 0))
177 t->tm_mday = daysinmonth(t);
184 if (val > 0 && val <= daysinmonth(t))
191 return mktime(t) != -1;
195 adjwday(struct tm *t, char type, int val, int istext)
203 if (val < t->tm_wday)
204 val = 7 - t->tm_wday + val; /* early next week */
206 val -= t->tm_wday; /* later this week */
208 val *= 7; /* "-W +5" == "5 weeks in the future" */
209 return adjday(t, '+', val);
212 if (val > t->tm_wday)
213 val = 7 - val + t->tm_wday; /* later last week */
215 val = t->tm_wday - val; /* early this week */
217 val *= 7; /* "-W -5" == "5 weeks ago" */
218 return adjday(t, '-', val);
220 if (val < t->tm_wday)
221 return adjday(t, '-', t->tm_wday - val);
224 else if (val > t->tm_wday)
225 return adjday(t, '+', val - t->tm_wday);
231 adjhour(struct tm *t, char type, int val)
238 if (!adjday(t, '+', (t->tm_hour + val) / 24))
247 if (!adjday(t, '-', val / 24))
250 if (val > t->tm_hour) {
251 if (!adjday(t, '-', 1))
264 return mktime(t) != -1;
268 adjmin(struct tm *t, char type, int val)
275 if (!adjhour(t, '+', (t->tm_min + val) / 60))
284 if (!adjhour(t, '-', val / 60))
287 if (val > t->tm_min) {
288 if (!adjhour(t, '-', 1))
301 return mktime(t) != -1;
305 vary_apply(const struct vary *v, struct tm *t)
313 for (; v; v = v->next) {
316 if (type == '+' || type == '-')
324 if (strspn(arg, digits) != len-1) {
325 val = trans(trans_wday, arg);
327 if (!adjwday(t, type, val, 1))
330 val = trans(trans_mon, arg);
332 if (!adjmon(t, type, val, 1))
343 if (!adjmin(t, type, val))
347 if (!adjhour(t, type, val))
351 if (!adjday(t, type, val))
355 if (!adjwday(t, type, val, 0))
359 if (!adjmon(t, type, val, 0))
363 if (!adjyear(t, type, val))
375 vary_destroy(struct vary *v)