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

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