%{
/* 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
}
}
+/* Increment PC->rel by FACTOR * REL (FACTOR is 1 or -1). */
+static void
+apply_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;
+}
+
+/* Set PC-> hour, minutes, seconds and nanoseconds members from arguments. */
+static void
+set_hhmmss (parser_control *pc, long int hour, long int minutes,
+ time_t sec, long int nsec)
+{
+ pc->hour = hour;
+ pc->minutes = minutes;
+ pc->seconds.tv_sec = sec;
+ pc->seconds.tv_nsec = nsec;
+}
+
%}
/* We want a reentrant parser, even if the TZ manipulation and the calls to
| day
{ pc->days_seen++; }
| rel
- { pc->rels_seen = true; }
| number
| hybrid
;
time:
tUNUMBER tMERIDIAN
{
- pc->hour = $1.value;
- pc->minutes = 0;
- pc->seconds.tv_sec = 0;
- pc->seconds.tv_nsec = 0;
+ set_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;
+ set_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;
+ set_hhmmss (pc, $1.value, $3.value, 0, 0);
pc->meridian = MER24;
pc->zones_seen++;
pc->time_zone = time_zone_hhmm ($4, $5);
}
| tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid
{
- pc->hour = $1.value;
- pc->minutes = $3.value;
- pc->seconds = $5;
+ set_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;
+ 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 = $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; }
+ apply_relative_time (pc, $2, 1); }
| tZONE tSNUMBER o_colon_minutes
{ pc->time_zone = $1 + time_zone_hhmm ($2, $3); }
| tDAYZONE
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;
- }
+ { apply_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;
- }
+ { apply_relative_time (pc, $1, 1); }
;
relunit:
/* 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;
+ apply_relative_time (pc, $2, 1);
}
;
#else
#if HAVE_TZNAME
{
-# ifndef tzname
+# if !HAVE_DECL_TZNAME
extern char *tzname[];
# endif
int i;
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)
{
goto fail;
}
+ /* The only "output" of this if-block is an updated Start value,
+ so this block must follow others that clobber Start. */
+ 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