X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=lib%2Fgetdate.y;h=4fe084c05b283bf548adb63e386556cbc7306149;hb=619c6ea42fb509a8f15fa72371325b684f891a61;hp=ed35cf3c6f055e084d59ccaff971006873cbce35;hpb=77de7dbb2f58c87ba6490fd3da39784b10dc826a;p=chaz%2Ftar diff --git a/lib/getdate.y b/lib/getdate.y index ed35cf3..4fe084c 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -1,6 +1,6 @@ %{ /* Parse a string into an internal time stamp. - Copyright 1999 Free Software Foundation, Inc. + Copyright 1999, 2000 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -73,7 +73,7 @@ # include #endif -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ # define __attribute__(x) #endif @@ -82,7 +82,7 @@ #endif #define EPOCH_YEAR 1970 -#define TM_YEAR_ORIGIN 1900 +#define TM_YEAR_BASE 1900 #define HOUR(x) ((x) * 60) @@ -99,7 +99,7 @@ enum { MERam, MERpm, MER24 }; /* Information passed to and from the parser. */ struct parser_control -{ +{ /* The input string remaining to be parsed. */ const char *input; @@ -146,6 +146,7 @@ struct parser_control table local_time_zone_table[3]; }; +#define PC (* (struct parser_control *) parm) #define YYLEX_PARAM parm #define YYPARSE_PARAM parm #define YYSTYPE int @@ -174,102 +175,100 @@ spec: item: time - { ((struct parser_control *) parm)->times_seen++; } + { PC.times_seen++; } | local_zone - { ((struct parser_control *) parm)->local_zones_seen++; } + { PC.local_zones_seen++; } | zone - { ((struct parser_control *) parm)->zones_seen++; } + { PC.zones_seen++; } | date - { ((struct parser_control *) parm)->dates_seen++; } + { PC.dates_seen++; } | day - { ((struct parser_control *) parm)->days_seen++; } + { PC.days_seen++; } | rel - { ((struct parser_control *) parm)->rels_seen++; } + { PC.rels_seen++; } | number ; time: tUNUMBER tMERIDIAN { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = 0; - ((struct parser_control *) parm)->seconds = 0; - ((struct parser_control *) parm)->meridian = $2; + PC.hour = $1; + PC.minutes = 0; + PC.seconds = 0; + PC.meridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = $3; - ((struct parser_control *) parm)->seconds = 0; - ((struct parser_control *) parm)->meridian = $4; + PC.hour = $1; + PC.minutes = $3; + PC.seconds = 0; + PC.meridian = $4; } | tUNUMBER ':' tUNUMBER tSNUMBER { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = $3; - ((struct parser_control *) parm)->meridian = MER24; - ((struct parser_control *) parm)->zones_seen++; - ((struct parser_control *) parm)->time_zone = - $4 % 100 + ($4 / 100) * 60; + PC.hour = $1; + PC.minutes = $3; + PC.meridian = MER24; + PC.zones_seen++; + PC.time_zone = $4 % 100 + ($4 / 100) * 60; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = $3; - ((struct parser_control *) parm)->seconds = $5; - ((struct parser_control *) parm)->meridian = $6; + PC.hour = $1; + PC.minutes = $3; + PC.seconds = $5; + PC.meridian = $6; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = $3; - ((struct parser_control *) parm)->seconds = $5; - ((struct parser_control *) parm)->meridian = MER24; - ((struct parser_control *) parm)->zones_seen++; - ((struct parser_control *) parm)->time_zone = - $6 % 100 + ($6 / 100) * 60; + PC.hour = $1; + PC.minutes = $3; + PC.seconds = $5; + PC.meridian = MER24; + PC.zones_seen++; + PC.time_zone = $6 % 100 + ($6 / 100) * 60; } ; local_zone: tLOCAL_ZONE - { ((struct parser_control *) parm)->local_isdst = $1; } + { PC.local_isdst = $1; } | tLOCAL_ZONE tDST - { ((struct parser_control *) parm)->local_isdst = $1 < 0 ? 1 : $1 + 1; } + { PC.local_isdst = $1 < 0 ? 1 : $1 + 1; } ; zone: tZONE - { ((struct parser_control *) parm)->time_zone = $1; } + { PC.time_zone = $1; } | tDAYZONE - { ((struct parser_control *) parm)->time_zone = $1 + 60; } + { PC.time_zone = $1 + 60; } | tZONE tDST - { ((struct parser_control *) parm)->time_zone = $1 + 60; } + { PC.time_zone = $1 + 60; } ; day: tDAY { - ((struct parser_control *) parm)->day_ordinal = 1; - ((struct parser_control *) parm)->day_number = $1; + PC.day_ordinal = 1; + PC.day_number = $1; } | tDAY ',' { - ((struct parser_control *) parm)->day_ordinal = 1; - ((struct parser_control *) parm)->day_number = $1; + PC.day_ordinal = 1; + PC.day_number = $1; } | tUNUMBER tDAY { - ((struct parser_control *) parm)->day_ordinal = $1; - ((struct parser_control *) parm)->day_number = $2; + PC.day_ordinal = $1; + PC.day_number = $2; } ; date: tUNUMBER '/' tUNUMBER { - ((struct parser_control *) parm)->month = $1; - ((struct parser_control *) parm)->day = $3; + PC.month = $1; + PC.day = $3; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { @@ -279,138 +278,136 @@ date: you want portability, use the ISO 8601 format. */ if (1000 <= $1) { - ((struct parser_control *) parm)->year = $1; - ((struct parser_control *) parm)->month = $3; - ((struct parser_control *) parm)->day = $5; + PC.year = $1; + PC.month = $3; + PC.day = $5; } else { - ((struct parser_control *) parm)->month = $1; - ((struct parser_control *) parm)->day = $3; - ((struct parser_control *) parm)->year = $5; + PC.month = $1; + PC.day = $3; + PC.year = $5; } } | tUNUMBER tSNUMBER tSNUMBER { /* ISO 8601 format. YYYY-MM-DD. */ - ((struct parser_control *) parm)->year = $1; - ((struct parser_control *) parm)->month = -$2; - ((struct parser_control *) parm)->day = -$3; + PC.year = $1; + PC.month = -$2; + PC.day = -$3; } | tUNUMBER tMONTH tSNUMBER { /* e.g. 17-JUN-1992. */ - ((struct parser_control *) parm)->day = $1; - ((struct parser_control *) parm)->month = $2; - ((struct parser_control *) parm)->year = -$3; + PC.day = $1; + PC.month = $2; + PC.year = -$3; } | tMONTH tUNUMBER { - ((struct parser_control *) parm)->month = $1; - ((struct parser_control *) parm)->day = $2; + PC.month = $1; + PC.day = $2; } | tMONTH tUNUMBER ',' tUNUMBER { - ((struct parser_control *) parm)->month = $1; - ((struct parser_control *) parm)->day = $2; - ((struct parser_control *) parm)->year = $4; + PC.month = $1; + PC.day = $2; + PC.year = $4; } | tUNUMBER tMONTH { - ((struct parser_control *) parm)->month = $2; - ((struct parser_control *) parm)->day = $1; + PC.month = $2; + PC.day = $1; } | tUNUMBER tMONTH tUNUMBER { - ((struct parser_control *) parm)->month = $2; - ((struct parser_control *) parm)->day = $1; - ((struct parser_control *) parm)->year = $3; + PC.month = $2; + PC.day = $1; + PC.year = $3; } ; rel: relunit tAGO { - ((struct parser_control *) parm)->rel_seconds = -((struct parser_control *) parm)->rel_seconds; - ((struct parser_control *) parm)->rel_minutes = -((struct parser_control *) parm)->rel_minutes; - ((struct parser_control *) parm)->rel_hour = -((struct parser_control *) parm)->rel_hour; - ((struct parser_control *) parm)->rel_day = -((struct parser_control *) parm)->rel_day; - ((struct parser_control *) parm)->rel_month = -((struct parser_control *) parm)->rel_month; - ((struct parser_control *) parm)->rel_year = -((struct parser_control *) parm)->rel_year; + PC.rel_seconds = -PC.rel_seconds; + PC.rel_minutes = -PC.rel_minutes; + PC.rel_hour = -PC.rel_hour; + PC.rel_day = -PC.rel_day; + PC.rel_month = -PC.rel_month; + PC.rel_year = -PC.rel_year; } | relunit ; relunit: tUNUMBER tYEAR_UNIT - { ((struct parser_control *) parm)->rel_year += $1 * $2; } + { PC.rel_year += $1 * $2; } | tSNUMBER tYEAR_UNIT - { ((struct parser_control *) parm)->rel_year += $1 * $2; } + { PC.rel_year += $1 * $2; } | tYEAR_UNIT - { ((struct parser_control *) parm)->rel_year += $1; } + { PC.rel_year += $1; } | tUNUMBER tMONTH_UNIT - { ((struct parser_control *) parm)->rel_month += $1 * $2; } + { PC.rel_month += $1 * $2; } | tSNUMBER tMONTH_UNIT - { ((struct parser_control *) parm)->rel_month += $1 * $2; } + { PC.rel_month += $1 * $2; } | tMONTH_UNIT - { ((struct parser_control *) parm)->rel_month += $1; } + { PC.rel_month += $1; } | tUNUMBER tDAY_UNIT - { ((struct parser_control *) parm)->rel_day += $1 * $2; } + { PC.rel_day += $1 * $2; } | tSNUMBER tDAY_UNIT - { ((struct parser_control *) parm)->rel_day += $1 * $2; } + { PC.rel_day += $1 * $2; } | tDAY_UNIT - { ((struct parser_control *) parm)->rel_day += $1; } + { PC.rel_day += $1; } | tUNUMBER tHOUR_UNIT - { ((struct parser_control *) parm)->rel_hour += $1 * $2; } + { PC.rel_hour += $1 * $2; } | tSNUMBER tHOUR_UNIT - { ((struct parser_control *) parm)->rel_hour += $1 * $2; } + { PC.rel_hour += $1 * $2; } | tHOUR_UNIT - { ((struct parser_control *) parm)->rel_hour += $1; } + { PC.rel_hour += $1; } | tUNUMBER tMINUTE_UNIT - { ((struct parser_control *) parm)->rel_minutes += $1 * $2; } + { PC.rel_minutes += $1 * $2; } | tSNUMBER tMINUTE_UNIT - { ((struct parser_control *) parm)->rel_minutes += $1 * $2; } + { PC.rel_minutes += $1 * $2; } | tMINUTE_UNIT - { ((struct parser_control *) parm)->rel_minutes += $1; } + { PC.rel_minutes += $1; } | tUNUMBER tSEC_UNIT - { ((struct parser_control *) parm)->rel_seconds += $1 * $2; } + { PC.rel_seconds += $1 * $2; } | tSNUMBER tSEC_UNIT - { ((struct parser_control *) parm)->rel_seconds += $1 * $2; } + { PC.rel_seconds += $1 * $2; } | tSEC_UNIT - { ((struct parser_control *) parm)->rel_seconds += $1; } + { PC.rel_seconds += $1; } ; number: tUNUMBER { - if (((struct parser_control *) parm)->times_seen - && ((struct parser_control *) parm)->dates_seen - && ! ((struct parser_control *) parm)->rels_seen) - ((struct parser_control *) parm)->year = $1; + if (PC.dates_seen && ! PC.rels_seen && (PC.times_seen || 100 <= $1)) + PC.year = $1; else { if (10000 < $1) { - ((struct parser_control *) parm)->dates_seen++; - ((struct parser_control *) parm)->day = $1 % 100; - ((struct parser_control *) parm)->month = ($1 / 100) % 100; - ((struct parser_control *) parm)->year = $1 / 10000; + PC.dates_seen++; + PC.day = $1 % 100; + PC.month = ($1 / 100) % 100; + PC.year = $1 / 10000; } else { - ((struct parser_control *) parm)->times_seen++; + PC.times_seen++; if ($1 < 100) { - ((struct parser_control *) parm)->hour = $1; - ((struct parser_control *) parm)->minutes = 0; + PC.hour = $1; + PC.minutes = 0; } else { - ((struct parser_control *) parm)->hour = $1 / 100; - ((struct parser_control *) parm)->minutes = $1 % 100; + PC.hour = $1 / 100; + PC.minutes = $1 % 100; } - ((struct parser_control *) parm)->seconds = 0; - ((struct parser_control *) parm)->meridian = MER24; + PC.seconds = 0; + PC.meridian = MER24; } } } @@ -506,7 +503,7 @@ static table const relative_time_table[] = { "TODAY", tMINUTE_UNIT, 0 }, { "NOW", tMINUTE_UNIT, 0 }, { "LAST", tUNUMBER, -1 }, - { "THIS", tMINUTE_UNIT, 0 }, + { "THIS", tUNUMBER, 0 }, { "NEXT", tUNUMBER, 1 }, { "FIRST", tUNUMBER, 1 }, /*{ "SECOND", tUNUMBER, 2 }, */ @@ -667,26 +664,32 @@ lookup_zone (struct parser_control const *pc, char const *name) return 0; } -/* Yield A - B, measured in seconds. */ +#if ! HAVE_TM_GMTOFF +/* Yield the difference between *A and *B, + measured in seconds, ignoring leap seconds. + The body of this function is taken directly from the GNU C Library; + see src/strftime.c. */ static int -difftm (struct tm *a, struct tm *b) +tm_diff (struct tm const *a, struct tm const *b) { - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int 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 */ - + (int) (ay - by) * 365 - ); + /* Compute intervening leap days correctly even if year is negative. + Take care to avoid int overflow in leap day calculations, + but it's OK to assume that A and B are close to each other. */ + int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); + int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = a100 >> 2; + int b400 = b100 >> 2; + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + int years = a->tm_year - b->tm_year; + int days = (365 * years + intervening_leap_days + + (a->tm_yday - b->tm_yday)); return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + (a->tm_min - b->tm_min)) + (a->tm_sec - b->tm_sec)); } +#endif /* ! HAVE_TM_GMTOFF */ static table const * lookup_word (struct parser_control const *pc, char *word) @@ -834,7 +837,10 @@ yyerror (char *s ATTRIBUTE_UNUSED) return 0; } -/* ?? */ +/* Parse a date/time string P. Return the corresponding time_t value, + or (time_t) -1 if there is an error. P can be an incomplete or + relative time specification; if so, use *NOW as the basis for the + returned time. */ time_t get_date (const char *p, const time_t *now) { @@ -848,7 +854,7 @@ get_date (const char *p, const time_t *now) return -1; pc.input = p; - pc.year = tmp->tm_year + TM_YEAR_ORIGIN; + pc.year = tmp->tm_year + TM_YEAR_BASE; pc.month = tmp->tm_mon + 1; pc.day = tmp->tm_mday; pc.hour = tmp->tm_hour; @@ -879,18 +885,18 @@ get_date (const char *p, const time_t *now) /* Probe the names used in the next three calendar quarters, looking for a tm_isdst different from the one we already have. */ { - int probe; - for (probe = 1; probe <= 3; probe++) + int quarter; + for (quarter = 1; quarter <= 3; quarter++) { - time_t probe = Start + probe * (90 * 24 * 60 * 60); - struct tm *tm = localtime (&probe); - if (tm && tm->tm_zone - && tm->tm_isdst != pc.local_time_zone_table[0].value) + time_t probe = Start + quarter * (90 * 24 * 60 * 60); + struct tm *probe_tm = localtime (&probe); + if (probe_tm && probe_tm->tm_zone + && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) { { - pc.local_time_zone_table[1].name = tm->tm_zone; + pc.local_time_zone_table[1].name = probe_tm->tm_zone; pc.local_time_zone_table[1].type = tLOCAL_ZONE; - pc.local_time_zone_table[1].value = tm->tm_isdst; + pc.local_time_zone_table[1].value = probe_tm->tm_isdst; pc.local_time_zone_table[2].name = 0; } break; @@ -934,7 +940,7 @@ get_date (const char *p, const time_t *now) || (pc.local_zones_seen && 1 < pc.local_isdst)) return -1; - tm.tm_year = to_year (pc.year) - TM_YEAR_ORIGIN + pc.rel_year; + tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year; tm.tm_mon = pc.month - 1 + pc.rel_month; tm.tm_mday = pc.day + pc.rel_day; if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) @@ -981,7 +987,7 @@ get_date (const char *p, const time_t *now) if (pc.zones_seen) { tm = tm0; - if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_ORIGIN) + if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE) { tm.tm_mday++; pc.time_zone += 24 * 60; @@ -1009,12 +1015,16 @@ get_date (const char *p, const time_t *now) if (pc.zones_seen) { - int delta; + int delta = pc.time_zone * 60; +#ifdef HAVE_TM_GMTOFF + delta -= tm.tm_gmtoff; +#else struct tm *gmt = gmtime (&Start); if (! gmt) return -1; - delta = pc.time_zone * 60 + difftm (gmt, &tm); - if ((Start - delta < Start) != (delta < 0)) + delta -= tm_diff (&tm, gmt); +#endif + if ((Start < Start - delta) != (delta < 0)) return -1; /* time_t overflow */ Start -= delta; }