diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/LYUtils.c | 255 | ||||
-rw-r--r-- | src/LYmktime.c | 337 | ||||
-rw-r--r-- | src/descrip.mms | 4 | ||||
-rw-r--r-- | src/makefile.dos | 9 | ||||
-rw-r--r-- | src/makefile.dsl | 9 | ||||
-rw-r--r-- | src/makefile.in | 18 | ||||
-rw-r--r-- | src/makefile.wsl | 9 | ||||
-rw-r--r-- | src/parsdate.c | 1453 | ||||
-rw-r--r-- | src/parsdate.h | 21 | ||||
-rw-r--r-- | src/parsdate.y | 919 |
10 files changed, 2766 insertions, 268 deletions
diff --git a/src/LYUtils.c b/src/LYUtils.c index 367222b1..806dfd06 100644 --- a/src/LYUtils.c +++ b/src/LYUtils.c @@ -1,4 +1,4 @@ -/* $LynxId: LYUtils.c,v 1.167 2008/02/17 18:30:19 ravenexp Exp $ */ +/* $LynxId: LYUtils.c,v 1.168 2008/06/29 21:44:03 tom Exp $ */ #include <HTUtils.h> #include <HTTCP.h> #include <HTParse.h> @@ -5526,259 +5526,6 @@ char *LYAddPathToSave(char *fname) return result; } -/* - * This function takes a string in the format - * "Mon, 01-Jan-96 13:45:35 GMT" or - * "Mon, 1 Jan 1996 13:45:35 GMT"" or - * "dd-mm-yyyy" - * as an argument, and returns its conversion to clock format (seconds since - * 00:00:00 Jan 1 1970), or 0 if the string doesn't match the expected pattern. - * It also returns 0 if the time is in the past and the "absolute" argument is - * FALSE. It is intended for handling 'expires' strings in Version 0 cookies - * homologously to 'max-age' strings in Version 1 cookies, for which 0 is the - * minimum, and greater values are handled as '[max-age seconds] + time(NULL)'. - * If "absolute" if TRUE, we return the clock format value itself, but if - * anything goes wrong when parsing the expected patterns, we still return 0. - * - FM - */ -time_t LYmktime(char *string, - BOOL absolute) -{ - char *s; - time_t now, clock2; - int day, month, year, hour, minutes, seconds; - char *start; - char temp[8]; - - /* - * Make sure we have a string to parse. - FM - */ - if (!non_empty(string)) - return (0); - s = string; - CTRACE((tfp, "LYmktime: Parsing '%s'\n", s)); - - /* - * Skip any lead alphabetic "Day, " field and seek a numeric day field. - - * FM - */ - while (*s != '\0' && !isdigit(UCH(*s))) - s++; - if (*s == '\0') - return (0); - - /* - * Get the numeric day and convert to an integer. - FM - */ - start = s; - while (*s != '\0' && isdigit(UCH(*s))) - s++; - if (*s == '\0' || (s - start) > 2) - return (0); - LYstrncpy(temp, start, (int) (s - start)); - day = atoi(temp); - if (day < 1 || day > 31) - return (0); - - /* - * Get the month string and convert to an integer. - FM - */ - while (*s != '\0' && !isalnum(UCH(*s))) - s++; - if (*s == '\0') - return (0); - start = s; - while (*s != '\0' && isalnum(UCH(*s))) - s++; - if ((*s == '\0') || - (s - start) < (isdigit(UCH(*(s - 1))) ? 2 : 3) || - (s - start) > (isdigit(UCH(*(s - 1))) ? 2 : 9)) - return (0); - LYstrncpy(temp, start, (isdigit(UCH(*(s - 1))) ? 2 : 3)); - switch (TOUPPER(temp[0])) { - case '0': - case '1': - month = atoi(temp); - if (month < 1 || month > 12) { - return (0); - } - break; - case 'A': - if (!strcasecomp(temp, "Apr")) { - month = 4; - } else if (!strcasecomp(temp, "Aug")) { - month = 8; - } else { - return (0); - } - break; - case 'D': - if (!strcasecomp(temp, "Dec")) { - month = 12; - } else { - return (0); - } - break; - case 'F': - if (!strcasecomp(temp, "Feb")) { - month = 2; - } else { - return (0); - } - break; - case 'J': - if (!strcasecomp(temp, "Jan")) { - month = 1; - } else if (!strcasecomp(temp, "Jun")) { - month = 6; - } else if (!strcasecomp(temp, "Jul")) { - month = 7; - } else { - return (0); - } - break; - case 'M': - if (!strcasecomp(temp, "Mar")) { - month = 3; - } else if (!strcasecomp(temp, "May")) { - month = 5; - } else { - return (0); - } - break; - case 'N': - if (!strcasecomp(temp, "Nov")) { - month = 11; - } else { - return (0); - } - break; - case 'O': - if (!strcasecomp(temp, "Oct")) { - month = 10; - } else { - return (0); - } - break; - case 'S': - if (!strcasecomp(temp, "Sep")) { - month = 9; - } else { - return (0); - } - break; - default: - return (0); - } - - /* - * Get the numeric year string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit(UCH(*s))) - s++; - if (*s == '\0') - return (0); - start = s; - while (*s != '\0' && isdigit(UCH(*s))) - s++; - if ((s - start) == 4) { - LYstrncpy(temp, start, 4); - } else if ((s - start) == 2) { - now = time(NULL); - /* - * Assume that received 2-digit dates >= 70 are 19xx; others - * are 20xx. Only matters when dealing with broken software - * (HTTP server or web page) which is not Y2K compliant. The - * line is drawn on a best-guess basis; it is impossible for - * this to be completely accurate because it depends on what - * the broken sender software intends. (This totally breaks - * in 2100 -- setting up the next crisis...) - BL - */ - if (atoi(start) >= 70) - LYstrncpy(temp, "19", 2); - else - LYstrncpy(temp, "20", 2); - strncat(temp, start, 2); - temp[4] = '\0'; - } else { - return (0); - } - year = atoi(temp); - - /* - * Get the numeric hour string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit(UCH(*s))) - s++; - if (*s == '\0') { - hour = 0; - minutes = 0; - seconds = 0; - } else { - start = s; - while (*s != '\0' && isdigit(UCH(*s))) - s++; - if (*s != ':' || (s - start) > 2) - return (0); - LYstrncpy(temp, start, (int) (s - start)); - hour = atoi(temp); - - /* - * Get the numeric minutes string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit(UCH(*s))) - s++; - if (*s == '\0') - return (0); - start = s; - while (*s != '\0' && isdigit(UCH(*s))) - s++; - if (*s != ':' || (s - start) > 2) - return (0); - LYstrncpy(temp, start, (int) (s - start)); - minutes = atoi(temp); - - /* - * Get the numeric seconds string and convert to an integer. - FM - */ - while (*s != '\0' && !isdigit(UCH(*s))) - s++; - if (*s == '\0') - return (0); - start = s; - while (*s != '\0' && isdigit(UCH(*s))) - s++; - if (*s == '\0' || (s - start) > 2) - return (0); - LYstrncpy(temp, start, (int) (s - start)); - seconds = atoi(temp); - } - - /* - * Convert to clock format (seconds since 00:00:00 Jan 1 1970), but then - * zero it if it's in the past and "absolute" is not TRUE. - FM - */ - month -= 3; - if (month < 0) { - month += 12; - year--; - } - day += (year - 1968) * 1461 / 4; - day += ((((month * 153) + 2) / 5) - 672); - clock2 = (time_t) ((day * 60 * 60 * 24) + - (hour * 60 * 60) + - (minutes * 60) + - seconds); - if (absolute == FALSE && (long) (time((time_t *) 0) - clock2) >= 0) - clock2 = (time_t) 0; - if (clock2 > 0) - CTRACE((tfp, "LYmktime: clock=%ld, ctime=%s", - (long) clock2, - ctime(&clock2))); - - return (clock2); -} - #if !defined(HAVE_PUTENV) && !defined(_WINDOWS) /* * No putenv on the NeXT so we use this code instead! diff --git a/src/LYmktime.c b/src/LYmktime.c new file mode 100644 index 00000000..dcec9bda --- /dev/null +++ b/src/LYmktime.c @@ -0,0 +1,337 @@ +/* $LynxId: LYmktime.c,v 1.5 2008/06/30 23:49:30 tom Exp $ */ + +#include <LYStrings.h> +#include <LYUtils.h> + +#include <parsdate.h> + +#ifdef TEST_DRIVER +char *LYstrncpy(char *dst, + const char *src, + int n) +{ + char *val; + int len; + + if (src == 0) + src = ""; + len = strlen(src); + + if (n < 0) + n = 0; + + val = strncpy(dst, src, n); + if (len < n) + *(dst + len) = '\0'; + else + *(dst + n) = '\0'; + return val; +} +#define strcasecomp strcasecmp +BOOLEAN WWW_TraceFlag = FALSE; +FILE *TraceFP(void) +{ + return stderr; +} +#define USE_PARSDATE 0 +#else +#define USE_PARSDATE 1 +#endif + +/* + * This function takes a string in the format + * "Mon, 01-Jan-96 13:45:35 GMT" or + * "Mon, 1 Jan 1996 13:45:35 GMT" or + * "dd-mm-yyyy" + * as an argument, and returns its conversion to clock format (seconds since + * 00:00:00 Jan 1 1970), or 0 if the string doesn't match the expected pattern. + * It also returns 0 if the time is in the past and the "absolute" argument is + * FALSE. It is intended for handling 'expires' strings in Version 0 cookies + * homologously to 'max-age' strings in Version 1 cookies, for which 0 is the + * minimum, and greater values are handled as '[max-age seconds] + time(NULL)'. + * If "absolute" if TRUE, we return the clock format value itself, but if + * anything goes wrong when parsing the expected patterns, we still return 0. + * - FM + */ +time_t LYmktime(char *string, + BOOL absolute) +{ +#if USE_PARSDATE + time_t result; + + if (non_empty(string)) { + CTRACE((tfp, "LYmktime: Parsing '%s'\n", string)); + result = parsedate(string, 0); + + if (!absolute) { + if ((time((time_t *) 0) - result) >= 0) + result = 0; + } + if (result != 0) { + CTRACE((tfp, "LYmktime: clock=%ld, ctime=%s", + (long) result, + ctime(&result))); + } + } + return result; +#else + char *s; + time_t now, clock2; + int day, month, year, hour, minutes, seconds; + char *start; + char temp[8]; + + /* + * Make sure we have a string to parse. - FM + */ + if (!non_empty(string)) + return (0); + s = string; + CTRACE((tfp, "LYmktime: Parsing '%s'\n", s)); + + /* + * Skip any lead alphabetic "Day, " field and seek a numeric day field. - + * FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + + /* + * Get the numeric day and convert to an integer. - FM + */ + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s == '\0' || (s - start) > 2) + return (0); + LYstrncpy(temp, start, (int) (s - start)); + day = atoi(temp); + if (day < 1 || day > 31) + return (0); + + /* + * Get the month string and convert to an integer. - FM + */ + while (*s != '\0' && !isalnum(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isalnum(UCH(*s))) + s++; + if ((*s == '\0') || + (s - start) < (isdigit(UCH(*(s - 1))) ? 2 : 3) || + (s - start) > (isdigit(UCH(*(s - 1))) ? 2 : 9)) + return (0); + LYstrncpy(temp, start, (isdigit(UCH(*(s - 1))) ? 2 : 3)); + switch (TOUPPER(temp[0])) { + case '0': + case '1': + month = atoi(temp); + if (month < 1 || month > 12) { + return (0); + } + break; + case 'A': + if (!strcasecomp(temp, "Apr")) { + month = 4; + } else if (!strcasecomp(temp, "Aug")) { + month = 8; + } else { + return (0); + } + break; + case 'D': + if (!strcasecomp(temp, "Dec")) { + month = 12; + } else { + return (0); + } + break; + case 'F': + if (!strcasecomp(temp, "Feb")) { + month = 2; + } else { + return (0); + } + break; + case 'J': + if (!strcasecomp(temp, "Jan")) { + month = 1; + } else if (!strcasecomp(temp, "Jun")) { + month = 6; + } else if (!strcasecomp(temp, "Jul")) { + month = 7; + } else { + return (0); + } + break; + case 'M': + if (!strcasecomp(temp, "Mar")) { + month = 3; + } else if (!strcasecomp(temp, "May")) { + month = 5; + } else { + return (0); + } + break; + case 'N': + if (!strcasecomp(temp, "Nov")) { + month = 11; + } else { + return (0); + } + break; + case 'O': + if (!strcasecomp(temp, "Oct")) { + month = 10; + } else { + return (0); + } + break; + case 'S': + if (!strcasecomp(temp, "Sep")) { + month = 9; + } else { + return (0); + } + break; + default: + return (0); + } + + /* + * Get the numeric year string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if ((s - start) == 4) { + LYstrncpy(temp, start, 4); + } else if ((s - start) == 2) { + now = time(NULL); + /* + * Assume that received 2-digit dates >= 70 are 19xx; others + * are 20xx. Only matters when dealing with broken software + * (HTTP server or web page) which is not Y2K compliant. The + * line is drawn on a best-guess basis; it is impossible for + * this to be completely accurate because it depends on what + * the broken sender software intends. (This totally breaks + * in 2100 -- setting up the next crisis...) - BL + */ + if (atoi(start) >= 70) + LYstrncpy(temp, "19", 2); + else + LYstrncpy(temp, "20", 2); + strncat(temp, start, 2); + temp[4] = '\0'; + } else { + return (0); + } + year = atoi(temp); + + /* + * Get the numeric hour string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') { + hour = 0; + minutes = 0; + seconds = 0; + } else { + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s != ':' || (s - start) > 2) + return (0); + LYstrncpy(temp, start, (int) (s - start)); + hour = atoi(temp); + + /* + * Get the numeric minutes string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s != ':' || (s - start) > 2) + return (0); + LYstrncpy(temp, start, (int) (s - start)); + minutes = atoi(temp); + + /* + * Get the numeric seconds string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s == '\0' || (s - start) > 2) + return (0); + LYstrncpy(temp, start, (int) (s - start)); + seconds = atoi(temp); + } + + /* + * Convert to clock format (seconds since 00:00:00 Jan 1 1970), but then + * zero it if it's in the past and "absolute" is not TRUE. - FM + */ + month -= 3; + if (month < 0) { + month += 12; + year--; + } + day += (year - 1968) * 1461 / 4; + day += ((((month * 153) + 2) / 5) - 672); + clock2 = (time_t) ((day * 60 * 60 * 24) + + (hour * 60 * 60) + + (minutes * 60) + + seconds); + if (absolute == FALSE && (long) (time((time_t *) 0) - clock2) >= 0) + clock2 = (time_t) 0; + if (clock2 > 0) + CTRACE((tfp, "LYmktime: clock=%ld, ctime=%s", + (long) clock2, + ctime(&clock2))); + + return (clock2); +#endif +} + +#ifdef TEST_DRIVER +static void test_mktime(char *source) +{ + time_t before = LYmktime(source, TRUE); + time_t after = parsedate(source, 0); + + printf("TEST %s\n", source); + printf("\t%10ld %s", (long) before, ctime(&before)); + printf("\t%10ld %s", (long) after, ctime(&after)); + if (before != after) + printf("\t****\n"); +} + +int main(void) +{ + test_mktime("Mon, 01-Jan-96 13:45:35 GMT"); + test_mktime("Mon, 1 Jan 1996 13:45:35 GMT"); + test_mktime("31-12-1999"); + test_mktime("Wed May 14 22:00:00 2008"); + test_mktime("Sun, 29-Jun-2008 23:19:30 GMT"); + test_mktime("Sun Jul 06 07:00:00 2008 GMT"); + return 0; +} +#endif diff --git a/src/descrip.mms b/src/descrip.mms index 3fc03ff2..6b22b78d 100644 --- a/src/descrip.mms +++ b/src/descrip.mms @@ -1,3 +1,5 @@ +! $LynxId: descrip.mms,v 1.12 2008/06/30 23:50:22 tom Exp $ +! ! Make LYNX hypertext browser under VMS ! ===================================== ! @@ -64,7 +66,7 @@ OBJS = DefaultStyle.obj, GridText.obj, HTAlert.obj, HTFWriter.obj, - LYMap.obj, LYNews.obj, LYOptions.obj, LYPrint.obj, LYReadCFG.obj, - LYSearch.obj, LYShowInfo.obj, LYStrings.obj, LYTraversal.obj, - LYUpload.obj, LYUtils.obj, LYexit.obj, LYrcFile.obj, TRSTable.obj, - - UCAuto.obj, UCAux.obj, UCdomap.obj + LYmktime.obj, UCAuto.obj, UCAux.obj, UCdomap.obj, parsdate.obj .ifdef SLANG SCREEN_DEF = USE_SLANG diff --git a/src/makefile.dos b/src/makefile.dos index 5aeee682..ed0358db 100644 --- a/src/makefile.dos +++ b/src/makefile.dos @@ -1,14 +1,15 @@ -# $LynxId: makefile.dos,v 1.30 2008/01/08 00:54:14 tom Exp $ +# $LynxId: makefile.dos,v 1.32 2008/06/30 23:53:42 tom Exp $ + OBJS= UCdomap.o UCAux.o UCAuto.o \ LYClean.o LYShowInfo.o LYEdit.o LYStrings.o \ LYMail.o HTAlert.o GridText.o LYGetFile.o \ -LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYUtils.o \ +LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYmktime.o LYUtils.o \ LYOptions.o LYReadCFG.o LYSearch.o LYHistory.o LYSession.o \ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \ HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \ LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \ LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \ -LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o +LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o parsdate.o CFLAGS= -O2 $(MCFLAGS) $(INTLFLAGS) -I. -I.. @@ -110,3 +111,5 @@ LYShowInfo.o: ../userdefs.h LYStrings.o: ../userdefs.h LYTraversal.o: ../userdefs.h LYUtils.o: ../userdefs.h +LYmktime.o: ../userdefs.h +parsdate.o: ../userdefs.h diff --git a/src/makefile.dsl b/src/makefile.dsl index beb0ccf6..64024f7f 100644 --- a/src/makefile.dsl +++ b/src/makefile.dsl @@ -1,14 +1,15 @@ -# $LynxId: makefile.dsl,v 1.17 2008/01/08 00:54:07 tom Exp $ +# $LynxId: makefile.dsl,v 1.19 2008/06/30 23:53:42 tom Exp $ + OBJS= UCdomap.o UCAux.o UCAuto.o \ LYClean.o LYShowInfo.o LYEdit.o LYStrings.o \ LYMail.o HTAlert.o GridText.o LYGetFile.o \ -LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYUtils.o \ +LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYmktime.o LYUtils.o \ LYOptions.o LYReadCFG.o LYSearch.o LYHistory.o LYSession.o \ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \ HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \ LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \ LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \ -LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o +LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o parsdate.o CFLAGS= -O2 $(MCFLAGS) $(INTLFLAGS) -I. -I.. $(SLANGINC) @@ -100,3 +101,5 @@ LYShowInfo.o: ../userdefs.h LYStrings.o: ../userdefs.h LYTraversal.o: ../userdefs.h LYUtils.o: ../userdefs.h +LYmktime.o: ../userdefs.h +parsdate.o: ../userdefs.h diff --git a/src/makefile.in b/src/makefile.in index 5e024615..cd446f31 100644 --- a/src/makefile.in +++ b/src/makefile.in @@ -1,4 +1,4 @@ -# $LynxId: makefile.in,v 1.50 2007/05/23 00:19:09 tom Exp $ +# $LynxId: makefile.in,v 1.52 2008/06/30 23:36:34 tom Exp $ # template-makefile for Lynx src directory SHELL = @CONFIG_SHELL@ @@ -71,14 +71,14 @@ CHARTRANS_OBJS = UCdomap$o UCAux$o UCAuto$o OBJS = \ LYClean$o LYShowInfo$o LYEdit$o LYStrings$o LYMail$o \ HTAlert$o GridText$o LYGetFile$o LYMain$o LYMainLoop$o \ - LYCurses$o LYBookmark$o LYUtils$o LYOptions$o \ + LYCurses$o LYBookmark$o LYmktime$o LYUtils$o LYOptions$o \ LYReadCFG$o LYSearch$o LYHistory$o LYForms$o LYPrint$o \ LYrcFile$o LYDownload$o LYNews$o LYKeymap$o HTML$o \ HTFWriter$o HTInit$o DefaultStyle$o LYUpload$o \ LYLeaks$o LYexit$o LYJump$o LYList$o LYCgi$o \ LYTraversal$o LYEditmap$o LYCharSets$o LYCharUtils$o \ LYMap$o LYCookie$o LYStyle$o LYHash$o LYPrettySrc$o \ - TRSTable$o $(CHARTRANS_OBJS) @EXTRA_OBJS@ @LIBOBJS@ + TRSTable$o parsdate$o $(CHARTRANS_OBJS) @EXTRA_OBJS@ @LIBOBJS@ C_SRC = $(OBJS:$o=.c) @@ -133,6 +133,7 @@ HTInit$o : $(top_srcdir)/userdefs.h LYCharSets$o : $(top_srcdir)/userdefs.h LYGetFile$o : $(top_srcdir)/userdefs.h LYKeymap$o : $(top_srcdir)/userdefs.h +LYLeaks$o : $(CMN)LYLeaks.h $(CMN)HTString.h LYMail$o : $(top_srcdir)/userdefs.h LYMain$o : $(top_srcdir)/userdefs.h $(top_builddir)/lynx_cfg.h LYMainLoop$o : $(top_srcdir)/userdefs.h @@ -141,8 +142,8 @@ LYReadCFG$o : $(top_srcdir)/userdefs.h LYShowInfo$o : $(top_builddir)/cfg_defs.h LYTraversal$o : $(top_srcdir)/userdefs.h LYUtils$o : $(top_srcdir)/userdefs.h +LYmktime$o : $(top_srcdir)/userdefs.h LYrcFile$o : $(top_srcdir)/userdefs.h -LYLeaks$o : $(CMN)LYLeaks.h $(CMN)HTString.h CHRTR= chrtrans/ @@ -201,6 +202,15 @@ chrtrans/makeuctb$(BUILD_EXEEXT): UCAux$o : UCAux.c $(CMN)UCAux.h $(CMN)UCDefs.h LYCookie$o : $(top_srcdir)/userdefs.h +# test-driver for LYmktime +test_mktime: LYmktime.c parsdate.o + $(CC) -o $@ $(CC_OPTS) -DTEST_DRIVER LYmktime.c parsdate.o + +# update generated source +parsdate.c : parsdate.y + yacc parsdate.y + mv y.tab.c $@ + depend : $(TABLES) makedepend -fmakefile -- $(CC_OPTS) -- $(C_SRC) diff --git a/src/makefile.wsl b/src/makefile.wsl index 342d6854..5890ec38 100644 --- a/src/makefile.wsl +++ b/src/makefile.wsl @@ -1,14 +1,15 @@ -# $LynxId: makefile.wsl,v 1.13 2008/01/08 00:53:56 tom Exp $ +# $LynxId: makefile.wsl,v 1.15 2008/06/30 23:53:42 tom Exp $ + OBJS= UCdomap.o UCAux.o UCAuto.o \ LYClean.o LYShowInfo.o LYEdit.o LYStrings.o \ LYMail.o HTAlert.o GridText.o LYGetFile.o \ -LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYUtils.o \ +LYMain.o LYMainLoop.o LYCurses.o LYBookmark.o LYmktime.o LYUtils.o \ LYOptions.o LYReadCFG.o LYSearch.o LYHistory.o LYSession.o \ LYForms.o LYPrint.o LYrcFile.o LYDownload.o LYNews.o LYKeymap.o \ HTML.o HTFWriter.o HTInit.o DefaultStyle.o LYLocal.o LYUpload.o \ LYLeaks.o LYexit.o LYJump.o LYList.o LYCgi.o LYTraversal.o \ LYEditmap.o LYCharSets.o LYCharUtils.o LYMap.o LYCookie.o LYExtern.o \ -LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o +LYStyle.o LYHash.o LYPrettySrc.o TRSTable.o parsdate.o CFLAGS= -O1 $(MCFLAGS) -I. -I.. $(SLANGINC) @@ -63,3 +64,5 @@ LYShowInfo.o: ../userdefs.h LYStrings.o: ../userdefs.h LYTraversal.o: ../userdefs.h LYUtils.o: ../userdefs.h +LYmktime.o: ../userdefs.h +parsdate.o: ../userdefs.h diff --git a/src/parsdate.c b/src/parsdate.c new file mode 100644 index 00000000..2db197a2 --- /dev/null +++ b/src/parsdate.c @@ -0,0 +1,1453 @@ +#ifndef lint +static const char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif + +#include <stdlib.h> + +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYPATCH 20050813 + +#define YYEMPTY (-1) +#define yyclearin (yychar = YYEMPTY) +#define yyerrok (yyerrflag = 0) +#define YYRECOVERING (yyerrflag != 0) + +extern int yyparse(void); + +static int yygrowstack(void); +#define YYPREFIX "yy" +#line 2 "parsdate.y" +/* + * $LynxId: parsdate.c,v 1.1 2008/06/30 23:25:19 tom Exp $ + * + * This module is adapted and extended from tin, to use for LYmktime(). + * + * Project : tin - a Usenet reader + * Module : parsedate.y + * Author : S. Bellovin, R. $alz, J. Berets, P. Eggert + * Created : 1990-08-01 + * Updated : 2008-06-30 (by Thomas Dickey, for Lynx) + * Notes : This grammar has 8 shift/reduce conflicts. + * + * Originally written by Steven M. Bellovin <smb@research.att.com> + * while at the University of North Carolina at Chapel Hill. + * Later tweaked by a couple of people on Usenet. Completely + * overhauled by Rich $alz <rsalz@osf.org> and Jim Berets + * <jberets@bbn.com> in August, 1990. + * + * Further revised (removed obsolete constructs and cleaned up + * timezone names) in August, 1991, by Rich. + * Paul Eggert <eggert@twinsun.com> helped in September 1992. + * Roland Rosenfeld added MET DST code in April 1994. + * + * Revision : 1.13 + * Copyright : This code is in the public domain and has no copyright. + */ + +/* SUPPRESS 530 */ /* Empty body for statement */ +/* SUPPRESS 593 on yyerrlab */ /* Label was not used */ +/* SUPPRESS 593 on yynewstate */ /* Label was not used */ +/* SUPPRESS 595 on yypvt */ /* Automatic variable may be used before set */ + +#include <parsdate.h> + +/* +** Get the number of elements in a fixed-size array, or a pointer just +** past the end of it. +*/ +#define ENDOF(array) (&array[ARRAY_SIZE(array)]) + +#define CTYPE(isXXXXX, c) (((unsigned char)(c) < 128) && isXXXXX(((int)c))) + +typedef char *STRING; + +extern int date_parse(void); + +#define yyparse date_parse +#define yylex date_lex +#define yyerror date_error + + + /* See the LeapYears table in Convert. */ +#define EPOCH 1970 +#define END_OF_TIME 2038 + + /* Constants for general time calculations. */ +#define DST_OFFSET 1 +#define SECSPERDAY (24L * 60L * 60L) + /* Readability for TABLE stuff. */ +#define HOUR(x) (x * 60) + +#define LPAREN '(' +#define RPAREN ')' +#define IS7BIT(x) ((unsigned int)(x) < 0200) + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of them by using a yacc +** union, but this is more efficient. (This routine predates the +** yacc %union construct.) +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static int yyHaveDate; +static int yyHaveRel; +static int yyHaveTime; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +static time_t ToSeconds(time_t, time_t, time_t, MERIDIAN); +static time_t Convert(time_t, time_t, time_t, time_t, time_t, time_t, MERIDIAN, DSTMODE); +static time_t DSTcorrect(time_t, time_t); +static time_t RelativeMonth(time_t, time_t); +static int LookupWord(char *, int); +static int date_lex(void); +static int GetTimeInfo(TIMEINFO *Now); + +/* + * The 'date_error()' function is declared here to work around a defect in + * bison 1.22, which redefines 'const' further down in this file, making it + * impossible to put a prototype here, and the function later. We're using + * 'const' on the parameter to quiet gcc's -Wwrite-strings warning. + */ +/*ARGSUSED*/ +static void +date_error(const char GCC_UNUSED *s) +{ + /*NOTREACHED*/ +} + +#line 127 "parsdate.y" +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} YYSTYPE; +#line 151 "y.tab.c" +#define tDAY 257 +#define tDAYZONE 258 +#define tMERIDIAN 259 +#define tMONTH 260 +#define tMONTH_UNIT 261 +#define tSEC_UNIT 262 +#define tSNUMBER 263 +#define tUNUMBER 264 +#define tZONE 265 +#define tDST 266 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 4, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 2, 2, 2, 2, 2, 1, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 8, + 8, 8, 8, 3, 3, +}; +short yylen[] = { 2, + 0, 2, 1, 2, 1, 1, 2, 1, 2, 4, + 4, 6, 6, 1, 1, 2, 2, 1, 1, 3, + 5, 2, 4, 2, 3, 5, 6, 3, 9, 2, + 2, 2, 2, 0, 1, +}; +short yydefred[] = { 1, + 0, 0, 0, 0, 0, 2, 0, 5, 0, 8, + 0, 0, 0, 32, 30, 35, 0, 33, 31, 0, + 0, 0, 9, 0, 19, 0, 18, 4, 7, 0, + 0, 0, 25, 28, 0, 0, 16, 17, 0, 0, + 0, 23, 0, 11, 10, 0, 0, 26, 0, 0, + 21, 0, 27, 13, 12, 0, 0, 29, +}; +short yydgoto[] = { 1, + 27, 28, 23, 6, 7, 8, 9, 10, +}; +short yysindex[] = { 0, + -240, -41, -256, -227, -45, 0, -251, 0, -251, 0, + -254, -249, -22, 0, 0, 0, -237, 0, 0, -235, + -228, -226, 0, -236, 0, -224, 0, 0, 0, -223, + -39, -222, 0, 0, -58, -7, 0, 0, -15, -220, + -215, 0, -218, 0, 0, -217, -216, 0, -214, -234, + 0, -8, 0, 0, 0, -213, -212, 0, +}; +short yyrindex[] = { 0, + 0, 0, 0, 0, 5, 0, 26, 0, 31, 0, + 0, 0, 11, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 16, 0, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 21, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, +}; +short yygindex[] = { 0, + -17, 44, -31, 0, 0, 0, 0, 0, +}; +#define YYTABLESIZE 300 +short yytable[] = { 43, + 34, 22, 12, 45, 34, 41, 24, 13, 38, 30, + 22, 25, 21, 26, 31, 15, 2, 44, 55, 3, + 20, 32, 4, 5, 16, 3, 33, 34, 25, 37, + 6, 14, 54, 14, 15, 35, 24, 36, 25, 46, + 39, 42, 47, 48, 49, 50, 51, 52, 53, 56, + 57, 58, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 17, 18, 19, 20, 11, 0, + 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 34, 34, 0, + 34, 34, 34, 0, 34, 34, 0, 22, 34, 34, + 22, 0, 15, 22, 22, 15, 0, 20, 15, 15, + 20, 0, 3, 20, 20, 3, 0, 6, 14, 3, + 6, 14, 0, 24, 6, 14, 24, 0, 0, 24, +}; +short yycheck[] = { 58, + 0, 47, 44, 35, 0, 45, 258, 264, 26, 264, + 0, 263, 58, 265, 264, 0, 257, 35, 50, 260, + 0, 44, 263, 264, 259, 0, 264, 263, 263, 266, + 0, 0, 50, 261, 262, 264, 0, 264, 263, 47, + 264, 264, 58, 264, 260, 264, 264, 264, 263, 58, + 264, 264, 9, -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, + 259, -1, -1, -1, 263, -1, -1, -1, -1, -1, + -1, -1, -1, 259, 260, 261, 262, 263, 260, -1, + 260, -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, 257, 258, -1, + 260, 257, 258, -1, 264, 265, -1, 257, 264, 265, + 260, -1, 257, 263, 264, 260, -1, 257, 263, 264, + 260, -1, 257, 263, 264, 260, -1, 257, 257, 264, + 260, 260, -1, 257, 264, 264, 260, -1, -1, 263, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 266 +#if YYDEBUG +char *yyname[] = { +"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,"tDAY","tDAYZONE", +"tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE", +"tDST", +}; +char *yyrule[] = { +"$accept : spec", +"spec :", +"spec : spec item", +"item : time", +"item : time zone", +"item : date", +"item : both", +"item : both zone", +"item : rel", +"time : tUNUMBER o_merid", +"time : tUNUMBER ':' tUNUMBER o_merid", +"time : tUNUMBER ':' tUNUMBER numzone", +"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", +"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone", +"zone : tZONE", +"zone : tDAYZONE", +"zone : tDAYZONE tDST", +"zone : tZONE numzone", +"zone : numzone", +"numzone : tSNUMBER", +"date : tUNUMBER '/' tUNUMBER", +"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", +"date : tMONTH tUNUMBER", +"date : tMONTH tUNUMBER ',' tUNUMBER", +"date : tUNUMBER tMONTH", +"date : tUNUMBER tMONTH tUNUMBER", +"date : tDAY ',' tUNUMBER tMONTH tUNUMBER", +"date : tDAY ',' tUNUMBER '-' tMONTH tSNUMBER", +"date : tUNUMBER tSNUMBER tSNUMBER", +"both : tDAY tMONTH tUNUMBER tUNUMBER ':' tUNUMBER ':' tUNUMBER tUNUMBER", +"rel : tSNUMBER tSEC_UNIT", +"rel : tUNUMBER tSEC_UNIT", +"rel : tSNUMBER tMONTH_UNIT", +"rel : tUNUMBER tMONTH_UNIT", +"o_merid :", +"o_merid : tMERIDIAN", +}; +#endif +#if YYDEBUG +#include <stdio.h> +#endif + +/* define the initial stack-sizes */ +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif + +#define YYINITSTACKSIZE 500 + +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; + +/* variables for the parser stack */ +static short *yyss; +static short *yysslim; +static YYSTYPE *yyvs; +static int yystacksize; +#line 349 "parsdate.y" + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + const char *name; + int type; + time_t value; +} TABLE; + +/* Month and day table. */ +static const TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + /* The value of the day isn't used... */ + { "sunday", tDAY, 0 }, + { "monday", tDAY, 0 }, + { "tuesday", tDAY, 0 }, + { "wednesday", tDAY, 0 }, + { "thursday", tDAY, 0 }, + { "friday", tDAY, 0 }, + { "saturday", tDAY, 0 }, +}; + +/* Time units table. */ +static const TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { "hour", tSEC_UNIT, 60 * 60 }, + { "minute", tSEC_UNIT, 60 }, + { "min", tSEC_UNIT, 60 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, +}; + +/* Timezone table. */ +static const TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal */ + { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ + { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ + { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ + { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ + { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ + { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ +/* Additional aliases for MET / MET DST *************************************/ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "mes", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "mesz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "msz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "metdst", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ +/****************************************************************************/ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ + { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ + { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ + { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ + { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ + { "cct", tZONE, -HOUR(8) }, /* China Coast */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ + { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ + { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ + { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ + { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + + /* For completeness we include the following entries. */ +#if 0 + + /* Duplicate names. Either they conflict with a zone listed above + * (which is either more likely to be seen or just been in circulation + * longer), or they conflict with another zone in this section and + * we could not reasonably choose one over the other. */ + { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ + { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ + { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ + { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ + { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ + { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ + { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ + { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ + { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ + { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ + { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ + { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ + { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ + { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ + { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ + { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ + { "cst", tZONE, -HOUR(8) }, /* China Standard */ + { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ + { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ + + /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ + { "wat", tZONE, -HOUR(1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ + { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad */ + { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ + { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ + { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ + { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ + { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ +#endif /* 0 */ +}; + +static time_t +ToSeconds( + time_t Hours, + time_t Minutes, + time_t Seconds, + MERIDIAN Meridian) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) + return -1; + if (Meridian == MER24) { + if (Hours < 0 || Hours > 23) + return -1; + } + else { + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + if (Meridian == MERpm) + Hours += 12; + } + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +static time_t +Convert( + time_t Month, + time_t Day, + time_t Year, + time_t Hours, + time_t Minutes, + time_t Seconds, + MERIDIAN Meridian, + DSTMODE dst) +{ + static const int DaysNormal[13] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const int DaysLeap[13] = { + 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const int LeapYears[] = { + 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 + }; + const int *yp; + const int *mp; + int i; + time_t Julian; + time_t tod; + + if (Year < 0) + Year = -Year; + if (Year < 70) + Year += 2000; + if (Year < 100) + Year += 1900; + if (Year < EPOCH) + Year += 100; + for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++) + if (Year == *yp) { + mp = DaysLeap; + break; + } + if (Year < EPOCH || Year > END_OF_TIME + || Month < 1 || Month > 12 + /* NOSTRICT */ /* conversion from long may lose accuracy */ + || Day < 1 || Day > mp[(int)Month]) { + return -1; + } + + Julian = Day - 1 + (Year - EPOCH) * 365; + for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++) + if (Year <= *yp) + break; + for (i = 1; i < Month; i++) + Julian += *++mp; + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) { + return -1; + } + Julian += tod; + tod = Julian; + if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) + Julian -= DST_OFFSET * 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect( + time_t Start, + time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; +} + + +static time_t +RelativeMonth( + time_t Start, + time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12 + 1900; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord( + char *buff, + int length) +{ + char *p; + const char *q; + const TABLE *tp; + int c; + + p = buff; + c = p[0]; + + /* See if we have an abbreviation for a month. */ + if (length == 3 || (length == 4 && p[3] == '.')) + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) { + q = tp->name; + if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { + yylval.Number = tp->value; + return tp->type; + } + } + else + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Try for a timezone. */ + for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + /* Try the units table. */ + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + if (--length > 0 && p[length] == 's') { + p[length] = '\0'; + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + p[length] = 's'; + yylval.Number = tp->value; + return tp->type; + } + p[length] = 's'; + } + length++; + + /* Drop out any periods. */ + for (p = buff, q = (STRING)buff; *q; q++) + if (*q != '.') + *p++ = *q; + *p = '\0'; + + /* Try the meridians. */ + if (buff[1] == 'm' && buff[2] == '\0') { + if (buff[0] == 'a') { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (buff[0] == 'p') { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + } + + /* If we saw any periods, try the timezones again. */ + if (p - buff != length) { + c = buff[0]; + for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Unknown word -- assume GMT timezone. */ + yylval.Number = 0; + return tZONE; +} + + +static int +date_lex(void) +{ + int c; + char *p; + char buff[20]; + int sign; + int i; + int nesting; + + for(;;) { + /* Get first character after the whitespace. */ + for(;;) { + while (CTYPE(isspace, *yyInput)) + yyInput++; + c = *yyInput; + + /* Ignore RFC 822 comments, typically time zone names. */ + if (c != LPAREN) + break; + for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) + if (c == LPAREN) + nesting++; + else if (!IS7BIT(c) || c == '\0' || c == '\r' + || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) { + /* Lexical error: bad comment. */ + return '?'; + } + yyInput++; + } + + /* A number? */ + if (CTYPE(isdigit, c) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + yyInput++; + if (!CTYPE(isdigit, *yyInput)) { + /* Return the isolated plus or minus sign. */ + --yyInput; + return *yyInput++; + } + } + else + sign = 0; + for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, c); ) + i = 10 * i + c - '0'; + yyInput--; + yylval.Number = sign < 0 ? -i : i; + return sign ? tSNUMBER : tUNUMBER; + } + + /* A word? */ + if (CTYPE(isalpha, c)) { + for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, c); ) + if (p < &buff[sizeof buff - 1]) + *p++ = CTYPE(isupper, c) ? tolower(c) : c; + *p = '\0'; + yyInput--; + return LookupWord(buff, p - buff); + } + + return *yyInput++; + } +} + + +static int +GetTimeInfo( + TIMEINFO *Now) +{ + static time_t LastTime; + static long LastTzone; + struct tm *tm; +#if defined(HAVE_GETTIMEOFDAY) + struct timeval tv; +#endif /* defined(HAVE_GETTIMEOFDAY) */ +#if defined(DONT_HAVE_TM_GMTOFF) + struct tm local; + struct tm gmt; +#endif /* !defined(DONT_HAVE_TM_GMTOFF) */ + + /* Get the basic time. */ +#if defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(&tv, (struct timezone *)NULL) == -1) + return -1; + Now->time = tv.tv_sec; + Now->usec = tv.tv_usec; +#else + /* Can't check for -1 since that might be a time, I guess. */ + (void)time(&Now->time); + Now->usec = 0; +#endif /* defined(HAVE_GETTIMEOFDAY) */ + + /* Now get the timezone if it's been an hour since the last time. */ + if (Now->time - LastTime > 60 * 60) { + LastTime = Now->time; + if ((tm = localtime(&Now->time)) == NULL) + return -1; +#if defined(DONT_HAVE_TM_GMTOFF) + /* To get the timezone, compare localtime with GMT. */ + local = *tm; + if ((tm = gmtime(&Now->time)) == NULL) + return -1; + gmt = *tm; + + /* Assume we are never more than 24 hours away. */ + LastTzone = gmt.tm_yday - local.tm_yday; + if (LastTzone > 1) + LastTzone = -24; + else if (LastTzone < -1) + LastTzone = 24; + else + LastTzone *= 24; + + /* Scale in the hours and minutes; ignore seconds. */ + LastTzone += gmt.tm_hour - local.tm_hour; + LastTzone *= 60; + LastTzone += gmt.tm_min - local.tm_min; +#else + LastTzone = (0 - tm->tm_gmtoff) / 60; +#endif /* defined(DONT_HAVE_TM_GMTOFF) */ + } + Now->tzone = LastTzone; + return 0; +} + + +time_t +parsedate( + char *p, + TIMEINFO *now) +{ + struct tm *tm; + TIMEINFO ti; + time_t Start; + + yyInput = p; + if (now == NULL) { + now = &ti; + (void)GetTimeInfo(&ti); + } + + tm = localtime(&now->time); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = now->tzone; + if (tm->tm_isdst) /* Correct timezone offset for DST */ + yyTimezone += DST_OFFSET * 60; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveRel = 0; + yyHaveTime = 0; + + if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) + return -1; + + if (yyHaveDate || yyHaveTime) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } else { + Start = now->time; + if (!yyHaveRel) + Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; + } + + Start += yyRelSeconds; + if (yyRelMonth) + Start += RelativeMonth(Start, yyRelMonth); + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} +#line 931 "y.tab.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack(void) +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + + i = yyssp - yyss; + newss = (yyss != 0) + ? (short *)realloc(yyss, newsize * sizeof(*newss)) + : (short *)malloc(newsize * sizeof(*newss)); + if (newss == 0) + return -1; + + yyss = newss; + yyssp = newss + i; + newvs = (yyvs != 0) + ? (YYSTYPE *)realloc(yyvs, newsize * sizeof(*newvs)) + : (YYSTYPE *)malloc(newsize * sizeof(*newvs)); + if (newvs == 0) + return -1; + + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse(void) +{ + register int yym, yyn, yystate; +#if YYDEBUG + register const char *yys; + + if ((yys = getenv("YYDEBUG")) != 0) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = YYEMPTY; + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = YYEMPTY; + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; + + yyerror("syntax error"); + +#ifdef lint + goto yyerrlab; +#endif + +yyerrlab: + ++yynerrs; + +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = YYEMPTY; + goto yyloop; + } + +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 3: +#line 145 "parsdate.y" +{ + yyHaveTime++; +#if defined(lint) + /* I am compulsive about lint natterings... */ + if (yyHaveTime == -1) { + YYERROR; + } +#endif /* defined(lint) */ + } +break; +case 4: +#line 154 "parsdate.y" +{ + yyHaveTime++; + yyTimezone = yyvsp[0].Number; + } +break; +case 5: +#line 158 "parsdate.y" +{ + yyHaveDate++; + } +break; +case 6: +#line 161 "parsdate.y" +{ + yyHaveDate++; + yyHaveTime++; + } +break; +case 7: +#line 165 "parsdate.y" +{ + yyHaveDate++; + yyHaveTime++; + yyTimezone = yyvsp[0].Number; + } +break; +case 8: +#line 170 "parsdate.y" +{ + yyHaveRel = 1; + } +break; +case 9: +#line 175 "parsdate.y" +{ + if (yyvsp[-1].Number < 100) { + yyHour = yyvsp[-1].Number; + yyMinutes = 0; + } + else { + yyHour = yyvsp[-1].Number / 100; + yyMinutes = yyvsp[-1].Number % 100; + } + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 10: +#line 187 "parsdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 11: +#line 193 "parsdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + } +break; +case 12: +#line 200 "parsdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 13: +#line 206 "parsdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + } +break; +case 14: +#line 216 "parsdate.y" +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + } +break; +case 15: +#line 220 "parsdate.y" +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSTon; + } +break; +case 16: +#line 224 "parsdate.y" +{ + yyTimezone = yyvsp[-1].Number; + yyDSTmode = DSTon; + } +break; +case 17: +#line 228 "parsdate.y" +{ + /* Only allow "GMT+300" and "GMT-0800" */ + if (yyvsp[-1].Number != 0) { + YYABORT; + } + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + } +break; +case 18: +#line 236 "parsdate.y" +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + } +break; +case 19: +#line 242 "parsdate.y" +{ + int i; + + /* Unix and GMT and numeric timezones -- a little confusing. */ + if ((int)yyvsp[0].Number < 0) { + /* Don't work with negative modulus. */ + yyvsp[0].Number = -(int)yyvsp[0].Number; + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = (yyvsp[0].Number / 100) * 60 + i; + } + else { + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = -((yyvsp[0].Number / 100) * 60 + i); + } + } +break; +case 20: +#line 263 "parsdate.y" +{ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } +break; +case 21: +#line 267 "parsdate.y" +{ + if (yyvsp[-4].Number > 100) { + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } + else { + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } + } +break; +case 22: +#line 279 "parsdate.y" +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + } +break; +case 23: +#line 283 "parsdate.y" +{ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } +break; +case 24: +#line 288 "parsdate.y" +{ + yyDay = yyvsp[-1].Number; + yyMonth = yyvsp[0].Number; + } +break; +case 25: +#line 292 "parsdate.y" +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + yyYear = yyvsp[0].Number; + } +break; +case 26: +#line 297 "parsdate.y" +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + yyYear = yyvsp[0].Number; + } +break; +case 27: +#line 302 "parsdate.y" +{ + yyDay = yyvsp[-3].Number; + yyMonth = yyvsp[-1].Number; + yyYear = -yyvsp[0].Number; + } +break; +case 28: +#line 307 "parsdate.y" +{ + yyDay = yyvsp[-2].Number; + yyMonth = -yyvsp[-1].Number; + yyYear = -yyvsp[0].Number; + yyDSTmode = DSToff; /* assume midnight if no time given */ + yyTimezone = 0; /* Lynx assumes GMT for this format */ + } +break; +case 29: +#line 316 "parsdate.y" +{ + yyMonth = yyvsp[-7].Number; + yyDay = yyvsp[-6].Number; + yyYear = yyvsp[0].Number; + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + } +break; +case 30: +#line 326 "parsdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 31: +#line 329 "parsdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 32: +#line 332 "parsdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 33: +#line 335 "parsdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 34: +#line 340 "parsdate.y" +{ + yyval.Meridian = MER24; + } +break; +case 35: +#line 343 "parsdate.y" +{ + yyval.Meridian = yyvsp[0].Meridian; + } +break; +#line 1395 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; + +yyoverflow: + yyerror("yacc stack overflow"); + +yyabort: + return (1); + +yyaccept: + return (0); +} diff --git a/src/parsdate.h b/src/parsdate.h new file mode 100644 index 00000000..ab24d318 --- /dev/null +++ b/src/parsdate.h @@ -0,0 +1,21 @@ +/* $LynxId: parsdate.h,v 1.1 2008/06/29 23:23:45 tom Exp $ */ +#ifndef PARSDATE_H +#define PARSDATE_H + +#ifdef __cplusplus +extern "C" { +#endif +#include <LYUtils.h> +#define ARRAY_SIZE(array) ((int) (sizeof(array) / sizeof(array[0]))) + typedef struct _TIMEINFO { + time_t time; + long usec; + long tzone; + } TIMEINFO; + + extern time_t parsedate(char *p, TIMEINFO * now); + +#ifdef __cplusplus +} +#endif +#endif /* PARSDATE_H */ diff --git a/src/parsdate.y b/src/parsdate.y new file mode 100644 index 00000000..c364f7a3 --- /dev/null +++ b/src/parsdate.y @@ -0,0 +1,919 @@ +%{ +/* + * $LynxId: parsdate.y,v 1.4 2008/06/30 23:25:14 tom Exp $ + * + * This module is adapted and extended from tin, to use for LYmktime(). + * + * Project : tin - a Usenet reader + * Module : parsedate.y + * Author : S. Bellovin, R. $alz, J. Berets, P. Eggert + * Created : 1990-08-01 + * Updated : 2008-06-30 (by Thomas Dickey, for Lynx) + * Notes : This grammar has 8 shift/reduce conflicts. + * + * Originally written by Steven M. Bellovin <smb@research.att.com> + * while at the University of North Carolina at Chapel Hill. + * Later tweaked by a couple of people on Usenet. Completely + * overhauled by Rich $alz <rsalz@osf.org> and Jim Berets + * <jberets@bbn.com> in August, 1990. + * + * Further revised (removed obsolete constructs and cleaned up + * timezone names) in August, 1991, by Rich. + * Paul Eggert <eggert@twinsun.com> helped in September 1992. + * Roland Rosenfeld added MET DST code in April 1994. + * + * Revision : 1.13 + * Copyright : This code is in the public domain and has no copyright. + */ + +/* SUPPRESS 530 */ /* Empty body for statement */ +/* SUPPRESS 593 on yyerrlab */ /* Label was not used */ +/* SUPPRESS 593 on yynewstate */ /* Label was not used */ +/* SUPPRESS 595 on yypvt */ /* Automatic variable may be used before set */ + +#include <parsdate.h> + +/* +** Get the number of elements in a fixed-size array, or a pointer just +** past the end of it. +*/ +#define ENDOF(array) (&array[ARRAY_SIZE(array)]) + +#define CTYPE(isXXXXX, c) (((unsigned char)(c) < 128) && isXXXXX(((int)c))) + +typedef char *STRING; + +extern int date_parse(void); + +#define yyparse date_parse +#define yylex date_lex +#define yyerror date_error + + + /* See the LeapYears table in Convert. */ +#define EPOCH 1970 +#define END_OF_TIME 2038 + + /* Constants for general time calculations. */ +#define DST_OFFSET 1 +#define SECSPERDAY (24L * 60L * 60L) + /* Readability for TABLE stuff. */ +#define HOUR(x) (x * 60) + +#define LPAREN '(' +#define RPAREN ')' +#define IS7BIT(x) ((unsigned int)(x) < 0200) + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of them by using a yacc +** union, but this is more efficient. (This routine predates the +** yacc %union construct.) +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static int yyHaveDate; +static int yyHaveRel; +static int yyHaveTime; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +static time_t ToSeconds(time_t, time_t, time_t, MERIDIAN); +static time_t Convert(time_t, time_t, time_t, time_t, time_t, time_t, MERIDIAN, DSTMODE); +static time_t DSTcorrect(time_t, time_t); +static time_t RelativeMonth(time_t, time_t); +static int LookupWord(char *, int); +static int date_lex(void); +static int GetTimeInfo(TIMEINFO *Now); + +/* + * The 'date_error()' function is declared here to work around a defect in + * bison 1.22, which redefines 'const' further down in this file, making it + * impossible to put a prototype here, and the function later. We're using + * 'const' on the parameter to quiet gcc's -Wwrite-strings warning. + */ +/*ARGSUSED*/ +static void +date_error(const char GCC_UNUSED *s) +{ + /*NOTREACHED*/ +} + +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER +%token tUNUMBER tZONE tDST + +%type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT +%type <Number> tSNUMBER tUNUMBER tZONE numzone zone +%type <Meridian> tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; +#if defined(lint) + /* I am compulsive about lint natterings... */ + if (yyHaveTime == -1) { + YYERROR; + } +#endif /* defined(lint) */ + } + | time zone { + yyHaveTime++; + yyTimezone = $2; + } + | date { + yyHaveDate++; + } + | both { + yyHaveDate++; + yyHaveTime++; + } + | both zone { + yyHaveDate++; + yyHaveTime++; + yyTimezone = $2; + } + | rel { + yyHaveRel = 1; + } + ; + +time : tUNUMBER o_merid { + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER numzone { + yyHour = $1; + yyMinutes = $3; + yyTimezone = $4; + yyMeridian = MER24; + yyDSTmode = DSToff; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyTimezone = $6; + yyMeridian = MER24; + yyDSTmode = DSToff; + } + ; + +zone : tZONE { + $$ = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + $$ = $1; + yyDSTmode = DSTon; + } + | tDAYZONE tDST { + yyTimezone = $1; + yyDSTmode = DSTon; + } + | tZONE numzone { + /* Only allow "GMT+300" and "GMT-0800" */ + if ($1 != 0) { + YYABORT; + } + $$ = $2; + yyDSTmode = DSToff; + } + | numzone { + $$ = $1; + yyDSTmode = DSToff; + } + ; + +numzone : tSNUMBER { + int i; + + /* Unix and GMT and numeric timezones -- a little confusing. */ + if ((int)$1 < 0) { + /* Don't work with negative modulus. */ + $1 = -(int)$1; + if ($1 > 9999 || (i = $1 % 100) >= 60) { + YYABORT; + } + $$ = ($1 / 100) * 60 + i; + } + else { + if ($1 > 9999 || (i = $1 % 100) >= 60) { + YYABORT; + } + $$ = -(($1 / 100) * 60 + i); + } + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + if ($1 > 100) { + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } + else { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + yyDay = $1; + yyMonth = $2; + } + | tUNUMBER tMONTH tUNUMBER { + yyDay = $1; + yyMonth = $2; + yyYear = $3; + } + | tDAY ',' tUNUMBER tMONTH tUNUMBER { + yyDay = $3; + yyMonth = $4; + yyYear = $5; + } + | tDAY ',' tUNUMBER '-' tMONTH tSNUMBER { + yyDay = $3; + yyMonth = $5; + yyYear = -$6; + } + | tUNUMBER tSNUMBER tSNUMBER { + yyDay = $1; + yyMonth = -$2; + yyYear = -$3; + yyDSTmode = DSToff; /* assume midnight if no time given */ + yyTimezone = 0; /* Lynx assumes GMT for this format */ + } + ; + +both : tDAY tMONTH tUNUMBER tUNUMBER ':' tUNUMBER ':' tUNUMBER tUNUMBER { + yyMonth = $2; + yyDay = $3; + yyYear = $9; + yyHour = $4; + yyMinutes = $6; + yySeconds = $8; + } + ; + +rel : tSNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + ; + +o_merid : /* NULL */ { + $$ = MER24; + } + | tMERIDIAN { + $$ = $1; + } + ; + +%% + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + const char *name; + int type; + time_t value; +} TABLE; + +/* Month and day table. */ +static const TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + /* The value of the day isn't used... */ + { "sunday", tDAY, 0 }, + { "monday", tDAY, 0 }, + { "tuesday", tDAY, 0 }, + { "wednesday", tDAY, 0 }, + { "thursday", tDAY, 0 }, + { "friday", tDAY, 0 }, + { "saturday", tDAY, 0 }, +}; + +/* Time units table. */ +static const TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { "hour", tSEC_UNIT, 60 * 60 }, + { "minute", tSEC_UNIT, 60 }, + { "min", tSEC_UNIT, 60 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, +}; + +/* Timezone table. */ +static const TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal */ + { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ + { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ + { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ + { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ + { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ + { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ +/* Additional aliases for MET / MET DST *************************************/ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "mes", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "mesz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "msz", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "metdst", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ +/****************************************************************************/ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ + { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ + { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ + { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ + { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ + { "cct", tZONE, -HOUR(8) }, /* China Coast */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ + { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ + { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ + { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ + { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + + /* For completeness we include the following entries. */ +#if 0 + + /* Duplicate names. Either they conflict with a zone listed above + * (which is either more likely to be seen or just been in circulation + * longer), or they conflict with another zone in this section and + * we could not reasonably choose one over the other. */ + { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ + { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ + { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ + { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ + { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ + { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ + { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ + { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ + { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ + { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ + { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ + { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ + { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ + { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ + { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ + { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ + { "cst", tZONE, -HOUR(8) }, /* China Standard */ + { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ + { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ + + /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ + { "wat", tZONE, -HOUR(1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ + { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad */ + { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ + { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ + { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ + { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ + { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ +#endif /* 0 */ +}; + +static time_t +ToSeconds( + time_t Hours, + time_t Minutes, + time_t Seconds, + MERIDIAN Meridian) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) + return -1; + if (Meridian == MER24) { + if (Hours < 0 || Hours > 23) + return -1; + } + else { + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + if (Meridian == MERpm) + Hours += 12; + } + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +static time_t +Convert( + time_t Month, + time_t Day, + time_t Year, + time_t Hours, + time_t Minutes, + time_t Seconds, + MERIDIAN Meridian, + DSTMODE dst) +{ + static const int DaysNormal[13] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const int DaysLeap[13] = { + 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static const int LeapYears[] = { + 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 + }; + const int *yp; + const int *mp; + int i; + time_t Julian; + time_t tod; + + if (Year < 0) + Year = -Year; + if (Year < 70) + Year += 2000; + if (Year < 100) + Year += 1900; + if (Year < EPOCH) + Year += 100; + for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++) + if (Year == *yp) { + mp = DaysLeap; + break; + } + if (Year < EPOCH || Year > END_OF_TIME + || Month < 1 || Month > 12 + /* NOSTRICT */ /* conversion from long may lose accuracy */ + || Day < 1 || Day > mp[(int)Month]) { + return -1; + } + + Julian = Day - 1 + (Year - EPOCH) * 365; + for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++) + if (Year <= *yp) + break; + for (i = 1; i < Month; i++) + Julian += *++mp; + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) { + return -1; + } + Julian += tod; + tod = Julian; + if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) + Julian -= DST_OFFSET * 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect( + time_t Start, + time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; +} + + +static time_t +RelativeMonth( + time_t Start, + time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12 + 1900; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord( + char *buff, + int length) +{ + char *p; + const char *q; + const TABLE *tp; + int c; + + p = buff; + c = p[0]; + + /* See if we have an abbreviation for a month. */ + if (length == 3 || (length == 4 && p[3] == '.')) + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) { + q = tp->name; + if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { + yylval.Number = tp->value; + return tp->type; + } + } + else + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Try for a timezone. */ + for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + /* Try the units table. */ + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + if (--length > 0 && p[length] == 's') { + p[length] = '\0'; + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + p[length] = 's'; + yylval.Number = tp->value; + return tp->type; + } + p[length] = 's'; + } + length++; + + /* Drop out any periods. */ + for (p = buff, q = (STRING)buff; *q; q++) + if (*q != '.') + *p++ = *q; + *p = '\0'; + + /* Try the meridians. */ + if (buff[1] == 'm' && buff[2] == '\0') { + if (buff[0] == 'a') { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (buff[0] == 'p') { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + } + + /* If we saw any periods, try the timezones again. */ + if (p - buff != length) { + c = buff[0]; + for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Unknown word -- assume GMT timezone. */ + yylval.Number = 0; + return tZONE; +} + + +static int +date_lex(void) +{ + int c; + char *p; + char buff[20]; + int sign; + int i; + int nesting; + + for(;;) { + /* Get first character after the whitespace. */ + for(;;) { + while (CTYPE(isspace, *yyInput)) + yyInput++; + c = *yyInput; + + /* Ignore RFC 822 comments, typically time zone names. */ + if (c != LPAREN) + break; + for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) + if (c == LPAREN) + nesting++; + else if (!IS7BIT(c) || c == '\0' || c == '\r' + || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) { + /* Lexical error: bad comment. */ + return '?'; + } + yyInput++; + } + + /* A number? */ + if (CTYPE(isdigit, c) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + yyInput++; + if (!CTYPE(isdigit, *yyInput)) { + /* Return the isolated plus or minus sign. */ + --yyInput; + return *yyInput++; + } + } + else + sign = 0; + for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, c); ) + i = 10 * i + c - '0'; + yyInput--; + yylval.Number = sign < 0 ? -i : i; + return sign ? tSNUMBER : tUNUMBER; + } + + /* A word? */ + if (CTYPE(isalpha, c)) { + for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, c); ) + if (p < &buff[sizeof buff - 1]) + *p++ = CTYPE(isupper, c) ? tolower(c) : c; + *p = '\0'; + yyInput--; + return LookupWord(buff, p - buff); + } + + return *yyInput++; + } +} + + +static int +GetTimeInfo( + TIMEINFO *Now) +{ + static time_t LastTime; + static long LastTzone; + struct tm *tm; +#if defined(HAVE_GETTIMEOFDAY) + struct timeval tv; +#endif /* defined(HAVE_GETTIMEOFDAY) */ +#if defined(DONT_HAVE_TM_GMTOFF) + struct tm local; + struct tm gmt; +#endif /* !defined(DONT_HAVE_TM_GMTOFF) */ + + /* Get the basic time. */ +#if defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(&tv, (struct timezone *)NULL) == -1) + return -1; + Now->time = tv.tv_sec; + Now->usec = tv.tv_usec; +#else + /* Can't check for -1 since that might be a time, I guess. */ + (void)time(&Now->time); + Now->usec = 0; +#endif /* defined(HAVE_GETTIMEOFDAY) */ + + /* Now get the timezone if it's been an hour since the last time. */ + if (Now->time - LastTime > 60 * 60) { + LastTime = Now->time; + if ((tm = localtime(&Now->time)) == NULL) + return -1; +#if defined(DONT_HAVE_TM_GMTOFF) + /* To get the timezone, compare localtime with GMT. */ + local = *tm; + if ((tm = gmtime(&Now->time)) == NULL) + return -1; + gmt = *tm; + + /* Assume we are never more than 24 hours away. */ + LastTzone = gmt.tm_yday - local.tm_yday; + if (LastTzone > 1) + LastTzone = -24; + else if (LastTzone < -1) + LastTzone = 24; + else + LastTzone *= 24; + + /* Scale in the hours and minutes; ignore seconds. */ + LastTzone += gmt.tm_hour - local.tm_hour; + LastTzone *= 60; + LastTzone += gmt.tm_min - local.tm_min; +#else + LastTzone = (0 - tm->tm_gmtoff) / 60; +#endif /* defined(DONT_HAVE_TM_GMTOFF) */ + } + Now->tzone = LastTzone; + return 0; +} + + +time_t +parsedate( + char *p, + TIMEINFO *now) +{ + struct tm *tm; + TIMEINFO ti; + time_t Start; + + yyInput = p; + if (now == NULL) { + now = &ti; + (void)GetTimeInfo(&ti); + } + + tm = localtime(&now->time); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = now->tzone; + if (tm->tm_isdst) /* Correct timezone offset for DST */ + yyTimezone += DST_OFFSET * 60; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveRel = 0; + yyHaveTime = 0; + + if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) + return -1; + + if (yyHaveDate || yyHaveTime) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } else { + Start = now->time; + if (!yyHaveRel) + Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; + } + + Start += yyRelSeconds; + if (yyRelMonth) + Start += RelativeMonth(Start, yyRelMonth); + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} |