idx_t zones_seen;
bool year_seen;
+#ifdef GNULIB_PARSE_DATETIME2
/* Print debugging output to stderr. */
bool parse_datetime_debug;
+#endif
/* Which of the 'seen' parts have been printed when debugging. */
bool debug_dates_seen;
table local_time_zone_table[3];
} parser_control;
+static bool
+debugging (parser_control const *pc)
+{
+#ifdef GNULIB_PARSE_DATETIME2
+ return pc->parse_datetime_debug;
+#else
+ return false;
+#endif
+}
+
union YYSTYPE;
static int yylex (union YYSTYPE *, parser_control *);
static int yyerror (parser_control const *, char const *);
{
bool space = false;
- if (!pc->parse_datetime_debug)
+ if (!debugging (pc))
return;
/* no newline, more items printed below */
{
bool space = false;
- if (!pc->parse_datetime_debug)
+ if (!debugging (pc))
return;
/* no newline, more items printed below */
you want portability, use the ISO 8601 format. */
if (4 <= $1.digits)
{
- if (pc->parse_datetime_debug)
+ if (debugging (pc))
{
intmax_t digits = $1.digits;
dbg_printf (_("warning: value %"PRIdMAX" has %"PRIdMAX" digits. "
}
else
{
- if (pc->parse_datetime_debug)
+ if (debugging (pc))
dbg_printf (_("warning: value %"PRIdMAX" has less than 4 digits. "
"Assuming MM/DD/YY[YY]\n"),
$1.value);
tp = lookup_word (pc, buff);
if (! tp)
{
- if (pc->parse_datetime_debug)
+ if (debugging (pc))
dbg_printf (_("error: unknown word '%s'\n"), buff);
return '?';
}
const bool dst_shift = eq_sec && eq_min && !eq_hour
&& eq_mday && eq_month && eq_year;
- if (!pc->parse_datetime_debug)
+ if (!debugging (pc))
return;
dbg_printf (_("error: invalid date/time value:\n"));
: _("missing timezone")));
}
-/* The original interface: run with debug=false and the default timezone. */
-bool
-parse_datetime (struct timespec *result, char const *p,
- struct timespec const *now)
-{
- char const *tzstring = getenv ("TZ");
- timezone_t tz = tzalloc (tzstring);
- if (!tz)
- return false;
- bool ok = parse_datetime2 (result, p, now, 0, tz, tzstring);
- tzfree (tz);
- return ok;
-}
-
/* Parse a date/time string, storing the resulting time value into *RESULT.
The string itself is pointed to by P. Return true if successful.
P can be an incomplete or relative time specification; if so, use
*NOW as the basis for the returned time. Default to timezone
TZDEFAULT, which corresponds to tzalloc (TZSTRING). */
-bool
-parse_datetime2 (struct timespec *result, char const *p,
- struct timespec const *now, unsigned int flags,
- timezone_t tzdefault, char const *tzstring)
+static bool
+parse_datetime_body (struct timespec *result, char const *p,
+ struct timespec const *now, unsigned int flags,
+ timezone_t tzdefault, char const *tzstring)
{
struct tm tm;
struct tm tm0;
parser_control pc;
pc.input = p;
+#ifdef GNULIB_PARSE_DATETIME2
pc.parse_datetime_debug = (flags & PARSE_DATETIME_DEBUG) != 0;
+#endif
if (INT_ADD_WRAPV (tmp.tm_year, TM_YEAR_BASE, &pc.year.value))
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: initial year out of range\n"));
goto fail;
}
if (yyparse (&pc) != 0)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf ((input_sentinel <= pc.input
? _("error: parsing failed\n")
: _("error: parsing failed, stopped at '%s'\n")),
/* Determine effective timezone source. */
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
dbg_printf (_("input timezone: "));
if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
| (pc.local_zones_seen + pc.zones_seen)))
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
if (pc.times_seen > 1)
dbg_printf ("error: seen multiple time parts\n");
goto fail;
}
- if (! to_tm_year (pc.year, pc.parse_datetime_debug, &tm.tm_year)
+ if (! to_tm_year (pc.year, debugging (&pc), &tm.tm_year)
|| INT_ADD_WRAPV (pc.month, -1, &tm.tm_mon)
|| INT_ADD_WRAPV (pc.day, 0, &tm.tm_mday))
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: year, month, or day overflow\n"));
goto fail;
}
{
char const *mrd = (pc.meridian == MERam ? "am"
: pc.meridian == MERpm ?"pm" : "");
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: invalid hour %"PRIdMAX"%s\n"),
pc.hour, mrd);
goto fail;
}
tm.tm_min = pc.minutes;
tm.tm_sec = pc.seconds.tv_sec;
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf ((pc.times_seen
? _("using specified time as starting value: '%s'\n")
: _("using current time as starting value: '%s'\n")),
{
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
pc.seconds.tv_nsec = 0;
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf ("warning: using midnight as starting time: 00:00:00\n");
}
timezone_t tz2 = tzalloc (tz2buf);
if (!tz2)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: tzalloc (\"%s\") failed\n"), tz2buf);
goto fail;
}
if (Start == (time_t) -1)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: day '%s' "
"(day ordinal=%"PRIdMAX" number=%d) "
"resulted in an invalid date: '%s'\n"),
goto fail;
}
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("new start date: '%s' is '%s'\n"),
str_days (&pc, dbg_ord, sizeof dbg_ord),
debug_strfdatetime (&tm, &pc, dbg_tm, sizeof dbg_tm));
}
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
if (!pc.dates_seen && !pc.days_seen)
dbg_printf (_("using current date as starting value: '%s'\n"),
/* Add relative date. */
if (pc.rel.year | pc.rel.month | pc.rel.day)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
if ((pc.rel.year != 0 || pc.rel.month != 0) && tm.tm_mday != 15)
dbg_printf (_("warning: when adding relative months/years, "
|| INT_ADD_WRAPV (tm.tm_mon, pc.rel.month, &month)
|| INT_ADD_WRAPV (tm.tm_mday, pc.rel.day, &day))
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: %s:%d\n"), __FILE__, __LINE__);
goto fail;
}
Start = mktime_z (tz, &tm);
if (Start == (time_t) -1)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: adding relative date resulted "
"in an invalid date: '%s'\n"),
debug_strfdatetime (&tm, &pc, dbg_tm,
goto fail;
}
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
dbg_printf (_("after date adjustment "
"(%+"PRIdMAX" years, %+"PRIdMAX" months, "
overflow |= INT_SUBTRACT_WRAPV (Start, delta, &t1);
if (overflow)
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: timezone %d caused time_t overflow\n"),
pc.time_zone);
goto fail;
Start = t1;
}
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
intmax_t Starti = Start;
dbg_printf (_("'%s' = %"PRIdMAX" epoch-seconds\n"),
|| INT_ADD_WRAPV (t2, pc.rel.seconds, &t3)
|| INT_ADD_WRAPV (t3, d4, &t4))
{
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
dbg_printf (_("error: adding relative time caused an "
"overflow\n"));
goto fail;
result->tv_sec = t4;
result->tv_nsec = normalized_ns;
- if (pc.parse_datetime_debug
+ if (debugging (&pc)
&& (pc.rel.hour | pc.rel.minutes | pc.rel.seconds | pc.rel.ns))
{
dbg_printf (_("after time adjustment (%+"PRIdMAX" hours, "
}
}
- if (pc.parse_datetime_debug)
+ if (debugging (&pc))
{
/* Special case: using 'date -u' simply set TZ=UTC0 */
if (! tzstring)
return ok;
}
+#ifdef GNULIB_PARSE_DATETIME2
+/* Parse a date/time string, storing the resulting time value into *RESULT.
+ The string itself is pointed to by P. Return true if successful.
+ P can be an incomplete or relative time specification; if so, use
+ *NOW as the basis for the returned time. Default to timezone
+ TZDEFAULT, which corresponds to tzalloc (TZSTRING). */
+bool
+parse_datetime2 (struct timespec *result, char const *p,
+ struct timespec const *now, unsigned int flags,
+ timezone_t tzdefault, char const *tzstring)
+{
+ return parse_datetime_body (result, p, now, flags, tzdefault, tzstring);
+}
+#endif
+
+
+/* The plain interface: run with debug=false and the default timezone. */
+bool
+parse_datetime (struct timespec *result, char const *p,
+ struct timespec const *now)
+{
+ char const *tzstring = getenv ("TZ");
+ timezone_t tz = tzalloc (tzstring);
+ if (!tz)
+ return false;
+ bool ok = parse_datetime_body (result, p, now, 0, tz, tzstring);
+ tzfree (tz);
+ return ok;
+}
+
#if TEST
int