X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fgetdate.y;h=29a4be14616fa403c2aad8f0374994d06aea8c67;hb=e5cf463ba47a430a4a2509e029222682f974499f;hp=868f98303dd096f96e5d92a76c766a2ad6a59eb0;hpb=267a39bafd249d7eb9c37df06dc6defcf41cb343;p=gnulib.git diff --git a/lib/getdate.y b/lib/getdate.y index 868f98303..29a4be146 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -1,7 +1,7 @@ %{ /* Parse a string into an internal time stamp. - Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -32,9 +32,7 @@ /* FIXME: Check for arithmetic overflow in all cases, not just some of them. */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include #include "getdate.h" @@ -68,27 +66,20 @@ #include "setenv.h" #include "xalloc.h" -#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII) -# define IN_CTYPE_DOMAIN(c) 1 -#else -# define IN_CTYPE_DOMAIN(c) isascii (c) -#endif - -#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) -#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) -#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) /* ISDIGIT differs from isdigit, 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. + - Its arg may be any int or unsigned int; it need not be an unsigned char + or EOF. - It's typically faster. POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to isdigit 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 int) (c) - '0' <= 9) -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ -# define __attribute__(x) +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif #endif #ifndef ATTRIBUTE_UNUSED @@ -137,6 +128,25 @@ enum { MERam, MERpm, MER24 }; enum { BILLION = 1000000000, LOG10_BILLION = 9 }; +/* Relative times. */ +typedef struct +{ + /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */ + long int year; + long int month; + long int day; + long int hour; + long int minutes; + long int seconds; + long int ns; +} relative_time; + +#if HAVE_COMPOUND_LITERALS +# define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 }) +#else +static relative_time const RELATIVE_TIME_0; +#endif + /* Information passed to and from the parser. */ typedef struct { @@ -167,13 +177,7 @@ typedef struct struct timespec seconds; /* includes nanoseconds */ /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */ - long int rel_year; - long int rel_month; - long int rel_day; - long int rel_hour; - long int rel_minutes; - long int rel_seconds; - long int rel_ns; + relative_time rel; /* Presence or counts of nonterminals of various flavors parsed so far. */ bool timespec_seen; @@ -210,13 +214,16 @@ static long int time_zone_hhmm (textint, long int); long int intval; textint textintval; struct timespec timespec; + relative_time rel; } %token tAGO tDST -%token tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tLOCAL_ZONE tMERIDIAN -%token tMINUTE_UNIT tMONTH tMONTH_UNIT tORDINAL -%token tSEC_UNIT tYEAR_UNIT tZONE +%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT +%token tDAY_UNIT + +%token tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN +%token tMONTH tORDINAL tZONE %token tSNUMBER tUNUMBER %token tSDECIMAL_NUMBER tUDECIMAL_NUMBER @@ -224,6 +231,8 @@ static long int time_zone_hhmm (textint, long int); %type o_colon_minutes o_merid %type seconds signed_seconds unsigned_seconds +%type relunit relunit_snumber + %% spec: @@ -322,7 +331,15 @@ zone: tZONE { pc->time_zone = $1; } | tZONE relunit_snumber - { pc->time_zone = $1; pc->rels_seen = true; } + { pc->time_zone = $1; + pc->rel.ns += $2.ns; + pc->rel.seconds += $2.seconds; + pc->rel.minutes += $2.minutes; + pc->rel.hour += $2.hour; + pc->rel.day += $2.day; + pc->rel.month += $2.month; + pc->rel.year += $2.year; + pc->rels_seen = true; } | tZONE tSNUMBER o_colon_minutes { pc->time_zone = $1 + time_zone_hhmm ($2, $3); } | tDAYZONE @@ -430,74 +447,83 @@ date: rel: relunit tAGO { - pc->rel_ns = -pc->rel_ns; - 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; + pc->rel.ns -= $1.ns; + pc->rel.seconds -= $1.seconds; + pc->rel.minutes -= $1.minutes; + pc->rel.hour -= $1.hour; + pc->rel.day -= $1.day; + pc->rel.month -= $1.month; + pc->rel.year -= $1.year; } | relunit + { + pc->rel.ns += $1.ns; + pc->rel.seconds += $1.seconds; + pc->rel.minutes += $1.minutes; + pc->rel.hour += $1.hour; + pc->rel.day += $1.day; + pc->rel.month += $1.month; + pc->rel.year += $1.year; + } ; relunit: tORDINAL tYEAR_UNIT - { pc->rel_year += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.year = $1; } | tUNUMBER tYEAR_UNIT - { pc->rel_year += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.year = $1.value; } | tYEAR_UNIT - { pc->rel_year += $1; } + { $$ = RELATIVE_TIME_0; $$.year = 1; } | tORDINAL tMONTH_UNIT - { pc->rel_month += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.month = $1; } | tUNUMBER tMONTH_UNIT - { pc->rel_month += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.month = $1.value; } | tMONTH_UNIT - { pc->rel_month += $1; } + { $$ = RELATIVE_TIME_0; $$.month = 1; } | tORDINAL tDAY_UNIT - { pc->rel_day += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; } | tUNUMBER tDAY_UNIT - { pc->rel_day += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } | tDAY_UNIT - { pc->rel_day += $1; } + { $$ = RELATIVE_TIME_0; $$.day = $1; } | tORDINAL tHOUR_UNIT - { pc->rel_hour += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.hour = $1; } | tUNUMBER tHOUR_UNIT - { pc->rel_hour += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.hour = $1.value; } | tHOUR_UNIT - { pc->rel_hour += $1; } + { $$ = RELATIVE_TIME_0; $$.hour = 1; } | tORDINAL tMINUTE_UNIT - { pc->rel_minutes += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.minutes = $1; } | tUNUMBER tMINUTE_UNIT - { pc->rel_minutes += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; } | tMINUTE_UNIT - { pc->rel_minutes += $1; } + { $$ = RELATIVE_TIME_0; $$.minutes = 1; } | tORDINAL tSEC_UNIT - { pc->rel_seconds += $1 * $2; } + { $$ = RELATIVE_TIME_0; $$.seconds = $1; } | tUNUMBER tSEC_UNIT - { pc->rel_seconds += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; } | tSDECIMAL_NUMBER tSEC_UNIT - { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; } + { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; } | tUDECIMAL_NUMBER tSEC_UNIT - { pc->rel_seconds += $1.tv_sec * $2; pc->rel_ns += $1.tv_nsec * $2; } + { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; } | tSEC_UNIT - { pc->rel_seconds += $1; } + { $$ = RELATIVE_TIME_0; $$.seconds = 1; } | relunit_snumber ; relunit_snumber: tSNUMBER tYEAR_UNIT - { pc->rel_year += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.year = $1.value; } | tSNUMBER tMONTH_UNIT - { pc->rel_month += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.month = $1.value; } | tSNUMBER tDAY_UNIT - { pc->rel_day += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } | tSNUMBER tHOUR_UNIT - { pc->rel_hour += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.hour = $1.value; } | tSNUMBER tMINUTE_UNIT - { pc->rel_minutes += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; } | tSNUMBER tSEC_UNIT - { pc->rel_seconds += $1.value * $2; } + { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; } ; seconds: signed_seconds | unsigned_seconds; @@ -859,8 +885,7 @@ lookup_word (parser_control const *pc, char *word) for (p = word; *p; p++) { unsigned char ch = *p; - if (ISLOWER (ch)) - *p = toupper (ch); + *p = toupper (ch); } for (tp = meridian_table; tp->name; tp++) @@ -925,7 +950,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) for (;;) { - while (c = *pc->input, ISSPACE (c)) + while (c = *pc->input, isspace (c)) pc->input++; if (ISDIGIT (c) || c == '-' || c == '+') @@ -936,7 +961,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; - while (c = *++pc->input, ISSPACE (c)) + while (c = *++pc->input, isspace (c)) continue; if (! ISDIGIT (c)) /* skip the '-' sign */ @@ -1040,7 +1065,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) } } - if (ISALPHA (c)) + if (isalpha (c)) { char buff[20]; char *p = buff; @@ -1052,7 +1077,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) *p++ = c; c = *++pc->input; } - while (ISALPHA (c) || c == '.'); + while (isalpha (c) || c == '.'); *p = '\0'; tp = lookup_word (pc, buff); @@ -1164,7 +1189,7 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) if (! tmp) return false; - while (c = *p, ISSPACE (c)) + while (c = *p, isspace (c)) p++; if (strncmp (p, "TZ=\"", 4) == 0) @@ -1215,13 +1240,7 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) tm.tm_isdst = tmp->tm_isdst; pc.meridian = MER24; - pc.rel_ns = 0; - pc.rel_seconds = 0; - pc.rel_minutes = 0; - pc.rel_hour = 0; - pc.rel_day = 0; - pc.rel_month = 0; - pc.rel_year = 0; + pc.rel = RELATIVE_TIME_0; pc.timespec_seen = false; pc.rels_seen = false; pc.dates_seen = 0; @@ -1318,7 +1337,7 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) } /* Let mktime deduce tm_isdst if we have an absolute time stamp. */ - if (!pc.rels_seen) + if (pc.dates_seen | pc.days_seen | pc.times_seen) tm.tm_isdst = -1; /* But if the input explicitly specifies local time with or without @@ -1396,18 +1415,22 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) } /* Add relative date. */ - if (pc.rel_year | pc.rel_month | pc.rel_day) + if (pc.rel.year | pc.rel.month | pc.rel.day) { - int year = tm.tm_year + pc.rel_year; - int month = tm.tm_mon + pc.rel_month; - int day = tm.tm_mday + pc.rel_day; - if (((year < tm.tm_year) ^ (pc.rel_year < 0)) - | ((month < tm.tm_mon) ^ (pc.rel_month < 0)) - | ((day < tm.tm_mday) ^ (pc.rel_day < 0))) + int year = tm.tm_year + pc.rel.year; + int month = tm.tm_mon + pc.rel.month; + int day = tm.tm_mday + pc.rel.day; + if (((year < tm.tm_year) ^ (pc.rel.year < 0)) + | ((month < tm.tm_mon) ^ (pc.rel.month < 0)) + | ((day < tm.tm_mday) ^ (pc.rel.day < 0))) goto fail; tm.tm_year = year; tm.tm_mon = month; tm.tm_mday = day; + tm.tm_hour = tm0.tm_hour; + tm.tm_min = tm0.tm_min; + tm.tm_sec = tm0.tm_sec; + tm.tm_isdst = tm0.tm_isdst; Start = mktime (&tm); if (Start == (time_t) -1) goto fail; @@ -1421,20 +1444,20 @@ get_date (struct timespec *result, char const *p, struct timespec const *now) must be applied before relative times, and if mktime is applied again the time zone will be lost. */ { - long int sum_ns = pc.seconds.tv_nsec + pc.rel_ns; + long int sum_ns = pc.seconds.tv_nsec + pc.rel.ns; long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION; time_t t0 = Start; - long int d1 = 60 * 60 * pc.rel_hour; + long int d1 = 60 * 60 * pc.rel.hour; time_t t1 = t0 + d1; - long int d2 = 60 * pc.rel_minutes; + long int d2 = 60 * pc.rel.minutes; time_t t2 = t1 + d2; - long int d3 = pc.rel_seconds; + long int d3 = pc.rel.seconds; time_t t3 = t2 + d3; long int d4 = (sum_ns - normalized_ns) / BILLION; time_t t4 = t3 + d4; - if ((d1 / (60 * 60) ^ pc.rel_hour) - | (d2 / 60 ^ pc.rel_minutes) + if ((d1 / (60 * 60) ^ pc.rel.hour) + | (d2 / 60 ^ pc.rel.minutes) | ((t1 < t0) ^ (d1 < 0)) | ((t2 < t1) ^ (d2 < 0)) | ((t3 < t2) ^ (d3 < 0))