From 55d067b5172b233c63b364cad8efc171910eddee Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?=
Date: Fri, 27 Jun 2008 12:34:08 +0200
Subject: [PATCH] * lib/getdate.y: Several fixes for date grammar, no longer replace time zone
after relative day/month/year offset
Signed-off-by: Ondřej Vašík
---
lib/getdate.y | 242 +++++++++++++++++++++++++++++++++------------------------
1 files changed, 140 insertions(+), 102 deletions(-)
diff --git a/lib/getdate.y b/lib/getdate.y
index 1deec51..f0773e9 100644
--- a/lib/getdate.y
+++ b/lib/getdate.y
@@ -1,8 +1,8 @@
%{
/* Parse a string into an internal time stamp.
- Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
- Foundation, Inc.
+ Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 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
@@ -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,
@@ -246,6 +246,28 @@ digits_to_date_time (parser_control *pc, textint text_int)
}
}
+static void extract_hhmmss (parser_control *pc, long int ho, long int mi, long int sec, long int nsec)
+{
+ pc->hour = ho;
+ pc->minutes = mi;
+ pc->seconds.tv_sec = sec;
+ pc->seconds.tv_nsec = nsec;
+}
+
+/* Extract relative time multiplied by factor */
+static void
+extract_relative_time (parser_control *pc, relative_time rel, int factor)
+{
+ pc->rel.ns += factor*rel.ns;
+ pc->rel.seconds += factor*rel.seconds;
+ pc->rel.minutes += factor*rel.minutes;
+ pc->rel.hour += factor*rel.hour;
+ pc->rel.day += factor*rel.day;
+ pc->rel.month += factor*rel.month;
+ pc->rel.year += factor*rel.year;
+ pc->rels_seen = true;
+}
+
%}
/* We want a reentrant parser, even if the TZ manipulation and the calls to
@@ -254,8 +276,8 @@ digits_to_date_time (parser_control *pc, textint text_int)
%parse-param { parser_control *pc }
%lex-param { parser_control *pc }
-/* This grammar has 20 shift/reduce conflicts. */
-%expect 20
+/* This grammar has 36 shift/reduce conflicts. */
+%expect 36
%union
{
@@ -267,8 +289,8 @@ digits_to_date_time (parser_control *pc, textint text_int)
%token tAGO tDST
-%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT
-%token tDAY_UNIT
+%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT tDAY_UNIT
+%token tDAY_SHIFT tWEEK_UNIT
%token tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN
%token tMONTH tORDINAL tZONE
@@ -313,7 +335,6 @@ item:
| day
{ pc->days_seen++; }
| rel
- { pc->rels_seen = true; }
| number
| hybrid
;
@@ -321,47 +342,70 @@ item:
time:
tUNUMBER tMERIDIAN
{
- pc->hour = $1.value;
- pc->minutes = 0;
- pc->seconds.tv_sec = 0;
- pc->seconds.tv_nsec = 0;
+ extract_hhmmss (pc, $1.value, 0, 0, 0);
pc->meridian = $2;
}
| tUNUMBER ':' tUNUMBER o_merid
{
- pc->hour = $1.value;
- pc->minutes = $3.value;
- pc->seconds.tv_sec = 0;
- pc->seconds.tv_nsec = 0;
+ extract_hhmmss (pc, $1.value, $3.value, 0, 0);
pc->meridian = $4;
}
| tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes
{
- pc->hour = $1.value;
- pc->minutes = $3.value;
- pc->seconds.tv_sec = 0;
- pc->seconds.tv_nsec = 0;
+ extract_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
{
- pc->hour = $1.value;
- pc->minutes = $3.value;
- pc->seconds = $5;
+ extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
pc->meridian = $6;
}
| tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes
{
- pc->hour = $1.value;
- pc->minutes = $3.value;
- pc->seconds = $5;
+ extract_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);
}
- ;
+ | tUNUMBER ':' tUNUMBER relunit_snumber
+ {
+ extract_hhmmss (pc, $1.value, $3.value, 0, 0);
+ pc->meridian = MER24;
+ extract_relative_time (pc, $4, 1);
+ }
+ | tUNUMBER ':' tUNUMBER ':' unsigned_seconds relunit_snumber
+ {
+ extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+ pc->meridian = MER24;
+ extract_relative_time (pc, $6, 1);
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER
+ {
+ extract_hhmmss (pc, $1.value, $3.value, 0, 0);
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm (pc, $4, -1);
+ }
+ | tUNUMBER ':' tUNUMBER ':' unsigned_seconds
+ {
+ extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+ pc->meridian = MER24;
+ }
+ | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER
+ {
+ extract_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
+ pc->meridian = MER24;
+ pc->zones_seen++;
+ pc->time_zone = time_zone_hhmm (pc, $6, -1);
+ }
+ | tUNUMBER ':' tUNUMBER
+ {
+ extract_hhmmss (pc, $1.value, $3.value, 0, 0);
+ pc->meridian = MER24;
+ }
+ ;
local_zone:
tLOCAL_ZONE
@@ -381,16 +425,12 @@ zone:
{ pc->time_zone = $1; }
| tZONE relunit_snumber
{ 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; }
+ extract_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); }
+ | tZONE tSNUMBER
+ { pc->time_zone = $1 + time_zone_hhmm (pc, $2, -1); }
| tDAYZONE
{ pc->time_zone = $1 + 60; }
| tZONE tDST
@@ -495,25 +535,9 @@ date:
rel:
relunit tAGO
- {
- 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;
- }
+ { extract_relative_time (pc , $1, -1); }
| 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;
- }
+ { extract_relative_time (pc , $1, 1); }
;
relunit:
@@ -530,10 +554,18 @@ relunit:
| tMONTH_UNIT
{ $$ = RELATIVE_TIME_0; $$.month = 1; }
| tORDINAL tDAY_UNIT
- { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; }
+ { $$ = RELATIVE_TIME_0; $$.day = $1; }
| tUNUMBER tDAY_UNIT
- { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
+ { $$ = RELATIVE_TIME_0; $$.day = $1.value; }
| tDAY_UNIT
+ { $$ = RELATIVE_TIME_0; $$.day = 1; }
+ | tORDINAL tWEEK_UNIT
+ { $$ = RELATIVE_TIME_0; $$.day = $1 * 7 * $2; }
+ | tUNUMBER tWEEK_UNIT
+ { $$ = RELATIVE_TIME_0; $$.day = $1.value * 7 * $2; }
+ | tWEEK_UNIT
+ { $$ = RELATIVE_TIME_0; $$.day = $1 * 7; }
+ | tDAY_SHIFT
{ $$ = RELATIVE_TIME_0; $$.day = $1; }
| tORDINAL tHOUR_UNIT
{ $$ = RELATIVE_TIME_0; $$.hour = $1; }
@@ -566,7 +598,9 @@ relunit_snumber:
| tSNUMBER tMONTH_UNIT
{ $$ = RELATIVE_TIME_0; $$.month = $1.value; }
| tSNUMBER tDAY_UNIT
- { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
+ { $$ = RELATIVE_TIME_0; $$.day = $1.value; }
+ | tSNUMBER tWEEK_UNIT
+ { $$ = RELATIVE_TIME_0; $$.day = 7* $1.value * $2; }
| tSNUMBER tHOUR_UNIT
{ $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
| tSNUMBER tMINUTE_UNIT
@@ -600,28 +634,17 @@ hybrid:
/* Hybrid all-digit and relative offset, so that we accept e.g.,
"YYYYMMDD +N days" as well as "YYYYMMDD N days". */
digits_to_date_time (pc, $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;
- }
+ extract_relative_time (pc, $2, 1);
+ }
;
o_colon_minutes:
- /* empty */
- { $$ = -1; }
- | ':' tUNUMBER
+ ':' tUNUMBER
{ $$ = $2.value; }
;
o_merid:
- /* empty */
- { $$ = MER24; }
- | tMERIDIAN
+ tMERIDIAN
{ $$ = $1; }
;
@@ -674,8 +697,8 @@ static table const time_units_table[] =
{
{ "YEAR", tYEAR_UNIT, 1 },
{ "MONTH", tMONTH_UNIT, 1 },
- { "FORTNIGHT",tDAY_UNIT, 14 },
- { "WEEK", tDAY_UNIT, 7 },
+ { "FORTNIGHT",tWEEK_UNIT, 2 },
+ { "WEEK", tWEEK_UNIT, 1 },
{ "DAY", tDAY_UNIT, 1 },
{ "HOUR", tHOUR_UNIT, 1 },
{ "MINUTE", tMINUTE_UNIT, 1 },
@@ -688,10 +711,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 },
@@ -817,12 +840,27 @@ static table const military_table[] =
to be picked apart; otherwise, S is of the form HH. */
static long int
-time_zone_hhmm (textint s, long int mm)
+time_zone_hhmm (parser_control *pc, textint s, long int mm)
{
+ long int returnvalue;
+
+ /* if s.value is lower than 15, add 00 minutes if mm not specified
+ as common time zones ranges between UTC-1200 and UTC+1400 */
+ if ((abs (s.value) < 15) && (mm < 0))
+ s.value *= 100;
+
if (mm < 0)
- return (s.value / 100) * 60 + s.value % 100;
+ returnvalue = (s.value / 100) * 60 + s.value % 100;
else
- return s.value * 60 + (s.negative ? -mm : mm);
+ returnvalue = s.value * 60 + (s.negative ? -mm : mm);
+
+ /* check if the return value is in real timezone range,
+ otherwise increment pc->zones_seen to cause time format
+ error, allow UTC-1200 to UTC+1400 */
+ if ((returnvalue > 840) || (returnvalue < -720))
+ pc->zones_seen++;
+
+ return returnvalue;
}
static int
@@ -1436,25 +1474,6 @@ get_date (struct timespec *result, char const *p, struct timespec const *now)
goto fail;
}
- if (pc.zones_seen)
- {
- long int delta = pc.time_zone * 60;
- time_t t1;
-#ifdef HAVE_TM_GMTOFF
- delta -= tm.tm_gmtoff;
-#else
- time_t t = Start;
- struct tm const *gmt = gmtime (&t);
- if (! gmt)
- goto fail;
- delta -= tm_diff (&tm, gmt);
-#endif
- t1 = Start - delta;
- if ((Start < t1) != (delta < 0))
- goto fail; /* time_t overflow */
- Start = t1;
- }
-
/* Add relative date. */
if (pc.rel.year | pc.rel.month | pc.rel.day)
{
@@ -1477,6 +1496,25 @@ get_date (struct timespec *result, char const *p, struct timespec const *now)
goto fail;
}
+ if (pc.zones_seen)
+ {
+ long int delta = pc.time_zone * 60;
+ time_t t1;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ time_t t = Start;
+ struct tm const *gmt = gmtime (&t);
+ if (! gmt)
+ goto fail;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ t1 = Start - delta;
+ if ((Start < t1) != (delta < 0))
+ goto fail; /* time_t overflow */
+ Start = t1;
+ }
+
/* Add relative hours, minutes, and seconds. On hosts that support
leap seconds, ignore the possibility of leap seconds; e.g.,
"+ 10 minutes" adds 600 seconds, even if one of them is a
--
1.5.2.2