X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fgetdate.y;h=9f8f95f1c29d226af96bbbc0d993ac30c1880b37;hb=e29fbaee8afd6fd9b6c0291562740807ca11a0c6;hp=8e35c9203d6084f4e204c0fc41d3226efb8e54e1;hpb=809464b39048da6beb7fa2c216ca8667f6799f67;p=gnulib.git diff --git a/lib/getdate.y b/lib/getdate.y index 8e35c9203..9f8f95f1c 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -3,22 +3,16 @@ ** Originally written by Steven M. Bellovin while ** at the University of North Carolina at Chapel Hill. Later tweaked by ** a couple of people on Usenet. Completely overhauled by Rich $alz -** and Jim Berets in August, 1990; -** send any email to Rich. -** -** This grammar has 10 shift/reduce conflicts. +** and Jim Berets in August, 1990. ** ** This code is in the public domain and has no copyright. */ -/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ -/* SUPPRESS 288 on yyerrlab *//* Label unused */ #ifdef HAVE_CONFIG_H -#include - -#ifdef FORCE_ALLOCA_H -#include -#endif +# include +# ifdef HAVE_ALLOCA_H +# include +# endif #endif /* Since the code of getdate.y is not included in the Emacs executable @@ -28,75 +22,52 @@ problems if we try to write to a static variable, which I don't think this code needs to do. */ #ifdef emacs -#undef static +# undef static #endif #include #include -#if defined (STDC_HEADERS) || !defined (isascii) -# define ISASCII(c) 1 +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 #else -# define ISASCII(c) isascii(c) +# define IN_CTYPE_DOMAIN(c) isascii(c) #endif -#define ISSPACE(c) (ISASCII (c) && isspace (c)) -#define ISALPHA(c) (ISASCII (c) && isalpha (c)) -#define ISUPPER(c) (ISASCII (c) && isupper (c)) -#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that + only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless + it's important to use the locale's definition of `digit' even when the + host does not conform to Posix. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) -#if defined (vms) -#include -#include -#else -#include -#ifdef TIME_WITH_SYS_TIME -#include -#include -#else -#ifdef HAVE_SYS_TIME_H -#include -#else -#include -#endif +#if defined (STDC_HEADERS) || defined (USG) +# include #endif -#ifdef timezone -#undef timezone /* needed for sgi */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(x) #endif -#if defined (HAVE_SYS_TIMEB_H) -#include -#else - -/* get_date uses the obsolete `struct timeb' in its interface! FIXME. - Since some systems don't have it, we define it here; - callers must do likewise. */ -struct timeb - { - time_t time; /* Seconds since the epoch */ - unsigned short millitm; /* Field not used */ - short timezone; /* Minutes west of GMT */ - short dstflag; /* Field not used */ -}; -#endif /* defined (HAVE_SYS_TIMEB_H) */ - -#endif /* defined (vms) */ - -#if defined (STDC_HEADERS) || defined (USG) -#include +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif /* Some old versions of bison generate parsers that use bcopy. That loses on systems that don't provide the function, so we have to redefine it here. */ #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy) -#define bcopy(from, to, len) memcpy ((to), (from), (len)) +# define bcopy(from, to, len) memcpy ((to), (from), (len)) #endif -extern struct tm *gmtime (); -extern struct tm *localtime (); - /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), as well as gratuitiously global symbol names, so we can have multiple yacc generated parsers in the same program. Note that these are only @@ -148,9 +119,7 @@ static int yylex (); static int yyerror (); #define EPOCH 1970 -#define DOOMSDAY 2038 -#define HOUR(x) ((time_t)(x) * 60) -#define SECSPERDAY (24L * 60L * 60L) +#define HOUR(x) ((x) * 60) #define MAX_BUFF_LEN 128 /* size of buffer to read the date into */ @@ -160,18 +129,11 @@ static int yyerror (); typedef struct _TABLE { const char *name; int type; - time_t value; + int value; } TABLE; /* -** 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 { @@ -185,38 +147,46 @@ typedef enum _MERIDIAN { ** yacc had the %union construct.) Maybe someday; right now we only use ** the %union very rarely. */ -static char *yyInput; -static DSTMODE yyDSTmode; -static time_t yyDayOrdinal; -static time_t yyDayNumber; +static const char *yyInput; +static int yyDayOrdinal; +static int yyDayNumber; static int yyHaveDate; static int yyHaveDay; static int yyHaveRel; static int yyHaveTime; static int yyHaveZone; -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 int yyTimezone; +static int yyDay; +static int yyHour; +static int yyMinutes; +static int yyMonth; +static int yySeconds; +static int yyYear; static MERIDIAN yyMeridian; -static time_t yyRelMonth; -static time_t yyRelSeconds; +static int yyRelDay; +static int yyRelHour; +static int yyRelMinutes; +static int yyRelMonth; +static int yyRelSeconds; +static int yyRelYear; %} +/* This grammar has 13 shift/reduce conflicts. */ +%expect 13 + %union { - time_t Number; + int Number; enum _MERIDIAN Meridian; } -%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT -%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST +%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID +%token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT +%token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE -%type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT -%type tSEC_UNIT tSNUMBER tUNUMBER tZONE +%type tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT +%type tMONTH tMONTH_UNIT +%type tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE %type tMERIDIAN o_merid %% @@ -259,8 +229,10 @@ time : tUNUMBER tMERIDIAN { yyHour = $1; yyMinutes = $3; yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($4 % 100 + ($4 / 100) * 60); + yyHaveZone++; + yyTimezone = ($4 < 0 + ? -$4 % 100 + (-$4 / 100) * 60 + : - ($4 % 100 + ($4 / 100) * 60)); } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; @@ -273,23 +245,22 @@ time : tUNUMBER tMERIDIAN { yyMinutes = $3; yySeconds = $5; yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($6 % 100 + ($6 / 100) * 60); + yyHaveZone++; + yyTimezone = ($6 < 0 + ? -$6 % 100 + (-$6 / 100) * 60 + : - ($6 % 100 + ($6 / 100) * 60)); } ; zone : tZONE { yyTimezone = $1; - yyDSTmode = DSToff; } | tDAYZONE { - yyTimezone = $1; - yyDSTmode = DSTon; + yyTimezone = $1 - 60; } | tZONE tDST { - yyTimezone = $1; - yyDSTmode = DSTon; + yyTimezone = $1 - 60; } ; @@ -363,77 +334,125 @@ date : tUNUMBER '/' tUNUMBER { rel : relunit tAGO { yyRelSeconds = -yyRelSeconds; + yyRelMinutes = -yyRelMinutes; + yyRelHour = -yyRelHour; + yyRelDay = -yyRelDay; yyRelMonth = -yyRelMonth; + yyRelYear = -yyRelYear; } | relunit ; -relunit : tUNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; +relunit : tUNUMBER tYEAR_UNIT { + yyRelYear += $1 * $2; } - | tSNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; + | tSNUMBER tYEAR_UNIT { + yyRelYear += $1 * $2; } - | tMINUTE_UNIT { - yyRelSeconds += $1 * 60L; + | tYEAR_UNIT { + yyRelYear += $1; } - | tSNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tUNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tSEC_UNIT { - yyRelSeconds++; - } - | tSNUMBER tMONTH_UNIT { + | tUNUMBER tMONTH_UNIT { yyRelMonth += $1 * $2; } - | tUNUMBER tMONTH_UNIT { + | tSNUMBER tMONTH_UNIT { yyRelMonth += $1 * $2; } | tMONTH_UNIT { yyRelMonth += $1; } + | tUNUMBER tDAY_UNIT { + yyRelDay += $1 * $2; + } + | tSNUMBER tDAY_UNIT { + yyRelDay += $1 * $2; + } + | tDAY_UNIT { + yyRelDay += $1; + } + | tUNUMBER tHOUR_UNIT { + yyRelHour += $1 * $2; + } + | tSNUMBER tHOUR_UNIT { + yyRelHour += $1 * $2; + } + | tHOUR_UNIT { + yyRelHour += $1; + } + | tUNUMBER tMINUTE_UNIT { + yyRelMinutes += $1 * $2; + } + | tSNUMBER tMINUTE_UNIT { + yyRelMinutes += $1 * $2; + } + | tMINUTE_UNIT { + yyRelMinutes += $1; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSNUMBER tSEC_UNIT { + yyRelSeconds += $1 * $2; + } + | tSEC_UNIT { + yyRelSeconds += $1; + } ; -number : tUNUMBER { +number : tUNUMBER + { if (yyHaveTime && yyHaveDate && !yyHaveRel) - yyYear = $1; - else { - if ($1>10000) { + yyYear = $1; + else + { + if ($1>10000) + { yyHaveDate++; yyDay= ($1)%100; yyMonth= ($1/100)%100; yyYear = $1/10000; - } - else { + } + else + { yyHaveTime++; - if ($1 < 100) { + if ($1 < 100) + { yyHour = $1; yyMinutes = 0; - } - else { + } + else + { yyHour = $1 / 100; yyMinutes = $1 % 100; - } + } yySeconds = 0; yyMeridian = MER24; - } - } - } + } + } + } ; -o_merid : /* NULL */ { +o_merid : /* NULL */ + { $$ = MER24; - } - | tMERIDIAN { + } + | tMERIDIAN + { $$ = $1; - } + } ; %% +/* Include this file down here because bison inserts code above which + may define-away `const'. We want the prototype for get_date to have + the same signature as the function definition does. */ +#include "getdate.h" + +extern struct tm *gmtime (); +extern struct tm *localtime (); +extern time_t mktime (); + /* Month and day table. */ static TABLE const MonthDayTable[] = { { "january", tMONTH, 1 }, @@ -460,22 +479,22 @@ static TABLE const MonthDayTable[] = { { "thurs", tDAY, 4 }, { "friday", tDAY, 5 }, { "saturday", tDAY, 6 }, - { NULL } + { NULL, 0, 0 } }; /* Time units table. */ static TABLE const UnitsTable[] = { - { "year", tMONTH_UNIT, 12 }, + { "year", tYEAR_UNIT, 1 }, { "month", tMONTH_UNIT, 1 }, - { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, - { "week", tMINUTE_UNIT, 7 * 24 * 60 }, - { "day", tMINUTE_UNIT, 1 * 24 * 60 }, - { "hour", tMINUTE_UNIT, 60 }, + { "fortnight", tDAY_UNIT, 14 }, + { "week", tDAY_UNIT, 7 }, + { "day", tDAY_UNIT, 1 }, + { "hour", tHOUR_UNIT, 1 }, { "minute", tMINUTE_UNIT, 1 }, { "min", tMINUTE_UNIT, 1 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 }, - { NULL } + { NULL, 0, 0 } }; /* Assorted relative-time words. */ @@ -486,7 +505,7 @@ static TABLE const OtherTable[] = { { "now", tMINUTE_UNIT, 0 }, { "last", tUNUMBER, -1 }, { "this", tMINUTE_UNIT, 0 }, - { "next", tUNUMBER, 2 }, + { "next", tUNUMBER, 1 }, { "first", tUNUMBER, 1 }, /* { "second", tUNUMBER, 2 }, */ { "third", tUNUMBER, 3 }, @@ -500,11 +519,10 @@ static TABLE const OtherTable[] = { { "eleventh", tUNUMBER, 11 }, { "twelfth", tUNUMBER, 12 }, { "ago", tAGO, 1 }, - { NULL } + { NULL, 0, 0 } }; /* The timezone table. */ -/* Some of these are commented out because a time_t can't store a float. */ static TABLE const TimezoneTable[] = { { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ @@ -586,7 +604,7 @@ static TABLE const TimezoneTable[] = { { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */ { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */ { "idle", tZONE, -HOUR (12) }, /* International Date Line East */ - { NULL } + { NULL, 0, 0 } }; /* Military timezone table. */ @@ -616,7 +634,7 @@ static TABLE const MilitaryTable[] = { { "x", tZONE, HOUR (-11) }, { "y", tZONE, HOUR (-12) }, { "z", tZONE, HOUR ( 0) }, - { NULL } + { NULL, 0, 0 } }; @@ -625,234 +643,159 @@ static TABLE const MilitaryTable[] = { /* ARGSUSED */ static int yyerror (s) - char *s; + char *s ATTRIBUTE_UNUSED; { return 0; } - -static time_t -ToSeconds (Hours, Minutes, Seconds, Meridian) - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; +static int +ToHour (Hours, Meridian) + int Hours; + MERIDIAN Meridian; { - if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) - return -1; - switch (Meridian) { - case MER24: - if (Hours < 0 || Hours > 23) - return -1; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERam: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERpm: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; - default: - abort (); - } + switch (Meridian) + { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return Hours; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return Hours + 12; + default: + abort (); + } /* NOTREACHED */ } - -static time_t -Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE DSTmode; +static int +ToYear (Year) + int Year; { - static int DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t tod; - time_t Julian; - int i; - if (Year < 0) Year = -Year; - if (Year < DOOMSDAY-2000) + + /* XPG4 suggests that years 00-68 map to 2000-2068, and + years 69-99 map to 1969-1999. */ + if (Year < 69) Year += 2000; else if (Year < 100) Year += 1900; - DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) - ? 29 : 28; - if (Year < EPOCH || Year >= DOOMSDAY - || Month < 1 || Month > 12 - /* Lint fluff: "conversion from long may lose accuracy" */ - || Day < 1 || Day > DaysInMonth[(int)--Month]) - return -1; - - for (Julian = Day - 1, i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - for (i = EPOCH; i < Year; i++) - Julian += 365 + (i % 4 == 0); - Julian *= SECSPERDAY; - Julian += yyTimezone * 60L; - if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0) - return -1; - Julian += tod; - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst)) - Julian -= 60 * 60; - return Julian; -} - - -static time_t -DSTcorrect (Start, Future) - 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) * 60L * 60L; + return Year; } - -static time_t -RelativeDate (Start, DayOrdinal, DayNumber) - time_t Start; - time_t DayOrdinal; - time_t DayNumber; -{ - struct tm *tm; - time_t now; - - now = Start; - tm = localtime (&now); - now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - return DSTcorrect (Start, now); -} - - -static time_t -RelativeMonth (Start, RelMonth) - time_t Start; - time_t RelMonth; -{ - struct tm *tm; - time_t Month; - time_t Year; - - if (RelMonth == 0) - return 0; - tm = localtime (&Start); - Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth; - Year = Month / 12; - 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 (buff) - char *buff; + char *buff; { - register char *p; - register char *q; - register const TABLE *tp; - int i; - int abbrev; + register char *p; + register char *q; + register const TABLE *tp; + int i; + int abbrev; /* Make it lowercase. */ for (p = buff; *p; p++) if (ISUPPER (*p)) *p = tolower (*p); - if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) { - yylval.Meridian = MERam; - return tMERIDIAN; - } - if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) { - yylval.Meridian = MERpm; - return tMERIDIAN; - } + if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) + { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) + { + yylval.Meridian = MERpm; + return tMERIDIAN; + } /* See if we have an abbreviation for a month. */ if (strlen (buff) == 3) abbrev = 1; - else if (strlen (buff) == 4 && buff[3] == '.') { - abbrev = 1; - buff[3] = '\0'; - } + else if (strlen (buff) == 4 && buff[3] == '.') + { + abbrev = 1; + buff[3] = '\0'; + } else abbrev = 0; - for (tp = MonthDayTable; tp->name; tp++) { - if (abbrev) { - if (strncmp (buff, tp->name, 3) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - else if (strcmp (buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; + for (tp = MonthDayTable; tp->name; tp++) + { + if (abbrev) + { + if (strncmp (buff, tp->name, 3) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } } - } for (tp = TimezoneTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } if (strcmp (buff, "dst") == 0) return tDST; for (tp = UnitsTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - /* Strip off any plural and try the units table again. */ - i = strlen (buff) - 1; - if (buff[i] == 's') { - buff[i] = '\0'; - for (tp = UnitsTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { + if (strcmp (buff, tp->name) == 0) + { yylval.Number = tp->value; return tp->type; } - buff[i] = 's'; /* Put back for "this" in OtherTable. */ - } - for (tp = OtherTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; + /* Strip off any plural and try the units table again. */ + i = strlen (buff) - 1; + if (buff[i] == 's') + { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ } - /* Military timezones. */ - if (buff[1] == '\0' && ISALPHA (*buff)) { - for (tp = MilitaryTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { + for (tp = OtherTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { yylval.Number = tp->value; return tp->type; } - } + + /* Military timezones. */ + if (buff[1] == '\0' && ISALPHA (*buff)) + { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } + } /* Drop out any periods and try the timezone table again. */ for (i = 0, p = q = buff; *q; q++) @@ -863,65 +806,71 @@ LookupWord (buff) *p = '\0'; if (i) for (tp = TimezoneTable; tp->name; tp++) - if (strcmp (buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } + if (strcmp (buff, tp->name) == 0) + { + yylval.Number = tp->value; + return tp->type; + } return tID; } - static int yylex () { - register char c; - register char *p; - char buff[20]; - int Count; - int sign; - - for ( ; ; ) { - while (ISSPACE (*yyInput)) - yyInput++; - - if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') { - if (c == '-' || c == '+') { - sign = c == '-' ? -1 : 1; - if (!ISDIGIT (*++yyInput)) - /* skip the '-' sign */ - continue; - } - else - sign = 0; - for (yylval.Number = 0; ISDIGIT (c = *yyInput++); ) - yylval.Number = 10 * yylval.Number + c - '0'; - yyInput--; - if (sign < 0) - yylval.Number = -yylval.Number; - return sign ? tSNUMBER : tUNUMBER; - } - if (ISALPHA (c)) { - for (p = buff; ISALPHA (c = *yyInput++) || c == '.'; ) - if (p < &buff[sizeof buff - 1]) - *p++ = c; - *p = '\0'; - yyInput--; - return LookupWord (buff); + register char c; + register char *p; + char buff[20]; + int Count; + int sign; + + for (;;) + { + while (ISSPACE (*yyInput)) + yyInput++; + + if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') + { + if (c == '-' || c == '+') + { + sign = c == '-' ? -1 : 1; + if (!ISDIGIT (*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; ISDIGIT (c = *yyInput++);) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (ISALPHA (c)) + { + for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord (buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do + { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } + while (Count > 0); } - if (c != '(') - return *yyInput++; - Count = 0; - do { - c = *yyInput++; - if (c == '\0') - return c; - if (c == '(') - Count++; - else if (c == ')') - Count--; - } while (Count > 0); - } } #define TM_YEAR_ORIGIN 1900 @@ -934,59 +883,42 @@ difftm (a, b) int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); int by = b->tm_year + (TM_YEAR_ORIGIN - 1); long days = ( - /* difference in day of year */ - a->tm_yday - b->tm_yday - /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - /* + difference in years * 365 */ - + (long)(ay-by) * 365 - ); - return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) - + (a->tm_min - b->tm_min)) + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay / 100 - by / 100) + + ((ay / 100 >> 2) - (by / 100 >> 2)) + /* + difference in years * 365 */ + + (long) (ay - by) * 365 + ); + return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec)); } time_t -get_date (p, now) - char *p; - struct timeb *now; +get_date (const char *p, const time_t *now) { - struct tm *tm, gmt; - struct timeb ftz; - time_t Start; - time_t tod; + struct tm tm, tm0, *tmp; + time_t Start; yyInput = p; - if (now == NULL) { - now = &ftz; - (void)time (&ftz.time); - - if (! (tm = gmtime (&ftz.time))) - return -1; - gmt = *tm; /* Make a copy, in case localtime modifies *tm. */ - - if (! (tm = localtime (&ftz.time))) - return -1; - - ftz.timezone = difftm (&gmt, tm) / 60; - if (tm->tm_isdst) - ftz.timezone += 60; - } - - tm = localtime (&now->time); - yyYear = tm->tm_year; - yyMonth = tm->tm_mon + 1; - yyDay = tm->tm_mday; - yyTimezone = now->timezone; - yyDSTmode = DSTmaybe; - yyHour = 0; - yyMinutes = 0; - yySeconds = 0; + Start = now ? *now : time ((time_t *) NULL); + tmp = localtime (&Start); + yyYear = tmp->tm_year + TM_YEAR_ORIGIN; + yyMonth = tmp->tm_mon + 1; + yyDay = tmp->tm_mday; + yyHour = tmp->tm_hour; + yyMinutes = tmp->tm_min; + yySeconds = tmp->tm_sec; yyMeridian = MER24; yyRelSeconds = 0; + yyRelMinutes = 0; + yyRelHour = 0; + yyRelDay = 0; yyRelMonth = 0; + yyRelYear = 0; yyHaveDate = 0; yyHaveDay = 0; yyHaveRel = 0; @@ -997,57 +929,106 @@ get_date (p, now) || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) return -1; - if (yyHaveDate || yyHaveTime || yyHaveDay) { - 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; - Start += RelativeMonth (Start, yyRelMonth); - - if (yyHaveDay && !yyHaveDate) { - tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber); - Start += tod; - } - - /* 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; -} + tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear; + tm.tm_mon = yyMonth - 1 + yyRelMonth; + tm.tm_mday = yyDay + yyRelDay; + if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay)) + { + tm.tm_hour = ToHour (yyHour, yyMeridian); + if (tm.tm_hour < 0) + return -1; + tm.tm_min = yyMinutes; + tm.tm_sec = yySeconds; + } + else + { + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + } + tm.tm_hour += yyRelHour; + tm.tm_min += yyRelMinutes; + tm.tm_sec += yyRelSeconds; + tm.tm_isdst = -1; + tm0 = tm; + + Start = mktime (&tm); + + if (Start == (time_t) -1) + { + + /* Guard against falsely reporting errors near the time_t boundaries + when parsing times in other time zones. For example, if the min + time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead + of UTC, then the min localtime value is 1970-01-01 08:00:00; if + we apply mktime to 1970-01-01 00:00:00 we will get an error, so + we apply mktime to 1970-01-02 08:00:00 instead and adjust the time + zone by 24 hours to compensate. This algorithm assumes that + there is no DST transition within a day of the time_t boundaries. */ + if (yyHaveZone) + { + tm = tm0; + if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) + { + tm.tm_mday++; + yyTimezone -= 24 * 60; + } + else + { + tm.tm_mday--; + yyTimezone += 24 * 60; + } + Start = mktime (&tm); + } + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveDay && !yyHaveDate) + { + tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7 + + 7 * (yyDayOrdinal - (0 < yyDayOrdinal))); + Start = mktime (&tm); + if (Start == (time_t) -1) + return Start; + } + + if (yyHaveZone) + { + long delta = yyTimezone * 60L + difftm (&tm, gmtime (&Start)); + if ((Start + delta < Start) != (delta < 0)) + return -1; /* time_t overflow */ + Start += delta; + } + + return Start; +} #if defined (TEST) /* ARGSUSED */ int main (ac, av) - int ac; - char *av[]; + int ac; + char *av[]; { char buff[MAX_BUFF_LEN + 1]; time_t d; - (void)printf ("Enter date, or blank line to exit.\n\t> "); - (void)fflush (stdout); + (void) printf ("Enter date, or blank line to exit.\n\t> "); + (void) fflush (stdout); buff[MAX_BUFF_LEN] = 0; - while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) { - d = get_date (buff, (struct timeb *)NULL); - if (d == -1) - (void)printf ("Bad format - couldn't convert.\n"); - else - (void)printf ("%s", ctime (&d)); - (void)printf ("\t> "); - (void)fflush (stdout); - } + while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) + { + d = get_date (buff, (time_t *) NULL); + if (d == -1) + (void) printf ("Bad format - couldn't convert.\n"); + else + (void) printf ("%s", ctime (&d)); + (void) printf ("\t> "); + (void) fflush (stdout); + } exit (0); /* NOTREACHED */ } -#endif /* defined (TEST) */ +#endif /* defined (TEST) */