xref: /freebsd/bin/date/vary.c (revision 7ecff35b0d88fb1aea2cefd4ff859bf505f529ff)
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 
327ca215a6SBrian Somers #include <time.h>
337ca215a6SBrian Somers #include <string.h>
347ca215a6SBrian Somers #include <stdlib.h>
357ca215a6SBrian Somers #include "vary.h"
367ca215a6SBrian Somers 
377ca215a6SBrian Somers struct trans {
387ca215a6SBrian Somers   int val;
397ca215a6SBrian Somers   char *str;
407ca215a6SBrian Somers };
417ca215a6SBrian Somers 
427ca215a6SBrian Somers static struct trans trans_mon[] = {
437ca215a6SBrian Somers   { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
443b006d8eSAlfred Perlstein   { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
453b006d8eSAlfred Perlstein   { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
467ca215a6SBrian Somers   { -1, NULL }
477ca215a6SBrian Somers };
487ca215a6SBrian Somers 
497ca215a6SBrian Somers static struct trans trans_wday[] = {
507ca215a6SBrian Somers   { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
517ca215a6SBrian Somers   { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
527ca215a6SBrian Somers   { -1, NULL }
537ca215a6SBrian Somers };
547ca215a6SBrian Somers 
557ca215a6SBrian Somers static char digits[] = "0123456789";
569263db41SBrian Somers static int adjhour(struct tm *, char, int, int);
57a625bfecSBrian Somers 
58a625bfecSBrian Somers static int
59a625bfecSBrian Somers domktime(struct tm *t, char type)
60a625bfecSBrian Somers {
619263db41SBrian Somers   time_t ret;
62a625bfecSBrian Somers 
639263db41SBrian Somers   while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
649263db41SBrian Somers     /* While mktime() fails, adjust by an hour */
659263db41SBrian Somers     adjhour(t, type == '-' ? type : '+', 1, 0);
66a625bfecSBrian Somers 
67a625bfecSBrian Somers   return ret;
68a625bfecSBrian Somers }
697ca215a6SBrian Somers 
707ca215a6SBrian Somers static int
717ca215a6SBrian Somers trans(const struct trans t[], const char *arg)
727ca215a6SBrian Somers {
737ca215a6SBrian Somers   int f;
747ca215a6SBrian Somers 
757ca215a6SBrian Somers   for (f = 0; t[f].val != -1; f++)
76698f86e4SBrian Somers     if (!strncasecmp(t[f].str, arg, 3) ||
77698f86e4SBrian Somers         !strncasecmp(t[f].str, arg, strlen(t[f].str)))
787ca215a6SBrian Somers       return t[f].val;
797ca215a6SBrian Somers 
807ca215a6SBrian Somers   return -1;
817ca215a6SBrian Somers }
827ca215a6SBrian Somers 
837ca215a6SBrian Somers struct vary *
84698f86e4SBrian Somers vary_append(struct vary *v, char *arg)
857ca215a6SBrian Somers {
867ca215a6SBrian Somers   struct vary *result, **nextp;
877ca215a6SBrian Somers 
887ca215a6SBrian Somers   if (v) {
897ca215a6SBrian Somers     result = v;
907ca215a6SBrian Somers     while (v->next)
917ca215a6SBrian Somers       v = v->next;
927ca215a6SBrian Somers     nextp = &v->next;
937ca215a6SBrian Somers   } else
947ca215a6SBrian Somers     nextp = &result;
957ca215a6SBrian Somers 
967ca215a6SBrian Somers   *nextp = (struct vary *)malloc(sizeof(struct vary));
977ca215a6SBrian Somers   (*nextp)->arg = arg;
987ca215a6SBrian Somers   (*nextp)->next = NULL;
997ca215a6SBrian Somers   return result;
1007ca215a6SBrian Somers }
1017ca215a6SBrian Somers 
1027ca215a6SBrian Somers static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1037ca215a6SBrian Somers 
1047ca215a6SBrian Somers static int
1057ca215a6SBrian Somers daysinmonth(const struct tm *t)
1067ca215a6SBrian Somers {
1077ca215a6SBrian Somers   int year;
1087ca215a6SBrian Somers 
1097ca215a6SBrian Somers   year = t->tm_year + 1900;
1107ca215a6SBrian Somers 
1117ca215a6SBrian Somers   if (t->tm_mon == 1)
1127ca215a6SBrian Somers     if (!(year % 400))
1137ca215a6SBrian Somers       return 29;
1147ca215a6SBrian Somers     else if (!(year % 100))
1157ca215a6SBrian Somers       return 28;
1167ca215a6SBrian Somers     else if (!(year % 4))
1177ca215a6SBrian Somers       return 29;
1187ca215a6SBrian Somers     else
1197ca215a6SBrian Somers       return 28;
1207ca215a6SBrian Somers   else if (t->tm_mon >= 0 && t->tm_mon < 12)
1217ca215a6SBrian Somers     return mdays[t->tm_mon];
1227ca215a6SBrian Somers 
1237ca215a6SBrian Somers   return 0;
1247ca215a6SBrian Somers }
1257ca215a6SBrian Somers 
1267ca215a6SBrian Somers 
1277ca215a6SBrian Somers static int
1289263db41SBrian Somers adjyear(struct tm *t, char type, int val, int mk)
1297ca215a6SBrian Somers {
1307ca215a6SBrian Somers   switch (type) {
1317ca215a6SBrian Somers     case '+':
1327ca215a6SBrian Somers       t->tm_year += val;
1337ca215a6SBrian Somers       break;
1347ca215a6SBrian Somers     case '-':
1357ca215a6SBrian Somers       t->tm_year -= val;
1367ca215a6SBrian Somers       break;
1377ca215a6SBrian Somers     default:
1387ca215a6SBrian Somers       t->tm_year = val;
1397ca215a6SBrian Somers       if (t->tm_year < 69)
1407ca215a6SBrian Somers       	t->tm_year += 100;		/* as per date.c */
1417ca215a6SBrian Somers       else if (t->tm_year > 1900)
1427ca215a6SBrian Somers         t->tm_year -= 1900;             /* struct tm holds years since 1900 */
1437ca215a6SBrian Somers       break;
1447ca215a6SBrian Somers   }
1459263db41SBrian Somers   return !mk || domktime(t, type) != -1;
1467ca215a6SBrian Somers }
1477ca215a6SBrian Somers 
1487ca215a6SBrian Somers static int
1499263db41SBrian Somers adjmon(struct tm *t, char type, int val, int istext, int mk)
1507ca215a6SBrian Somers {
1517ca215a6SBrian Somers   if (val < 0)
1527ca215a6SBrian Somers     return 0;
1537ca215a6SBrian Somers 
1547ca215a6SBrian Somers   switch (type) {
1557ca215a6SBrian Somers     case '+':
156426e9c1dSWarner Losh       if (istext) {
1577ca215a6SBrian Somers         if (val <= t->tm_mon)
1587ca215a6SBrian Somers           val += 11 - t->tm_mon;	/* early next year */
1597ca215a6SBrian Somers         else
1607ca215a6SBrian Somers           val -= t->tm_mon + 1;		/* later this year */
161426e9c1dSWarner Losh       }
162a625bfecSBrian Somers       if (val) {
1639263db41SBrian Somers         if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
1647ca215a6SBrian Somers           return 0;
1657ca215a6SBrian Somers         val %= 12;
1667ca215a6SBrian Somers         t->tm_mon += val;
1677ca215a6SBrian Somers         if (t->tm_mon > 11)
1687ca215a6SBrian Somers           t->tm_mon -= 12;
169a625bfecSBrian Somers       }
1707ca215a6SBrian Somers       break;
1717ca215a6SBrian Somers 
1727ca215a6SBrian Somers     case '-':
173426e9c1dSWarner Losh       if (istext) {
1747ca215a6SBrian Somers         if (val-1 > t->tm_mon)
1757ca215a6SBrian Somers           val = 13 - val + t->tm_mon;	/* later last year */
1767ca215a6SBrian Somers         else
1777ca215a6SBrian Somers           val = t->tm_mon - val + 1;	/* early this year */
178426e9c1dSWarner Losh       }
179a625bfecSBrian Somers       if (val) {
1809263db41SBrian Somers         if (!adjyear(t, '-', val / 12, 0))
1817ca215a6SBrian Somers           return 0;
1827ca215a6SBrian Somers         val %= 12;
1837ca215a6SBrian Somers         if (val > t->tm_mon) {
1849263db41SBrian Somers           if (!adjyear(t, '-', 1, 0))
1857ca215a6SBrian Somers             return 0;
1867ca215a6SBrian Somers           val -= 12;
1877ca215a6SBrian Somers         }
1887ca215a6SBrian Somers         t->tm_mon -= val;
189a625bfecSBrian Somers       }
1907ca215a6SBrian Somers       break;
1917ca215a6SBrian Somers 
1927ca215a6SBrian Somers     default:
1937ca215a6SBrian Somers       if (val > 12 || val < 1)
1947ca215a6SBrian Somers         return 0;
1957ca215a6SBrian Somers       t->tm_mon = --val;
1967ca215a6SBrian Somers   }
1977ca215a6SBrian Somers 
1989263db41SBrian Somers   return !mk || domktime(t, type) != -1;
1997ca215a6SBrian Somers }
2007ca215a6SBrian Somers 
2017ca215a6SBrian Somers static int
2029263db41SBrian Somers adjday(struct tm *t, char type, int val, int mk)
2037ca215a6SBrian Somers {
2047ca215a6SBrian Somers   int mdays;
205a625bfecSBrian Somers 
2067ca215a6SBrian Somers   switch (type) {
2077ca215a6SBrian Somers     case '+':
2087ca215a6SBrian Somers       while (val) {
2097ca215a6SBrian Somers         mdays = daysinmonth(t);
2107ca215a6SBrian Somers         if (val > mdays - t->tm_mday) {
2117ca215a6SBrian Somers           val -= mdays - t->tm_mday + 1;
2127ca215a6SBrian Somers           t->tm_mday = 1;
2139263db41SBrian Somers           if (!adjmon(t, '+', 1, 0, 0))
2147ca215a6SBrian Somers             return 0;
2157ca215a6SBrian Somers         } else {
2167ca215a6SBrian Somers           t->tm_mday += val;
2177ca215a6SBrian Somers           val = 0;
2187ca215a6SBrian Somers         }
2197ca215a6SBrian Somers       }
2207ca215a6SBrian Somers       break;
2217ca215a6SBrian Somers     case '-':
2227ca215a6SBrian Somers       while (val)
2237ca215a6SBrian Somers         if (val >= t->tm_mday) {
2247ca215a6SBrian Somers           val -= t->tm_mday;
2257ca215a6SBrian Somers           t->tm_mday = 1;
2269263db41SBrian Somers           if (!adjmon(t, '-', 1, 0, 0))
2277ca215a6SBrian Somers             return 0;
2287ca215a6SBrian Somers           t->tm_mday = daysinmonth(t);
2297ca215a6SBrian Somers         } else {
2307ca215a6SBrian Somers           t->tm_mday -= val;
2317ca215a6SBrian Somers           val = 0;
2327ca215a6SBrian Somers         }
2337ca215a6SBrian Somers       break;
2347ca215a6SBrian Somers     default:
2357ca215a6SBrian Somers       if (val > 0 && val <= daysinmonth(t))
2367ca215a6SBrian Somers         t->tm_mday = val;
2377ca215a6SBrian Somers       else
2387ca215a6SBrian Somers         return 0;
2397ca215a6SBrian Somers       break;
2407ca215a6SBrian Somers   }
2417ca215a6SBrian Somers 
2429263db41SBrian Somers   return !mk || domktime(t, type) != -1;
2437ca215a6SBrian Somers }
2447ca215a6SBrian Somers 
2457ca215a6SBrian Somers static int
2469263db41SBrian Somers adjwday(struct tm *t, char type, int val, int istext, int mk)
2477ca215a6SBrian Somers {
2487ca215a6SBrian Somers   if (val < 0)
2497ca215a6SBrian Somers     return 0;
2507ca215a6SBrian Somers 
251698f86e4SBrian Somers   switch (type) {
2527ca215a6SBrian Somers     case '+':
2537ca215a6SBrian Somers       if (istext)
2547ca215a6SBrian Somers         if (val < t->tm_wday)
2557ca215a6SBrian Somers           val = 7 - t->tm_wday + val;  /* early next week */
2567ca215a6SBrian Somers         else
2577ca215a6SBrian Somers           val -= t->tm_wday;           /* later this week */
2587ca215a6SBrian Somers       else
259a625bfecSBrian Somers         val *= 7;                      /* "-v+5w" == "5 weeks in the future" */
2607ecff35bSBrian Somers       return !val || adjday(t, '+', val, mk);
2617ca215a6SBrian Somers     case '-':
262a625bfecSBrian Somers       if (istext) {
2637ca215a6SBrian Somers         if (val > t->tm_wday)
2647ca215a6SBrian Somers           val = 7 - val + t->tm_wday;  /* later last week */
2657ca215a6SBrian Somers         else
2667ca215a6SBrian Somers           val = t->tm_wday - val;      /* early this week */
267a625bfecSBrian Somers       } else
268a625bfecSBrian Somers         val *= 7;                      /* "-v-5w" == "5 weeks ago" */
2697ecff35bSBrian Somers       return !val || adjday(t, '-', val, mk);
2707ca215a6SBrian Somers     default:
2717ca215a6SBrian Somers       if (val < t->tm_wday)
2727ecff35bSBrian Somers         return adjday(t, '-', t->tm_wday - val, mk);
2737ca215a6SBrian Somers       else if (val > 6)
2747ca215a6SBrian Somers         return 0;
2757ca215a6SBrian Somers       else if (val > t->tm_wday)
2767ecff35bSBrian Somers         return adjday(t, '+', val - t->tm_wday, mk);
2777ca215a6SBrian Somers   }
2787ca215a6SBrian Somers   return 1;
2797ca215a6SBrian Somers }
2807ca215a6SBrian Somers 
2817ca215a6SBrian Somers static int
2829263db41SBrian Somers adjhour(struct tm *t, char type, int val, int mk)
2837ca215a6SBrian Somers {
284698f86e4SBrian Somers   if (val < 0)
285698f86e4SBrian Somers     return 0;
286698f86e4SBrian Somers 
287698f86e4SBrian Somers   switch (type) {
2887ca215a6SBrian Somers     case '+':
289a625bfecSBrian Somers       if (val) {
290a625bfecSBrian Somers         int days;
291a625bfecSBrian Somers 
292a625bfecSBrian Somers         days = (t->tm_hour + val) / 24;
293698f86e4SBrian Somers         val %= 24;
294698f86e4SBrian Somers         t->tm_hour += val;
295a625bfecSBrian Somers         t->tm_hour %= 24;
2969263db41SBrian Somers         if (!adjday(t, '+', days, 0))
297a625bfecSBrian Somers           return 0;
298a625bfecSBrian Somers       }
299698f86e4SBrian Somers       break;
300698f86e4SBrian Somers 
3017ca215a6SBrian Somers     case '-':
302a625bfecSBrian Somers       if (val) {
303a625bfecSBrian Somers         int days;
304a625bfecSBrian Somers 
305a625bfecSBrian Somers         days = val / 24;
306698f86e4SBrian Somers         val %= 24;
307698f86e4SBrian Somers         if (val > t->tm_hour) {
308a625bfecSBrian Somers           days++;
309698f86e4SBrian Somers           val -= 24;
3107ca215a6SBrian Somers         }
311698f86e4SBrian Somers         t->tm_hour -= val;
3129263db41SBrian Somers         if (!adjday(t, '-', days, 0))
313a625bfecSBrian Somers           return 0;
314a625bfecSBrian Somers       }
315698f86e4SBrian Somers       break;
316698f86e4SBrian Somers 
317698f86e4SBrian Somers     default:
318698f86e4SBrian Somers       if (val > 23)
319698f86e4SBrian Somers         return 0;
320698f86e4SBrian Somers       t->tm_hour = val;
321698f86e4SBrian Somers   }
322698f86e4SBrian Somers 
3239263db41SBrian Somers   return !mk || domktime(t, type) != -1;
324698f86e4SBrian Somers }
325698f86e4SBrian Somers 
326698f86e4SBrian Somers static int
3279263db41SBrian Somers adjmin(struct tm *t, char type, int val, int mk)
328698f86e4SBrian Somers {
329698f86e4SBrian Somers   if (val < 0)
330698f86e4SBrian Somers     return 0;
331698f86e4SBrian Somers 
332698f86e4SBrian Somers   switch (type) {
333698f86e4SBrian Somers     case '+':
334a625bfecSBrian Somers       if (val) {
3359263db41SBrian Somers         if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
336698f86e4SBrian Somers           return 0;
337698f86e4SBrian Somers         val %= 60;
338698f86e4SBrian Somers         t->tm_min += val;
339698f86e4SBrian Somers         if (t->tm_min > 59)
340698f86e4SBrian Somers           t->tm_min -= 60;
341a625bfecSBrian Somers       }
342698f86e4SBrian Somers       break;
343698f86e4SBrian Somers 
344698f86e4SBrian Somers     case '-':
345a625bfecSBrian Somers       if (val) {
3469263db41SBrian Somers         if (!adjhour(t, '-', val / 60, 0))
347698f86e4SBrian Somers           return 0;
348698f86e4SBrian Somers         val %= 60;
349698f86e4SBrian Somers         if (val > t->tm_min) {
3509263db41SBrian Somers           if (!adjhour(t, '-', 1, 0))
351698f86e4SBrian Somers             return 0;
352698f86e4SBrian Somers           val -= 60;
353698f86e4SBrian Somers         }
354698f86e4SBrian Somers         t->tm_min -= val;
355a625bfecSBrian Somers       }
356698f86e4SBrian Somers       break;
357698f86e4SBrian Somers 
358698f86e4SBrian Somers     default:
359698f86e4SBrian Somers       if (val > 59)
360698f86e4SBrian Somers         return 0;
361698f86e4SBrian Somers       t->tm_min = val;
362698f86e4SBrian Somers   }
363698f86e4SBrian Somers 
3649263db41SBrian Somers   return !mk || domktime(t, type) != -1;
3657ca215a6SBrian Somers }
3667ca215a6SBrian Somers 
367269dfbeeSBrian Somers static int
3689263db41SBrian Somers adjsec(struct tm *t, char type, int val, int mk)
369269dfbeeSBrian Somers {
370269dfbeeSBrian Somers   if (val < 0)
371269dfbeeSBrian Somers     return 0;
372269dfbeeSBrian Somers 
373269dfbeeSBrian Somers   switch (type) {
374269dfbeeSBrian Somers     case '+':
375a625bfecSBrian Somers       if (val) {
3769263db41SBrian Somers         if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
377269dfbeeSBrian Somers           return 0;
378269dfbeeSBrian Somers         val %= 60;
379269dfbeeSBrian Somers         t->tm_sec += val;
380269dfbeeSBrian Somers         if (t->tm_sec > 59)
381269dfbeeSBrian Somers           t->tm_sec -= 60;
382a625bfecSBrian Somers       }
383269dfbeeSBrian Somers       break;
384269dfbeeSBrian Somers 
385269dfbeeSBrian Somers     case '-':
386a625bfecSBrian Somers       if (val) {
3879263db41SBrian Somers         if (!adjmin(t, '-', val / 60, 0))
388269dfbeeSBrian Somers           return 0;
389269dfbeeSBrian Somers         val %= 60;
390269dfbeeSBrian Somers         if (val > t->tm_sec) {
3919263db41SBrian Somers           if (!adjmin(t, '-', 1, 0))
392269dfbeeSBrian Somers             return 0;
393269dfbeeSBrian Somers           val -= 60;
394269dfbeeSBrian Somers         }
395269dfbeeSBrian Somers         t->tm_sec -= val;
396a625bfecSBrian Somers       }
397269dfbeeSBrian Somers       break;
398269dfbeeSBrian Somers 
399269dfbeeSBrian Somers     default:
400269dfbeeSBrian Somers       if (val > 59)
401269dfbeeSBrian Somers         return 0;
402269dfbeeSBrian Somers       t->tm_sec = val;
403269dfbeeSBrian Somers   }
404269dfbeeSBrian Somers 
4059263db41SBrian Somers   return !mk || domktime(t, type) != -1;
406269dfbeeSBrian Somers }
407269dfbeeSBrian Somers 
4087ca215a6SBrian Somers const struct vary *
4097ca215a6SBrian Somers vary_apply(const struct vary *v, struct tm *t)
4107ca215a6SBrian Somers {
411698f86e4SBrian Somers   char type;
412698f86e4SBrian Somers   char which;
413698f86e4SBrian Somers   char *arg;
414698f86e4SBrian Somers   int len;
415698f86e4SBrian Somers   int val;
416698f86e4SBrian Somers 
4177ca215a6SBrian Somers   for (; v; v = v->next) {
418698f86e4SBrian Somers     type = *v->arg;
419698f86e4SBrian Somers     arg = v->arg;
420698f86e4SBrian Somers     if (type == '+' || type == '-')
421698f86e4SBrian Somers       arg++;
422698f86e4SBrian Somers     else
423698f86e4SBrian Somers       type = '\0';
424698f86e4SBrian Somers     len = strlen(arg);
425698f86e4SBrian Somers     if (len < 2)
4267ca215a6SBrian Somers       return v;
427698f86e4SBrian Somers 
4289263db41SBrian Somers     if (type == '\0')
4299263db41SBrian Somers       t->tm_isdst = -1;
4309263db41SBrian Somers 
431698f86e4SBrian Somers     if (strspn(arg, digits) != len-1) {
432698f86e4SBrian Somers       val = trans(trans_wday, arg);
433698f86e4SBrian Somers       if (val != -1) {
4349263db41SBrian Somers           if (!adjwday(t, type, val, 1, 1))
4357ca215a6SBrian Somers             return v;
436698f86e4SBrian Somers       } else {
437698f86e4SBrian Somers         val = trans(trans_mon, arg);
438698f86e4SBrian Somers         if (val != -1) {
4399263db41SBrian Somers           if (!adjmon(t, type, val, 1, 1))
440698f86e4SBrian Somers             return v;
441698f86e4SBrian Somers         } else
442698f86e4SBrian Somers           return v;
443698f86e4SBrian Somers       }
444698f86e4SBrian Somers     } else {
445698f86e4SBrian Somers       val = atoi(arg);
446698f86e4SBrian Somers       which = arg[len-1];
447698f86e4SBrian Somers 
448698f86e4SBrian Somers       switch (which) {
449269dfbeeSBrian Somers         case 'S':
4509263db41SBrian Somers           if (!adjsec(t, type, val, 1))
451269dfbeeSBrian Somers             return v;
452269dfbeeSBrian Somers           break;
4537ca215a6SBrian Somers         case 'M':
4549263db41SBrian Somers           if (!adjmin(t, type, val, 1))
4557ca215a6SBrian Somers             return v;
4567ca215a6SBrian Somers           break;
457698f86e4SBrian Somers         case 'H':
4589263db41SBrian Somers           if (!adjhour(t, type, val, 1))
459698f86e4SBrian Somers             return v;
460698f86e4SBrian Somers           break;
461698f86e4SBrian Somers         case 'd':
4629263db41SBrian Somers           t->tm_isdst = -1;
4639263db41SBrian Somers           if (!adjday(t, type, val, 1))
464698f86e4SBrian Somers             return v;
465698f86e4SBrian Somers           break;
466698f86e4SBrian Somers         case 'w':
4679263db41SBrian Somers           t->tm_isdst = -1;
4689263db41SBrian Somers           if (!adjwday(t, type, val, 0, 1))
469698f86e4SBrian Somers             return v;
470698f86e4SBrian Somers           break;
471698f86e4SBrian Somers         case 'm':
4729263db41SBrian Somers           t->tm_isdst = -1;
4739263db41SBrian Somers           if (!adjmon(t, type, val, 0, 1))
474698f86e4SBrian Somers             return v;
475698f86e4SBrian Somers           break;
476698f86e4SBrian Somers         case 'y':
4779263db41SBrian Somers           t->tm_isdst = -1;
4789263db41SBrian Somers           if (!adjyear(t, type, val, 1))
4797ca215a6SBrian Somers             return v;
4807ca215a6SBrian Somers           break;
4817ca215a6SBrian Somers         default:
4827ca215a6SBrian Somers           return v;
4837ca215a6SBrian Somers       }
4847ca215a6SBrian Somers     }
485698f86e4SBrian Somers   }
4867ca215a6SBrian Somers   return 0;
4877ca215a6SBrian Somers }
4887ca215a6SBrian Somers 
4897ca215a6SBrian Somers void
4907ca215a6SBrian Somers vary_destroy(struct vary *v)
4917ca215a6SBrian Somers {
4927ca215a6SBrian Somers   struct vary *n;
4937ca215a6SBrian Somers 
4947ca215a6SBrian Somers   while (v) {
4957ca215a6SBrian Somers     n = v->next;
4967ca215a6SBrian Somers     free(v);
4977ca215a6SBrian Somers     v = n;
4987ca215a6SBrian Somers   }
4997ca215a6SBrian Somers }
500