%{
/* Parse a string into an internal time stamp.
Copyright (C) 1999-2000, 2002-2013 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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Originally written by Steven M. Bellovin <smb@research.att.com> while
at the University of North Carolina at Chapel Hill. Later tweaked by
a couple of people on Usenet. Completely overhauled by Rich $alz
<rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
the right thing about local DST. Also modified by Paul Eggert
<eggert@cs.ucla.edu> in February 2004 to support
nanosecond-resolution time stamps, and in October 2004 to support
TZ strings in dates. */
/* FIXME: Check for arithmetic overflow in all cases, not just
some of them. */
#include <config.h>
#include <time.h>
#include <sys/time.h>
/* There's no need to extend the stack, so there's no need to involve
alloca. */
#define YYSTACK_USE_ALLOCA 0
/* Tell Bison how much stack space is needed. 20 should be plenty for
this grammar, which is not right recursive. Beware setting it too
high, since that might cause problems on machines whose
implementations have lame stack-overflow checking. */
#define YYMAXDEPTH 20
#define YYINITDEPTH YYMAXDEPTH
/* Since the code of parse-datetime.y is not included in the Emacs executable
itself, there is no need to #define static in this file. Even if
the code were included in the Emacs executable, it probably
wouldn't do any harm to #undef it here; this will only cause
problems if we try to write to a static variable, which I don't
think this code needs to do. */
#ifdef emacs
# undef static
#endif
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "err.h"
#include "xalloc.h"
/* ISDIGIT differs from isdigit, as follows:
- Its arg may be any int or unsigned int; it need not be an unsigned char
or EOF.
- It's typically faster.
POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
isdigit unless it's important to use the locale's definition
of "digit" even when the host does not conform to POSIX. */
#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
/* Shift A right by B bits portably, by dividing A by 2**B and
truncating towards minus infinity. A and B should be free of side
effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
INT_BITS is the number of useful bits in an int. GNU code can
assume that INT_BITS is at least 32.
ISO C99 says that A >> B is implementation-defined if A < 0. Some
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
right in the usual way when A < 0, so SHR falls back on division if
ordinary A >> B doesn't seem to be the usual signed shift. */
#define SHR(a, b) \
(-1 >> 1 == -1 \
? (a) >> (b) \
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
#define EPOCH_YEAR 1970
#define TM_YEAR_BASE 1900
#define HOUR(x) ((x) * 60)
/* Convert a possibly-signed character to an unsigned character. This is
a bit safer than casting to unsigned char, since it catches some type
errors that the cast doesn't. */
static unsigned char to_uchar (char ch) { return ch; }
#define long_time_t time_t
/* An integer value, and the number of digits in its textual
representation. */
typedef struct
{
int negative;
long int value;
size_t digits;
} textint;
/* An entry in the lexical lookup table. */
typedef struct
{
char const *name;
int type;
int value;
} table;
/* Meridian: am, pm, or 24-hour style. */
enum { MERam, MERpm, MER24 };
enum { BILLION = 1000000000, LOG10_BILLION = 9 };
/* Relative times. */
typedef struct
{
/* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */
long int year;
long int month;
long int day;
long int hour;
long int minutes;
long_time_t seconds;
long int ns;
} relative_time;
#if HAVE_COMPOUND_LITERALS
# define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 })
#else
static relative_time const RELATIVE_TIME_0;
#endif
/* Information passed to and from the parser. */
typedef struct
{
/* The input string remaining to be parsed. */
const char *input;
/* N, if this is the Nth Tuesday. */
long int day_ordinal;
/* Day of week; Sunday is 0. */
int day_number;
/* tm_isdst flag for the local zone. */
int local_isdst;
/* Time zone, in minutes east of UTC. */
long int time_zone;
/* Style used for time. */
int meridian;
/* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds. */
textint year;
long int month;
long int day;
long int hour;
long int minutes;
struct timespec seconds; /* includes nanoseconds */
/* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */
relative_time rel;
/* Presence or counts of nonterminals of various flavors parsed so far. */
int timespec_seen;
int rels_seen;
size_t dates_seen;
size_t days_seen;
size_t local_zones_seen;
size_t dsts_seen;
size_t times_seen;
size_t zones_seen;
/* Table of local time zone abbreviations, terminated by a null entry. */
table local_time_zone_table[3];
} parser_control;
union YYSTYPE;
static int yylex (union YYSTYPE *, parser_control *);
static int yyerror (parser_control const *, char const *);
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,
YYYY, ...). */
static void
digits_to_date_time (parser_control *pc, textint text_int)
{
if (pc->dates_seen && ! pc->year.digits
&& ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits))
pc->year = text_int;
else
{
if (4 < text_int.digits)
{
pc->dates_seen++;
pc->day = text_int.value % 100;
pc->month = (text_int.value / 100) % 100;
pc->year.value = text_int.value / 10000;
pc->year.digits = text_int.dig
|