xref: /freebsd/bin/date/vary.c (revision 9afa09cd0eb32581d301f6b9f9dc252e2a879a05)
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 
27cbf6f7d3SPhilippe Charnier #ifndef lint
28cbf6f7d3SPhilippe Charnier static const char rcsid[] =
292a456239SPeter Wemm   "$FreeBSD$";
30cbf6f7d3SPhilippe Charnier #endif /* not lint */
31cbf6f7d3SPhilippe Charnier 
329afa09cdSMark Murray #include <sys/cdefs.h>
336e4cd31dSBrian Somers #include <err.h>
347ca215a6SBrian Somers #include <time.h>
357ca215a6SBrian Somers #include <string.h>
367ca215a6SBrian Somers #include <stdlib.h>
377ca215a6SBrian Somers #include "vary.h"
387ca215a6SBrian Somers 
397ca215a6SBrian Somers struct trans {
407ca215a6SBrian Somers   int val;
419afa09cdSMark Murray   const char *str;
427ca215a6SBrian Somers };
437ca215a6SBrian Somers 
447ca215a6SBrian Somers static struct trans trans_mon[] = {
457ca215a6SBrian Somers   { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
463b006d8eSAlfred Perlstein   { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
473b006d8eSAlfred Perlstein   { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
487ca215a6SBrian Somers   { -1, NULL }
497ca215a6SBrian Somers };
507ca215a6SBrian Somers 
517ca215a6SBrian Somers static struct trans trans_wday[] = {
527ca215a6SBrian Somers   { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
537ca215a6SBrian Somers   { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
547ca215a6SBrian Somers   { -1, NULL }
557ca215a6SBrian Somers };
567ca215a6SBrian Somers 
577ca215a6SBrian Somers static char digits[] = "0123456789";
589263db41SBrian Somers static int adjhour(struct tm *, char, int, int);
59a625bfecSBrian Somers 
60a625bfecSBrian Somers static int
61a625bfecSBrian Somers domktime(struct tm *t, char type)
62a625bfecSBrian Somers {
639263db41SBrian Somers   time_t ret;
64a625bfecSBrian Somers 
659263db41SBrian Somers   while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
669263db41SBrian Somers     /* While mktime() fails, adjust by an hour */
679263db41SBrian Somers     adjhour(t, type == '-' ? type : '+', 1, 0);
68a625bfecSBrian Somers 
69a625bfecSBrian Somers   return ret;
70a625bfecSBrian Somers }
717ca215a6SBrian Somers 
727ca215a6SBrian Somers static int
737ca215a6SBrian Somers trans(const struct trans t[], const char *arg)
747ca215a6SBrian Somers {
757ca215a6SBrian Somers   int f;
767ca215a6SBrian Somers 
777ca215a6SBrian Somers   for (f = 0; t[f].val != -1; f++)
78698f86e4SBrian Somers     if (!strncasecmp(t[f].str, arg, 3) ||
79698f86e4SBrian Somers         !strncasecmp(t[f].str, arg, strlen(t[f].str)))
807ca215a6SBrian Somers       return t[f].val;
817ca215a6SBrian Somers 
827ca215a6SBrian Somers   return -1;
837ca215a6SBrian Somers }
847ca215a6SBrian Somers 
857ca215a6SBrian Somers struct vary *
86698f86e4SBrian Somers vary_append(struct vary *v, char *arg)
877ca215a6SBrian Somers {
887ca215a6SBrian Somers   struct vary *result, **nextp;
897ca215a6SBrian Somers 
907ca215a6SBrian Somers   if (v) {
917ca215a6SBrian Somers     result = v;
927ca215a6SBrian Somers     while (v->next)
937ca215a6SBrian Somers       v = v->next;
947ca215a6SBrian Somers     nextp = &v->next;
957ca215a6SBrian Somers   } else
967ca215a6SBrian Somers     nextp = &result;
977ca215a6SBrian Somers 
986e4cd31dSBrian Somers   if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
996e4cd31dSBrian Somers     err(1, "malloc");
1007ca215a6SBrian Somers   (*nextp)->arg = arg;
1017ca215a6SBrian Somers   (*nextp)->next = NULL;
1027ca215a6SBrian Somers   return result;
1037ca215a6SBrian Somers }
1047ca215a6SBrian Somers 
1057ca215a6SBrian Somers static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1067ca215a6SBrian Somers 
1077ca215a6SBrian Somers static int
1087ca215a6SBrian Somers daysinmonth(const struct tm *t)
1097ca215a6SBrian Somers {
1107ca215a6SBrian Somers   int year;
1117ca215a6SBrian Somers 
1127ca215a6SBrian Somers   year = t->tm_year + 1900;
1137ca215a6SBrian Somers 
1147ca215a6SBrian Somers   if (t->tm_mon == 1)
1157ca215a6SBrian Somers     if (!(year % 400))
1167ca215a6SBrian Somers       return 29;
1177ca215a6SBrian Somers     else if (!(year % 100))
1187ca215a6SBrian Somers       return 28;
1197ca215a6SBrian Somers     else if (!(year % 4))
1207ca215a6SBrian Somers       return 29;
1217ca215a6SBrian Somers     else
1227ca215a6SBrian Somers       return 28;
1237ca215a6SBrian Somers   else if (t->tm_mon >= 0 && t->tm_mon < 12)
1247ca215a6SBrian Somers     return mdays[t->tm_mon];
1257ca215a6SBrian Somers 
1267ca215a6SBrian Somers   return 0;
1277ca215a6SBrian Somers }
1287ca215a6SBrian Somers 
1297ca215a6SBrian Somers 
1307ca215a6SBrian Somers static int
1319263db41SBrian Somers adjyear(struct tm *t, char type, int val, int mk)
1327ca215a6SBrian Somers {
1337ca215a6SBrian Somers   switch (type) {
1347ca215a6SBrian Somers     case '+':
1357ca215a6SBrian Somers       t->tm_year += val;
1367ca215a6SBrian Somers       break;
1377ca215a6SBrian Somers     case '-':
1387ca215a6SBrian Somers       t->tm_year -= val;
1397ca215a6SBrian Somers       break;
1407ca215a6SBrian Somers     default:
1417ca215a6SBrian Somers       t->tm_year = val;
1427ca215a6SBrian Somers       if (t->tm_year < 69)
1437ca215a6SBrian Somers       	t->tm_year += 100;		/* as per date.c */
1447ca215a6SBrian Somers       else if (t->tm_year > 1900)
1457ca215a6SBrian Somers         t->tm_year -= 1900;             /* struct tm holds years since 1900 */
1467ca215a6SBrian Somers       break;
1477ca215a6SBrian Somers   }
1489263db41SBrian Somers   return !mk || domktime(t, type) != -1;
1497ca215a6SBrian Somers }
1507ca215a6SBrian Somers 
1517ca215a6SBrian Somers static int
1529263db41SBrian Somers adjmon(struct tm *t, char type, int val, int istext, int mk)
1537ca215a6SBrian Somers {
1547ca215a6SBrian Somers   if (val < 0)
1557ca215a6SBrian Somers     return 0;
1567ca215a6SBrian Somers 
1577ca215a6SBrian Somers   switch (type) {
1587ca215a6SBrian Somers     case '+':
159426e9c1dSWarner Losh       if (istext) {
1607ca215a6SBrian Somers         if (val <= t->tm_mon)
1617ca215a6SBrian Somers           val += 11 - t->tm_mon;	/* early next year */
1627ca215a6SBrian Somers         else
1637ca215a6SBrian Somers           val -= t->tm_mon + 1;		/* later this year */
164426e9c1dSWarner Losh       }
165a625bfecSBrian Somers       if (val) {
1669263db41SBrian Somers         if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
1677ca215a6SBrian Somers           return 0;
1687ca215a6SBrian Somers         val %= 12;
1697ca215a6SBrian Somers         t->tm_mon += val;
1707ca215a6SBrian Somers         if (t->tm_mon > 11)
1717ca215a6SBrian Somers           t->tm_mon -= 12;
172a625bfecSBrian Somers       }
1737ca215a6SBrian Somers       break;
1747ca215a6SBrian Somers 
1757ca215a6SBrian Somers     case '-':
176426e9c1dSWarner Losh       if (istext) {
1777ca215a6SBrian Somers         if (val-1 > t->tm_mon)
1787ca215a6SBrian Somers           val = 13 - val + t->tm_mon;	/* later last year */
1797ca215a6SBrian Somers         else
1807ca215a6SBrian Somers           val = t->tm_mon - val + 1;	/* early this year */
181426e9c1dSWarner Losh       }
182a625bfecSBrian Somers       if (val) {
1839263db41SBrian Somers         if (!adjyear(t, '-', val / 12, 0))
1847ca215a6SBrian Somers           return 0;
1857ca215a6SBrian Somers         val %= 12;
1867ca215a6SBrian Somers         if (val > t->tm_mon) {
1879263db41SBrian Somers           if (!adjyear(t, '-', 1, 0))
1887ca215a6SBrian Somers             return 0;
1897ca215a6SBrian Somers           val -= 12;
1907ca215a6SBrian Somers         }
1917ca215a6SBrian Somers         t->tm_mon -= val;
192a625bfecSBrian Somers       }
1937ca215a6SBrian Somers       break;
1947ca215a6SBrian Somers 
1957ca215a6SBrian Somers     default:
1967ca215a6SBrian Somers       if (val > 12 || val < 1)
1977ca215a6SBrian Somers         return 0;
1987ca215a6SBrian Somers       t->tm_mon = --val;
1997ca215a6SBrian Somers   }
2007ca215a6SBrian Somers 
2019263db41SBrian Somers   return !mk || domktime(t, type) != -1;
2027ca215a6SBrian Somers }
2037ca215a6SBrian Somers 
2047ca215a6SBrian Somers static int
2059263db41SBrian Somers adjday(struct tm *t, char type, int val, int mk)
2067ca215a6SBrian Somers {
2079afa09cdSMark Murray   int lmdays;
208a625bfecSBrian Somers 
2097ca215a6SBrian Somers   switch (type) {
2107ca215a6SBrian Somers     case '+':
2117ca215a6SBrian Somers       while (val) {
2129afa09cdSMark Murray         lmdays = daysinmonth(t);
2139afa09cdSMark Murray         if (val > lmdays - t->tm_mday) {
2149afa09cdSMark Murray           val -= lmdays - t->tm_mday + 1;
2157ca215a6SBrian Somers           t->tm_mday = 1;
2169263db41SBrian Somers           if (!adjmon(t, '+', 1, 0, 0))
2177ca215a6SBrian Somers             return 0;
2187ca215a6SBrian Somers         } else {
2197ca215a6SBrian Somers           t->tm_mday += val;
2207ca215a6SBrian Somers           val = 0;
2217ca215a6SBrian Somers         }
2227ca215a6SBrian Somers       }
2237ca215a6SBrian Somers       break;
2247ca215a6SBrian Somers     case '-':
2257ca215a6SBrian Somers       while (val)
2267ca215a6SBrian Somers         if (val >= t->tm_mday) {
2277ca215a6SBrian Somers           val -= t->tm_mday;
2287ca215a6SBrian Somers           t->tm_mday = 1;
2299263db41SBrian Somers           if (!adjmon(t, '-', 1, 0, 0))
2307ca215a6SBrian Somers             return 0;
2317ca215a6SBrian Somers           t->tm_mday = daysinmonth(t);
2327ca215a6SBrian Somers         } else {
2337ca215a6SBrian Somers           t->tm_mday -= val;
2347ca215a6SBrian Somers           val = 0;
2357ca215a6SBrian Somers         }
2367ca215a6SBrian Somers       break;
2377ca215a6SBrian Somers     default:
2387ca215a6SBrian Somers       if (val > 0 && val <= daysinmonth(t))
2397ca215a6SBrian Somers         t->tm_mday = val;
2407ca215a6SBrian Somers       else
2417ca215a6SBrian Somers         return 0;
2427ca215a6SBrian Somers       break;
2437ca215a6SBrian Somers   }
2447ca215a6SBrian Somers 
2459263db41SBrian Somers   return !mk || domktime(t, type) != -1;
2467ca215a6SBrian Somers }
2477ca215a6SBrian Somers 
2487ca215a6SBrian Somers static int
2499263db41SBrian Somers adjwday(struct tm *t, char type, int val, int istext, int mk)
2507ca215a6SBrian Somers {
2517ca215a6SBrian Somers   if (val < 0)
2527ca215a6SBrian Somers     return 0;
2537ca215a6SBrian Somers 
254698f86e4SBrian Somers   switch (type) {
2557ca215a6SBrian Somers     case '+':
2567ca215a6SBrian Somers       if (istext)
2577ca215a6SBrian Somers         if (val < t->tm_wday)
2587ca215a6SBrian Somers           val = 7 - t->tm_wday + val;  /* early next week */
2597ca215a6SBrian Somers         else
2607ca215a6SBrian Somers           val -= t->tm_wday;           /* later this week */
2617ca215a6SBrian Somers       else
262a625bfecSBrian Somers         val *= 7;                      /* "-v+5w" == "5 weeks in the future" */
2637ecff35bSBrian Somers       return !val || adjday(t, '+', val, mk);
2647ca215a6SBrian Somers     case '-':
265a625bfecSBrian Somers       if (istext) {
2667ca215a6SBrian Somers         if (val > t->tm_wday)
2677ca215a6SBrian Somers           val = 7 - val + t->tm_wday;  /* later last week */
2687ca215a6SBrian Somers         else
2697ca215a6SBrian Somers           val = t->tm_wday - val;      /* early this week */
270a625bfecSBrian Somers       } else
271a625bfecSBrian Somers         val *= 7;                      /* "-v-5w" == "5 weeks ago" */
2727ecff35bSBrian Somers       return !val || adjday(t, '-', val, mk);
2737ca215a6SBrian Somers     default:
2747ca215a6SBrian Somers       if (val < t->tm_wday)
2757ecff35bSBrian Somers         return adjday(t, '-', t->tm_wday - val, mk);
2767ca215a6SBrian Somers       else if (val > 6)
2777ca215a6SBrian Somers         return 0;
2787ca215a6SBrian Somers       else if (val > t->tm_wday)
2797ecff35bSBrian Somers         return adjday(t, '+', val - t->tm_wday, mk);
2807ca215a6SBrian Somers   }
2817ca215a6SBrian Somers   return 1;
2827ca215a6SBrian Somers }
2837ca215a6SBrian Somers 
2847ca215a6SBrian Somers static int
2859263db41SBrian Somers adjhour(struct tm *t, char type, int val, int mk)
2867ca215a6SBrian Somers {
287698f86e4SBrian Somers   if (val < 0)
288698f86e4SBrian Somers     return 0;
289698f86e4SBrian Somers 
290698f86e4SBrian Somers   switch (type) {
2917ca215a6SBrian Somers     case '+':
292a625bfecSBrian Somers       if (val) {
293a625bfecSBrian Somers         int days;
294a625bfecSBrian Somers 
295a625bfecSBrian Somers         days = (t->tm_hour + val) / 24;
296698f86e4SBrian Somers         val %= 24;
297698f86e4SBrian Somers         t->tm_hour += val;
298a625bfecSBrian Somers         t->tm_hour %= 24;
2999263db41SBrian Somers         if (!adjday(t, '+', days, 0))
300a625bfecSBrian Somers           return 0;
301a625bfecSBrian Somers       }
302698f86e4SBrian Somers       break;
303698f86e4SBrian Somers 
3047ca215a6SBrian Somers     case '-':
305a625bfecSBrian Somers       if (val) {
306a625bfecSBrian Somers         int days;
307a625bfecSBrian Somers 
308a625bfecSBrian Somers         days = val / 24;
309698f86e4SBrian Somers         val %= 24;
310698f86e4SBrian Somers         if (val > t->tm_hour) {
311a625bfecSBrian Somers           days++;
312698f86e4SBrian Somers           val -= 24;
3137ca215a6SBrian Somers         }
314698f86e4SBrian Somers         t->tm_hour -= val;
3159263db41SBrian Somers         if (!adjday(t, '-', days, 0))
316a625bfecSBrian Somers           return 0;
317a625bfecSBrian Somers       }
318698f86e4SBrian Somers       break;
319698f86e4SBrian Somers 
320698f86e4SBrian Somers     default:
321698f86e4SBrian Somers       if (val > 23)
322698f86e4SBrian Somers         return 0;
323698f86e4SBrian Somers       t->tm_hour = val;
324698f86e4SBrian Somers   }
325698f86e4SBrian Somers 
3269263db41SBrian Somers   return !mk || domktime(t, type) != -1;
327698f86e4SBrian Somers }
328698f86e4SBrian Somers 
329698f86e4SBrian Somers static int
3309263db41SBrian Somers adjmin(struct tm *t, char type, int val, int mk)
331698f86e4SBrian Somers {
332698f86e4SBrian Somers   if (val < 0)
333698f86e4SBrian Somers     return 0;
334698f86e4SBrian Somers 
335698f86e4SBrian Somers   switch (type) {
336698f86e4SBrian Somers     case '+':
337a625bfecSBrian Somers       if (val) {
3389263db41SBrian Somers         if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
339698f86e4SBrian Somers           return 0;
340698f86e4SBrian Somers         val %= 60;
341698f86e4SBrian Somers         t->tm_min += val;
342698f86e4SBrian Somers         if (t->tm_min > 59)
343698f86e4SBrian Somers           t->tm_min -= 60;
344a625bfecSBrian Somers       }
345698f86e4SBrian Somers       break;
346698f86e4SBrian Somers 
347698f86e4SBrian Somers     case '-':
348a625bfecSBrian Somers       if (val) {
3499263db41SBrian Somers         if (!adjhour(t, '-', val / 60, 0))
350698f86e4SBrian Somers           return 0;
351698f86e4SBrian Somers         val %= 60;
352698f86e4SBrian Somers         if (val > t->tm_min) {
3539263db41SBrian Somers           if (!adjhour(t, '-', 1, 0))
354698f86e4SBrian Somers             return 0;
355698f86e4SBrian Somers           val -= 60;
356698f86e4SBrian Somers         }
357698f86e4SBrian Somers         t->tm_min -= val;
358a625bfecSBrian Somers       }
359698f86e4SBrian Somers       break;
360698f86e4SBrian Somers 
361698f86e4SBrian Somers     default:
362698f86e4SBrian Somers       if (val > 59)
363698f86e4SBrian Somers         return 0;
364698f86e4SBrian Somers       t->tm_min = val;
365698f86e4SBrian Somers   }
366698f86e4SBrian Somers 
3679263db41SBrian Somers   return !mk || domktime(t, type) != -1;
3687ca215a6SBrian Somers }
3697ca215a6SBrian Somers 
370269dfbeeSBrian Somers static int
3719263db41SBrian Somers adjsec(struct tm *t, char type, int val, int mk)
372269dfbeeSBrian Somers {
373269dfbeeSBrian Somers   if (val < 0)
374269dfbeeSBrian Somers     return 0;
375269dfbeeSBrian Somers 
376269dfbeeSBrian Somers   switch (type) {
377269dfbeeSBrian Somers     case '+':
378a625bfecSBrian Somers       if (val) {
3799263db41SBrian Somers         if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
380269dfbeeSBrian Somers           return 0;
381269dfbeeSBrian Somers         val %= 60;
382269dfbeeSBrian Somers         t->tm_sec += val;
383269dfbeeSBrian Somers         if (t->tm_sec > 59)
384269dfbeeSBrian Somers           t->tm_sec -= 60;
385a625bfecSBrian Somers       }
386269dfbeeSBrian Somers       break;
387269dfbeeSBrian Somers 
388269dfbeeSBrian Somers     case '-':
389a625bfecSBrian Somers       if (val) {
3909263db41SBrian Somers         if (!adjmin(t, '-', val / 60, 0))
391269dfbeeSBrian Somers           return 0;
392269dfbeeSBrian Somers         val %= 60;
393269dfbeeSBrian Somers         if (val > t->tm_sec) {
3949263db41SBrian Somers           if (!adjmin(t, '-', 1, 0))
395269dfbeeSBrian Somers             return 0;
396269dfbeeSBrian Somers           val -= 60;
397269dfbeeSBrian Somers         }
398269dfbeeSBrian Somers         t->tm_sec -= val;
399a625bfecSBrian Somers       }
400269dfbeeSBrian Somers       break;
401269dfbeeSBrian Somers 
402269dfbeeSBrian Somers     default:
403269dfbeeSBrian Somers       if (val > 59)
404269dfbeeSBrian Somers         return 0;
405269dfbeeSBrian Somers       t->tm_sec = val;
406269dfbeeSBrian Somers   }
407269dfbeeSBrian Somers 
4089263db41SBrian Somers   return !mk || domktime(t, type) != -1;
409269dfbeeSBrian Somers }
410269dfbeeSBrian Somers 
4117ca215a6SBrian Somers const struct vary *
4127ca215a6SBrian Somers vary_apply(const struct vary *v, struct tm *t)
4137ca215a6SBrian Somers {
414698f86e4SBrian Somers   char type;
415698f86e4SBrian Somers   char which;
416698f86e4SBrian Somers   char *arg;
4179afa09cdSMark Murray   size_t len;
418698f86e4SBrian Somers   int val;
419698f86e4SBrian Somers 
4207ca215a6SBrian Somers   for (; v; v = v->next) {
421698f86e4SBrian Somers     type = *v->arg;
422698f86e4SBrian Somers     arg = v->arg;
423698f86e4SBrian Somers     if (type == '+' || type == '-')
424698f86e4SBrian Somers       arg++;
425698f86e4SBrian Somers     else
426698f86e4SBrian Somers       type = '\0';
427698f86e4SBrian Somers     len = strlen(arg);
428698f86e4SBrian Somers     if (len < 2)
4297ca215a6SBrian Somers       return v;
430698f86e4SBrian Somers 
4319263db41SBrian Somers     if (type == '\0')
4329263db41SBrian Somers       t->tm_isdst = -1;
4339263db41SBrian Somers 
434698f86e4SBrian Somers     if (strspn(arg, digits) != len-1) {
435698f86e4SBrian Somers       val = trans(trans_wday, arg);
436698f86e4SBrian Somers       if (val != -1) {
4379263db41SBrian Somers           if (!adjwday(t, type, val, 1, 1))
4387ca215a6SBrian Somers             return v;
439698f86e4SBrian Somers       } else {
440698f86e4SBrian Somers         val = trans(trans_mon, arg);
441698f86e4SBrian Somers         if (val != -1) {
4429263db41SBrian Somers           if (!adjmon(t, type, val, 1, 1))
443698f86e4SBrian Somers             return v;
444698f86e4SBrian Somers         } else
445698f86e4SBrian Somers           return v;
446698f86e4SBrian Somers       }
447698f86e4SBrian Somers     } else {
448698f86e4SBrian Somers       val = atoi(arg);
449698f86e4SBrian Somers       which = arg[len-1];
450698f86e4SBrian Somers 
451698f86e4SBrian Somers       switch (which) {
452269dfbeeSBrian Somers         case 'S':
4539263db41SBrian Somers           if (!adjsec(t, type, val, 1))
454269dfbeeSBrian Somers             return v;
455269dfbeeSBrian Somers           break;
4567ca215a6SBrian Somers         case 'M':
4579263db41SBrian Somers           if (!adjmin(t, type, val, 1))
4587ca215a6SBrian Somers             return v;
4597ca215a6SBrian Somers           break;
460698f86e4SBrian Somers         case 'H':
4619263db41SBrian Somers           if (!adjhour(t, type, val, 1))
462698f86e4SBrian Somers             return v;
463698f86e4SBrian Somers           break;
464698f86e4SBrian Somers         case 'd':
4659263db41SBrian Somers           t->tm_isdst = -1;
4669263db41SBrian Somers           if (!adjday(t, type, val, 1))
467698f86e4SBrian Somers             return v;
468698f86e4SBrian Somers           break;
469698f86e4SBrian Somers         case 'w':
4709263db41SBrian Somers           t->tm_isdst = -1;
4719263db41SBrian Somers           if (!adjwday(t, type, val, 0, 1))
472698f86e4SBrian Somers             return v;
473698f86e4SBrian Somers           break;
474698f86e4SBrian Somers         case 'm':
4759263db41SBrian Somers           t->tm_isdst = -1;
4769263db41SBrian Somers           if (!adjmon(t, type, val, 0, 1))
477698f86e4SBrian Somers             return v;
478698f86e4SBrian Somers           break;
479698f86e4SBrian Somers         case 'y':
4809263db41SBrian Somers           t->tm_isdst = -1;
4819263db41SBrian Somers           if (!adjyear(t, type, val, 1))
4827ca215a6SBrian Somers             return v;
4837ca215a6SBrian Somers           break;
4847ca215a6SBrian Somers         default:
4857ca215a6SBrian Somers           return v;
4867ca215a6SBrian Somers       }
4877ca215a6SBrian Somers     }
488698f86e4SBrian Somers   }
4897ca215a6SBrian Somers   return 0;
4907ca215a6SBrian Somers }
4917ca215a6SBrian Somers 
4927ca215a6SBrian Somers void
4937ca215a6SBrian Somers vary_destroy(struct vary *v)
4947ca215a6SBrian Somers {
4957ca215a6SBrian Somers   struct vary *n;
4967ca215a6SBrian Somers 
4977ca215a6SBrian Somers   while (v) {
4987ca215a6SBrian Somers     n = v->next;
4997ca215a6SBrian Somers     free(v);
5007ca215a6SBrian Somers     v = n;
5017ca215a6SBrian Somers   }
5027ca215a6SBrian Somers }
503