[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.9

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