# include <string.h>
#endif
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
# define __attribute__(x)
#endif
#endif
#define EPOCH_YEAR 1970
-#define TM_YEAR_ORIGIN 1900
+#define TM_YEAR_BASE 1900
#define HOUR(x) ((x) * 60)
/* Information passed to and from the parser. */
struct parser_control
-{
+{
/* The input string remaining to be parsed. */
const char *input;
table local_time_zone_table[3];
};
+#define PC (* (struct parser_control *) parm)
#define YYLEX_PARAM parm
#define YYPARSE_PARAM parm
#define YYSTYPE int
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
{
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;
}
}
}
{ "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 }, */
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)
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)
{
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;
/* 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;
|| (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))
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;
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;
}