parsetime.c revision 35729
119370Spst/* 2130803Smarcel * parsetime.c - parse time for at(1) 398944Sobrien * Copyright (C) 1993, 1994 Thomas Koenig 4130803Smarcel * 546283Sdfr * modifications for english-language times 619370Spst * Copyright (C) 1993 David Parsons 798944Sobrien * 819370Spst * Redistribution and use in source and binary forms, with or without 998944Sobrien * modification, are permitted provided that the following conditions 1098944Sobrien * are met: 1198944Sobrien * 1. Redistributions of source code must retain the above copyright 1298944Sobrien * notice, this list of conditions and the following disclaimer. 1319370Spst * 2. The name of the author(s) may not be used to endorse or promote 1498944Sobrien * products derived from this software without specific prior written 1598944Sobrien * permission. 1698944Sobrien * 1798944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1819370Spst * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1998944Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2098944Sobrien * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 2198944Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2298944Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2319370Spst * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2419370Spst * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2519370Spst * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2619370Spst * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2798944Sobrien * 28130803Smarcel * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS 2998944Sobrien * /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \ 30130803Smarcel * |NOON | |[TOMORROW] | 31130803Smarcel * |MIDNIGHT | |[DAY OF WEEK] | 32130803Smarcel * \TEATIME / |NUMBER [SLASH NUMBER [SLASH NUMBER]]| 33130803Smarcel * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/ 34130803Smarcel */ 35130803Smarcel 3619370Spst/* System Headers */ 37130803Smarcel 38130803Smarcel 39130803Smarcel#include <sys/types.h> 40130803Smarcel#include <err.h> 41130803Smarcel#include <errno.h> 4219370Spst#include <stdio.h> 43130803Smarcel#include <stdlib.h> 44130803Smarcel#include <string.h> 45130803Smarcel#include <time.h> 46130803Smarcel#include <unistd.h> 47130803Smarcel#include <ctype.h> 48130803Smarcel#ifndef __FreeBSD__ 49130803Smarcel#include <getopt.h> 50130803Smarcel#endif 51130803Smarcel 52130803Smarcel/* Local headers */ 5319370Spst 54130803Smarcel#include "at.h" 55130803Smarcel#include "panic.h" 56130803Smarcel 57130803Smarcel 58130803Smarcel/* Structures and unions */ 59130803Smarcel 60130803Smarcelenum { /* symbols */ 61130803Smarcel MIDNIGHT, NOON, TEATIME, 62130803Smarcel PM, AM, TOMORROW, TODAY, NOW, 63130803Smarcel MINUTES, HOURS, DAYS, WEEKS, 64130803Smarcel NUMBER, PLUS, DOT, SLASH, ID, JUNK, 65130803Smarcel JAN, FEB, MAR, APR, MAY, JUN, 66130803Smarcel JUL, AUG, SEP, OCT, NOV, DEC, 67130803Smarcel SUN, MON, TUE, WED, THU, FRI, SAT 68130803Smarcel }; 69130803Smarcel 70130803Smarcel/* parse translation table - table driven parsers can be your FRIEND! 71130803Smarcel */ 72130803Smarcelstruct { 73130803Smarcel char *name; /* token name */ 74130803Smarcel int value; /* token id */ 75130803Smarcel int plural; /* is this plural? */ 76130803Smarcel} Specials[] = { 77130803Smarcel { "midnight", MIDNIGHT,0 }, /* 00:00:00 of today or tomorrow */ 78130803Smarcel { "noon", NOON,0 }, /* 12:00:00 of today or tomorrow */ 7919370Spst { "teatime", TEATIME,0 }, /* 16:00:00 of today or tomorrow */ 8098944Sobrien { "am", AM,0 }, /* morning times for 0-12 clock */ 81130803Smarcel { "pm", PM,0 }, /* evening times for 0-12 clock */ 82130803Smarcel { "tomorrow", TOMORROW,0 }, /* execute 24 hours from time */ 83130803Smarcel { "today", TODAY, 0 }, /* execute today - don't advance time */ 84130803Smarcel { "now", NOW,0 }, /* opt prefix for PLUS */ 85130803Smarcel 86130803Smarcel { "minute", MINUTES,0 }, /* minutes multiplier */ 8746283Sdfr { "minutes", MINUTES,1 }, /* (pluralized) */ 88130803Smarcel { "hour", HOURS,0 }, /* hours ... */ 89130803Smarcel { "hours", HOURS,1 }, /* (pluralized) */ 9098944Sobrien { "day", DAYS,0 }, /* days ... */ 91130803Smarcel { "days", DAYS,1 }, /* (pluralized) */ 92130803Smarcel { "week", WEEKS,0 }, /* week ... */ 93130803Smarcel { "weeks", WEEKS,1 }, /* (pluralized) */ 94130803Smarcel { "jan", JAN,0 }, 95130803Smarcel { "feb", FEB,0 }, 96130803Smarcel { "mar", MAR,0 }, 9798944Sobrien { "apr", APR,0 }, 98130803Smarcel { "may", MAY,0 }, 99130803Smarcel { "jun", JUN,0 }, 100130803Smarcel { "jul", JUL,0 }, 101130803Smarcel { "aug", AUG,0 }, 102130803Smarcel { "sep", SEP,0 }, 10398944Sobrien { "oct", OCT,0 }, 104130803Smarcel { "nov", NOV,0 }, 105130803Smarcel { "dec", DEC,0 }, 106130803Smarcel { "sunday", SUN, 0 }, 10798944Sobrien { "sun", SUN, 0 }, 108130803Smarcel { "monday", MON, 0 }, 109130803Smarcel { "mon", MON, 0 }, 110130803Smarcel { "tuesday", TUE, 0 }, 11198944Sobrien { "tue", TUE, 0 }, 112130803Smarcel { "wednesday", WED, 0 }, 113130803Smarcel { "wed", WED, 0 }, 114130803Smarcel { "thursday", THU, 0 }, 115130803Smarcel { "thu", THU, 0 }, 116130803Smarcel { "friday", FRI, 0 }, 117130803Smarcel { "fri", FRI, 0 }, 11898944Sobrien { "saturday", SAT, 0 }, 119130803Smarcel { "sat", SAT, 0 }, 120130803Smarcel} ; 121130803Smarcel 122130803Smarcel/* File scope variables */ 123130803Smarcel 124130803Smarcelstatic char **scp; /* scanner - pointer at arglist */ 125130803Smarcelstatic char scc; /* scanner - count of remaining arguments */ 126130803Smarcelstatic char *sct; /* scanner - next char pointer in current argument */ 127130803Smarcelstatic int need; /* scanner - need to advance to next argument */ 128130803Smarcel 129130803Smarcelstatic char *sc_token; /* scanner - token buffer */ 130130803Smarcelstatic size_t sc_len; /* scanner - lenght of token buffer */ 13146283Sdfrstatic int sc_tokid; /* scanner - token id */ 13298944Sobrienstatic int sc_tokplur; /* scanner - is token plural? */ 13398944Sobrien 13498944Sobrienstatic char rcsid[] = "$Id: parsetime.c,v 1.11 1997/06/24 06:26:32 charnier Exp $"; 13519370Spst 13619370Spst/* Local functions */ 13719370Spst 13819370Spst/* 13919370Spst * parse a token, checking if it's something special to us 14019370Spst */ 141130803Smarcelstatic int 14219370Spstparse_token(char *arg) 14398944Sobrien{ 144130803Smarcel int i; 145130803Smarcel 146130803Smarcel for (i=0; i<(sizeof Specials/sizeof Specials[0]); i++) 147130803Smarcel if (strcasecmp(Specials[i].name, arg) == 0) { 148130803Smarcel sc_tokplur = Specials[i].plural; 14998944Sobrien return sc_tokid = Specials[i].value; 15098944Sobrien } 15198944Sobrien 15298944Sobrien /* not special - must be some random id */ 15398944Sobrien return ID; 15498944Sobrien} /* parse_token */ 15598944Sobrien 15698944Sobrien 15798944Sobrien/* 15898944Sobrien * init_scanner() sets up the scanner to eat arguments 15919370Spst */ 160130803Smarcelstatic void 16119370Spstinit_scanner(int argc, char **argv) 16219370Spst{ 16319370Spst scp = argv; 164130803Smarcel scc = argc; 16546283Sdfr need = 1; 16646283Sdfr sc_len = 1; 167130803Smarcel while (argc-- > 0) 16819370Spst sc_len += strlen(*argv++); 16919370Spst 17019370Spst sc_token = (char *) mymalloc(sc_len); 17146283Sdfr} /* init_scanner */ 17246283Sdfr 17398944Sobrien/* 174130803Smarcel * token() fetches a token from the input stream 175130803Smarcel */ 176130803Smarcelstatic int 177130803Smarceltoken() 178130803Smarcel{ 179130803Smarcel int idx; 180130803Smarcel 181130803Smarcel while (1) { 182130803Smarcel memset(sc_token, 0, sc_len); 18319370Spst sc_tokid = EOF; 18419370Spst sc_tokplur = 0; 18546283Sdfr idx = 0; 18619370Spst 187130803Smarcel /* if we need to read another argument, walk along the argument list; 18819370Spst * when we fall off the arglist, we'll just return EOF forever 189130803Smarcel */ 190130803Smarcel if (need) { 191130803Smarcel if (scc < 1) 192130803Smarcel return sc_tokid; 193130803Smarcel sct = *scp; 194130803Smarcel scp++; 195130803Smarcel scc--; 196130803Smarcel need = 0; 19746283Sdfr } 19846283Sdfr /* eat whitespace now - if we walk off the end of the argument, 199130803Smarcel * we'll continue, which puts us up at the top of the while loop 20046283Sdfr * to fetch the next argument in 201130803Smarcel */ 202130803Smarcel while (isspace(*sct)) 203130803Smarcel ++sct; 204130803Smarcel if (!*sct) { 20546283Sdfr need = 1; 20646283Sdfr continue; 207130803Smarcel } 20898944Sobrien 20946283Sdfr /* preserve the first character of the new token 210130803Smarcel */ 211130803Smarcel sc_token[0] = *sct++; 212130803Smarcel 21319370Spst /* then see what it is 21498944Sobrien */ 21598944Sobrien if (isdigit(sc_token[0])) { 21619370Spst while (isdigit(*sct)) 21719370Spst sc_token[++idx] = *sct++; 21819370Spst sc_token[++idx] = 0; 21919370Spst return sc_tokid = NUMBER; 220130803Smarcel } 22119370Spst else if (isalpha(sc_token[0])) { 22219370Spst while (isalpha(*sct)) 22319370Spst sc_token[++idx] = *sct++; 22419370Spst sc_token[++idx] = 0; 22519370Spst return parse_token(sc_token); 22619370Spst } 22746283Sdfr else if (sc_token[0] == ':' || sc_token[0] == '.') 22846283Sdfr return sc_tokid = DOT; 22946283Sdfr else if (sc_token[0] == '+') 23019370Spst return sc_tokid = PLUS; 231130803Smarcel else if (sc_token[0] == '/') 23219370Spst return sc_tokid = SLASH; 233130803Smarcel else 234130803Smarcel return sc_tokid = JUNK; 235130803Smarcel } /* while (1) */ 236130803Smarcel} /* token */ 237130803Smarcel 238130803Smarcel 239130803Smarcel/* 240130803Smarcel * plonk() gives an appropriate error message if a token is incorrect 241130803Smarcel */ 24219370Spststatic void 24319370Spstplonk(int tok) 24419370Spst{ 24519370Spst panic((tok == EOF) ? "incomplete time" 24619370Spst : "garbled time"); 24719370Spst} /* plonk */ 24819370Spst 249130803Smarcel 250130803Smarcel/* 251130803Smarcel * expect() gets a token and dies most horribly if it's not the token we want 252130803Smarcel */ 253130803Smarcelstatic void 254130803Smarcelexpect(int desired) 255130803Smarcel{ 256130803Smarcel if (token() != desired) 257130803Smarcel plonk(sc_tokid); /* and we die here... */ 25819370Spst} /* expect */ 259130803Smarcel 260130803Smarcel 26119370Spst/* 262130803Smarcel * dateadd() adds a number of minutes to a date. It is extraordinarily 263130803Smarcel * stupid regarding day-of-month overflow, and will most likely not 264130803Smarcel * work properly 26519370Spst */ 26619370Spststatic void 26719370Spstdateadd(int minutes, struct tm *tm) 268130803Smarcel{ 269130803Smarcel /* increment days */ 270130803Smarcel 271130803Smarcel while (minutes > 24*60) { 272130803Smarcel minutes -= 24*60; 27319370Spst tm->tm_mday++; 27419370Spst } 27519370Spst 27619370Spst /* increment hours */ 27719370Spst while (minutes > 60) { 278130803Smarcel minutes -= 60; 279130803Smarcel tm->tm_hour++; 280130803Smarcel if (tm->tm_hour > 23) { 281130803Smarcel tm->tm_mday++; 282130803Smarcel tm->tm_hour = 0; 28319370Spst } 284130803Smarcel } 28519370Spst 28619370Spst /* increment minutes */ 28719370Spst tm->tm_min += minutes; 28819370Spst 28998944Sobrien if (tm->tm_min > 59) { 29019370Spst tm->tm_hour++; 29119370Spst tm->tm_min -= 60; 29219370Spst 29319370Spst if (tm->tm_hour > 23) { 29419370Spst tm->tm_mday++; 29519370Spst tm->tm_hour = 0; 29619370Spst } 29719370Spst } 29898944Sobrien} /* dateadd */ 29919370Spst 30098944Sobrien 30198944Sobrien/* 30298944Sobrien * plus() parses a now + time 30319370Spst * 304130803Smarcel * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS] 305130803Smarcel * 306130803Smarcel */ 307130803Smarcelstatic void 308130803Smarcelplus(struct tm *tm) 30998944Sobrien{ 31019370Spst int delay; 31198944Sobrien int expectplur; 31298944Sobrien 31398944Sobrien expect(NUMBER); 31498944Sobrien 31519370Spst delay = atoi(sc_token); 31698944Sobrien expectplur = (delay != 1) ? 1 : 0; 31798944Sobrien 31898944Sobrien switch (token()) { 31998944Sobrien case WEEKS: 32019370Spst delay *= 7; 32198944Sobrien case DAYS: 32298944Sobrien delay *= 24; 32319370Spst case HOURS: 32498944Sobrien delay *= 60; 32519370Spst case MINUTES: 326130803Smarcel if (expectplur != sc_tokplur) 327130803Smarcel warnx("pluralization is wrong"); 32819370Spst dateadd(delay, tm); 32998944Sobrien return; 33019370Spst } 33198944Sobrien plonk(sc_tokid); 33298944Sobrien} /* plus */ 33319370Spst 33498944Sobrien 33598944Sobrien/* 33619370Spst * tod() computes the time of day 33798944Sobrien * [NUMBER [DOT NUMBER] [AM|PM]] 33819370Spst */ 33998944Sobrienstatic void 34019370Spsttod(struct tm *tm) 34198944Sobrien{ 34298944Sobrien int hour, minute = 0; 34319370Spst int tlen; 34498944Sobrien 34519370Spst hour = atoi(sc_token); 34698944Sobrien tlen = strlen(sc_token); 34719370Spst 34898944Sobrien /* first pick out the time of day - if it's 4 digits, we assume 34998944Sobrien * a HHMM time, otherwise it's HH DOT MM time 35019370Spst */ 35198944Sobrien if (token() == DOT) { 35298944Sobrien expect(NUMBER); 35319370Spst minute = atoi(sc_token); 35498944Sobrien if (minute > 59) 35519370Spst panic("garbled time"); 35698944Sobrien token(); 35798944Sobrien } 35819370Spst else if (tlen == 4) { 35998944Sobrien minute = hour%100; 36019370Spst if (minute > 59) 36198944Sobrien panic("garbeld time"); 36219370Spst hour = hour/100; 36398944Sobrien } 36419370Spst 36598944Sobrien /* check if an AM or PM specifier was given 36619370Spst */ 36798944Sobrien if (sc_tokid == AM || sc_tokid == PM) { 36819370Spst if (hour > 12) 36998944Sobrien panic("garbled time"); 37019370Spst 37198944Sobrien if (sc_tokid == PM) { 37219370Spst if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */ 37398944Sobrien hour += 12; 37419370Spst } else { 37598944Sobrien if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */ 37646283Sdfr hour = 0; 37798944Sobrien } 37898944Sobrien token(); 37998944Sobrien } 38098944Sobrien else if (hour > 23) 38146283Sdfr panic("garbled time"); 382130803Smarcel 383130803Smarcel /* if we specify an absolute time, we don't want to bump the day even 384130803Smarcel * if we've gone past that time - but if we're specifying a time plus 38519370Spst * a relative offset, it's okay to bump things 38698944Sobrien */ 38719370Spst if ((sc_tokid == EOF || sc_tokid == PLUS) && tm->tm_hour > hour) { 38898944Sobrien tm->tm_mday++; 389130803Smarcel tm->tm_wday++; 39098944Sobrien } 39146283Sdfr 39298944Sobrien tm->tm_hour = hour; 39398944Sobrien tm->tm_min = minute; 39498944Sobrien if (tm->tm_hour == 24) { 39598944Sobrien tm->tm_hour = 0; 39698944Sobrien tm->tm_mday++; 39746283Sdfr } 39898944Sobrien} /* tod */ 39946283Sdfr 40098944Sobrien 40198944Sobrien/* 40298944Sobrien * assign_date() assigns a date, wrapping to next year if needed 40319370Spst */ 40419370Spststatic void 40598944Sobrienassign_date(struct tm *tm, long mday, long mon, long year) 40698944Sobrien{ 40719370Spst if (year > 99) { 40898944Sobrien if (year > 1899) 40998944Sobrien year -= 1900; 41019370Spst else 41198944Sobrien panic("garbled time"); 41219370Spst } else { 41398944Sobrien struct tm *lt; 41419370Spst time_t now; 41598944Sobrien 41619370Spst time(&now); 41798944Sobrien lt = localtime(&now); 41819370Spst 419130803Smarcel /* 420130803Smarcel * check if the specified year is in the next century. 42119370Spst * allow for one year of user error as many people will 42298944Sobrien * enter n - 1 at the start of year n. 42319370Spst */ 42498944Sobrien if (year < (lt->tm_year % 100) - 1) 42519370Spst year += 100; 426130803Smarcel /* adjust for the year 2000 and beyond */ 42719370Spst year += lt->tm_year - (lt->tm_year % 100); 42898944Sobrien } 42919370Spst 43098944Sobrien if (year < 0 && 43119370Spst (tm->tm_mon > mon ||(tm->tm_mon == mon && tm->tm_mday > mday))) 43298944Sobrien year = tm->tm_year + 1; 43398944Sobrien 43419370Spst tm->tm_mday = mday; 43598944Sobrien tm->tm_mon = mon; 43619370Spst 43798944Sobrien if (year >= 0) 43819370Spst tm->tm_year = year; 43998944Sobrien} /* assign_date */ 44019370Spst 44198944Sobrien 44219370Spst/* 44398944Sobrien * month() picks apart a month specification 44419370Spst * 44598944Sobrien * /[<month> NUMBER [NUMBER]] \ 44619370Spst * |[TOMORROW] | 44798944Sobrien * |[DAY OF WEEK] | 44819370Spst * |NUMBER [SLASH NUMBER [SLASH NUMBER]]| 44998944Sobrien * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/ 45019370Spst */ 45198944Sobrienstatic void 45219370Spstmonth(struct tm *tm) 45398944Sobrien{ 45498944Sobrien long year= (-1); 45598944Sobrien long mday, wday, mon; 45698944Sobrien int tlen; 45719370Spst 45898944Sobrien switch (sc_tokid) { 45919370Spst case PLUS: 46098944Sobrien plus(tm); 46119370Spst break; 46298944Sobrien 46319370Spst case TOMORROW: 46498944Sobrien /* do something tomorrow */ 46519370Spst tm->tm_mday ++; 46698944Sobrien tm->tm_wday ++; 46719370Spst case TODAY: /* force ourselves to stay in today - no further processing */ 46898944Sobrien token(); 46919370Spst break; 47098944Sobrien 47198944Sobrien case JAN: case FEB: case MAR: case APR: case MAY: case JUN: 47298944Sobrien case JUL: case AUG: case SEP: case OCT: case NOV: case DEC: 47398944Sobrien /* do month mday [year] 47419370Spst */ 47598944Sobrien mon = (sc_tokid-JAN); 47698944Sobrien expect(NUMBER); 47719370Spst mday = atol(sc_token); 47898944Sobrien if (token() == NUMBER) { 47998944Sobrien year = atol(sc_token); 48019370Spst token(); 48198944Sobrien } 48298944Sobrien assign_date(tm, mday, mon, year); 48319370Spst break; 48498944Sobrien 48519370Spst case SUN: case MON: case TUE: 48698944Sobrien case WED: case THU: case FRI: 48719370Spst case SAT: 48898944Sobrien /* do a particular day of the week 48919370Spst */ 49098944Sobrien wday = (sc_tokid-SUN); 49119370Spst 49298944Sobrien mday = tm->tm_mday; 49319370Spst 49498944Sobrien /* if this day is < today, then roll to next week 49519370Spst */ 496130803Smarcel if (wday < tm->tm_wday) 497130803Smarcel mday += 7 - (tm->tm_wday - wday); 49819370Spst else 49998944Sobrien mday += (wday - tm->tm_wday); 50098944Sobrien 50146283Sdfr tm->tm_wday = wday; 50298944Sobrien 50398944Sobrien assign_date(tm, mday, tm->tm_mon, tm->tm_year); 50419370Spst break; 50598944Sobrien 50698944Sobrien case NUMBER: 50719370Spst /* get numeric MMDDYY, mm/dd/yy, or dd.mm.yy 50898944Sobrien */ 50998944Sobrien tlen = strlen(sc_token); 51019370Spst mon = atol(sc_token); 51198944Sobrien token(); 51298944Sobrien 51319370Spst if (sc_tokid == SLASH || sc_tokid == DOT) { 51498944Sobrien int sep; 51598944Sobrien 51698944Sobrien sep = sc_tokid; 51719370Spst expect(NUMBER); 51898944Sobrien mday = atol(sc_token); 51919370Spst if (token() == sep) { 52098944Sobrien expect(NUMBER); 52198944Sobrien year = atol(sc_token); 52298944Sobrien token(); 52398944Sobrien } 52498944Sobrien 52519370Spst /* flip months and days for european timing 526242936Semaste */ 527242936Semaste if (sep == DOT) { 528242936Semaste int x = mday; 529242936Semaste mday = mon; 530242936Semaste mon = x; 53198944Sobrien } 53219370Spst } 53398944Sobrien else if (tlen == 6 || tlen == 8) { 53498944Sobrien if (tlen == 8) { 53598944Sobrien year = (mon % 10000) - 1900; 53619370Spst mon /= 10000; 53798944Sobrien } 53819370Spst else { 53998944Sobrien year = mon % 100; 54098944Sobrien mon /= 100; 54119370Spst } 54298944Sobrien mday = mon % 100; 54319370Spst mon /= 100; 54498944Sobrien } 54519370Spst else 54698944Sobrien panic("garbled time"); 54719370Spst 54898944Sobrien mon--; 54919370Spst if (mon < 0 || mon > 11 || mday < 1 || mday > 31) 55098944Sobrien panic("garbled time"); 55119370Spst 55298944Sobrien assign_date(tm, mday, mon, year); 55319370Spst break; 55498944Sobrien } /* case */ 55519370Spst} /* month */ 55698944Sobrien 55719370Spst 55898944Sobrien/* Global functions */ 55998944Sobrien 56019370Spsttime_t 56198944Sobrienparsetime(int argc, char **argv) 56298944Sobrien{ 56319370Spst/* Do the argument parsing, die if necessary, and return the time the job 564130803Smarcel * should be run. 56519370Spst */ 56698944Sobrien time_t nowtimer, runtimer; 56719370Spst struct tm nowtime, runtime; 568130803Smarcel int hr = 0; 569130803Smarcel /* this MUST be initialized to zero for midnight/noon/teatime */ 570130803Smarcel 57146283Sdfr nowtimer = time(NULL); 572130803Smarcel nowtime = *localtime(&nowtimer); 573130803Smarcel 57498944Sobrien runtime = nowtime; 575 runtime.tm_sec = 0; 576 runtime.tm_isdst = 0; 577 578 if (argc <= optind) 579 usage(); 580 581 init_scanner(argc-optind, argv+optind); 582 583 switch (token()) { 584 case NOW: /* now is optional prefix for PLUS tree */ 585 expect(PLUS); 586 case PLUS: 587 plus(&runtime); 588 break; 589 590 case NUMBER: 591 tod(&runtime); 592 month(&runtime); 593 break; 594 595 /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialised 596 * hr to zero up above, then fall into this case in such a 597 * way so we add +12 +4 hours to it for teatime, +12 hours 598 * to it for noon, and nothing at all for midnight, then 599 * set our runtime to that hour before leaping into the 600 * month scanner 601 */ 602 case TEATIME: 603 hr += 4; 604 case NOON: 605 hr += 12; 606 case MIDNIGHT: 607 if (runtime.tm_hour >= hr) { 608 runtime.tm_mday++; 609 runtime.tm_wday++; 610 } 611 runtime.tm_hour = hr; 612 runtime.tm_min = 0; 613 token(); 614 /* fall through to month setting */ 615 default: 616 month(&runtime); 617 break; 618 } /* ugly case statement */ 619 expect(EOF); 620 621 /* adjust for daylight savings time 622 */ 623 runtime.tm_isdst = -1; 624 runtimer = mktime(&runtime); 625 if (runtime.tm_isdst > 0) { 626 runtimer -= 3600; 627 runtimer = mktime(&runtime); 628 } 629 630 if (runtimer < 0) 631 panic("garbled time"); 632 633 if (nowtimer > runtimer) 634 panic("Trying to travel back in time"); 635 636 return runtimer; 637} /* parsetime */ 638