[BACK]Return to parsetime.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / at

Annotation of src/usr.bin/at/parsetime.c, Revision 1.27

1.27    ! naddy       1: /*     $OpenBSD: parsetime.c,v 1.26 2015/11/11 17:42:51 millert Exp $  */
1.1       deraadt     2:
1.14      millert     3: /*
1.1       deraadt     4:  * parsetime.c - parse time for at(1)
1.4       millert     5:  * Copyright (C) 1993, 1994  Thomas Koenig
1.1       deraadt     6:  *
                      7:  * modifications for english-language times
                      8:  * Copyright (C) 1993  David Parsons
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. The name of the author(s) may not be used to endorse or promote
                     16:  *    products derived from this software without specific prior written
                     17:  *    permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
                     20:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     21:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1.4       millert    22:  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1.1       deraadt    23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     24:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1.18      krw        26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1.1       deraadt    27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     28:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  *
1.20      millert    30:  *  at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS
1.1       deraadt    31:  *     /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]]             \
                     32:  *     |NOON                       | |[TOMORROW]                          |
1.4       millert    33:  *     |MIDNIGHT                   | |[DAY OF WEEK]                       |
                     34:  *     \TEATIME                    / |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
1.20      millert    35:  *                                   \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS/
1.1       deraadt    36:  */
                     37:
                     38: #include <sys/types.h>
1.26      millert    39:
                     40: #include <err.h>
1.1       deraadt    41: #include <errno.h>
1.11      millert    42: #include <ctype.h>
1.1       deraadt    43: #include <stdio.h>
                     44: #include <stdlib.h>
                     45: #include <string.h>
                     46: #include <time.h>
                     47: #include <unistd.h>
                     48:
1.13      millert    49: #include "globals.h"
1.1       deraadt    50: #include "at.h"
                     51:
                     52: /* Structures and unions */
                     53:
                     54: enum { /* symbols */
1.4       millert    55:        MIDNIGHT, NOON, TEATIME,
                     56:        PM, AM, TOMORROW, TODAY, NOW,
1.20      millert    57:        MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
                     58:        NUMBER, NEXT, PLUS, DOT, SLASH, ID, JUNK,
1.4       millert    59:        JAN, FEB, MAR, APR, MAY, JUN,
                     60:        JUL, AUG, SEP, OCT, NOV, DEC,
                     61:        SUN, MON, TUE, WED, THU, FRI, SAT
1.1       deraadt    62: };
                     63:
                     64: /*
                     65:  * parse translation table - table driven parsers can be your FRIEND!
                     66:  */
                     67: struct {
1.4       millert    68:        char *name;     /* token name */
                     69:        int value;      /* token id */
                     70:        int plural;     /* is this plural? */
1.1       deraadt    71: } Specials[] = {
1.4       millert    72:        { "midnight", MIDNIGHT, 0 },    /* 00:00:00 of today or tomorrow */
                     73:        { "noon", NOON, 0 },            /* 12:00:00 of today or tomorrow */
                     74:        { "teatime", TEATIME, 0 },      /* 16:00:00 of today or tomorrow */
                     75:        { "am", AM, 0 },                /* morning times for 0-12 clock */
                     76:        { "pm", PM, 0 },                /* evening times for 0-12 clock */
                     77:        { "tomorrow", TOMORROW, 0 },    /* execute 24 hours from time */
                     78:        { "today", TODAY, 0 },          /* execute today - don't advance time */
                     79:        { "now", NOW, 0 },              /* opt prefix for PLUS */
1.20      millert    80:        { "next", NEXT, 0 },            /* opt prefix for + 1 */
1.4       millert    81:
                     82:        { "minute", MINUTES, 0 },       /* minutes multiplier */
                     83:        { "min", MINUTES, 0 },
                     84:        { "m", MINUTES, 0 },
                     85:        { "minutes", MINUTES, 1 },      /* (pluralized) */
                     86:        { "hour", HOURS, 0 },           /* hours ... */
                     87:        { "hr", HOURS, 0 },             /* abbreviated */
                     88:        { "h", HOURS, 0 },
                     89:        { "hours", HOURS, 1 },          /* (pluralized) */
                     90:        { "day", DAYS, 0 },             /* days ... */
                     91:        { "d", DAYS, 0 },
                     92:        { "days", DAYS, 1 },            /* (pluralized) */
                     93:        { "week", WEEKS, 0 },           /* week ... */
                     94:        { "w", WEEKS, 0 },
                     95:        { "weeks", WEEKS, 1 },          /* (pluralized) */
1.20      millert    96:        { "month", MONTHS, 0 },         /* month ... */
                     97:        { "mo", MONTHS, 0 },
                     98:        { "mth", MONTHS, 0 },
                     99:        { "months", MONTHS, 1 },        /* (pluralized) */
                    100:        { "year", YEARS, 0 },           /* year ... */
                    101:        { "y", YEARS, 0 },
                    102:        { "years", YEARS, 1 },          /* (pluralized) */
1.4       millert   103:        { "jan", JAN, 0 },
                    104:        { "feb", FEB, 0 },
                    105:        { "mar", MAR, 0 },
                    106:        { "apr", APR, 0 },
                    107:        { "may", MAY, 0 },
                    108:        { "jun", JUN, 0 },
                    109:        { "jul", JUL, 0 },
                    110:        { "aug", AUG, 0 },
                    111:        { "sep", SEP, 0 },
                    112:        { "oct", OCT, 0 },
                    113:        { "nov", NOV, 0 },
                    114:        { "dec", DEC, 0 },
1.7       deraadt   115:        { "january", JAN,0 },
                    116:        { "february", FEB,0 },
                    117:        { "march", MAR,0 },
                    118:        { "april", APR,0 },
                    119:        { "may", MAY,0 },
                    120:        { "june", JUN,0 },
                    121:        { "july", JUL,0 },
                    122:        { "august", AUG,0 },
                    123:        { "september", SEP,0 },
                    124:        { "october", OCT,0 },
                    125:        { "november", NOV,0 },
                    126:        { "december", DEC,0 },
1.4       millert   127:        { "sunday", SUN, 0 },
                    128:        { "sun", SUN, 0 },
                    129:        { "monday", MON, 0 },
                    130:        { "mon", MON, 0 },
                    131:        { "tuesday", TUE, 0 },
                    132:        { "tue", TUE, 0 },
                    133:        { "wednesday", WED, 0 },
                    134:        { "wed", WED, 0 },
                    135:        { "thursday", THU, 0 },
                    136:        { "thu", THU, 0 },
                    137:        { "friday", FRI, 0 },
                    138:        { "fri", FRI, 0 },
                    139:        { "saturday", SAT, 0 },
                    140:        { "sat", SAT, 0 },
                    141: };
1.1       deraadt   142:
                    143: static char **scp;     /* scanner - pointer at arglist */
1.15      cloder    144: static int scc;                /* scanner - count of remaining arguments */
1.1       deraadt   145: static char *sct;      /* scanner - next char pointer in current argument */
                    146: static int need;       /* scanner - need to advance to next argument */
                    147: static char *sc_token; /* scanner - token buffer */
1.12      todd      148: static size_t sc_len;   /* scanner - length of token buffer */
1.1       deraadt   149: static int sc_tokid;   /* scanner - token id */
1.4       millert   150: static int sc_tokplur; /* scanner - is token plural? */
1.1       deraadt   151:
                    152: /*
                    153:  * parse a token, checking if it's something special to us
                    154:  */
                    155: static int
1.10      millert   156: parse_token(char *arg)
1.1       deraadt   157: {
1.4       millert   158:        int i;
1.1       deraadt   159:
1.4       millert   160:        for (i=0; i < sizeof(Specials) / sizeof(Specials[0]); i++) {
                    161:                if (strcasecmp(Specials[i].name, arg) == 0) {
                    162:                        sc_tokplur = Specials[i].plural;
                    163:                        return (sc_tokid = Specials[i].value);
                    164:                }
1.1       deraadt   165:        }
                    166:
1.4       millert   167:        /* not special - must be some random id */
                    168:        return (ID);
1.11      millert   169: }
1.1       deraadt   170:
                    171:
                    172: /*
                    173:  * init_scanner() sets up the scanner to eat arguments
                    174:  */
1.13      millert   175: static int
1.10      millert   176: init_scanner(int argc, char **argv)
1.1       deraadt   177: {
1.4       millert   178:        scp = argv;
                    179:        scc = argc;
                    180:        need = 1;
                    181:        sc_len = 1;
                    182:        while (argc-- > 0)
                    183:                sc_len += strlen(*argv++);
                    184:
1.23      deraadt   185:        if ((sc_token = malloc(sc_len)) == NULL) {
1.26      millert   186:                warn(NULL);
1.13      millert   187:                return (-1);
                    188:        }
                    189:        return (0);
1.11      millert   190: }
1.1       deraadt   191:
                    192: /*
                    193:  * token() fetches a token from the input stream
                    194:  */
                    195: static int
1.10      millert   196: token(void)
1.1       deraadt   197: {
1.4       millert   198:        int idx;
1.1       deraadt   199:
1.10      millert   200:        for (;;) {
1.13      millert   201:                bzero(sc_token, sc_len);
1.4       millert   202:                sc_tokid = EOF;
                    203:                sc_tokplur = 0;
                    204:                idx = 0;
1.1       deraadt   205:
1.4       millert   206:                /*
                    207:                 * if we need to read another argument, walk along the
                    208:                 * argument list; when we fall off the arglist, we'll
                    209:                 * just return EOF forever
                    210:                 */
                    211:                if (need) {
                    212:                        if (scc < 1)
                    213:                                return (sc_tokid);
                    214:                        sct = *scp;
                    215:                        scp++;
                    216:                        scc--;
                    217:                        need = 0;
                    218:                }
                    219:                /*
                    220:                 * eat whitespace now - if we walk off the end of the argument,
                    221:                 * we'll continue, which puts us up at the top of the while loop
                    222:                 * to fetch the next argument in
                    223:                 */
1.19      deraadt   224:                while (isspace((unsigned char)*sct))
1.4       millert   225:                        ++sct;
                    226:                if (!*sct) {
                    227:                        need = 1;
                    228:                        continue;
                    229:                }
1.1       deraadt   230:
1.4       millert   231:                /*
                    232:                 * preserve the first character of the new token
                    233:                 */
                    234:                sc_token[0] = *sct++;
1.1       deraadt   235:
1.4       millert   236:                /*
                    237:                 * then see what it is
                    238:                 */
1.19      deraadt   239:                if (isdigit((unsigned char)sc_token[0])) {
                    240:                        while (isdigit((unsigned char)*sct))
1.4       millert   241:                                sc_token[++idx] = *sct++;
                    242:                        sc_token[++idx] = 0;
                    243:                        return ((sc_tokid = NUMBER));
1.19      deraadt   244:                } else if (isalpha((unsigned char)sc_token[0])) {
                    245:                        while (isalpha((unsigned char)*sct))
1.4       millert   246:                                sc_token[++idx] = *sct++;
                    247:                        sc_token[++idx] = 0;
                    248:                        return (parse_token(sc_token));
                    249:                }
                    250:                else if (sc_token[0] == ':' || sc_token[0] == '.')
                    251:                        return ((sc_tokid = DOT));
                    252:                else if (sc_token[0] == '+')
                    253:                        return ((sc_tokid = PLUS));
                    254:                else if (sc_token[0] == '/')
                    255:                        return ((sc_tokid = SLASH));
                    256:                else
                    257:                        return ((sc_tokid = JUNK));
1.11      millert   258:        }
                    259: }
1.1       deraadt   260:
                    261:
                    262: /*
                    263:  * plonk() gives an appropriate error message if a token is incorrect
                    264:  */
                    265: static void
1.10      millert   266: plonk(int tok)
1.1       deraadt   267: {
1.26      millert   268:        warnx("%s time", (tok == EOF) ? "incomplete" : "garbled");
1.11      millert   269: }
1.1       deraadt   270:
                    271:
1.14      millert   272: /*
1.13      millert   273:  * expect() gets a token and returns -1 if it's not the token we want
1.1       deraadt   274:  */
1.13      millert   275: static int
1.10      millert   276: expect(int desired)
1.1       deraadt   277: {
1.13      millert   278:        if (token() != desired) {
                    279:                plonk(sc_tokid);
                    280:                return (-1);
                    281:        }
                    282:        return (0);
1.11      millert   283: }
1.1       deraadt   284:
                    285:
                    286: /*
                    287:  * dateadd() adds a number of minutes to a date.  It is extraordinarily
                    288:  * stupid regarding day-of-month overflow, and will most likely not
                    289:  * work properly
                    290:  */
                    291: static void
1.10      millert   292: dateadd(int minutes, struct tm *tm)
1.1       deraadt   293: {
1.4       millert   294:        /* increment days */
1.1       deraadt   295:
1.4       millert   296:        while (minutes > 24*60) {
                    297:                minutes -= 24*60;
                    298:                tm->tm_mday++;
1.1       deraadt   299:        }
                    300:
1.4       millert   301:        /* increment hours */
                    302:        while (minutes > 60) {
                    303:                minutes -= 60;
                    304:                tm->tm_hour++;
                    305:                if (tm->tm_hour > 23) {
                    306:                        tm->tm_mday++;
                    307:                        tm->tm_hour = 0;
                    308:                }
                    309:        }
                    310:
                    311:        /* increment minutes */
                    312:        tm->tm_min += minutes;
1.1       deraadt   313:
1.4       millert   314:        if (tm->tm_min > 59) {
                    315:                tm->tm_hour++;
                    316:                tm->tm_min -= 60;
                    317:
                    318:                if (tm->tm_hour > 23) {
                    319:                        tm->tm_mday++;
                    320:                        tm->tm_hour = 0;
                    321:                }
1.1       deraadt   322:        }
1.11      millert   323: }
1.1       deraadt   324:
                    325:
                    326: /*
                    327:  * plus() parses a now + time
                    328:  *
1.20      millert   329:  *  at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
1.1       deraadt   330:  *
                    331:  */
1.13      millert   332: static int
1.10      millert   333: plus(struct tm *tm)
1.1       deraadt   334: {
1.20      millert   335:        int increment;
1.4       millert   336:        int expectplur;
                    337:
1.20      millert   338:        if (sc_tokid == NEXT) {
                    339:                increment = 1;
                    340:                expectplur = 0;
                    341:        } else {
                    342:                if (expect(NUMBER) != 0)
                    343:                        return (-1);
                    344:                increment = atoi(sc_token);
                    345:                expectplur = (increment != 1) ? 1 : 0;
                    346:        }
1.1       deraadt   347:
1.4       millert   348:        switch (token()) {
1.20      millert   349:        case YEARS:
                    350:                tm->tm_year += increment;
                    351:                return (0);
                    352:        case MONTHS:
                    353:                tm->tm_mon += increment;
                    354:                while (tm->tm_mon >= 12) {
                    355:                    tm->tm_year++;
                    356:                    tm->tm_mon -= 12;
                    357:                }
                    358:                return (0);
1.4       millert   359:        case WEEKS:
1.20      millert   360:                increment *= 7;
1.15      cloder    361:                /* FALLTHROUGH */
1.4       millert   362:        case DAYS:
1.20      millert   363:                increment *= 24;
1.15      cloder    364:                /* FALLTHROUGH */
1.4       millert   365:        case HOURS:
1.20      millert   366:                increment *= 60;
1.15      cloder    367:                /* FALLTHROUGH */
1.4       millert   368:        case MINUTES:
                    369:                if (expectplur != sc_tokplur)
1.26      millert   370:                        warnx("pluralization is wrong");
1.20      millert   371:                dateadd(increment, tm);
1.13      millert   372:                return (0);
1.4       millert   373:        }
1.1       deraadt   374:
1.4       millert   375:        plonk(sc_tokid);
1.13      millert   376:        return (-1);
1.11      millert   377: }
1.1       deraadt   378:
                    379:
                    380: /*
                    381:  * tod() computes the time of day
                    382:  *     [NUMBER [DOT NUMBER] [AM|PM]]
                    383:  */
1.13      millert   384: static int
1.10      millert   385: tod(struct tm *tm)
1.1       deraadt   386: {
1.4       millert   387:        int hour, minute = 0;
                    388:        size_t tlen;
                    389:
                    390:        hour = atoi(sc_token);
                    391:        tlen = strlen(sc_token);
                    392:
                    393:        /*
                    394:         * first pick out the time of day - if it's 4 digits, we assume
                    395:         * a HHMM time, otherwise it's HH DOT MM time
                    396:         */
                    397:        if (token() == DOT) {
1.13      millert   398:                if (expect(NUMBER) != 0)
                    399:                        return (-1);
1.4       millert   400:                minute = atoi(sc_token);
                    401:                if (minute > 59)
1.13      millert   402:                        goto bad;
1.4       millert   403:                token();
                    404:        } else if (tlen == 4) {
                    405:                minute = hour % 100;
                    406:                if (minute > 59)
1.13      millert   407:                        goto bad;
1.4       millert   408:                hour = hour / 100;
                    409:        }
1.1       deraadt   410:
1.4       millert   411:        /*
                    412:         * check if an AM or PM specifier was given
                    413:         */
                    414:        if (sc_tokid == AM || sc_tokid == PM) {
                    415:                if (hour > 12)
1.13      millert   416:                        goto bad;
1.4       millert   417:
                    418:                if (sc_tokid == PM) {
                    419:                        if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
                    420:                                hour += 12;
                    421:                } else {
                    422:                        if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
                    423:                                hour = 0;
                    424:                }
                    425:                token();
                    426:        } else if (hour > 23)
1.13      millert   427:                goto bad;
1.1       deraadt   428:
1.4       millert   429:        /*
                    430:         * if we specify an absolute time, we don't want to bump the day even
                    431:         * if we've gone past that time - but if we're specifying a time plus
                    432:         * a relative offset, it's okay to bump things
                    433:         */
1.20      millert   434:        if ((sc_tokid == EOF || sc_tokid == PLUS || sc_tokid == NEXT) &&
1.27    ! naddy     435:            (tm->tm_hour > hour ||
        !           436:            (tm->tm_hour == hour && tm->tm_min > minute))) {
1.4       millert   437:                tm->tm_mday++;
                    438:                tm->tm_wday++;
                    439:        }
1.1       deraadt   440:
1.4       millert   441:        tm->tm_hour = hour;
                    442:        tm->tm_min = minute;
                    443:        if (tm->tm_hour == 24) {
                    444:                tm->tm_hour = 0;
                    445:                tm->tm_mday++;
                    446:        }
1.13      millert   447:        return (0);
                    448: bad:
1.26      millert   449:        warnx("garbled time");
1.13      millert   450:        return (-1);
1.11      millert   451: }
1.1       deraadt   452:
                    453:
                    454: /*
                    455:  * assign_date() assigns a date, wrapping to next year if needed
                    456:  */
                    457: static void
1.10      millert   458: assign_date(struct tm *tm, int mday, int mon, int year)
1.1       deraadt   459: {
1.9       millert   460:
                    461:        /*
                    462:         * Convert year into tm_year format (year - 1900).
                    463:         * We may be given the year in 2 digit, 4 digit, or tm_year format.
                    464:         */
                    465:        if (year != -1) {
1.22      millert   466:                if (year >= 1900)
                    467:                        year -= 1900;   /* convert from 4 digit year */
1.9       millert   468:                else if (year < 100) {
                    469:                        /* Convert to tm_year assuming current century */
                    470:                        year += (tm->tm_year / 100) * 100;
                    471:
                    472:                        if (year == tm->tm_year - 1)
                    473:                                year++;         /* Common off by one error */
                    474:                        else if (year < tm->tm_year)
                    475:                                year += 100;    /* must be in next century */
                    476:                }
1.4       millert   477:        }
                    478:
                    479:        if (year < 0 &&
                    480:            (tm->tm_mon > mon ||(tm->tm_mon == mon && tm->tm_mday > mday)))
                    481:                year = tm->tm_year + 1;
1.1       deraadt   482:
1.4       millert   483:        tm->tm_mday = mday;
                    484:        tm->tm_mon = mon;
1.1       deraadt   485:
1.4       millert   486:        if (year >= 0)
                    487:                tm->tm_year = year;
1.11      millert   488: }
1.1       deraadt   489:
                    490:
1.14      millert   491: /*
1.1       deraadt   492:  * month() picks apart a month specification
                    493:  *
                    494:  *  /[<month> NUMBER [NUMBER]]           \
                    495:  *  |[TOMORROW]                          |
1.4       millert   496:  *  |[DAY OF WEEK]                       |
1.1       deraadt   497:  *  |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
1.20      millert   498:  *  \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS/
1.1       deraadt   499:  */
1.13      millert   500: static int
1.10      millert   501: month(struct tm *tm)
1.1       deraadt   502: {
1.4       millert   503:        int year = (-1);
                    504:        int mday, wday, mon;
                    505:        size_t tlen;
                    506:
                    507:        switch (sc_tokid) {
1.20      millert   508:        case NEXT:
1.4       millert   509:        case PLUS:
1.13      millert   510:                if (plus(tm) != 0)
                    511:                        return (-1);
1.4       millert   512:                break;
                    513:
                    514:        case TOMORROW:
                    515:                /* do something tomorrow */
                    516:                tm->tm_mday++;
                    517:                tm->tm_wday++;
                    518:        case TODAY:
                    519:                /* force ourselves to stay in today - no further processing */
1.1       deraadt   520:                token();
1.4       millert   521:                break;
1.1       deraadt   522:
1.4       millert   523:        case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
                    524:        case JUL: case AUG: case SEP: case OCT: case NOV: case DEC:
                    525:                /*
                    526:                 * do month mday [year]
                    527:                 */
                    528:                mon = sc_tokid - JAN;
1.13      millert   529:                if (expect(NUMBER) != 0)
                    530:                        return (-1);
1.4       millert   531:                mday = atoi(sc_token);
                    532:                if (token() == NUMBER) {
                    533:                        year = atoi(sc_token);
                    534:                        token();
1.1       deraadt   535:                }
1.4       millert   536:                assign_date(tm, mday, mon, year);
                    537:                break;
                    538:
                    539:        case SUN: case MON: case TUE:
                    540:        case WED: case THU: case FRI:
                    541:        case SAT:
                    542:                /* do a particular day of the week */
                    543:                wday = sc_tokid - SUN;
                    544:
                    545:                mday = tm->tm_mday;
                    546:
                    547:                /* if this day is < today, then roll to next week */
                    548:                if (wday < tm->tm_wday)
                    549:                        mday += 7 - (tm->tm_wday - wday);
                    550:                else
                    551:                        mday += (wday - tm->tm_wday);
                    552:
                    553:                tm->tm_wday = wday;
                    554:
                    555:                assign_date(tm, mday, tm->tm_mon, tm->tm_year);
                    556:                break;
1.1       deraadt   557:
1.4       millert   558:        case NUMBER:
1.1       deraadt   559:                /*
1.4       millert   560:                 * get numeric MMDDYY, mm/dd/yy, or dd.mm.yy
1.1       deraadt   561:                 */
1.4       millert   562:                tlen = strlen(sc_token);
                    563:                mon = atoi(sc_token);
                    564:                token();
1.1       deraadt   565:
1.4       millert   566:                if (sc_tokid == SLASH || sc_tokid == DOT) {
                    567:                        int sep;
1.1       deraadt   568:
1.4       millert   569:                        sep = sc_tokid;
1.13      millert   570:                        if (expect(NUMBER) != 0)
                    571:                                return (-1);
1.4       millert   572:                        mday = atoi(sc_token);
                    573:                        if (token() == sep) {
1.13      millert   574:                                if (expect(NUMBER) != 0)
                    575:                                        return (-1);
1.4       millert   576:                                year = atoi(sc_token);
                    577:                                token();
                    578:                        }
                    579:
                    580:                        /*
                    581:                         * flip months and days for european timing
                    582:                         */
                    583:                        if (sep == DOT) {
                    584:                                int x = mday;
                    585:                                mday = mon;
                    586:                                mon = x;
                    587:                        }
                    588:                } else if (tlen == 6 || tlen == 8) {
                    589:                        if (tlen == 8) {
1.22      millert   590:                                year = (mon % 10000) - 1900;
1.4       millert   591:                                mon /= 10000;
                    592:                        } else {
                    593:                                year = mon % 100;
                    594:                                mon /= 100;
                    595:                        }
                    596:                        mday = mon % 100;
                    597:                        mon /= 100;
                    598:                } else
1.13      millert   599:                        goto bad;
1.4       millert   600:
                    601:                mon--;
                    602:                if (mon < 0 || mon > 11 || mday < 1 || mday > 31)
1.13      millert   603:                        goto bad;
1.4       millert   604:
                    605:                assign_date(tm, mday, mon, year);
                    606:                break;
1.13      millert   607:        }
                    608:        return (0);
                    609: bad:
1.26      millert   610:        warnx("garbled time");
1.13      millert   611:        return (-1);
1.11      millert   612: }
1.1       deraadt   613:
                    614:
                    615: time_t
1.10      millert   616: parsetime(int argc, char **argv)
1.1       deraadt   617: {
1.4       millert   618:        /*
                    619:         * Do the argument parsing, die if necessary, and return the
                    620:         * time the job should be run.
                    621:         */
                    622:        time_t nowtimer, runtimer;
                    623:        struct tm nowtime, runtime;
                    624:        int hr = 0;
                    625:        /* this MUST be initialized to zero for midnight/noon/teatime */
                    626:
1.13      millert   627:        if (argc == 0)
                    628:                return (-1);
                    629:
1.4       millert   630:        nowtimer = time(NULL);
                    631:        nowtime = *localtime(&nowtimer);
                    632:
                    633:        runtime = nowtime;
                    634:        runtime.tm_sec = 0;
                    635:        runtime.tm_isdst = 0;
                    636:
1.13      millert   637:        if (init_scanner(argc, argv) == -1)
                    638:                return (-1);
1.4       millert   639:
                    640:        switch (token()) {
                    641:        case NOW:       /* now is optional prefix for PLUS tree */
1.5       millert   642:                token();
                    643:                if (sc_tokid == EOF) {
                    644:                        runtime = nowtime;
                    645:                        break;
                    646:                }
1.20      millert   647:                else if (sc_tokid != PLUS && sc_tokid != NEXT)
1.5       millert   648:                        plonk(sc_tokid);
1.20      millert   649:        case NEXT:
1.4       millert   650:        case PLUS:
1.13      millert   651:                if (plus(&runtime) != 0)
                    652:                        return (-1);
1.4       millert   653:                break;
                    654:
                    655:        case NUMBER:
1.13      millert   656:                if (tod(&runtime) != 0 || month(&runtime) != 0)
                    657:                        return (-1);
1.4       millert   658:                break;
                    659:
                    660:                /*
                    661:                 * evil coding for TEATIME|NOON|MIDNIGHT - we've initialised
                    662:                 * hr to zero up above, then fall into this case in such a
                    663:                 * way so we add +12 +4 hours to it for teatime, +12 hours
                    664:                 * to it for noon, and nothing at all for midnight, then
                    665:                 * set our runtime to that hour before leaping into the
                    666:                 * month scanner
                    667:                 */
                    668:        case TEATIME:
                    669:                hr += 4;
1.15      cloder    670:                /* FALLTHROUGH */
1.4       millert   671:        case NOON:
                    672:                hr += 12;
1.15      cloder    673:                /* FALLTHROUGH */
1.4       millert   674:        case MIDNIGHT:
                    675:                if (runtime.tm_hour >= hr) {
                    676:                        runtime.tm_mday++;
                    677:                        runtime.tm_wday++;
                    678:                }
                    679:                runtime.tm_hour = hr;
                    680:                runtime.tm_min = 0;
                    681:                token();
                    682:                /* fall through to month setting */
1.15      cloder    683:                /* FALLTHROUGH */
1.4       millert   684:        default:
1.13      millert   685:                if (month(&runtime) != 0)
                    686:                        return (-1);
1.4       millert   687:                break;
                    688:        } /* ugly case statement */
1.13      millert   689:        if (expect(EOF) != 0)
                    690:                return (-1);
1.4       millert   691:
                    692:        /*
                    693:         * adjust for daylight savings time
                    694:         */
                    695:        runtime.tm_isdst = -1;
1.1       deraadt   696:        runtimer = mktime(&runtime);
                    697:
1.13      millert   698:        if (runtimer < 0) {
1.26      millert   699:                warnx("garbled time");
1.13      millert   700:                return (-1);
                    701:        }
1.1       deraadt   702:
1.13      millert   703:        if (nowtimer > runtimer) {
1.26      millert   704:                warnx("cannot schedule jobs in the past");
1.13      millert   705:                return (-1);
                    706:        }
1.1       deraadt   707:
1.4       millert   708:        return (runtimer);
1.11      millert   709: }