Avoid integer overflow on exotic platforms.
[gnulib.git] / lib / posixtm.c
index c029a16..85936f3 100644 (file)
+/* Parse dates for touch and date.
 
 
-/*  A Bison parser, made from ./posixtm.y with Bison version GNU Bison version 1.22
-  */
-
-#define YYBISON 1  /* Identify Bison output.  */
-
-#define        DIGIT   258
-
-#line 19 "./posixtm.y"
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-/* The following block of alloca-related preprocessor directives is here
-   solely to allow compilation by non GNU-C compilers of the C parser
-   produced from this file by old versions of bison.  Newer versions of
-   bison include a block similar to this one in bison.simple.  */
-   
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#else
-#ifdef _AIX
- #pragma alloca
-#else
-void *alloca ();
-#endif
-#endif
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#ifdef TM_IN_SYS_TIME
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif
-
-/* Some old versions of bison generate parsers that use bcopy.
-   That loses on systems that don't provide the function, so we have
-   to redefine it here.  */
-#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
-#define bcopy(from, to, len) memcpy ((to), (from), (len))
-#endif
-
-#define YYDEBUG 1
-
-/* Lexical analyzer's current scan position in the input string. */
-static char *curpos;
-
-/* The return value. */
-static struct tm t;
-
-time_t mktime ();
-
-#define zzparse posixtime_zzparse
-static int zzlex ();
-static int zzerror ();
-
-#ifndef YYLTYPE
-typedef
-  struct zzltype
-    {
-      int timestamp;
-      int first_line;
-      int first_column;
-      int last_line;
-      int last_column;
-      char *text;
-   }
-  zzltype;
-
-#define YYLTYPE zzltype
-#endif
-
-#ifndef YYSTYPE
-#define YYSTYPE int
-#endif
-#include <stdio.h>
-
-#ifndef __cplusplus
-#ifndef __STDC__
-#define const
-#endif
-#endif
-
-
-
-#define        YYFINAL         15
-#define        YYFLAG          -32768
-#define        YYNTBASE        5
-
-#define YYTRANSLATE(x) ((unsigned)(x) <= 258 ? zztranslate[x] : 9)
-
-static const char zztranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     4,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     1,     2,     3
-};
-
-#if YYDEBUG != 0
-static const short zzprhs[] = {     0,
-     0,     7,     9,    12,    13,    14,    17
-};
-
-static const short zzrhs[] = {     8,
-     8,     8,     8,     6,     7,     0,     8,     0,     8,     8,
-     0,     0,     0,     4,     8,     0,     3,     3,     0
-};
-
-#endif
-
-#if YYDEBUG != 0
-static const short zzrline[] = { 0,
-    78,   107,   114,   121,   132,   135,   144
-};
-
-static const char * const zztname[] = {   "$","error","$illegal.","DIGIT","'.'",
-"date","year","seconds","digitpair",""
-};
-#endif
-
-static const short zzr1[] = {     0,
-     5,     6,     6,     6,     7,     7,     8
-};
-
-static const short zzr2[] = {     0,
-     6,     1,     2,     0,     0,     2,     2
-};
-
-static const short zzdefact[] = {     0,
-     0,     0,     7,     0,     0,     4,     5,     2,     0,     1,
-     3,     6,     0,     0,     0
-};
-
-static const short zzdefgoto[] = {    13,
-     7,    10,     2
-};
-
-static const short zzpact[] = {     2,
-     5,     2,-32768,     2,     2,     2,    -3,     2,     2,-32768,
--32768,-32768,     9,    10,-32768
-};
-
-static const short zzpgoto[] = {-32768,
--32768,-32768,    -2
-};
-
-
-#define        YYLAST          10
-
-
-static const short zztable[] = {     4,
-     9,     5,     6,     8,     1,    11,    12,     3,    14,    15
-};
-
-static const short zzcheck[] = {     2,
-     4,     4,     5,     6,     3,     8,     9,     3,     0,     0
-};
-/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
-#line 3 "/usr/local/lib/bison.simple"
-
-/* Skeleton output parser for bison,
-   Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman
+   Copyright (C) 1989, 1990, 1991, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+   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
 
    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 1, or (at your option)
+   the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
    any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -202,777 +14,321 @@ static const short zzcheck[] = {     2,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-
-#ifndef alloca
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else /* not GNU C.  */
-#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
-#include <alloca.h>
-#else /* not sparc */
-#if defined (MSDOS) && !defined (__TURBOC__)
-#include <malloc.h>
-#else /* not MSDOS, or __TURBOC__ */
-#if defined(_AIX)
-#include <malloc.h>
- #pragma alloca
-#else /* not MSDOS, __TURBOC__, or _AIX */
-#ifdef __hpux
-#ifdef __cplusplus
-extern "C" {
-void *alloca (unsigned int);
-};
-#else /* not __cplusplus */
-void *alloca ();
-#endif /* not __cplusplus */
-#endif /* __hpux */
-#endif /* not _AIX */
-#endif /* not MSDOS, or __TURBOC__ */
-#endif /* not sparc.  */
-#endif /* not GNU C.  */
-#endif /* alloca not defined.  */
-
-/* This is the parser code that is written into each bison parser
-  when the %semantic_parser declaration is not specified in the grammar.
-  It was written by Richard Stallman by simplifying the hairy parser
-  used when %semantic_parser is specified.  */
-
-/* Note: there must be only one dollar sign in this file.
-   It is replaced by the list of actions, each action
-   as one case of the switch.  */
-
-#define zzerrok                (zzerrstatus = 0)
-#define zzclearin      (zzchar = YYEMPTY)
-#define YYEMPTY                -2
-#define YYEOF          0
-#define YYACCEPT       return(0)
-#define YYABORT        return(1)
-#define YYERROR                goto zzerrlab1
-/* Like YYERROR except do call zzerror.
-   This remains here temporarily to ease the
-   transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-#define YYFAIL         goto zzerrlab
-#define YYRECOVERING()  (!!zzerrstatus)
-#define YYBACKUP(token, value) \
-do                                                             \
-  if (zzchar == YYEMPTY && zzlen == 1)                         \
-    { zzchar = (token), zzlval = (value);                      \
-      zzchar1 = YYTRANSLATE (zzchar);                          \
-      YYPOPSTACK;                                              \
-      goto zzbackup;                                           \
-    }                                                          \
-  else                                                         \
-    { zzerror ("syntax error: cannot back up"); YYERROR; }     \
-while (0)
-
-#define YYTERROR       1
-#define YYERRCODE      256
-
-#ifndef YYPURE
-#define YYLEX          zzlex()
-#endif
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 
-#ifdef YYPURE
-#ifdef YYLSP_NEEDED
-#define YYLEX          zzlex(&zzlval, &zzlloc)
-#else
-#define YYLEX          zzlex(&zzlval)
-#endif
-#endif
+/* Yacc-based version written by Jim Kingdon and David MacKenzie.
+   Rewritten by Jim Meyering.  */
 
 
-/* If nonreentrant, generate the variables here */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
 
-#ifndef YYPURE
+#include <stdbool.h>
 
 
-int    zzchar;                 /*  the lookahead symbol                */
-YYSTYPE        zzlval;                 /*  the semantic value of the           */
-                               /*  lookahead symbol                    */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
 
 
-#ifdef YYLSP_NEEDED
-YYLTYPE zzlloc;                        /*  location data for the lookahead     */
-                               /*  symbol                              */
+#ifdef TM_IN_SYS_TIME
+# include <sys/time.h>
+#else
+# include <time.h>
 #endif
 
 #endif
 
-int zznerrs;                   /*  number of parse errors so far       */
-#endif  /* not YYPURE */
+#include "posixtm.h"
 
 
-#if YYDEBUG != 0
-int zzdebug;                   /*  nonzero means print parse trace     */
-/* Since this is uninitialized, it does not stop multiple parsers
-   from coexisting.  */
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
 #endif
 
 #endif
 
-/*  YYINITDEPTH indicates the initial size of the parser's stacks      */
+/* ISDIGIT differs from isdigit, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
+   ISDIGIT_LOCALE 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)
 
 
-#ifndef        YYINITDEPTH
-#define YYINITDEPTH 200
-#endif
+time_t mktime ();
 
 
-/*  YYMAXDEPTH is the maximum size the stacks can grow to
-    (effective only if the built-in stack extension method is used).  */
+/*
+  POSIX requires:
 
 
-#if YYMAXDEPTH == 0
-#undef YYMAXDEPTH
-#endif
+  touch -t [[CC]YY]mmddhhmm[.ss] FILE...
+    8, 10, or 12 digits, followed by optional .ss
+    (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS)
 
 
-#ifndef YYMAXDEPTH
-#define YYMAXDEPTH 10000
-#endif
-
-/* Prevent warning if -Wstrict-prototypes.  */
-#ifdef __GNUC__
-int zzparse (void);
-#endif
-\f
-#if __GNUC__ > 1               /* GNU C and GNU C++ define this.  */
-#define __zz_bcopy(FROM,TO,COUNT)      __builtin_memcpy(TO,FROM,COUNT)
-#else                          /* not GNU C or C++ */
-#ifndef __cplusplus
-
-/* This is the most reliable way to avoid incompatibilities
-   in available built-in functions on various systems.  */
-static void
-__zz_bcopy (from, to, count)
-     char *from;
-     char *to;
-     int count;
-{
-  register char *f = from;
-  register char *t = to;
-  register int i = count;
+  touch mmddhhmm[YY] FILE... (obsoleted by POSIX 1003.1-2001)
+    8 or 10 digits
+    (PDS_TRAILING_YEAR)
 
 
-  while (i-- > 0)
-    *t++ = *f++;
-}
+  date mmddhhmm[[CC]YY]
+    8, 10, or 12 digits
+    (PDS_TRAILING_YEAR | PDS_CENTURY)
 
 
-#else /* __cplusplus */
+*/
 
 
-/* This is the most reliable way to avoid incompatibilities
-   in available built-in functions on various systems.  */
-static void
-__zz_bcopy (char *from, char *to, int count)
+static int
+year (struct tm *tm, const int *digit_pair, size_t n, int allow_century)
 {
 {
-  register char *f = from;
-  register char *t = to;
-  register int i = count;
+  switch (n)
+    {
+    case 1:
+      tm->tm_year = *digit_pair;
+      /* Deduce the century based on the year.
+        POSIX requires that 00-68 be interpreted as 2000-2068,
+        and that 69-99 be interpreted as 1969-1999.  */
+      if (digit_pair[0] <= 68)
+       tm->tm_year += 100;
+      break;
+
+    case 2:
+      if (!allow_century)
+       return 1;
+      tm->tm_year = digit_pair[0] * 100 + digit_pair[1] - 1900;
+      break;
+
+    case 0:
+      {
+       time_t now;
+       struct tm *tmp;
+
+       /* Use current year.  */
+       time (&now);
+       tmp = localtime (&now);
+       if (! tmp)
+         return 1;
+       tm->tm_year = tmp->tm_year;
+      }
+      break;
+
+    default:
+      abort ();
+    }
 
 
-  while (i-- > 0)
-    *t++ = *f++;
+  return 0;
 }
 
 }
 
-#endif
-#endif
-\f
-#line 184 "/usr/local/lib/bison.simple"
-int
-zzparse()
+static int
+posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
 {
 {
-  register int zzstate;
-  register int zzn;
-  register short *zzssp;
-  register YYSTYPE *zzvsp;
-  int zzerrstatus;     /*  number of tokens to shift before error messages enabled */
-  int zzchar1 = 0;             /*  lookahead token as an internal (translated) token number */
-
-  short        zzssa[YYINITDEPTH];     /*  the state stack                     */
-  YYSTYPE zzvsa[YYINITDEPTH];  /*  the semantic value stack            */
+  const char *dot = NULL;
+  int pair[6];
+  int *p;
+  size_t i;
 
 
-  short *zzss = zzssa;         /*  refer to the stacks thru separate pointers */
-  YYSTYPE *zzvs = zzvsa;       /*  to allow zzoverflow to reallocate them elsewhere */
+  size_t s_len = strlen (s);
+  size_t len = (((syntax_bits & PDS_SECONDS) && (dot = strchr (s, '.')))
+               ? (size_t) (dot - s)
+               : s_len);
 
 
-#ifdef YYLSP_NEEDED
-  YYLTYPE zzlsa[YYINITDEPTH];  /*  the location stack                  */
-  YYLTYPE *zzls = zzlsa;
-  YYLTYPE *zzlsp;
-
-#define YYPOPSTACK   (zzvsp--, zzssp--, zzlsp--)
-#else
-#define YYPOPSTACK   (zzvsp--, zzssp--)
-#endif
+  if (len != 8 && len != 10 && len != 12)
+    return 1;
 
 
-  int zzstacksize = YYINITDEPTH;
-
-#ifdef YYPURE
-  int zzchar;
-  YYSTYPE zzlval;
-  int zznerrs;
-#ifdef YYLSP_NEEDED
-  YYLTYPE zzlloc;
-#endif
-#endif
-
-  YYSTYPE zzval;               /*  the variable used to return         */
-                               /*  semantic values from the action     */
-                               /*  routines                            */
-
-  int zzlen;
-
-#if YYDEBUG != 0
-  if (zzdebug)
-    fprintf(stderr, "Starting parse\n");
-#endif
-
-  zzstate = 0;
-  zzerrstatus = 0;
-  zznerrs = 0;
-  zzchar = YYEMPTY;            /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  zzssp = zzss - 1;
-  zzvsp = zzvs;
-#ifdef YYLSP_NEEDED
-  zzlsp = zzls;
-#endif
-
-/* Push a new state, which is found in  zzstate  .  */
-/* In all cases, when you get here, the value and location stacks
-   have just been pushed. so pushing a state here evens the stacks.  */
-zznewstate:
-
-  *++zzssp = zzstate;
-
-  if (zzssp >= zzss + zzstacksize - 1)
+  if (dot)
     {
     {
-      /* Give user a chance to reallocate the stack */
-      /* Use copies of these so that the &'s don't force the real ones into memory. */
-      YYSTYPE *zzvs1 = zzvs;
-      short *zzss1 = zzss;
-#ifdef YYLSP_NEEDED
-      YYLTYPE *zzls1 = zzls;
-#endif
+      if (!(syntax_bits & PDS_SECONDS))
+       return 1;
 
 
-      /* Get the current used size of the three stacks, in elements.  */
-      int size = zzssp - zzss + 1;
-
-#ifdef zzoverflow
-      /* Each stack pointer address is followed by the size of
-        the data in use in that stack, in bytes.  */
-#ifdef YYLSP_NEEDED
-      /* This used to be a conditional around just the two extra args,
-        but that might be undefined if zzoverflow is a macro.  */
-      zzoverflow("parser stack overflow",
-                &zzss1, size * sizeof (*zzssp),
-                &zzvs1, size * sizeof (*zzvsp),
-                &zzls1, size * sizeof (*zzlsp),
-                &zzstacksize);
-#else
-      zzoverflow("parser stack overflow",
-                &zzss1, size * sizeof (*zzssp),
-                &zzvs1, size * sizeof (*zzvsp),
-                &zzstacksize);
-#endif
-
-      zzss = zzss1; zzvs = zzvs1;
-#ifdef YYLSP_NEEDED
-      zzls = zzls1;
-#endif
-#else /* no zzoverflow */
-      /* Extend the stack our own way.  */
-      if (zzstacksize >= YYMAXDEPTH)
-       {
-         zzerror("parser stack overflow");
-         return 2;
-       }
-      zzstacksize *= 2;
-      if (zzstacksize > YYMAXDEPTH)
-       zzstacksize = YYMAXDEPTH;
-      zzss = (short *) alloca (zzstacksize * sizeof (*zzssp));
-      __zz_bcopy ((char *)zzss1, (char *)zzss, size * sizeof (*zzssp));
-      zzvs = (YYSTYPE *) alloca (zzstacksize * sizeof (*zzvsp));
-      __zz_bcopy ((char *)zzvs1, (char *)zzvs, size * sizeof (*zzvsp));
-#ifdef YYLSP_NEEDED
-      zzls = (YYLTYPE *) alloca (zzstacksize * sizeof (*zzlsp));
-      __zz_bcopy ((char *)zzls1, (char *)zzls, size * sizeof (*zzlsp));
-#endif
-#endif /* no zzoverflow */
-
-      zzssp = zzss + size - 1;
-      zzvsp = zzvs + size - 1;
-#ifdef YYLSP_NEEDED
-      zzlsp = zzls + size - 1;
-#endif
-
-#if YYDEBUG != 0
-      if (zzdebug)
-       fprintf(stderr, "Stack size increased to %d\n", zzstacksize);
-#endif
-
-      if (zzssp >= zzss + zzstacksize - 1)
-       YYABORT;
+      if (s_len - len != 3)
+       return 1;
     }
 
     }
 
-#if YYDEBUG != 0
-  if (zzdebug)
-    fprintf(stderr, "Entering state %d\n", zzstate);
-#endif
-
-  goto zzbackup;
- zzbackup:
+  for (i = 0; i < len; i++)
+    if (!ISDIGIT (s[i]))
+      return 1;
 
 
-/* Do appropriate processing given the current state.  */
-/* Read a lookahead token if we need one and don't already have one.  */
-/* zzresume: */
+  len /= 2;
+  for (i = 0; i < len; i++)
+    pair[i] = 10 * (s[2*i] - '0') + s[2*i + 1] - '0';
 
 
-  /* First try to decide what to do without reference to lookahead token.  */
-
-  zzn = zzpact[zzstate];
-  if (zzn == YYFLAG)
-    goto zzdefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* zzchar is either YYEMPTY or YYEOF
-     or a valid token in external form.  */
-
-  if (zzchar == YYEMPTY)
+  p = pair;
+  if (syntax_bits & PDS_LEADING_YEAR)
     {
     {
-#if YYDEBUG != 0
-      if (zzdebug)
-       fprintf(stderr, "Reading a token: ");
-#endif
-      zzchar = YYLEX;
+      if (year (tm, p, len - 4, syntax_bits & PDS_CENTURY))
+       return 1;
+      p += len - 4;
+      len = 4;
     }
 
     }
 
-  /* Convert token to internal form (in zzchar1) for indexing tables with */
+  /* Handle 8 digits worth of `MMDDhhmm'.  */
+  tm->tm_mon = *p++ - 1;
+  tm->tm_mday = *p++;
+  tm->tm_hour = *p++;
+  tm->tm_min = *p++;
+  len -= 4;
 
 
-  if (zzchar <= 0)             /* This means end of input. */
+  /* Handle any trailing year.  */
+  if (syntax_bits & PDS_TRAILING_YEAR)
     {
     {
-      zzchar1 = 0;
-      zzchar = YYEOF;          /* Don't call YYLEX any more */
-
-#if YYDEBUG != 0
-      if (zzdebug)
-       fprintf(stderr, "Now at end of input.\n");
-#endif
-    }
-  else
-    {
-      zzchar1 = YYTRANSLATE(zzchar);
-
-#if YYDEBUG != 0
-      if (zzdebug)
-       {
-         fprintf (stderr, "Next token is %d (%s", zzchar, zztname[zzchar1]);
-         /* Give the individual parser a way to print the precise meaning
-            of a token, for further debugging info.  */
-#ifdef YYPRINT
-         YYPRINT (stderr, zzchar, zzlval);
-#endif
-         fprintf (stderr, ")\n");
-       }
-#endif
+      if (year (tm, p, len, syntax_bits & PDS_CENTURY))
+       return 1;
     }
 
     }
 
-  zzn += zzchar1;
-  if (zzn < 0 || zzn > YYLAST || zzcheck[zzn] != zzchar1)
-    goto zzdefault;
-
-  zzn = zztable[zzn];
-
-  /* zzn is what to do for this token type in this state.
-     Negative => reduce, -zzn is rule number.
-     Positive => shift, zzn is new state.
-       New state is final state => don't bother to shift,
-       just return success.
-     0, or most negative number => error.  */
-
-  if (zzn < 0)
+  /* Handle seconds.  */
+  if (!dot)
     {
     {
-      if (zzn == YYFLAG)
-       goto zzerrlab;
-      zzn = -zzn;
-      goto zzreduce;
+      tm->tm_sec = 0;
     }
     }
-  else if (zzn == 0)
-    goto zzerrlab;
-
-  if (zzn == YYFINAL)
-    YYACCEPT;
-
-  /* Shift the lookahead token.  */
-
-#if YYDEBUG != 0
-  if (zzdebug)
-    fprintf(stderr, "Shifting token %d (%s), ", zzchar, zztname[zzchar1]);
-#endif
-
-  /* Discard the token being shifted unless it is eof.  */
-  if (zzchar != YYEOF)
-    zzchar = YYEMPTY;
-
-  *++zzvsp = zzlval;
-#ifdef YYLSP_NEEDED
-  *++zzlsp = zzlloc;
-#endif
-
-  /* count tokens shifted since error; after three, turn off error status.  */
-  if (zzerrstatus) zzerrstatus--;
-
-  zzstate = zzn;
-  goto zznewstate;
-
-/* Do the default action for the current state.  */
-zzdefault:
-
-  zzn = zzdefact[zzstate];
-  if (zzn == 0)
-    goto zzerrlab;
-
-/* Do a reduction.  zzn is the number of a rule to reduce with.  */
-zzreduce:
-  zzlen = zzr2[zzn];
-  if (zzlen > 0)
-    zzval = zzvsp[1-zzlen]; /* implement default value of the action */
-
-#if YYDEBUG != 0
-  if (zzdebug)
+  else
     {
     {
-      int i;
+      int seconds;
 
 
-      fprintf (stderr, "Reducing via rule %d (line %d), ",
-              zzn, zzrline[zzn]);
+      ++dot;
+      if (!ISDIGIT (dot[0]) || !ISDIGIT (dot[1]))
+       return 1;
+      seconds = 10 * (dot[0] - '0') + dot[1] - '0';
 
 
-      /* Print the symbols being reduced, and their result.  */
-      for (i = zzprhs[zzn]; zzrhs[i] > 0; i++)
-       fprintf (stderr, "%s ", zztname[zzrhs[i]]);
-      fprintf (stderr, " -> %s\n", zztname[zzr1[zzn]]);
+      tm->tm_sec = seconds;
     }
     }
-#endif
-
 
 
-  switch (zzn) {
-
-case 1:
-#line 84 "./posixtm.y"
-{
-                if (zzvsp[-5] >= 1 && zzvsp[-5] <= 12)
-                  t.tm_mon = zzvsp[-5] - 1;
-                else {
-                  YYABORT;
-                }
-                if (zzvsp[-4] >= 1 && zzvsp[-4] <= 31)
-                  t.tm_mday = zzvsp[-4];
-                else {
-                  YYABORT;
-                }
-                if (zzvsp[-3] >= 0 && zzvsp[-3] <= 23)
-                  t.tm_hour = zzvsp[-3];
-                else {
-                  YYABORT;
-                }
-                if (zzvsp[-2] >= 0 && zzvsp[-2] <= 59)
-                  t.tm_min = zzvsp[-2];
-                else {
-                  YYABORT;
-                }
-              ;
-    break;}
-case 2:
-#line 107 "./posixtm.y"
-{
-                   t.tm_year = zzvsp[0];
-                  /* Deduce the century based on the year.
-                     See POSIX.2 section 4.63.3.  */
-                  if (zzvsp[0] <= 68)
-                    t.tm_year += 100;
-                ;
-    break;}
-case 3:
-#line 114 "./posixtm.y"
-{
-                            t.tm_year = zzvsp[-1] * 100 + zzvsp[0];
-                           if (t.tm_year < 1900) {
-                             YYABORT;
-                           } else
-                             t.tm_year -= 1900;
-                         ;
-    break;}
-case 4:
-#line 121 "./posixtm.y"
-{
-                    time_t now;
-                   struct tm *tmp;
-
-                    /* Use current year.  */
-                    time (&now);
-                   tmp = localtime (&now);
-                   t.tm_year = tmp->tm_year;
-                 ;
-    break;}
-case 5:
-#line 132 "./posixtm.y"
-{
-                        t.tm_sec = 0;
-                     ;
-    break;}
-case 6:
-#line 135 "./posixtm.y"
-{
-                         if (zzvsp[0] >= 0 && zzvsp[0] <= 61)
-                           t.tm_sec = zzvsp[0];
-                         else {
-                           YYABORT;
-                         }
-                       ;
-    break;}
-case 7:
-#line 144 "./posixtm.y"
-{
-                          zzval = zzvsp[-1] * 10 + zzvsp[0];
-                       ;
-    break;}
+  return 0;
 }
 }
-   /* the action file gets copied in in place of this dollarsign */
-#line 465 "/usr/local/lib/bison.simple"
-\f
-  zzvsp -= zzlen;
-  zzssp -= zzlen;
-#ifdef YYLSP_NEEDED
-  zzlsp -= zzlen;
-#endif
 
 
-#if YYDEBUG != 0
-  if (zzdebug)
-    {
-      short *ssp1 = zzss - 1;
-      fprintf (stderr, "state stack now");
-      while (ssp1 != zzssp)
-       fprintf (stderr, " %d", *++ssp1);
-      fprintf (stderr, "\n");
-    }
-#endif
-
-  *++zzvsp = zzval;
+/* Parse a POSIX-style date, returning true if successful.  */
 
 
-#ifdef YYLSP_NEEDED
-  zzlsp++;
-  if (zzlen == 0)
-    {
-      zzlsp->first_line = zzlloc.first_line;
-      zzlsp->first_column = zzlloc.first_column;
-      zzlsp->last_line = (zzlsp-1)->last_line;
-      zzlsp->last_column = (zzlsp-1)->last_column;
-      zzlsp->text = 0;
-    }
+bool
+posixtime (time_t *p, const char *s, unsigned int syntax_bits)
+{
+  struct tm tm0
+#ifdef lint
+  /* Placate gcc-4's -Wuninitialized.
+     posix_time_parse fails to set all of tm0 only when it returns
+     nonzero (due to year() returning nonzero), and in that case,
+     this code doesn't use the tm0 at all.  */
+    = { 0, }
+#endif
+    ;
+  struct tm tm1;
+  struct tm const *tm;
+  time_t t;
+
+  if (posix_time_parse (&tm0, s, syntax_bits))
+    return false;
+
+  tm1 = tm0;
+  tm1.tm_isdst = -1;
+  t = mktime (&tm1);
+
+  if (t != (time_t) -1)
+    tm = &tm1;
   else
     {
   else
     {
-      zzlsp->last_line = (zzlsp+zzlen-1)->last_line;
-      zzlsp->last_column = (zzlsp+zzlen-1)->last_column;
+      /* mktime returns -1 for errors, but -1 is also a valid time_t
+        value.  Check whether an error really occurred.  */
+      tm = localtime (&t);
+      if (! tm)
+       return false;
     }
     }
-#endif
 
 
-  /* Now "shift" the result of the reduction.
-     Determine what state that goes to,
-     based on the state we popped back to
-     and the rule number reduced by.  */
-
-  zzn = zzr1[zzn];
-
-  zzstate = zzpgoto[zzn - YYNTBASE] + *zzssp;
-  if (zzstate >= 0 && zzstate <= YYLAST && zzcheck[zzstate] == *zzssp)
-    zzstate = zztable[zzstate];
-  else
-    zzstate = zzdefgoto[zzn - YYNTBASE];
+  /* Reject dates like "September 31" and times like "25:61".  */
+  if ((tm0.tm_year ^ tm->tm_year)
+      | (tm0.tm_mon ^ tm->tm_mon)
+      | (tm0.tm_mday ^ tm->tm_mday)
+      | (tm0.tm_hour ^ tm->tm_hour)
+      | (tm0.tm_min ^ tm->tm_min)
+      | (tm0.tm_sec ^ tm->tm_sec))
+    return false;
+
+  *p = t;
+  return true;
+}
 
 
-  goto zznewstate;
+#ifdef TEST_POSIXTIME
+/*
+    Test mainly with syntax_bits == 13
+    (aka: (PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS))
+
+    This test data assumes Universal Time, e.g., TZ="UTC0".
+
+    This test data also assumes that time_t is signed and is at least
+    39 bits wide, so that it can represent all years from 0000 through
+    9999.  A host with 32-bit signed time_t can represent only time
+    stamps in the range 1901-12-13 20:45:52 through 2038-01-18
+    03:14:07 UTC, assuming POSIX time_t with no leap seconds, so test
+    cases outside this range will not work on such a host.
+
+    Also, the first two lines of test data assume that the current
+    year is 2002.
+
+BEGIN-DATA
+12131415.16     13   1039788916 Fri Dec 13 14:15:16 2002
+12131415.16     13   1039788916 Fri Dec 13 14:15:16 2002
+000001010000.00 13 -62167132800 Sun Jan  1 00:00:00 0000
+190112132045.52 13  -2147483648 Fri Dec 13 20:45:52 1901
+190112132045.53 13  -2147483647 Fri Dec 13 20:45:53 1901
+190112132046.52 13  -2147483588 Fri Dec 13 20:46:52 1901
+190112132145.52 13  -2147480048 Fri Dec 13 21:45:52 1901
+190112142045.52 13  -2147397248 Sat Dec 14 20:45:52 1901
+190201132045.52 13  -2144805248 Mon Jan 13 20:45:52 1902
+196912312359.59 13           -1 Wed Dec 31 23:59:59 1969
+197001010000.00 13            0 Thu Jan  1 00:00:00 1970
+197001010000.01 13            1 Thu Jan  1 00:00:01 1970
+197001010001.00 13           60 Thu Jan  1 00:01:00 1970
+197001010100.00 13         3600 Thu Jan  1 01:00:00 1970
+197001020000.00 13        86400 Fri Jan  2 00:00:00 1970
+197002010000.00 13      2678400 Sun Feb  1 00:00:00 1970
+197101010000.00 13     31536000 Fri Jan  1 00:00:00 1971
+197001000000.00 13            * *
+197000010000.00 13            * *
+197001010000.60 13            * *
+197001010060.00 13            * *
+197001012400.00 13            * *
+197001320000.00 13            * *
+197013010000.00 13            * *
+203801190314.06 13   2147483646 Tue Jan 19 03:14:06 2038
+203801190314.07 13   2147483647 Tue Jan 19 03:14:07 2038
+203801190314.08 13   2147483648 Tue Jan 19 03:14:08 2038
+999912312359.59 13 253402300799 Fri Dec 31 23:59:59 9999
+1112131415      13   1323785700 Tue Dec 13 14:15:00 2011
+1112131415.16   13   1323785716 Tue Dec 13 14:15:16 2011
+201112131415.16 13   1323785716 Tue Dec 13 14:15:16 2011
+191112131415.16 13  -1831974284 Wed Dec 13 14:15:16 1911
+203712131415.16 13   2144326516 Sun Dec 13 14:15:16 2037
+3712131415.16   13   2144326516 Sun Dec 13 14:15:16 2037
+6812131415.16   13   3122633716 Thu Dec 13 14:15:16 2068
+6912131415.16   13     -1590284 Sat Dec 13 14:15:16 1969
+7012131415.16   13     29945716 Sun Dec 13 14:15:16 1970
+1213141599       2    945094500 Mon Dec 13 14:15:00 1999
+1213141500       2    976716900 Wed Dec 13 14:15:00 2000
+END-DATA
+
+*/
+
+# define MAX_BUFF_LEN 1024
 
 
-zzerrlab:   /* here on detecting error */
+int
+main (void)
+{
+  char buff[MAX_BUFF_LEN + 1];
 
 
-  if (! zzerrstatus)
-    /* If not already recovering from an error, report this error.  */
+  buff[MAX_BUFF_LEN] = 0;
+  while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
     {
     {
-      ++zznerrs;
-
-#ifdef YYERROR_VERBOSE
-      zzn = zzpact[zzstate];
-
-      if (zzn > YYFLAG && zzn < YYLAST)
+      char time_str[MAX_BUFF_LEN];
+      unsigned int syntax_bits;
+      time_t t;
+      if (sscanf (buff, "%s %u", time_str, &syntax_bits) != 2)
+       printf ("*\n");
+      else
        {
        {
-         int size = 0;
-         char *msg;
-         int x, count;
-
-         count = 0;
-         /* Start X at -zzn if nec to avoid negative indexes in zzcheck.  */
-         for (x = (zzn < 0 ? -zzn : 0);
-              x < (sizeof(zztname) / sizeof(char *)); x++)
-           if (zzcheck[x + zzn] == x)
-             size += strlen(zztname[x]) + 15, count++;
-         msg = (char *) malloc(size + 15);
-         if (msg != 0)
-           {
-             strcpy(msg, "parse error");
-
-             if (count < 5)
-               {
-                 count = 0;
-                 for (x = (zzn < 0 ? -zzn : 0);
-                      x < (sizeof(zztname) / sizeof(char *)); x++)
-                   if (zzcheck[x + zzn] == x)
-                     {
-                       strcat(msg, count == 0 ? ", expecting `" : " or `");
-                       strcat(msg, zztname[x]);
-                       strcat(msg, "'");
-                       count++;
-                     }
-               }
-             zzerror(msg);
-             free(msg);
-           }
+         printf ("%-15s %2u ", time_str, syntax_bits);
+         if (posixtime (&t, time_str, syntax_bits))
+           printf ("%12ld %s", (long int) t, ctime (&t));
          else
          else
-           zzerror ("parse error; also virtual memory exceeded");
+           printf ("%12s %s", "*", "*\n");
        }
        }
-      else
-#endif /* YYERROR_VERBOSE */
-       zzerror("parse error");
-    }
-
-  goto zzerrlab1;
-zzerrlab1:   /* here on error raised explicitly by an action */
-
-  if (zzerrstatus == 3)
-    {
-      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
-
-      /* return failure if at end of input */
-      if (zzchar == YYEOF)
-       YYABORT;
-
-#if YYDEBUG != 0
-      if (zzdebug)
-       fprintf(stderr, "Discarding token %d (%s).\n", zzchar, zztname[zzchar1]);
-#endif
-
-      zzchar = YYEMPTY;
-    }
-
-  /* Else will try to reuse lookahead token
-     after shifting the error token.  */
-
-  zzerrstatus = 3;             /* Each real token shifted decrements this */
-
-  goto zzerrhandle;
-
-zzerrdefault:  /* current state does not do anything special for the error token. */
-
-#if 0
-  /* This is wrong; only states that explicitly want error tokens
-     should shift them.  */
-  zzn = zzdefact[zzstate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
-  if (zzn) goto zzdefault;
-#endif
-
-zzerrpop:   /* pop the current state because it cannot handle the error token */
-
-  if (zzssp == zzss) YYABORT;
-  zzvsp--;
-  zzstate = *--zzssp;
-#ifdef YYLSP_NEEDED
-  zzlsp--;
-#endif
-
-#if YYDEBUG != 0
-  if (zzdebug)
-    {
-      short *ssp1 = zzss - 1;
-      fprintf (stderr, "Error: state stack now");
-      while (ssp1 != zzssp)
-       fprintf (stderr, " %d", *++ssp1);
-      fprintf (stderr, "\n");
-    }
-#endif
-
-zzerrhandle:
-
-  zzn = zzpact[zzstate];
-  if (zzn == YYFLAG)
-    goto zzerrdefault;
-
-  zzn += YYTERROR;
-  if (zzn < 0 || zzn > YYLAST || zzcheck[zzn] != YYTERROR)
-    goto zzerrdefault;
-
-  zzn = zztable[zzn];
-  if (zzn < 0)
-    {
-      if (zzn == YYFLAG)
-       goto zzerrpop;
-      zzn = -zzn;
-      goto zzreduce;
     }
     }
-  else if (zzn == 0)
-    goto zzerrpop;
+  exit (0);
 
 
-  if (zzn == YYFINAL)
-    YYACCEPT;
-
-#if YYDEBUG != 0
-  if (zzdebug)
-    fprintf(stderr, "Shifting error token, ");
-#endif
-
-  *++zzvsp = zzlval;
-#ifdef YYLSP_NEEDED
-  *++zzlsp = zzlloc;
-#endif
-
-  zzstate = zzn;
-  goto zznewstate;
-}
-#line 148 "./posixtm.y"
-
-static int
-zzlex ()
-{
-  char ch = *curpos++;
-
-  if (ch >= '0' && ch <= '9')
-    {
-      zzlval = ch - '0';
-      return DIGIT;
-    }
-  else if (ch == '.' || ch == 0)
-    return ch;
-  else
-    return '?';                        /* Cause an error.  */
-}
-
-static int
-zzerror ()
-{
-  return 0;
-}
-
-/* Parse a POSIX-style date and return it, or (time_t)-1 for an error.  */
-
-time_t
-posixtime (s)
-     char *s;
-{
-  curpos = s;
-  /* Let mktime decide whether it is daylight savings time.  */
-  t.tm_isdst = -1;
-  if (zzparse ())
-    return (time_t)-1;
-  else
-    return mktime (&t);
-}
-
-/* Parse a POSIX-style date and return it, or NULL for an error.  */
-
-struct tm *
-posixtm (s)
-     char *s;
-{
-  if (posixtime (s) == -1)
-    return NULL;
-  return &t;
 }
 }
+#endif
+\f
+/*
+Local Variables:
+compile-command: "gcc -DTEST_POSIXTIME -DHAVE_CONFIG_H -I.. -g -O -Wall -W posixtm.c"
+End:
+*/