#include #ifndef lint #if 0 static char date_sccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #else __IDSTRING(date_rcsid, "$NetBSD: skeleton.c,v 1.14 1997/10/20 03:41:16 lukem Exp $"); #endif #endif #define date_BYACC 1 #define date_MAJOR 1 #define date_MINOR 9 #define date_LEX date_lex() #define date_EMPTY -1 #define date_clearin (date_char=(date_EMPTY)) #define date_errok (date_errflag=0) #define date_RECOVERING (date_errflag!=0) #define date_PREFIX "date_" #line 31 "cooktime/date.y" #include #include #include #include #include #include #include #include #define date_STYPE int #define daysec (24L * 60L * 60L) #define AM 1 #define PM 2 #define DAYLIGHT 1 #define STANDARD 2 #define MAYBE 3 #define MAX_ID_LENGTH 20 static int timeflag; static int zoneflag; static int dateflag; static int dayflag; static int relflag; static time_t relsec; static time_t relmonth; static int hh; static int mm; static int ss; static int merid; static int day_light_flag; static int dayord; static int dayreq; static int month; static int day; static int year; static int ourzone; static char *lptr; extern date_STYPE date_lval; extern int date_debug; static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define epoch 1970 int date_parse(void); /* forward */ static int date_lex(void); /* forward */ /* * NAME * timeconv - convert a time * * SYNOPSIS * time_t timeconv(int hh, int mm, int ss, int mer); * * DESCRIPTION * The timeconv function is used to convert a time * specified in hours minutes and seconds, into seconds past midnight. * * ARGUMENTS * hh hours, range depends on the meridian * mm minutes, 0..59 * ss seconds, 0..59 * mer meridian to use: AM, PM or 24 * * RETURNS * time_t; seconds past midnight; -1 on any error. */ static time_t timeconv(int ahh, int amm, int ass, int mer) { time_t result; /* * perform sanity checks on input */ trace(("timeconv(ahh = %d, amm = %d, ass = %d, mer = %d)\n{\n", ahh, amm, ass, mer)); result = -1; if (amm < 0 || amm > 59 || ass < 0 || ass > 59) goto done; /* * perform range checks depending on the meridian */ switch (mer) { case AM: if (ahh < 1 || ahh > 12) goto done; if (ahh == 12) ahh = 0; break; case PM: if (ahh < 1 || ahh > 12) goto done; if (ahh == 12) ahh = 0; ahh += 12; break; case 24: if (ahh < 0 || ahh > 23) goto done; break; default: goto done; } result = ((ahh * 60L + amm) * 60L + ass); done: trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * dateconv - convert a date * * SYNOPSIS * time_t dateconv(int mm, int dd, int year, int h, int m, int s, * int mer, int zone, int dayflag); * * DESCRIPTION * The dateconv function may be used to convert a date after the * date string has been taken apart by date_parse. * * ARGUMENTS * mm month number, in the range 1..12 * year year number, in several ranges: * 0..37 means 2000..2037 * 70..99 means 1970..1999 * 1970..2037 mean themselves. * dd day of month, in the range 1..max, where max varies for * each month, as per the catchy jingle (except February, * which is a monster). * h hours since midnight or meridian * m minutes past hour * s seconds past minute * mer meridian, AM or PM. * zone minutes correction for the time zone. * dayflag whether to use daylight savings: STANDARD, DAYLIGHT or MAYBE. * * RETURNS * time_t; the time in seconds past Jan 1 0:00:00 1970 GMT, this will * always be positive or zero; -1 is returned for any error. * * CAVEAT * The date functions only work between 1970 and 2037, * because 0 is Jan 1 00:00:00 1970 GMT * and (2^31-1) is Jan 19 03:14:07 2038 GMT * hence some if the weir magic number below. * * Because -1 is used to represent errors, times before noon Jan 1 1970 * in places east of GMT can't always be represented. */ static time_t dateconv(int amm, int dd, int ayear, int h, int m, int s, int mer, int zone, int adayflag) { time_t result; time_t tod; time_t jdate; int i; /* * make corrections for the year * * If it is 0..99, RFC822 says pick closest century. */ trace(("dateconv(amm = %d, dd = %d, ayear = %d, h = %d, m = %d, s = %d, " "mer = %d, zone = %d, adayflag = %d)\n{\n", amm, dd, ayear, h, m, s, mer, zone, adayflag)); result = -1; if (ayear < 0) ayear = -ayear; if (ayear < 38) ayear += 2000; else if (ayear < 100) ayear += 1900; /* * correct February length once we know the year */ mdays[1] = 28 + (ayear % 4 == 0 && (ayear % 100 != 0 || ayear % 400 == 0)); /* * perform some sanity checks on the input */ if ( ayear < epoch || ayear >= 2038 || amm < 1 || amm > 12 || dd < 1 || dd > mdays[--amm] ) goto done; /* * Determine the julian day number of the dd-mm-date_ given. * Turn it into seconds, and add in the time zone correction. */ jdate = dd - 1; for (i = 0; i < amm; i++) jdate += mdays[i]; for (i = epoch; i < ayear; i++) jdate += 365 + (i % 4 == 0); jdate *= daysec; jdate += zone * 60L; /* * Determine the time of day. * that is, seconds from midnight. * Add it into the julian date. */ tod = timeconv(h, m, s, mer); if (tod < 0) goto done; jdate += tod; /* * Perform daylight savings correction if necessary. * (This assumes 1 hour daylite savings, which is probably wrong.) */ if ( adayflag == DAYLIGHT || (adayflag == MAYBE && localtime(&jdate)->tm_isdst) ) jdate += -1 * 60 * 60; /* * there you have it. */ result = jdate; done: trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * daylcorr * * SYNOPSIS * time_t daylcorr(time_t future, time_t now); * * DESCRIPTION * The daylcorr function is used to determine the difference in seconds * between two times, taking daylight savings into account. * * ARGUMENTS * future - a later time * now - an earlier time * * RETURNS * time_t; the difference in seconds * * CAVEAT * Assumes daylight savings is alays an integral number of hours. * This is wrong is Saudi Arabia (time zone changes during the day), * and South Australia (half hour DLS). */ static time_t daylcorr(time_t future, time_t now) { int fdayl; int nowdayl; time_t result; trace(("daylcorr(future = %ld, now = %ld)\n{\n", (long)future, (long)now)); nowdayl = (localtime(&now)->tm_hour + 1) % 24; fdayl = (localtime(&future)->tm_hour + 1) % 24; result = ((future - now) + 60L * 60L * (nowdayl - fdayl)); trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * dayconv * * SYNOPSIS * time_t dayconv(int ord, int day, time_t now); * * DESCRIPTION * The dayconv function is used to convert a day-of-the-week into * a meaningful time. * * ARGUMENTS * ord - the ord'th day from now * day - which day of the week * now - relative to this * * RETURNS * time_t; time in seconds from epoch */ static time_t dayconv(int ord, int aday, time_t now) { time_t tod; time_t result; trace(("dayconv(ord = %d, aday = %d, now = %ld)\n{\n", ord, aday, (long)now)); tod = now; tod += daysec * ((aday - localtime(&tod)->tm_wday + 7) % 7); tod += 7 * daysec * (ord <= 0 ? ord : ord - 1); result = daylcorr(tod, now); trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * monthadd * * SYNOPSIS * time_t monthadd(time_t sdate, time_t relmonth); * * DESCRIPTION * The monthadd function is used to add a given number of * months to a specified time. * * ARGUMENTS * sdate - add the months to this * relmonth - add this many months * * RETURNS * time_t; seconds since the epoch */ static time_t monthadd(time_t sdate, time_t arelmonth) { struct tm *ltime; int amm; int ayear; time_t result; trace(("monthadd(sdate = %ld, arelmonth = %ld)\n{\n", (long)sdate, (long)arelmonth)); if (arelmonth == 0) result = 0; else { ltime = localtime(&sdate); amm = 12 * (ltime->tm_year + 1900) + ltime->tm_mon + arelmonth; ayear = amm / 12; amm = amm % 12 + 1; result = dateconv ( amm, ltime->tm_mday, ayear, ltime->tm_hour, ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE ); if (result >= 0) result = daylcorr(result, sdate); } trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * date_scan * * SYNOPSIS * time_t date_scan(char *s); * * DESCRIPTION * The date_scan function is used to scan a string and * return a number of seconds since epoch. * * ARGUMENTS * s - string to scan * * RETURNS * time_t; seconds to epoch, -1 on error. * * CAVEAT * it isn't psychic */ time_t date_scan(char *p) { time_t now; struct tm *lt; time_t result; time_t tod; /* * find time zone info, if not given */ trace(("date_scan(p = \"%s\")\n{\n", p)); lptr = p; /* * initialize things */ time(&now); lt = localtime(&now); year = lt->tm_year + 1900; month = lt->tm_mon + 1; day = lt->tm_mday; relsec = 0; relmonth = 0; timeflag = 0; zoneflag = 0; dateflag = 0; dayflag = 0; relflag = 0; ourzone = 0; day_light_flag = MAYBE; hh = 0; mm = 0; ss = 0; merid = 24; /* * parse the string */ #ifdef DEBUG date_debug = trace_pretest_; #endif trace(("date_parse()\n{\n")); result = date_parse(); trace(("}\n")); if (result) { result = -1; goto done; } /* * sanity checks */ result = -1; if (timeflag > 1 || zoneflag > 1 || dateflag > 1 || dayflag > 1) goto done; if (dateflag || timeflag || dayflag) { result = dateconv ( month, day, year, hh, mm, ss, merid, ourzone, day_light_flag ); if (result < 0) goto done; } else { result = now; if (!relflag) { result -= ((lt->tm_hour * 60L + lt->tm_min * 60) + lt->tm_sec); } } result += relsec; relsec = monthadd(result, relmonth); if (relsec < 0) { result = -1; goto done; } result += relsec; if (dayflag && !dateflag) { tod = dayconv(dayord, dayreq, result); result += tod; } /* * here for all exits */ done: trace(("return %ld;\n", (long)result)); trace(("}\n")); return result; } /* * NAME * date_string - build one * * SYNOPSIS * char *date_string(time_t when); * * DESCRIPTION * The date_string function may be used to construct a * string from a given time in seconds. * * The string will conform to the RFC822 standard, * which states a definite preference for GMT dates. * * ARGUMENTS * when the time to be rendered. * * RETURNS * Pointer to string containing rendered time. * The contents of this string will remain undisturbed * only until the next call to date_string. */ char * date_string(time_t when) { struct tm *tm; static char buffer[32]; static char *weekday_name[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }; static char *month_name[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; /* * break the given time down into components * (RFC1036 likes GMT, remember) */ trace(("date_string(when = %ld)\n{\n", (long)when)); tm = gmtime(&when); /* * build the date string */ snprintf ( buffer, sizeof(buffer), "%s,%3d %s %4.4d %2.2d:%2.2d:%2.2d GMT", weekday_name[tm->tm_wday], tm->tm_mday, month_name[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec ); trace(("return \"%s\";\n", buffer)); trace(("}\n")); return buffer; } /* * NAME * date_error * * SYNOPSIS * void date_error(char *); * * DESCRIPTION * The date_error function is invoked by yacc to report * errors, but we just throw it away. * * ARGUMENTS * s - error to report */ static void date_error(char *s) { trace(("date_error(s = \"%s\")\n{\n", s)); (void)s; trace(("}\n")); } /* * NAME * date_trace - follow parser actions * * SYNOPSIS * void date_trace(char *, ...); * * DESCRIPTION * The date_trace function is used to print the various shifts * and reductions, etc, done by the yacc-generated parser. * lines are accumulated and printed whole, * so as to avoid confusing the trace output. * * ARGUMENTS * as for printf * * CAVEAT * only available when DEBUG is defined */ #ifdef DEBUG #define date_DEBUG 1 #define printf date_trace static void date_trace(char *s, ...) { va_list ap; static char line[1024]; string_ty *buffer; char *cp; sva_init(ap, s); buffer = str_vformat(s, ap); va_end(ap); cp = line + strlen(line); cp = strendcpy(cp, buffer->str_text, line + sizeof(line)); str_free(buffer); if (cp > line && cp[-1] == '\n') { --cp; *cp = 0; trace_printf("%s\n", line); line[0] = 0; } } #endif /* DEBUG */ #line 698 "y.tab.c" #define AGO 257 #define COLON 258 #define COMMA 259 #define DAY 260 #define DAYZONE 261 #define ID 262 #define JUNK 263 #define MERIDIAN 264 #define MONTH 265 #define MUNIT 266 #define NUMBER 267 #define SLASH 268 #define SUNIT 269 #define UNIT 270 #define ZONE 271 #define date_ERRCODE 256 short date_lhs[] = { -1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 2, 2, 2, 2, 2, 2, 2, 3, 3, 5, 5, 5, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, }; short date_len[] = { 2, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, 5, 6, 6, 1, 1, 1, 2, 2, 3, 5, 2, 4, 2, 3, 2, 2, 2, 1, 1, 1, 2, }; short date_defred[] = { 0, 3, 0, 0, 19, 0, 33, 0, 34, 32, 18, 2, 4, 5, 6, 7, 0, 9, 21, 0, 0, 22, 11, 0, 30, 0, 31, 29, 35, 0, 0, 28, 0, 26, 0, 13, 14, 0, 0, 24, 16, 17, }; short date_dgoto[] = { 2, 11, 12, 13, 14, 15, 16, 17, }; short date_sindex[] = { -253, 0, -243, -255, 0, -262, 0, -258, 0, 0, 0, 0, 0, 0, 0, 0, -242, 0, 0, -250, -247, 0, 0, -246, 0, -237, 0, 0, 0, -236, -229, 0, -254, 0, -235, 0, 0, -234, -248, 0, 0, 0, }; short date_rindex[] = { 1, 0, 0, 13, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 37, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 68, 0, 49, 0, 0, 0, 0, 0, 75, 0, 0, 0, }; short date_gindex[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; #define date_TABLESIZE 352 short date_table[] = { 20, 1, 21, 1, 18, 19, 22, 23, 24, 29, 25, 26, 27, 20, 37, 28, 40, 3, 4, 41, 30, 31, 5, 6, 7, 8, 8, 9, 10, 34, 32, 33, 38, 39, 0, 35, 0, 25, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 20, 20, 0, 0, 0, 20, 20, 20, 0, 20, 20, 20, 8, 8, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 25, 25, 0, 0, 0, 25, 25, 25, 0, 25, 25, 25, 23, 23, 0, 0, 0, 23, 23, 23, 0, 23, 23, 23, 27, 27, 0, 0, 0, 27, 27, 12, 12, 27, 27, 27, 12, 12, 15, 15, 12, 12, 12, 15, 15, 10, 0, 15, 15, 15, 0, 10, 0, 0, 0, 10, }; short date_check[] = { 258, 0, 260, 256, 259, 267, 264, 265, 266, 259, 268, 269, 270, 0, 268, 257, 264, 260, 261, 267, 267, 267, 265, 266, 267, 0, 269, 270, 271, 258, 267, 267, 267, 267, -1, 264, -1, 0, 267, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 260, 261, -1, -1, -1, 265, 266, 267, -1, 269, 270, 271, 260, 261, -1, -1, -1, 265, 266, 267, -1, 269, 270, 271, 260, 261, -1, -1, -1, 265, 266, 267, -1, 269, 270, 271, 260, 261, -1, -1, -1, 265, 266, 267, -1, 269, 270, 271, 260, 261, -1, -1, -1, 265, 266, 267, -1, 269, 270, 271, 260, 261, -1, -1, -1, 265, 266, 260, 261, 269, 270, 271, 265, 266, 260, 261, 269, 270, 271, 265, 266, 261, -1, 269, 270, 271, -1, 267, -1, -1, -1, 271, }; #define date_FINAL 2 #ifndef date_DEBUG #define date_DEBUG 0 #endif #define date_MAXTOKEN 271 #if date_DEBUG char *date_name[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"AGO","COLON","COMMA","DAY", "DAYZONE","ID","JUNK","MERIDIAN","MONTH","MUNIT","NUMBER","SLASH","SUNIT", "UNIT","ZONE", }; char *date_rule[] = { "$accept : timedate", "timedate :", "timedate : timedate item", "timedate : error", "item : TimeSpecification", "item : TimeZone", "item : DateSpecification", "item : DayOfWeekSpecification", "item : RelativeSpecification", "item : NumberSpecification", "NumberSpecification : NUMBER", "TimeSpecification : NUMBER MERIDIAN", "TimeSpecification : NUMBER COLON NUMBER", "TimeSpecification : NUMBER COLON NUMBER MERIDIAN", "TimeSpecification : NUMBER COLON NUMBER NUMBER", "TimeSpecification : NUMBER COLON NUMBER COLON NUMBER", "TimeSpecification : NUMBER COLON NUMBER COLON NUMBER MERIDIAN", "TimeSpecification : NUMBER COLON NUMBER COLON NUMBER NUMBER", "TimeZone : ZONE", "TimeZone : DAYZONE", "DayOfWeekSpecification : DAY", "DayOfWeekSpecification : DAY COMMA", "DayOfWeekSpecification : NUMBER DAY", "DateSpecification : NUMBER SLASH NUMBER", "DateSpecification : NUMBER SLASH NUMBER SLASH NUMBER", "DateSpecification : MONTH NUMBER", "DateSpecification : MONTH NUMBER COMMA NUMBER", "DateSpecification : NUMBER MONTH", "DateSpecification : NUMBER MONTH NUMBER", "RelativeSpecification : NUMBER UNIT", "RelativeSpecification : NUMBER MUNIT", "RelativeSpecification : NUMBER SUNIT", "RelativeSpecification : UNIT", "RelativeSpecification : MUNIT", "RelativeSpecification : SUNIT", "RelativeSpecification : RelativeSpecification AGO", }; #endif #ifndef date_STYPE typedef int date_STYPE; #endif #ifdef date_STACKSIZE #undef date_MAXDEPTH #define date_MAXDEPTH date_STACKSIZE #else #ifdef date_MAXDEPTH #define date_STACKSIZE date_MAXDEPTH #else #define date_STACKSIZE 10000 #define date_MAXDEPTH 10000 #endif #endif #define date_INITSTACKSIZE 200 int date_debug; int date_nerrs; int date_errflag; int date_char; short *date_ssp; date_STYPE *date_vsp; date_STYPE date_val; date_STYPE date_lval; short *date_ss; short *date_sslim; date_STYPE *date_vs; int date_stacksize; #line 899 "cooktime/date.y" /* The following need to be here to make sure Berkeley Yacc doesn't puke. */ /* * NAME * table - list of known names * * SYNOPSIS * table_t table[]; * * DESCRIPTION * The table is used to hold the list of known names. * This includes time zone names and days of the week, etc. * * CAVEAT * It is in English. * It is impossible to have a full list of time zones. */ typedef struct table_t table_t; struct table_t { char *name; int type; int value; }; #define HRMIN(a, b) ((a) * 60 + (b)) static table_t table[] = { { "a", ZONE, HRMIN(1, 0), }, { "a.c.s.s.t.", DAYZONE, -HRMIN(9, 30), }, { "a.c.s.t.", ZONE, -HRMIN(9, 30), }, { "a.d.t.", DAYZONE, HRMIN(4, 0), }, { "a.e.s.s.t.", DAYZONE, -HRMIN(10, 0), }, { "a.e.s.t.", ZONE, -HRMIN(10, 0), }, { "a.m.", MERIDIAN, AM, }, { "a.s.t.", ZONE, HRMIN(4, 0), }, { "a.w.s.t.", ZONE, -HRMIN(8, 0), }, /* (no daylight time there, I'm told */ { "acsst", DAYZONE, -HRMIN(9, 30), }, /* Australian Central Summer */ { "acst", ZONE, -HRMIN(9, 30), }, /* Australian Central Time */ { "adt", DAYZONE, HRMIN(4, 0), }, { "aesst", DAYZONE, -HRMIN(10, 0), }, /* Australian Eastern Summer Time */ { "aest", ZONE, -HRMIN(10, 0), }, /* Australian Eastern Time */ { "ago", AGO, 1, }, { "am", MERIDIAN, AM, }, { "apr", MONTH, 4, }, { "apr.", MONTH, 4, }, { "april", MONTH, 4, }, { "ast", ZONE, HRMIN(4, 0), }, /* Atlantic */ { "aug", MONTH, 8, }, { "aug.", MONTH, 8, }, { "august", MONTH, 8, }, { "awst", ZONE, -HRMIN(8, 0), }, /* Australian Western Time */ { "b", ZONE, HRMIN(2, 0), }, { "b.s.t.", DAYZONE, HRMIN(0, 0), }, { "bst", DAYZONE, HRMIN(0, 0), }, /* British Summer Time */ { "c", ZONE, HRMIN(3, 0), }, { "c.d.t.", DAYZONE, HRMIN(6, 0), }, { "c.s.t.", ZONE, HRMIN(6, 0), }, { "cdt", DAYZONE, HRMIN(6, 0), }, { "cst", ZONE, HRMIN(6, 0), }, /* Central */ { "d", ZONE, HRMIN(4, 0), }, { "day", UNIT, 1 * 24 * 60, }, { "days", UNIT, 1 * 24 * 60, }, { "dec", MONTH, 12, }, { "dec.", MONTH, 12, }, { "december", MONTH, 12, }, { "e", ZONE, HRMIN(5, 0), }, { "e.d.t.", DAYZONE, HRMIN(5, 0), }, { "e.e.s.t.", DAYZONE, HRMIN(0, 0), }, { "e.e.t.", ZONE, HRMIN(0, 0), }, { "e.s.t.", ZONE, HRMIN(5, 0), }, { "edt", DAYZONE, HRMIN(5, 0), }, { "eest", DAYZONE, HRMIN(0, 0), }, /* European Eastern Summer Time */ { "eet", ZONE, HRMIN(0, 0), }, /* European Eastern Time */ { "eigth", NUMBER, 8, }, { "eleventh", NUMBER, 11, }, { "est", ZONE, HRMIN(5, 0), }, /* Eastern */ { "f", ZONE, HRMIN(6, 0), }, { "feb", MONTH, 2, }, { "feb.", MONTH, 2, }, { "february", MONTH, 2, }, { "fifth", NUMBER, 5, }, { "first", NUMBER, 1, }, { "fortnight", UNIT, 14 * 24 * 60, }, { "fortnights", UNIT, 14 * 24 * 60, }, { "fourth", NUMBER, 4, }, { "fri", DAY, 5, }, { "fri.", DAY, 5, }, { "friday", DAY, 5, }, { "g", ZONE, HRMIN(7, 0), }, { "g.m.t.", ZONE, HRMIN(0, 0), }, { "gmt", ZONE, HRMIN(0, 0), }, { "h", ZONE, HRMIN(8, 0), }, { "h.d.t.", DAYZONE, HRMIN(10, 0), }, { "h.s.t.", ZONE, HRMIN(10, 0), }, { "hdt", DAYZONE, HRMIN(10, 0), }, { "hour", UNIT, 60, }, { "hours", UNIT, 60, }, { "hr", UNIT, 60, }, { "hrs", UNIT, 60, }, { "hst", ZONE, HRMIN(10, 0), }, /* Hawaii */ { "i", ZONE, HRMIN(9, 0), }, { "j.s.t.", ZONE, -HRMIN(9, 0), }, /* Japan Standard Time */ { "jan", MONTH, 1, }, { "jan.", MONTH, 1, }, { "january", MONTH, 1, }, { "jst", ZONE, -HRMIN(9, 0), }, /* Japan Standard Time */ { "jul", MONTH, 7, }, { "jul.", MONTH, 7, }, { "july", MONTH, 7, }, { "jun", MONTH, 6, }, { "jun.", MONTH, 6, }, { "june", MONTH, 6, }, { "k", ZONE, HRMIN(10, 0), }, { "l", ZONE, HRMIN(11, 0), }, { "last", NUMBER, -1, }, { "m", ZONE, HRMIN(12, 0), }, { "m.d.t.", DAYZONE, HRMIN(7, 0), }, { "m.e.s.t.", DAYZONE, -HRMIN(1, 0), }, { "m.e.t.", ZONE, -HRMIN(1, 0), }, { "m.s.t.", ZONE, HRMIN(7, 0), }, { "mar", MONTH, 3, }, { "mar.", MONTH, 3, }, { "march", MONTH, 3, }, { "may", MONTH, 5, }, { "mdt", DAYZONE, HRMIN(7, 0), }, { "mest", DAYZONE, -HRMIN(1, 0), }, /* Middle European Summer Time */ { "met", ZONE, -HRMIN(1, 0), }, /* Middle European Time */ { "min", UNIT, 1, }, { "mins", UNIT, 1, }, { "minute", UNIT, 1, }, { "minutes", UNIT, 1, }, { "mon", DAY, 1, }, { "mon.", DAY, 1, }, { "monday", DAY, 1, }, { "month", MUNIT, 1, }, { "months", MUNIT, 1, }, { "mst", ZONE, HRMIN(7, 0), }, /* Mountain */ { "n", ZONE, -HRMIN(1, 0), }, { "n.s.t.", ZONE, HRMIN(3, 30), }, { "next", NUMBER, 2, }, { "ninth", NUMBER, 9, }, { "nov", MONTH, 11, }, { "nov.", MONTH, 11, }, { "november", MONTH, 11, }, { "now", UNIT, 0, }, { "nst", ZONE, HRMIN(3, 30), }, /* Newfoundland */ { "o", ZONE, -HRMIN(2, 0), }, { "oct", MONTH, 10, }, { "oct.", MONTH, 10, }, { "october", MONTH, 10, }, { "p", ZONE, -HRMIN(3, 0), }, { "p.d.t.", DAYZONE, HRMIN(8, 0), }, { "p.m.", MERIDIAN, PM, }, { "p.s.t.", ZONE, HRMIN(8, 0), }, { "pdt", DAYZONE, HRMIN(8, 0), }, { "pm", MERIDIAN, PM, }, { "pst", ZONE, HRMIN(8, 0), }, /* Pacific */ { "q", ZONE, -HRMIN(4, 0), }, { "r", ZONE, -HRMIN(5, 0), }, { "s", ZONE, -HRMIN(6, 0), }, { "sat", DAY, 6, }, { "sat.", DAY, 6, }, { "saturday", DAY, 6, }, { "sec", SUNIT, 1, }, { "second", SUNIT, 1, }, { "seconds", SUNIT, 1, }, { "secs", SUNIT, 1, }, { "sep", MONTH, 9, }, { "sep.", MONTH, 9, }, { "sept", MONTH, 9, }, { "sept.", MONTH, 9, }, { "september", MONTH, 9, }, { "seventh", NUMBER, 7, }, { "sixth", NUMBER, 6, }, { "sun", DAY, 0, }, { "sun.", DAY, 0, }, { "sunday", DAY, 0, }, { "t", ZONE, -HRMIN(7, 0), }, { "tenth", NUMBER, 10, }, { "third", NUMBER, 3, }, { "this", UNIT, 0, }, { "thu", DAY, 4, }, { "thu.", DAY, 4, }, { "thur", DAY, 4, }, { "thur.", DAY, 4, }, { "thurs", DAY, 4, }, { "thurs.", DAY, 4, }, { "thursday", DAY, 4, }, { "today", UNIT, 0, }, { "tomorrow", UNIT, 1 * 24 * 60, }, { "tue", DAY, 2, }, { "tue.", DAY, 2, }, { "tues", DAY, 2, }, { "tues.", DAY, 2, }, { "tuesday", DAY, 2, }, { "twelfth", NUMBER, 12, }, { "u", ZONE, -HRMIN(8, 0), }, { "u.t.", ZONE, HRMIN(0, 0), }, { "ut", ZONE, HRMIN(0, 0), }, { "v", ZONE, -HRMIN(9, 0), }, { "w", ZONE, -HRMIN(10, 0), }, { "w.e.s.t.", DAYZONE, -HRMIN(2, 0), }, { "w.e.t.", ZONE, -HRMIN(2, 0), }, { "wed", DAY, 3, }, { "wed.", DAY, 3, }, { "wednes", DAY, 3, }, { "wednes.", DAY, 3, }, { "wednesday", DAY, 3, }, { "week", UNIT, 7 * 24 * 60, }, { "weeks", UNIT, 7 * 24 * 60, }, { "west", DAYZONE, -HRMIN(2, 0), }, /* Western European Summer Time */ { "wet", ZONE, -HRMIN(2, 0), }, /* Western European Time */ { "x", ZONE, -HRMIN(11, 0), }, { "y", ZONE, -HRMIN(12, 0), }, { "y.d.t.", DAYZONE, HRMIN(9, 0), }, { "y.s.t.", ZONE, HRMIN(9, 0), }, { "ydt", DAYZONE, HRMIN(9, 0), }, { "year", MUNIT, 12, }, { "years", MUNIT, 12, }, { "yesterday", UNIT, -1*24*60, }, { "yst", ZONE, HRMIN(9, 0), }, /* Yukon */ { "z", ZONE, HRMIN(0, 0), }, }; /* * NAME * lookup - find name * * SYNOPSIS * int lookup(char *id); * * DESCRIPTION * The lookup function is used to find a token corresponding to * a given name. * * ARGUMENTS * id - name to search for. Assumes already downcased. * * RETURNS * int; yacc token, ID if not found. */ static int lookup(char *id) { table_t *tp; int min; int max; int mid; int cmp; int result; /* * binary chop the table */ trace(("lookup(id = \"%s\")\n{\n", id)); result = ID; min = 0; max = SIZEOF(table) - 1; while (min <= max) { mid = (min + max) / 2; tp = table + mid; cmp = strcmp(id, tp->name); if (!cmp) { date_lval = tp->value; result = tp->type; break; } if (cmp < 0) max = mid - 1; else min = mid + 1; } trace(("return %d;\n", result)); trace(("}\n")); return result; } /* * NAME * date_lex - lexical analyser * * SYNOPSIS * int date_lex(void); * * DESCRIPTION * The date_lex function is used to scan the input string * and break it into discrete tokens. * * RETURNS * int; the yacc token, 0 means the-end. */ static int date_lex(void) { int sign; int c; char *p; char idbuf[MAX_ID_LENGTH]; int pcnt; int token; trace(("date_lex()\n{\n")); date_lval = 0; for (;;) { /* * get the next input character */ c = *lptr++; /* * action depends on the character */ switch (c) { case 0: token = 0; lptr--; break; case ' ': case '\t': /* * ignore white space */ continue; case ':': token = COLON; break; case ',': token = COMMA; break; case '/': token = SLASH; break; case '-': if (!isdigit(*lptr)) { /* * ignore lonely '-'s */ continue; } sign = -1; c = *lptr++; goto number; case '+': if (!isdigit(*lptr)) { token = c; break; } sign = 1; c = *lptr++; goto number; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* * numbers */ sign = 1; number: for (;;) { date_lval = date_lval * 10 + c - '0'; c = *lptr++; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; } break; } date_lval *= sign; lptr--; token = NUMBER; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': /* * name */ p = idbuf; for (;;) { if (isupper(c)) c = tolower(c); if (p < idbuf + sizeof(idbuf) - 1) *p++ = c; c = *lptr++; switch (c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '.': continue; } break; } *p = 0; lptr--; token = lookup(idbuf); break; case '(': /* * comment */ for (pcnt = 1; pcnt > 0;) { c = *lptr++; switch (c) { case 0: --lptr; pcnt = 0; break; case '(': pcnt++; break; case ')': pcnt--; break; } } continue; default: /* * unrecognosed */ token = JUNK; break; } break; } trace(("date_lval = %d;\n", date_lval)); trace(("return %d;\n", token)); trace(("}\n")); return token; } #line 1493 "y.tab.c" /* allocate initial stack or double stack size, up to date_MAXDEPTH */ int date_parse __P((void)); static int date_growstack __P((void)); static int date_growstack() { int newsize, i; short *newss; date_STYPE *newvs; if ((newsize = date_stacksize) == 0) newsize = date_INITSTACKSIZE; else if (newsize >= date_MAXDEPTH) return -1; else if ((newsize *= 2) > date_MAXDEPTH) newsize = date_MAXDEPTH; i = date_ssp - date_ss; if ((newss = (short *)realloc(date_ss, newsize * sizeof *newss)) == NULL) return -1; date_ss = newss; date_ssp = newss + i; if ((newvs = (date_STYPE *)realloc(date_vs, newsize * sizeof *newvs)) == NULL) return -1; date_vs = newvs; date_vsp = newvs + i; date_stacksize = newsize; date_sslim = date_ss + newsize - 1; return 0; } #define date_ABORT goto date_abort #define date_REJECT goto date_abort #define date_ACCEPT goto date_accept #define date_ERROR goto date_errlab int date_parse() { int date_m, date_n, date_state; #if date_DEBUG char *date_s; if ((date_s = getenv("date_DEBUG")) != NULL) { date_n = *date_s; if (date_n >= '0' && date_n <= '9') date_debug = date_n - '0'; } #endif date_nerrs = 0; date_errflag = 0; date_char = (-1); if (date_ss == NULL && date_growstack()) goto date_overflow; date_ssp = date_ss; date_vsp = date_vs; *date_ssp = date_state = 0; date_loop: if ((date_n = date_defred[date_state]) != 0) goto date_reduce; if (date_char < 0) { if ((date_char = date_lex()) < 0) date_char = 0; #if date_DEBUG if (date_debug) { date_s = 0; if (date_char <= date_MAXTOKEN) date_s = date_name[date_char]; if (!date_s) date_s = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", date_PREFIX, date_state, date_char, date_s); } #endif } if ((date_n = date_sindex[date_state]) && (date_n += date_char) >= 0 && date_n <= date_TABLESIZE && date_check[date_n] == date_char) { #if date_DEBUG if (date_debug) printf("%sdebug: state %d, shifting to state %d\n", date_PREFIX, date_state, date_table[date_n]); #endif if (date_ssp >= date_sslim && date_growstack()) { goto date_overflow; } *++date_ssp = date_state = date_table[date_n]; *++date_vsp = date_lval; date_char = (-1); if (date_errflag > 0) --date_errflag; goto date_loop; } if ((date_n = date_rindex[date_state]) && (date_n += date_char) >= 0 && date_n <= date_TABLESIZE && date_check[date_n] == date_char) { date_n = date_table[date_n]; goto date_reduce; } if (date_errflag) goto date_inrecovery; goto date_newerror; date_newerror: date_error("syntax error"); goto date_errlab; date_errlab: ++date_nerrs; date_inrecovery: if (date_errflag < 3) { date_errflag = 3; for (;;) { if ((date_n = date_sindex[*date_ssp]) && (date_n += date_ERRCODE) >= 0 && date_n <= date_TABLESIZE && date_check[date_n] == date_ERRCODE) { #if date_DEBUG if (date_debug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", date_PREFIX, *date_ssp, date_table[date_n]); #endif if (date_ssp >= date_sslim && date_growstack()) { goto date_overflow; } *++date_ssp = date_state = date_table[date_n]; *++date_vsp = date_lval; goto date_loop; } else { #if date_DEBUG if (date_debug) printf("%sdebug: error recovery discarding state %d\n", date_PREFIX, *date_ssp); #endif if (date_ssp <= date_ss) goto date_abort; --date_ssp; --date_vsp; } } } else { if (date_char == 0) goto date_abort; #if date_DEBUG if (date_debug) { date_s = 0; if (date_char <= date_MAXTOKEN) date_s = date_name[date_char]; if (!date_s) date_s = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", date_PREFIX, date_state, date_char, date_s); } #endif date_char = (-1); goto date_loop; } date_reduce: #if date_DEBUG if (date_debug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", date_PREFIX, date_state, date_n, date_rule[date_n]); #endif date_m = date_len[date_n]; date_val = date_vsp[1-date_m]; switch (date_n) { case 3: #line 716 "cooktime/date.y" { /* * Mostly, this production is unnecessary, * however it silences warnings about unused * labels, etc. */ return -1; } break; case 4: #line 728 "cooktime/date.y" { timeflag++; } break; case 5: #line 730 "cooktime/date.y" { zoneflag++; } break; case 6: #line 732 "cooktime/date.y" { dateflag++; } break; case 7: #line 734 "cooktime/date.y" { dayflag++; } break; case 8: #line 736 "cooktime/date.y" { relflag++; } break; case 10: #line 742 "cooktime/date.y" { if (timeflag && dateflag && !relflag) year = date_vsp[0]; else { timeflag++; hh = date_vsp[0] / 100; mm = date_vsp[0] % 100; ss = 0; merid = 24; } } break; case 11: #line 758 "cooktime/date.y" { hh = date_vsp[-1]; mm = 0; ss = 0; merid = date_vsp[0]; } break; case 12: #line 765 "cooktime/date.y" { hh = date_vsp[-2]; mm = date_vsp[0]; merid = 24; } break; case 13: #line 771 "cooktime/date.y" { hh = date_vsp[-3]; mm = date_vsp[-1]; merid = date_vsp[0]; } break; case 14: #line 777 "cooktime/date.y" { hh = date_vsp[-3]; mm = date_vsp[-1]; merid = 24; day_light_flag = STANDARD; date_vsp[0] = -date_vsp[0]; ourzone = date_vsp[0] % 100 + 60 * date_vsp[0] / 100; } break; case 15: #line 786 "cooktime/date.y" { hh = date_vsp[-4]; mm = date_vsp[-2]; ss = date_vsp[0]; merid = 24; } break; case 16: #line 793 "cooktime/date.y" { hh = date_vsp[-5]; mm = date_vsp[-3]; ss = date_vsp[-1]; merid = date_vsp[0]; } break; case 17: #line 800 "cooktime/date.y" { hh = date_vsp[-5]; mm = date_vsp[-3]; ss = date_vsp[-1]; merid = 24; day_light_flag = STANDARD; date_vsp[0] = -date_vsp[0]; ourzone = date_vsp[0] % 100 + 60 * date_vsp[0] / 100; } break; case 18: #line 813 "cooktime/date.y" { ourzone = date_vsp[0]; day_light_flag = STANDARD; } break; case 19: #line 818 "cooktime/date.y" { ourzone = date_vsp[0]; day_light_flag = DAYLIGHT; } break; case 20: #line 826 "cooktime/date.y" { dayord = 1; dayreq = date_vsp[0]; } break; case 21: #line 831 "cooktime/date.y" { dayord = 1; dayreq = date_vsp[-1]; } break; case 22: #line 836 "cooktime/date.y" { dayord = date_vsp[-1]; dayreq = date_vsp[0]; } break; case 23: #line 844 "cooktime/date.y" { month = date_vsp[-2]; day = date_vsp[0]; } break; case 24: #line 849 "cooktime/date.y" { month = date_vsp[-4]; day = date_vsp[-2]; year = date_vsp[0]; } break; case 25: #line 855 "cooktime/date.y" { month = date_vsp[-1]; day = date_vsp[0]; } break; case 26: #line 860 "cooktime/date.y" { month = date_vsp[-3]; day = date_vsp[-2]; year = date_vsp[0]; } break; case 27: #line 866 "cooktime/date.y" { month = date_vsp[0]; day = date_vsp[-1]; } break; case 28: #line 871 "cooktime/date.y" { month = date_vsp[-1]; day = date_vsp[-2]; year = date_vsp[0]; } break; case 29: #line 880 "cooktime/date.y" { relsec += 60L * date_vsp[-1] * date_vsp[0]; } break; case 30: #line 882 "cooktime/date.y" { relmonth += date_vsp[-1] * date_vsp[0]; } break; case 31: #line 884 "cooktime/date.y" { relsec += date_vsp[-1]; } break; case 32: #line 886 "cooktime/date.y" { relsec += 60L * date_vsp[0]; } break; case 33: #line 888 "cooktime/date.y" { relmonth += date_vsp[0]; } break; case 34: #line 890 "cooktime/date.y" { relsec++; } break; case 35: #line 892 "cooktime/date.y" { relsec = -relsec; relmonth = -relmonth; } break; #line 1882 "y.tab.c" } date_ssp -= date_m; date_state = *date_ssp; date_vsp -= date_m; date_m = date_lhs[date_n]; if (date_state == 0 && date_m == 0) { #if date_DEBUG if (date_debug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", date_PREFIX, date_FINAL); #endif date_state = date_FINAL; *++date_ssp = date_FINAL; *++date_vsp = date_val; if (date_char < 0) { if ((date_char = date_lex()) < 0) date_char = 0; #if date_DEBUG if (date_debug) { date_s = 0; if (date_char <= date_MAXTOKEN) date_s = date_name[date_char]; if (!date_s) date_s = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", date_PREFIX, date_FINAL, date_char, date_s); } #endif } if (date_char == 0) goto date_accept; goto date_loop; } if ((date_n = date_gindex[date_m]) && (date_n += date_state) >= 0 && date_n <= date_TABLESIZE && date_check[date_n] == date_state) date_state = date_table[date_n]; else date_state = date_dgoto[date_m]; #if date_DEBUG if (date_debug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", date_PREFIX, *date_ssp, date_state); #endif if (date_ssp >= date_sslim && date_growstack()) { goto date_overflow; } *++date_ssp = date_state; *++date_vsp = date_val; goto date_loop; date_overflow: date_error("yacc stack overflow"); date_abort: return (1); date_accept: return (0); }