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