X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fgetdate.y;h=877b264250ac6c15d6f0e73faf8c2f4528f1c29e;hb=d952dbeaa9ceb3f9cef0684e7d9d3ecfa71a6294;hp=695fd59c47e47d850c2cecbdb6d08d82f4b36400;hpb=e2f9495d87e4f2eaf2bfb87ebfaa2c79df2f50b6;p=gnulib.git diff --git a/lib/getdate.y b/lib/getdate.y index 695fd59c4..877b26425 100644 --- a/lib/getdate.y +++ b/lib/getdate.y @@ -60,7 +60,7 @@ # undef static #endif -#include +#include #include #include #include @@ -205,7 +205,7 @@ typedef struct union YYSTYPE; static int yylex (union YYSTYPE *, parser_control *); static int yyerror (parser_control const *, char const *); -static long int time_zone_hhmm (textint, long int); +static long int time_zone_hhmm (parser_control *, textint, long int); /* Extract into *PC any date and time info from a string of digits of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY, @@ -293,7 +293,7 @@ set_hhmmss (parser_control *pc, long int hour, long int minutes, %token tAGO tDST %token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT -%token tDAY_UNIT +%token tDAY_UNIT tDAY_SHIFT %token tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN %token tMONTH tORDINAL tZONE @@ -304,7 +304,7 @@ set_hhmmss (parser_control *pc, long int hour, long int minutes, %type o_colon_minutes o_merid %type seconds signed_seconds unsigned_seconds -%type relunit relunit_snumber +%type relunit relunit_snumber dayshift %% @@ -358,7 +358,7 @@ time: set_hhmmss (pc, $1.value, $3.value, 0, 0); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($4, $5); + pc->time_zone = time_zone_hhmm (pc, $4, $5); } | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid { @@ -370,7 +370,7 @@ time: set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); pc->meridian = MER24; pc->zones_seen++; - pc->time_zone = time_zone_hhmm ($6, $7); + pc->time_zone = time_zone_hhmm (pc, $6, $7); } ; @@ -394,7 +394,7 @@ zone: { pc->time_zone = $1; apply_relative_time (pc, $2, 1); } | tZONE tSNUMBER o_colon_minutes - { pc->time_zone = $1 + time_zone_hhmm ($2, $3); } + { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); } | tDAYZONE { pc->time_zone = $1 + 60; } | tZONE tDST @@ -502,6 +502,8 @@ rel: { apply_relative_time (pc, $1, -1); } | relunit { apply_relative_time (pc, $1, 1); } + | dayshift + { apply_relative_time (pc, $1, 1); } ; relunit: @@ -563,6 +565,11 @@ relunit_snumber: { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; } ; +dayshift: + tDAY_SHIFT + { $$ = RELATIVE_TIME_0; $$.day = $1; } + ; + seconds: signed_seconds | unsigned_seconds; signed_seconds: @@ -669,10 +676,10 @@ static table const time_units_table[] = /* Assorted relative-time words. */ static table const relative_time_table[] = { - { "TOMORROW", tDAY_UNIT, 1 }, - { "YESTERDAY",tDAY_UNIT, -1 }, - { "TODAY", tDAY_UNIT, 0 }, - { "NOW", tDAY_UNIT, 0 }, + { "TOMORROW", tDAY_SHIFT, 1 }, + { "YESTERDAY",tDAY_SHIFT, -1 }, + { "TODAY", tDAY_SHIFT, 0 }, + { "NOW", tDAY_SHIFT, 0 }, { "LAST", tORDINAL, -1 }, { "THIS", tORDINAL, 0 }, { "NEXT", tORDINAL, 1 }, @@ -795,15 +802,33 @@ static table const military_table[] = /* Convert a time zone expressed as HH:MM into an integer count of minutes. If MM is negative, then S is of the form HHMM and needs - to be picked apart; otherwise, S is of the form HH. */ + to be picked apart; otherwise, S is of the form HH. As specified in + http://www.opengroup.org/susv3xbd/xbd_chap08.html#tag_08_03, allow + only valid TZ range, and consider first two digits as hours, if no + minutes specified. */ static long int -time_zone_hhmm (textint s, long int mm) +time_zone_hhmm (parser_control *pc, textint s, long int mm) { + long int n_minutes; + + /* If the length of S is 1 or 2 and no minutes are specified, + interpret it as a number of hours. */ + if (s.digits <= 2 && mm < 0) + s.value *= 100; + if (mm < 0) - return (s.value / 100) * 60 + s.value % 100; + n_minutes = (s.value / 100) * 60 + s.value % 100; else - return s.value * 60 + (s.negative ? -mm : mm); + n_minutes = s.value * 60 + (s.negative ? -mm : mm); + + /* If the absolute number of minutes is larger than 24 hours, + arrange to reject it by incrementing pc->zones_seen. Thus, + we allow only values in the range UTC-24:00 to UTC+24:00. */ + if (24 * 60 < abs (n_minutes)) + pc->zones_seen++; + + return n_minutes; } static int @@ -900,7 +925,7 @@ lookup_word (parser_control const *pc, char *word) for (p = word; *p; p++) { unsigned char ch = *p; - *p = toupper (ch); + *p = c_toupper (ch); } for (tp = meridian_table; tp->name; tp++) @@ -965,7 +990,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) for (;;) { - while (c = *pc->input, isspace (c)) + while (c = *pc->input, c_isspace (c)) pc->input++; if (ISDIGIT (c) || c == '-' || c == '+') @@ -976,7 +1001,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; - while (c = *++pc->input, isspace (c)) + while (c = *++pc->input, c_isspace (c)) continue; if (! ISDIGIT (c)) /* skip the '-' sign */ @@ -1080,7 +1105,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) } } - if (isalpha (c)) + if (c_isalpha (c)) { char buff[20]; char *p = buff; @@ -1092,7 +1117,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc) *p++ = c; c = *++pc->input; } - while (isalpha (c) || c == '.'); + while (c_isalpha (c) || c == '.'); *p = '\0'; tp = lookup_word (pc, buff); @@ -1205,7 +1230,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, c_isspace (c)) p++; if (strncmp (p, "TZ=\"", 4) == 0)