xref: /freebsd/bin/date/vary.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1c39934eaSBrian Somers /*-
2c39934eaSBrian Somers  * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
3c39934eaSBrian Somers  * All rights reserved.
4c39934eaSBrian Somers  *
5c39934eaSBrian Somers  * Redistribution and use in source and binary forms, with or without
6c39934eaSBrian Somers  * modification, are permitted provided that the following conditions
7c39934eaSBrian Somers  * are met:
8c39934eaSBrian Somers  * 1. Redistributions of source code must retain the above copyright
9c39934eaSBrian Somers  *    notice, this list of conditions and the following disclaimer.
10c39934eaSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11c39934eaSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12c39934eaSBrian Somers  *    documentation and/or other materials provided with the distribution.
13c39934eaSBrian Somers  *
14c39934eaSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c39934eaSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c39934eaSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c39934eaSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c39934eaSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c39934eaSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c39934eaSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c39934eaSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c39934eaSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c39934eaSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c39934eaSBrian Somers  * SUCH DAMAGE.
25c39934eaSBrian Somers  */
26c39934eaSBrian Somers 
279afa09cdSMark Murray #include <sys/cdefs.h>
286e4cd31dSBrian Somers #include <err.h>
297ca215a6SBrian Somers #include <time.h>
30*4ef3964bSPedro F. Giffuni #include <stdint.h>
317ca215a6SBrian Somers #include <string.h>
327ca215a6SBrian Somers #include <stdlib.h>
337ca215a6SBrian Somers #include "vary.h"
347ca215a6SBrian Somers 
357ca215a6SBrian Somers struct trans {
36*4ef3964bSPedro F. Giffuni   int64_t val;
379afa09cdSMark Murray   const char *str;
387ca215a6SBrian Somers };
397ca215a6SBrian Somers 
407ca215a6SBrian Somers static struct trans trans_mon[] = {
417ca215a6SBrian Somers   { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
423b006d8eSAlfred Perlstein   { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
433b006d8eSAlfred Perlstein   { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
447ca215a6SBrian Somers   { -1, NULL }
457ca215a6SBrian Somers };
467ca215a6SBrian Somers 
477ca215a6SBrian Somers static struct trans trans_wday[] = {
487ca215a6SBrian Somers   { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
497ca215a6SBrian Somers   { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
507ca215a6SBrian Somers   { -1, NULL }
517ca215a6SBrian Somers };
527ca215a6SBrian Somers 
537ca215a6SBrian Somers static char digits[] = "0123456789";
54*4ef3964bSPedro F. Giffuni static int adjhour(struct tm *, char, int64_t, int);
55a625bfecSBrian Somers 
56a625bfecSBrian Somers static int
domktime(struct tm * t,char type)57a625bfecSBrian Somers domktime(struct tm *t, char type)
58a625bfecSBrian Somers {
599263db41SBrian Somers   time_t ret;
60a625bfecSBrian Somers 
619263db41SBrian Somers   while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
629263db41SBrian Somers     /* While mktime() fails, adjust by an hour */
639263db41SBrian Somers     adjhour(t, type == '-' ? type : '+', 1, 0);
64a625bfecSBrian Somers 
65a625bfecSBrian Somers   return ret;
66a625bfecSBrian Somers }
677ca215a6SBrian Somers 
687ca215a6SBrian Somers static int
trans(const struct trans t[],const char * arg)697ca215a6SBrian Somers trans(const struct trans t[], const char *arg)
707ca215a6SBrian Somers {
717ca215a6SBrian Somers   int f;
727ca215a6SBrian Somers 
737ca215a6SBrian Somers   for (f = 0; t[f].val != -1; f++)
74698f86e4SBrian Somers     if (!strncasecmp(t[f].str, arg, 3) ||
75698f86e4SBrian Somers         !strncasecmp(t[f].str, arg, strlen(t[f].str)))
767ca215a6SBrian Somers       return t[f].val;
777ca215a6SBrian Somers 
787ca215a6SBrian Somers   return -1;
797ca215a6SBrian Somers }
807ca215a6SBrian Somers 
817ca215a6SBrian Somers struct vary *
vary_append(struct vary * v,char * arg)82698f86e4SBrian Somers vary_append(struct vary *v, char *arg)
837ca215a6SBrian Somers {
847ca215a6SBrian Somers   struct vary *result, **nextp;
857ca215a6SBrian Somers 
867ca215a6SBrian Somers   if (v) {
877ca215a6SBrian Somers     result = v;
887ca215a6SBrian Somers     while (v->next)
897ca215a6SBrian Somers       v = v->next;
907ca215a6SBrian Somers     nextp = &v->next;
917ca215a6SBrian Somers   } else
927ca215a6SBrian Somers     nextp = &result;
937ca215a6SBrian Somers 
946e4cd31dSBrian Somers   if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
956e4cd31dSBrian Somers     err(1, "malloc");
967ca215a6SBrian Somers   (*nextp)->arg = arg;
977ca215a6SBrian Somers   (*nextp)->next = NULL;
987ca215a6SBrian Somers   return result;
997ca215a6SBrian Somers }
1007ca215a6SBrian Somers 
1017ca215a6SBrian Somers static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1027ca215a6SBrian Somers 
1037ca215a6SBrian Somers static int
daysinmonth(const struct tm * t)1047ca215a6SBrian Somers daysinmonth(const struct tm *t)
1057ca215a6SBrian Somers {
1067ca215a6SBrian Somers   int year;
1077ca215a6SBrian Somers 
1087ca215a6SBrian Somers   year = t->tm_year + 1900;
1097ca215a6SBrian Somers 
1107ca215a6SBrian Somers   if (t->tm_mon == 1)
1117ca215a6SBrian Somers     if (!(year % 400))
1127ca215a6SBrian Somers       return 29;
1137ca215a6SBrian Somers     else if (!(year % 100))
1147ca215a6SBrian Somers       return 28;
1157ca215a6SBrian Somers     else if (!(year % 4))
1167ca215a6SBrian Somers       return 29;
1177ca215a6SBrian Somers     else
1187ca215a6SBrian Somers       return 28;
1197ca215a6SBrian Somers   else if (t->tm_mon >= 0 && t->tm_mon < 12)
1207ca215a6SBrian Somers     return mdays[t->tm_mon];
1217ca215a6SBrian Somers 
1227ca215a6SBrian Somers   return 0;
1237ca215a6SBrian Somers }
1247ca215a6SBrian Somers 
1257ca215a6SBrian Somers 
1267ca215a6SBrian Somers static int
adjyear(struct tm * t,char type,int64_t val,int mk)127*4ef3964bSPedro F. Giffuni adjyear(struct tm *t, char type, int64_t val, int mk)
1287ca215a6SBrian Somers {
1297ca215a6SBrian Somers   switch (type) {
1307ca215a6SBrian Somers     case '+':
1317ca215a6SBrian Somers       t->tm_year += val;
1327ca215a6SBrian Somers       break;
1337ca215a6SBrian Somers     case '-':
1347ca215a6SBrian Somers       t->tm_year -= val;
1357ca215a6SBrian Somers       break;
1367ca215a6SBrian Somers     default:
1377ca215a6SBrian Somers       t->tm_year = val;
1387ca215a6SBrian Somers       if (t->tm_year < 69)
1397ca215a6SBrian Somers       	t->tm_year += 100;		/* as per date.c */
1407ca215a6SBrian Somers       else if (t->tm_year > 1900)
1417ca215a6SBrian Somers         t->tm_year -= 1900;             /* struct tm holds years since 1900 */
1427ca215a6SBrian Somers       break;
1437ca215a6SBrian Somers   }
1449263db41SBrian Somers   return !mk || domktime(t, type) != -1;
1457ca215a6SBrian Somers }
1467ca215a6SBrian Somers 
1477ca215a6SBrian Somers static int
adjmon(struct tm * t,char type,int64_t val,int istext,int mk)148*4ef3964bSPedro F. Giffuni adjmon(struct tm *t, char type, int64_t val, int istext, int mk)
1497ca215a6SBrian Somers {
150d3e240cbSYaroslav Tykhiy   int lmdays;
151d3e240cbSYaroslav Tykhiy 
1527ca215a6SBrian Somers   if (val < 0)
1537ca215a6SBrian Somers     return 0;
1547ca215a6SBrian Somers 
1557ca215a6SBrian Somers   switch (type) {
1567ca215a6SBrian Somers     case '+':
157426e9c1dSWarner Losh       if (istext) {
1587ca215a6SBrian Somers         if (val <= t->tm_mon)
1597ca215a6SBrian Somers           val += 11 - t->tm_mon;	/* early next year */
1607ca215a6SBrian Somers         else
1617ca215a6SBrian Somers           val -= t->tm_mon + 1;		/* later this year */
162426e9c1dSWarner Losh       }
163a625bfecSBrian Somers       if (val) {
1649263db41SBrian Somers         if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
1657ca215a6SBrian Somers           return 0;
1667ca215a6SBrian Somers         val %= 12;
1677ca215a6SBrian Somers         t->tm_mon += val;
1687ca215a6SBrian Somers         if (t->tm_mon > 11)
1697ca215a6SBrian Somers           t->tm_mon -= 12;
170a625bfecSBrian Somers       }
1717ca215a6SBrian Somers       break;
1727ca215a6SBrian Somers 
1737ca215a6SBrian Somers     case '-':
174426e9c1dSWarner Losh       if (istext) {
1757ca215a6SBrian Somers         if (val-1 > t->tm_mon)
1767ca215a6SBrian Somers           val = 13 - val + t->tm_mon;	/* later last year */
1777ca215a6SBrian Somers         else
1787ca215a6SBrian Somers           val = t->tm_mon - val + 1;	/* early this year */
179426e9c1dSWarner Losh       }
180a625bfecSBrian Somers       if (val) {
1819263db41SBrian Somers         if (!adjyear(t, '-', val / 12, 0))
1827ca215a6SBrian Somers           return 0;
1837ca215a6SBrian Somers         val %= 12;
1847ca215a6SBrian Somers         if (val > t->tm_mon) {
1859263db41SBrian Somers           if (!adjyear(t, '-', 1, 0))
1867ca215a6SBrian Somers             return 0;
1877ca215a6SBrian Somers           val -= 12;
1887ca215a6SBrian Somers         }
1897ca215a6SBrian Somers         t->tm_mon -= val;
190a625bfecSBrian Somers       }
1917ca215a6SBrian Somers       break;
1927ca215a6SBrian Somers 
1937ca215a6SBrian Somers     default:
1947ca215a6SBrian Somers       if (val > 12 || val < 1)
1957ca215a6SBrian Somers         return 0;
1967ca215a6SBrian Somers       t->tm_mon = --val;
1977ca215a6SBrian Somers   }
1987ca215a6SBrian Somers 
199d3e240cbSYaroslav Tykhiy   /* e.g., -v-1m on March, 31 is the last day of February in common sense */
200d3e240cbSYaroslav Tykhiy   lmdays = daysinmonth(t);
201d3e240cbSYaroslav Tykhiy   if (t->tm_mday > lmdays)
202d3e240cbSYaroslav Tykhiy     t->tm_mday = lmdays;
203d3e240cbSYaroslav Tykhiy 
2049263db41SBrian Somers   return !mk || domktime(t, type) != -1;
2057ca215a6SBrian Somers }
2067ca215a6SBrian Somers 
2077ca215a6SBrian Somers static int
adjday(struct tm * t,char type,int64_t val,int mk)208*4ef3964bSPedro F. Giffuni adjday(struct tm *t, char type, int64_t val, int mk)
2097ca215a6SBrian Somers {
2109afa09cdSMark Murray   int lmdays;
211a625bfecSBrian Somers 
2127ca215a6SBrian Somers   switch (type) {
2137ca215a6SBrian Somers     case '+':
2147ca215a6SBrian Somers       while (val) {
2159afa09cdSMark Murray         lmdays = daysinmonth(t);
2169afa09cdSMark Murray         if (val > lmdays - t->tm_mday) {
2179afa09cdSMark Murray           val -= lmdays - t->tm_mday + 1;
2187ca215a6SBrian Somers           t->tm_mday = 1;
2199263db41SBrian Somers           if (!adjmon(t, '+', 1, 0, 0))
2207ca215a6SBrian Somers             return 0;
2217ca215a6SBrian Somers         } else {
2227ca215a6SBrian Somers           t->tm_mday += val;
2237ca215a6SBrian Somers           val = 0;
2247ca215a6SBrian Somers         }
2257ca215a6SBrian Somers       }
2267ca215a6SBrian Somers       break;
2277ca215a6SBrian Somers     case '-':
2287ca215a6SBrian Somers       while (val)
2297ca215a6SBrian Somers         if (val >= t->tm_mday) {
2307ca215a6SBrian Somers           val -= t->tm_mday;
2317ca215a6SBrian Somers           t->tm_mday = 1;
2329263db41SBrian Somers           if (!adjmon(t, '-', 1, 0, 0))
2337ca215a6SBrian Somers             return 0;
2347ca215a6SBrian Somers           t->tm_mday = daysinmonth(t);
2357ca215a6SBrian Somers         } else {
2367ca215a6SBrian Somers           t->tm_mday -= val;
2377ca215a6SBrian Somers           val = 0;
2387ca215a6SBrian Somers         }
2397ca215a6SBrian Somers       break;
2407ca215a6SBrian Somers     default:
2417ca215a6SBrian Somers       if (val > 0 && val <= daysinmonth(t))
2427ca215a6SBrian Somers         t->tm_mday = val;
2437ca215a6SBrian Somers       else
2447ca215a6SBrian Somers         return 0;
2457ca215a6SBrian Somers       break;
2467ca215a6SBrian Somers   }
2477ca215a6SBrian Somers 
2489263db41SBrian Somers   return !mk || domktime(t, type) != -1;
2497ca215a6SBrian Somers }
2507ca215a6SBrian Somers 
2517ca215a6SBrian Somers static int
adjwday(struct tm * t,char type,int64_t val,int istext,int mk)252*4ef3964bSPedro F. Giffuni adjwday(struct tm *t, char type, int64_t val, int istext, int mk)
2537ca215a6SBrian Somers {
2547ca215a6SBrian Somers   if (val < 0)
2557ca215a6SBrian Somers     return 0;
2567ca215a6SBrian Somers 
257698f86e4SBrian Somers   switch (type) {
2587ca215a6SBrian Somers     case '+':
2597ca215a6SBrian Somers       if (istext)
2607ca215a6SBrian Somers         if (val < t->tm_wday)
2617ca215a6SBrian Somers           val = 7 - t->tm_wday + val;  /* early next week */
2627ca215a6SBrian Somers         else
2637ca215a6SBrian Somers           val -= t->tm_wday;           /* later this week */
2647ca215a6SBrian Somers       else
265a625bfecSBrian Somers         val *= 7;                      /* "-v+5w" == "5 weeks in the future" */
2667ecff35bSBrian Somers       return !val || adjday(t, '+', val, mk);
2677ca215a6SBrian Somers     case '-':
268a625bfecSBrian Somers       if (istext) {
2697ca215a6SBrian Somers         if (val > t->tm_wday)
2707ca215a6SBrian Somers           val = 7 - val + t->tm_wday;  /* later last week */
2717ca215a6SBrian Somers         else
2727ca215a6SBrian Somers           val = t->tm_wday - val;      /* early this week */
273a625bfecSBrian Somers       } else
274a625bfecSBrian Somers         val *= 7;                      /* "-v-5w" == "5 weeks ago" */
2757ecff35bSBrian Somers       return !val || adjday(t, '-', val, mk);
2767ca215a6SBrian Somers     default:
2777ca215a6SBrian Somers       if (val < t->tm_wday)
2787ecff35bSBrian Somers         return adjday(t, '-', t->tm_wday - val, mk);
2797ca215a6SBrian Somers       else if (val > 6)
2807ca215a6SBrian Somers         return 0;
2817ca215a6SBrian Somers       else if (val > t->tm_wday)
2827ecff35bSBrian Somers         return adjday(t, '+', val - t->tm_wday, mk);
2837ca215a6SBrian Somers   }
2847ca215a6SBrian Somers   return 1;
2857ca215a6SBrian Somers }
2867ca215a6SBrian Somers 
2877ca215a6SBrian Somers static int
adjhour(struct tm * t,char type,int64_t val,int mk)288*4ef3964bSPedro F. Giffuni adjhour(struct tm *t, char type, int64_t val, int mk)
2897ca215a6SBrian Somers {
290698f86e4SBrian Somers   if (val < 0)
291698f86e4SBrian Somers     return 0;
292698f86e4SBrian Somers 
293698f86e4SBrian Somers   switch (type) {
2947ca215a6SBrian Somers     case '+':
295a625bfecSBrian Somers       if (val) {
296a625bfecSBrian Somers         int days;
297a625bfecSBrian Somers 
298a625bfecSBrian Somers         days = (t->tm_hour + val) / 24;
299698f86e4SBrian Somers         val %= 24;
300698f86e4SBrian Somers         t->tm_hour += val;
301a625bfecSBrian Somers         t->tm_hour %= 24;
3029263db41SBrian Somers         if (!adjday(t, '+', days, 0))
303a625bfecSBrian Somers           return 0;
304a625bfecSBrian Somers       }
305698f86e4SBrian Somers       break;
306698f86e4SBrian Somers 
3077ca215a6SBrian Somers     case '-':
308a625bfecSBrian Somers       if (val) {
309a625bfecSBrian Somers         int days;
310a625bfecSBrian Somers 
311a625bfecSBrian Somers         days = val / 24;
312698f86e4SBrian Somers         val %= 24;
313698f86e4SBrian Somers         if (val > t->tm_hour) {
314a625bfecSBrian Somers           days++;
315698f86e4SBrian Somers           val -= 24;
3167ca215a6SBrian Somers         }
317698f86e4SBrian Somers         t->tm_hour -= val;
3189263db41SBrian Somers         if (!adjday(t, '-', days, 0))
319a625bfecSBrian Somers           return 0;
320a625bfecSBrian Somers       }
321698f86e4SBrian Somers       break;
322698f86e4SBrian Somers 
323698f86e4SBrian Somers     default:
324698f86e4SBrian Somers       if (val > 23)
325698f86e4SBrian Somers         return 0;
326698f86e4SBrian Somers       t->tm_hour = val;
327698f86e4SBrian Somers   }
328698f86e4SBrian Somers 
3299263db41SBrian Somers   return !mk || domktime(t, type) != -1;
330698f86e4SBrian Somers }
331698f86e4SBrian Somers 
332698f86e4SBrian Somers static int
adjmin(struct tm * t,char type,int64_t val,int mk)333*4ef3964bSPedro F. Giffuni adjmin(struct tm *t, char type, int64_t val, int mk)
334698f86e4SBrian Somers {
335698f86e4SBrian Somers   if (val < 0)
336698f86e4SBrian Somers     return 0;
337698f86e4SBrian Somers 
338698f86e4SBrian Somers   switch (type) {
339698f86e4SBrian Somers     case '+':
340a625bfecSBrian Somers       if (val) {
3419263db41SBrian Somers         if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
342698f86e4SBrian Somers           return 0;
343698f86e4SBrian Somers         val %= 60;
344698f86e4SBrian Somers         t->tm_min += val;
345698f86e4SBrian Somers         if (t->tm_min > 59)
346698f86e4SBrian Somers           t->tm_min -= 60;
347a625bfecSBrian Somers       }
348698f86e4SBrian Somers       break;
349698f86e4SBrian Somers 
350698f86e4SBrian Somers     case '-':
351a625bfecSBrian Somers       if (val) {
3529263db41SBrian Somers         if (!adjhour(t, '-', val / 60, 0))
353698f86e4SBrian Somers           return 0;
354698f86e4SBrian Somers         val %= 60;
355698f86e4SBrian Somers         if (val > t->tm_min) {
3569263db41SBrian Somers           if (!adjhour(t, '-', 1, 0))
357698f86e4SBrian Somers             return 0;
358698f86e4SBrian Somers           val -= 60;
359698f86e4SBrian Somers         }
360698f86e4SBrian Somers         t->tm_min -= val;
361a625bfecSBrian Somers       }
362698f86e4SBrian Somers       break;
363698f86e4SBrian Somers 
364698f86e4SBrian Somers     default:
365698f86e4SBrian Somers       if (val > 59)
366698f86e4SBrian Somers         return 0;
367698f86e4SBrian Somers       t->tm_min = val;
368698f86e4SBrian Somers   }
369698f86e4SBrian Somers 
3709263db41SBrian Somers   return !mk || domktime(t, type) != -1;
3717ca215a6SBrian Somers }
3727ca215a6SBrian Somers 
373269dfbeeSBrian Somers static int
adjsec(struct tm * t,char type,int64_t val,int mk)374*4ef3964bSPedro F. Giffuni adjsec(struct tm *t, char type, int64_t val, int mk)
375269dfbeeSBrian Somers {
376269dfbeeSBrian Somers   if (val < 0)
377269dfbeeSBrian Somers     return 0;
378269dfbeeSBrian Somers 
379269dfbeeSBrian Somers   switch (type) {
380269dfbeeSBrian Somers     case '+':
381a625bfecSBrian Somers       if (val) {
3829263db41SBrian Somers         if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
383269dfbeeSBrian Somers           return 0;
384269dfbeeSBrian Somers         val %= 60;
385269dfbeeSBrian Somers         t->tm_sec += val;
386269dfbeeSBrian Somers         if (t->tm_sec > 59)
387269dfbeeSBrian Somers           t->tm_sec -= 60;
388a625bfecSBrian Somers       }
389269dfbeeSBrian Somers       break;
390269dfbeeSBrian Somers 
391269dfbeeSBrian Somers     case '-':
392a625bfecSBrian Somers       if (val) {
3939263db41SBrian Somers         if (!adjmin(t, '-', val / 60, 0))
394269dfbeeSBrian Somers           return 0;
395269dfbeeSBrian Somers         val %= 60;
396269dfbeeSBrian Somers         if (val > t->tm_sec) {
3979263db41SBrian Somers           if (!adjmin(t, '-', 1, 0))
398269dfbeeSBrian Somers             return 0;
399269dfbeeSBrian Somers           val -= 60;
400269dfbeeSBrian Somers         }
401269dfbeeSBrian Somers         t->tm_sec -= val;
402a625bfecSBrian Somers       }
403269dfbeeSBrian Somers       break;
404269dfbeeSBrian Somers 
405269dfbeeSBrian Somers     default:
406269dfbeeSBrian Somers       if (val > 59)
407269dfbeeSBrian Somers         return 0;
408269dfbeeSBrian Somers       t->tm_sec = val;
409269dfbeeSBrian Somers   }
410269dfbeeSBrian Somers 
4119263db41SBrian Somers   return !mk || domktime(t, type) != -1;
412269dfbeeSBrian Somers }
413269dfbeeSBrian Somers 
4147ca215a6SBrian Somers const struct vary *
vary_apply(const struct vary * v,struct tm * t)4157ca215a6SBrian Somers vary_apply(const struct vary *v, struct tm *t)
4167ca215a6SBrian Somers {
417698f86e4SBrian Somers   char type;
418698f86e4SBrian Somers   char which;
419698f86e4SBrian Somers   char *arg;
4209afa09cdSMark Murray   size_t len;
421*4ef3964bSPedro F. Giffuni   int64_t val;
422698f86e4SBrian Somers 
4237ca215a6SBrian Somers   for (; v; v = v->next) {
424698f86e4SBrian Somers     type = *v->arg;
425698f86e4SBrian Somers     arg = v->arg;
426698f86e4SBrian Somers     if (type == '+' || type == '-')
427698f86e4SBrian Somers       arg++;
428698f86e4SBrian Somers     else
429698f86e4SBrian Somers       type = '\0';
430698f86e4SBrian Somers     len = strlen(arg);
431698f86e4SBrian Somers     if (len < 2)
4327ca215a6SBrian Somers       return v;
433698f86e4SBrian Somers 
4349263db41SBrian Somers     if (type == '\0')
4359263db41SBrian Somers       t->tm_isdst = -1;
4369263db41SBrian Somers 
437698f86e4SBrian Somers     if (strspn(arg, digits) != len-1) {
438698f86e4SBrian Somers       val = trans(trans_wday, arg);
439698f86e4SBrian Somers       if (val != -1) {
4409263db41SBrian Somers           if (!adjwday(t, type, val, 1, 1))
4417ca215a6SBrian Somers             return v;
442698f86e4SBrian Somers       } else {
443698f86e4SBrian Somers         val = trans(trans_mon, arg);
444698f86e4SBrian Somers         if (val != -1) {
4459263db41SBrian Somers           if (!adjmon(t, type, val, 1, 1))
446698f86e4SBrian Somers             return v;
447698f86e4SBrian Somers         } else
448698f86e4SBrian Somers           return v;
449698f86e4SBrian Somers       }
450698f86e4SBrian Somers     } else {
451698f86e4SBrian Somers       val = atoi(arg);
452698f86e4SBrian Somers       which = arg[len-1];
453698f86e4SBrian Somers 
454698f86e4SBrian Somers       switch (which) {
455269dfbeeSBrian Somers         case 'S':
4569263db41SBrian Somers           if (!adjsec(t, type, val, 1))
457269dfbeeSBrian Somers             return v;
458269dfbeeSBrian Somers           break;
4597ca215a6SBrian Somers         case 'M':
4609263db41SBrian Somers           if (!adjmin(t, type, val, 1))
4617ca215a6SBrian Somers             return v;
4627ca215a6SBrian Somers           break;
463698f86e4SBrian Somers         case 'H':
4649263db41SBrian Somers           if (!adjhour(t, type, val, 1))
465698f86e4SBrian Somers             return v;
466698f86e4SBrian Somers           break;
467698f86e4SBrian Somers         case 'd':
4689263db41SBrian Somers           t->tm_isdst = -1;
4699263db41SBrian Somers           if (!adjday(t, type, val, 1))
470698f86e4SBrian Somers             return v;
471698f86e4SBrian Somers           break;
472698f86e4SBrian Somers         case 'w':
4739263db41SBrian Somers           t->tm_isdst = -1;
4749263db41SBrian Somers           if (!adjwday(t, type, val, 0, 1))
475698f86e4SBrian Somers             return v;
476698f86e4SBrian Somers           break;
477698f86e4SBrian Somers         case 'm':
4789263db41SBrian Somers           t->tm_isdst = -1;
4799263db41SBrian Somers           if (!adjmon(t, type, val, 0, 1))
480698f86e4SBrian Somers             return v;
481698f86e4SBrian Somers           break;
482698f86e4SBrian Somers         case 'y':
4839263db41SBrian Somers           t->tm_isdst = -1;
4849263db41SBrian Somers           if (!adjyear(t, type, val, 1))
4857ca215a6SBrian Somers             return v;
4867ca215a6SBrian Somers           break;
4877ca215a6SBrian Somers         default:
4887ca215a6SBrian Somers           return v;
4897ca215a6SBrian Somers       }
4907ca215a6SBrian Somers     }
491698f86e4SBrian Somers   }
4927ca215a6SBrian Somers   return 0;
4937ca215a6SBrian Somers }
4947ca215a6SBrian Somers 
4957ca215a6SBrian Somers void
vary_destroy(struct vary * v)4967ca215a6SBrian Somers vary_destroy(struct vary *v)
4977ca215a6SBrian Somers {
4987ca215a6SBrian Somers   struct vary *n;
4997ca215a6SBrian Somers 
5007ca215a6SBrian Somers   while (v) {
5017ca215a6SBrian Somers     n = v->next;
5027ca215a6SBrian Somers     free(v);
5037ca215a6SBrian Somers     v = n;
5047ca215a6SBrian Somers   }
5057ca215a6SBrian Somers }
506