LCOV - code coverage report
Current view: top level - shishi/gl - getdate.y (source / functions) Hit Total Coverage
Test: GNU Shishi Lines: 0 576 0.0 %
Date: 2010-05-20 Functions: 0 13 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 311 0.0 %

           Branch data     Line data    Source code
       1                 :            : %{
       2                 :            : /* Parse a string into an internal time stamp.
       3                 :            : 
       4                 :            :    Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
       5                 :            :    2010 Free Software Foundation, Inc.
       6                 :            : 
       7                 :            :    This program is free software: you can redistribute it and/or modify
       8                 :            :    it under the terms of the GNU General Public License as published by
       9                 :            :    the Free Software Foundation; either version 3 of the License, or
      10                 :            :    (at your option) any later version.
      11                 :            : 
      12                 :            :    This program is distributed in the hope that it will be useful,
      13                 :            :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :    GNU General Public License for more details.
      16                 :            : 
      17                 :            :    You should have received a copy of the GNU General Public License
      18                 :            :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      19                 :            : 
      20                 :            : /* Originally written by Steven M. Bellovin <smb@research.att.com> while
      21                 :            :    at the University of North Carolina at Chapel Hill.  Later tweaked by
      22                 :            :    a couple of people on Usenet.  Completely overhauled by Rich $alz
      23                 :            :    <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
      24                 :            : 
      25                 :            :    Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
      26                 :            :    the right thing about local DST.  Also modified by Paul Eggert
      27                 :            :    <eggert@cs.ucla.edu> in February 2004 to support
      28                 :            :    nanosecond-resolution time stamps, and in October 2004 to support
      29                 :            :    TZ strings in dates.  */
      30                 :            : 
      31                 :            : /* FIXME: Check for arithmetic overflow in all cases, not just
      32                 :            :    some of them.  */
      33                 :            : 
      34                 :            : #include <config.h>
      35                 :            : 
      36                 :            : #include "getdate.h"
      37                 :            : 
      38                 :            : #include "intprops.h"
      39                 :            : #include "timespec.h"
      40                 :            : #include "verify.h"
      41                 :            : 
      42                 :            : /* There's no need to extend the stack, so there's no need to involve
      43                 :            :    alloca.  */
      44                 :            : #define YYSTACK_USE_ALLOCA 0
      45                 :            : 
      46                 :            : /* Tell Bison how much stack space is needed.  20 should be plenty for
      47                 :            :    this grammar, which is not right recursive.  Beware setting it too
      48                 :            :    high, since that might cause problems on machines whose
      49                 :            :    implementations have lame stack-overflow checking.  */
      50                 :            : #define YYMAXDEPTH 20
      51                 :            : #define YYINITDEPTH YYMAXDEPTH
      52                 :            : 
      53                 :            : /* Since the code of getdate.y is not included in the Emacs executable
      54                 :            :    itself, there is no need to #define static in this file.  Even if
      55                 :            :    the code were included in the Emacs executable, it probably
      56                 :            :    wouldn't do any harm to #undef it here; this will only cause
      57                 :            :    problems if we try to write to a static variable, which I don't
      58                 :            :    think this code needs to do.  */
      59                 :            : #ifdef emacs
      60                 :            : # undef static
      61                 :            : #endif
      62                 :            : 
      63                 :            : #include <c-ctype.h>
      64                 :            : #include <limits.h>
      65                 :            : #include <stdio.h>
      66                 :            : #include <stdlib.h>
      67                 :            : #include <string.h>
      68                 :            : 
      69                 :            : #include "xalloc.h"
      70                 :            : 
      71                 :            : 
      72                 :            : /* ISDIGIT differs from isdigit, as follows:
      73                 :            :    - Its arg may be any int or unsigned int; it need not be an unsigned char
      74                 :            :      or EOF.
      75                 :            :    - It's typically faster.
      76                 :            :    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
      77                 :            :    isdigit unless it's important to use the locale's definition
      78                 :            :    of `digit' even when the host does not conform to POSIX.  */
      79                 :            : #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
      80                 :            : 
      81                 :            : /* Shift A right by B bits portably, by dividing A by 2**B and
      82                 :            :    truncating towards minus infinity.  A and B should be free of side
      83                 :            :    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
      84                 :            :    INT_BITS is the number of useful bits in an int.  GNU code can
      85                 :            :    assume that INT_BITS is at least 32.
      86                 :            : 
      87                 :            :    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
      88                 :            :    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
      89                 :            :    right in the usual way when A < 0, so SHR falls back on division if
      90                 :            :    ordinary A >> B doesn't seem to be the usual signed shift.  */
      91                 :            : #define SHR(a, b)       \
      92                 :            :   (-1 >> 1 == -1        \
      93                 :            :    ? (a) >> (b)         \
      94                 :            :    : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
      95                 :            : 
      96                 :            : #define EPOCH_YEAR 1970
      97                 :            : #define TM_YEAR_BASE 1900
      98                 :            : 
      99                 :            : #define HOUR(x) ((x) * 60)
     100                 :            : 
     101                 :            : /* long_time_t is a signed integer type that contains all time_t values.  */
     102                 :            : verify (TYPE_IS_INTEGER (time_t));
     103                 :            : #if TIME_T_FITS_IN_LONG_INT
     104                 :            : typedef long int long_time_t;
     105                 :            : #else
     106                 :            : typedef time_t long_time_t;
     107                 :            : #endif
     108                 :            : 
     109                 :            : /* Lots of this code assumes time_t and time_t-like values fit into
     110                 :            :    long_time_t.  */
     111                 :            : verify (TYPE_MINIMUM (long_time_t) <= TYPE_MINIMUM (time_t)
     112                 :            :         && TYPE_MAXIMUM (time_t) <= TYPE_MAXIMUM (long_time_t));
     113                 :            : 
     114                 :            : /* FIXME: It also assumes that signed integer overflow silently wraps around,
     115                 :            :    but this is not true any more with recent versions of GCC 4.  */
     116                 :            : 
     117                 :            : /* An integer value, and the number of digits in its textual
     118                 :            :    representation.  */
     119                 :            : typedef struct
     120                 :            : {
     121                 :            :   bool negative;
     122                 :            :   long int value;
     123                 :            :   size_t digits;
     124                 :            : } textint;
     125                 :            : 
     126                 :            : /* An entry in the lexical lookup table.  */
     127                 :            : typedef struct
     128                 :            : {
     129                 :            :   char const *name;
     130                 :            :   int type;
     131                 :            :   int value;
     132                 :            : } table;
     133                 :            : 
     134                 :            : /* Meridian: am, pm, or 24-hour style.  */
     135                 :            : enum { MERam, MERpm, MER24 };
     136                 :            : 
     137                 :            : enum { BILLION = 1000000000, LOG10_BILLION = 9 };
     138                 :            : 
     139                 :            : /* Relative times.  */
     140                 :            : typedef struct
     141                 :            : {
     142                 :            :   /* Relative year, month, day, hour, minutes, seconds, and nanoseconds.  */
     143                 :            :   long int year;
     144                 :            :   long int month;
     145                 :            :   long int day;
     146                 :            :   long int hour;
     147                 :            :   long int minutes;
     148                 :            :   long_time_t seconds;
     149                 :            :   long int ns;
     150                 :            : } relative_time;
     151                 :            : 
     152                 :            : #if HAVE_COMPOUND_LITERALS
     153                 :            : # define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 })
     154                 :            : #else
     155                 :            : static relative_time const RELATIVE_TIME_0;
     156                 :            : #endif
     157                 :            : 
     158                 :            : /* Information passed to and from the parser.  */
     159                 :            : typedef struct
     160                 :            : {
     161                 :            :   /* The input string remaining to be parsed. */
     162                 :            :   const char *input;
     163                 :            : 
     164                 :            :   /* N, if this is the Nth Tuesday.  */
     165                 :            :   long int day_ordinal;
     166                 :            : 
     167                 :            :   /* Day of week; Sunday is 0.  */
     168                 :            :   int day_number;
     169                 :            : 
     170                 :            :   /* tm_isdst flag for the local zone.  */
     171                 :            :   int local_isdst;
     172                 :            : 
     173                 :            :   /* Time zone, in minutes east of UTC.  */
     174                 :            :   long int time_zone;
     175                 :            : 
     176                 :            :   /* Style used for time.  */
     177                 :            :   int meridian;
     178                 :            : 
     179                 :            :   /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds.  */
     180                 :            :   textint year;
     181                 :            :   long int month;
     182                 :            :   long int day;
     183                 :            :   long int hour;
     184                 :            :   long int minutes;
     185                 :            :   struct timespec seconds; /* includes nanoseconds */
     186                 :            : 
     187                 :            :   /* Relative year, month, day, hour, minutes, seconds, and nanoseconds.  */
     188                 :            :   relative_time rel;
     189                 :            : 
     190                 :            :   /* Presence or counts of nonterminals of various flavors parsed so far.  */
     191                 :            :   bool timespec_seen;
     192                 :            :   bool rels_seen;
     193                 :            :   size_t dates_seen;
     194                 :            :   size_t days_seen;
     195                 :            :   size_t local_zones_seen;
     196                 :            :   size_t dsts_seen;
     197                 :            :   size_t times_seen;
     198                 :            :   size_t zones_seen;
     199                 :            : 
     200                 :            :   /* Table of local time zone abbrevations, terminated by a null entry.  */
     201                 :            :   table local_time_zone_table[3];
     202                 :            : } parser_control;
     203                 :            : 
     204                 :            : union YYSTYPE;
     205                 :            : static int yylex (union YYSTYPE *, parser_control *);
     206                 :            : static int yyerror (parser_control const *, char const *);
     207                 :            : static long int time_zone_hhmm (parser_control *, textint, long int);
     208                 :            : 
     209                 :            : /* Extract into *PC any date and time info from a string of digits
     210                 :            :    of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY,
     211                 :            :    YYYY, ...).  */
     212                 :            : static void
     213                 :          0 : digits_to_date_time (parser_control *pc, textint text_int)
     214                 :            : {
     215 [ #  # ][ #  # ]:          0 :   if (pc->dates_seen && ! pc->year.digits
         [ #  # ][ #  # ]
                 [ #  # ]
     216                 :          0 :       && ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits))
     217                 :          0 :     pc->year = text_int;
     218                 :            :   else
     219                 :            :     {
     220         [ #  # ]:          0 :       if (4 < text_int.digits)
     221                 :            :         {
     222                 :          0 :           pc->dates_seen++;
     223                 :          0 :           pc->day = text_int.value % 100;
     224                 :          0 :           pc->month = (text_int.value / 100) % 100;
     225                 :          0 :           pc->year.value = text_int.value / 10000;
     226                 :          0 :           pc->year.digits = text_int.digits - 4;
     227                 :            :         }
     228                 :            :       else
     229                 :            :         {
     230                 :          0 :           pc->times_seen++;
     231         [ #  # ]:          0 :           if (text_int.digits <= 2)
     232                 :            :             {
     233                 :          0 :               pc->hour = text_int.value;
     234                 :          0 :               pc->minutes = 0;
     235                 :            :             }
     236                 :            :           else
     237                 :            :             {
     238                 :          0 :               pc->hour = text_int.value / 100;
     239                 :          0 :               pc->minutes = text_int.value % 100;
     240                 :            :             }
     241                 :          0 :           pc->seconds.tv_sec = 0;
     242                 :          0 :           pc->seconds.tv_nsec = 0;
     243                 :          0 :           pc->meridian = MER24;
     244                 :            :         }
     245                 :            :     }
     246                 :          0 : }
     247                 :            : 
     248                 :            : /* Increment PC->rel by FACTOR * REL (FACTOR is 1 or -1).  */
     249                 :            : static void
     250                 :          0 : apply_relative_time (parser_control *pc, relative_time rel, int factor)
     251                 :            : {
     252                 :          0 :   pc->rel.ns += factor * rel.ns;
     253                 :          0 :   pc->rel.seconds += factor * rel.seconds;
     254                 :          0 :   pc->rel.minutes += factor * rel.minutes;
     255                 :          0 :   pc->rel.hour += factor * rel.hour;
     256                 :          0 :   pc->rel.day += factor * rel.day;
     257                 :          0 :   pc->rel.month += factor * rel.month;
     258                 :          0 :   pc->rel.year += factor * rel.year;
     259                 :          0 :   pc->rels_seen = true;
     260                 :          0 : }
     261                 :            : 
     262                 :            : /* Set PC-> hour, minutes, seconds and nanoseconds members from arguments.  */
     263                 :            : static void
     264                 :          0 : set_hhmmss (parser_control *pc, long int hour, long int minutes,
     265                 :            :             time_t sec, long int nsec)
     266                 :            : {
     267                 :          0 :   pc->hour = hour;
     268                 :          0 :   pc->minutes = minutes;
     269                 :          0 :   pc->seconds.tv_sec = sec;
     270                 :          0 :   pc->seconds.tv_nsec = nsec;
     271                 :          0 : }
     272                 :            : 
     273                 :            : %}
     274                 :            : 
     275                 :            : /* We want a reentrant parser, even if the TZ manipulation and the calls to
     276                 :            :    localtime and gmtime are not reentrant.  */
     277                 :            : %pure-parser
     278                 :            : %parse-param { parser_control *pc }
     279                 :            : %lex-param { parser_control *pc }
     280                 :            : 
     281                 :            : /* This grammar has 20 shift/reduce conflicts. */
     282                 :            : %expect 20
     283                 :            : 
     284                 :            : %union
     285                 :            : {
     286                 :            :   long int intval;
     287                 :            :   textint textintval;
     288                 :            :   struct timespec timespec;
     289                 :            :   relative_time rel;
     290                 :            : }
     291                 :            : 
     292                 :            : %token tAGO tDST
     293                 :            : 
     294                 :            : %token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT
     295                 :            : %token <intval> tDAY_UNIT tDAY_SHIFT
     296                 :            : 
     297                 :            : %token <intval> tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN
     298                 :            : %token <intval> tMONTH tORDINAL tZONE
     299                 :            : 
     300                 :            : %token <textintval> tSNUMBER tUNUMBER
     301                 :            : %token <timespec> tSDECIMAL_NUMBER tUDECIMAL_NUMBER
     302                 :            : 
     303                 :            : %type <intval> o_colon_minutes o_merid
     304                 :            : %type <timespec> seconds signed_seconds unsigned_seconds
     305                 :            : 
     306                 :            : %type <rel> relunit relunit_snumber dayshift
     307                 :            : 
     308                 :            : %%
     309                 :            : 
     310                 :            : spec:
     311                 :            :     timespec
     312                 :            :   | items
     313                 :            :   ;
     314                 :            : 
     315                 :            : timespec:
     316                 :            :     '@' seconds
     317                 :            :       {
     318                 :          0 :         pc->seconds = $2;
     319                 :          0 :         pc->timespec_seen = true;
     320                 :            :       }
     321                 :          0 :   ;
     322                 :            : 
     323                 :            : items:
     324                 :            :     /* empty */
     325                 :            :   | items item
     326                 :            :   ;
     327                 :            : 
     328                 :            : item:
     329                 :            :     time
     330                 :          0 :       { pc->times_seen++; }
     331                 :          0 :   | local_zone
     332                 :          0 :       { pc->local_zones_seen++; }
     333                 :          0 :   | zone
     334                 :          0 :       { pc->zones_seen++; }
     335                 :          0 :   | date
     336                 :          0 :       { pc->dates_seen++; }
     337                 :          0 :   | day
     338                 :          0 :       { pc->days_seen++; }
     339                 :          0 :   | rel
     340                 :            :   | number
     341                 :            :   | hybrid
     342                 :            :   ;
     343                 :            : 
     344                 :            : time:
     345                 :            :     tUNUMBER tMERIDIAN
     346                 :            :       {
     347                 :          0 :         set_hhmmss (pc, $1.value, 0, 0, 0);
     348                 :          0 :         pc->meridian = $2;
     349                 :            :       }
     350                 :          0 :   | tUNUMBER ':' tUNUMBER o_merid
     351                 :            :       {
     352                 :          0 :         set_hhmmss (pc, $1.value, $3.value, 0, 0);
     353                 :          0 :         pc->meridian = $4;
     354                 :            :       }
     355                 :          0 :   | tUNUMBER ':' tUNUMBER tSNUMBER o_colon_minutes
     356                 :            :       {
     357                 :          0 :         set_hhmmss (pc, $1.value, $3.value, 0, 0);
     358                 :          0 :         pc->meridian = MER24;
     359                 :          0 :         pc->zones_seen++;
     360                 :          0 :         pc->time_zone = time_zone_hhmm (pc, $4, $5);
     361                 :            :       }
     362                 :          0 :   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_merid
     363                 :            :       {
     364                 :          0 :         set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
     365                 :          0 :         pc->meridian = $6;
     366                 :            :       }
     367                 :          0 :   | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tSNUMBER o_colon_minutes
     368                 :            :       {
     369                 :          0 :         set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec);
     370                 :          0 :         pc->meridian = MER24;
     371                 :          0 :         pc->zones_seen++;
     372                 :          0 :         pc->time_zone = time_zone_hhmm (pc, $6, $7);
     373                 :            :       }
     374                 :          0 :   ;
     375                 :            : 
     376                 :            : local_zone:
     377                 :            :     tLOCAL_ZONE
     378                 :            :       {
     379                 :          0 :         pc->local_isdst = $1;
     380                 :          0 :         pc->dsts_seen += (0 < $1);
     381                 :            :       }
     382                 :          0 :   | tLOCAL_ZONE tDST
     383                 :            :       {
     384                 :          0 :         pc->local_isdst = 1;
     385         [ #  # ]:          0 :         pc->dsts_seen += (0 < $1) + 1;
     386                 :            :       }
     387                 :          0 :   ;
     388                 :            : 
     389                 :            : zone:
     390                 :            :     tZONE
     391                 :          0 :       { pc->time_zone = $1; }
     392                 :          0 :   | tZONE relunit_snumber
     393                 :          0 :       { pc->time_zone = $1;
     394                 :          0 :         apply_relative_time (pc, $2, 1); }
     395                 :          0 :   | tZONE tSNUMBER o_colon_minutes
     396                 :          0 :       { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); }
     397                 :          0 :   | tDAYZONE
     398                 :          0 :       { pc->time_zone = $1 + 60; }
     399                 :          0 :   | tZONE tDST
     400                 :          0 :       { pc->time_zone = $1 + 60; }
     401                 :          0 :   ;
     402                 :            : 
     403                 :            : day:
     404                 :            :     tDAY
     405                 :            :       {
     406                 :          0 :         pc->day_ordinal = 0;
     407                 :          0 :         pc->day_number = $1;
     408                 :            :       }
     409                 :          0 :   | tDAY ','
     410                 :            :       {
     411                 :          0 :         pc->day_ordinal = 0;
     412                 :          0 :         pc->day_number = $1;
     413                 :            :       }
     414                 :          0 :   | tORDINAL tDAY
     415                 :            :       {
     416                 :          0 :         pc->day_ordinal = $1;
     417                 :          0 :         pc->day_number = $2;
     418                 :            :       }
     419                 :          0 :   | tUNUMBER tDAY
     420                 :            :       {
     421                 :          0 :         pc->day_ordinal = $1.value;
     422                 :          0 :         pc->day_number = $2;
     423                 :            :       }
     424                 :          0 :   ;
     425                 :            : 
     426                 :            : date:
     427                 :            :     tUNUMBER '/' tUNUMBER
     428                 :            :       {
     429                 :          0 :         pc->month = $1.value;
     430                 :          0 :         pc->day = $3.value;
     431                 :            :       }
     432                 :          0 :   | tUNUMBER '/' tUNUMBER '/' tUNUMBER
     433                 :            :       {
     434                 :            :         /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
     435                 :            :            otherwise as MM/DD/YY.
     436                 :            :            The goal in recognizing YYYY/MM/DD is solely to support legacy
     437                 :            :            machine-generated dates like those in an RCS log listing.  If
     438                 :            :            you want portability, use the ISO 8601 format.  */
     439         [ #  # ]:          0 :         if (4 <= $1.digits)
     440                 :            :           {
     441                 :          0 :             pc->year = $1;
     442                 :          0 :             pc->month = $3.value;
     443                 :          0 :             pc->day = $5.value;
     444                 :            :           }
     445                 :            :         else
     446                 :            :           {
     447                 :          0 :             pc->month = $1.value;
     448                 :          0 :             pc->day = $3.value;
     449                 :          0 :             pc->year = $5;
     450                 :            :           }
     451                 :            :       }
     452                 :          0 :   | tUNUMBER tSNUMBER tSNUMBER
     453                 :            :       {
     454                 :            :         /* ISO 8601 format.  YYYY-MM-DD.  */
     455                 :          0 :         pc->year = $1;
     456                 :          0 :         pc->month = -$2.value;
     457                 :          0 :         pc->day = -$3.value;
     458                 :            :       }
     459                 :          0 :   | tUNUMBER tMONTH tSNUMBER
     460                 :            :       {
     461                 :            :         /* e.g. 17-JUN-1992.  */
     462                 :          0 :         pc->day = $1.value;
     463                 :          0 :         pc->month = $2;
     464                 :          0 :         pc->year.value = -$3.value;
     465                 :          0 :         pc->year.digits = $3.digits;
     466                 :            :       }
     467                 :          0 :   | tMONTH tSNUMBER tSNUMBER
     468                 :            :       {
     469                 :            :         /* e.g. JUN-17-1992.  */
     470                 :          0 :         pc->month = $1;
     471                 :          0 :         pc->day = -$2.value;
     472                 :          0 :         pc->year.value = -$3.value;
     473                 :          0 :         pc->year.digits = $3.digits;
     474                 :            :       }
     475                 :          0 :   | tMONTH tUNUMBER
     476                 :            :       {
     477                 :          0 :         pc->month = $1;
     478                 :          0 :         pc->day = $2.value;
     479                 :            :       }
     480                 :          0 :   | tMONTH tUNUMBER ',' tUNUMBER
     481                 :            :       {
     482                 :          0 :         pc->month = $1;
     483                 :          0 :         pc->day = $2.value;
     484                 :          0 :         pc->year = $4;
     485                 :            :       }
     486                 :          0 :   | tUNUMBER tMONTH
     487                 :            :       {
     488                 :          0 :         pc->day = $1.value;
     489                 :          0 :         pc->month = $2;
     490                 :            :       }
     491                 :          0 :   | tUNUMBER tMONTH tUNUMBER
     492                 :            :       {
     493                 :          0 :         pc->day = $1.value;
     494                 :          0 :         pc->month = $2;
     495                 :          0 :         pc->year = $3;
     496                 :            :       }
     497                 :          0 :   ;
     498                 :            : 
     499                 :            : rel:
     500                 :            :     relunit tAGO
     501                 :          0 :       { apply_relative_time (pc, $1, -1); }
     502                 :          0 :   | relunit
     503                 :          0 :       { apply_relative_time (pc, $1, 1); }
     504                 :          0 :   | dayshift
     505                 :          0 :       { apply_relative_time (pc, $1, 1); }
     506                 :          0 :   ;
     507                 :            : 
     508                 :            : relunit:
     509                 :            :     tORDINAL tYEAR_UNIT
     510                 :          0 :       { $$ = RELATIVE_TIME_0; $$.year = $1; }
     511                 :          0 :   | tUNUMBER tYEAR_UNIT
     512                 :          0 :       { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
     513                 :          0 :   | tYEAR_UNIT
     514                 :          0 :       { $$ = RELATIVE_TIME_0; $$.year = 1; }
     515                 :          0 :   | tORDINAL tMONTH_UNIT
     516                 :          0 :       { $$ = RELATIVE_TIME_0; $$.month = $1; }
     517                 :          0 :   | tUNUMBER tMONTH_UNIT
     518                 :          0 :       { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
     519                 :          0 :   | tMONTH_UNIT
     520                 :          0 :       { $$ = RELATIVE_TIME_0; $$.month = 1; }
     521                 :          0 :   | tORDINAL tDAY_UNIT
     522                 :          0 :       { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; }
     523                 :          0 :   | tUNUMBER tDAY_UNIT
     524                 :          0 :       { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
     525                 :          0 :   | tDAY_UNIT
     526                 :          0 :       { $$ = RELATIVE_TIME_0; $$.day = $1; }
     527                 :          0 :   | tORDINAL tHOUR_UNIT
     528                 :          0 :       { $$ = RELATIVE_TIME_0; $$.hour = $1; }
     529                 :          0 :   | tUNUMBER tHOUR_UNIT
     530                 :          0 :       { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
     531                 :          0 :   | tHOUR_UNIT
     532                 :          0 :       { $$ = RELATIVE_TIME_0; $$.hour = 1; }
     533                 :          0 :   | tORDINAL tMINUTE_UNIT
     534                 :          0 :       { $$ = RELATIVE_TIME_0; $$.minutes = $1; }
     535                 :          0 :   | tUNUMBER tMINUTE_UNIT
     536                 :          0 :       { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
     537                 :          0 :   | tMINUTE_UNIT
     538                 :          0 :       { $$ = RELATIVE_TIME_0; $$.minutes = 1; }
     539                 :          0 :   | tORDINAL tSEC_UNIT
     540                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = $1; }
     541                 :          0 :   | tUNUMBER tSEC_UNIT
     542                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
     543                 :          0 :   | tSDECIMAL_NUMBER tSEC_UNIT
     544                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
     545                 :          0 :   | tUDECIMAL_NUMBER tSEC_UNIT
     546                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; }
     547                 :          0 :   | tSEC_UNIT
     548                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = 1; }
     549                 :          0 :   | relunit_snumber
     550                 :            :   ;
     551                 :            : 
     552                 :            : relunit_snumber:
     553                 :            :     tSNUMBER tYEAR_UNIT
     554                 :          0 :       { $$ = RELATIVE_TIME_0; $$.year = $1.value; }
     555                 :          0 :   | tSNUMBER tMONTH_UNIT
     556                 :          0 :       { $$ = RELATIVE_TIME_0; $$.month = $1.value; }
     557                 :          0 :   | tSNUMBER tDAY_UNIT
     558                 :          0 :       { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; }
     559                 :          0 :   | tSNUMBER tHOUR_UNIT
     560                 :          0 :       { $$ = RELATIVE_TIME_0; $$.hour = $1.value; }
     561                 :          0 :   | tSNUMBER tMINUTE_UNIT
     562                 :          0 :       { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; }
     563                 :          0 :   | tSNUMBER tSEC_UNIT
     564                 :          0 :       { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; }
     565                 :          0 :   ;
     566                 :            : 
     567                 :            : dayshift:
     568                 :            :     tDAY_SHIFT
     569                 :          0 :       { $$ = RELATIVE_TIME_0; $$.day = $1; }
     570                 :          0 :   ;
     571                 :            : 
     572                 :            : seconds: signed_seconds | unsigned_seconds;
     573                 :            : 
     574                 :            : signed_seconds:
     575                 :            :     tSDECIMAL_NUMBER
     576                 :            :   | tSNUMBER
     577                 :          0 :       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
     578                 :          0 :   ;
     579                 :            : 
     580                 :            : unsigned_seconds:
     581                 :            :     tUDECIMAL_NUMBER
     582                 :            :   | tUNUMBER
     583                 :          0 :       { $$.tv_sec = $1.value; $$.tv_nsec = 0; }
     584                 :          0 :   ;
     585                 :            : 
     586                 :            : number:
     587                 :            :     tUNUMBER
     588                 :          0 :       { digits_to_date_time (pc, $1); }
     589                 :          0 :   ;
     590                 :            : 
     591                 :            : hybrid:
     592                 :            :     tUNUMBER relunit_snumber
     593                 :            :       {
     594                 :            :         /* Hybrid all-digit and relative offset, so that we accept e.g.,
     595                 :            :            "YYYYMMDD +N days" as well as "YYYYMMDD N days".  */
     596                 :          0 :         digits_to_date_time (pc, $1);
     597                 :          0 :         apply_relative_time (pc, $2, 1);
     598                 :            :       }
     599                 :          0 :   ;
     600                 :            : 
     601                 :            : o_colon_minutes:
     602                 :            :     /* empty */
     603                 :          0 :       { $$ = -1; }
     604                 :          0 :   | ':' tUNUMBER
     605                 :          0 :       { $$ = $2.value; }
     606                 :          0 :   ;
     607                 :            : 
     608                 :            : o_merid:
     609                 :            :     /* empty */
     610                 :          0 :       { $$ = MER24; }
     611                 :          0 :   | tMERIDIAN
     612                 :          0 :       { $$ = $1; }
     613                 :            :   ;
     614                 :            : 
     615                 :            : %%
     616                 :            : 
     617                 :            : static table const meridian_table[] =
     618                 :            : {
     619                 :            :   { "AM",   tMERIDIAN, MERam },
     620                 :            :   { "A.M.", tMERIDIAN, MERam },
     621                 :            :   { "PM",   tMERIDIAN, MERpm },
     622                 :            :   { "P.M.", tMERIDIAN, MERpm },
     623                 :            :   { NULL, 0, 0 }
     624                 :            : };
     625                 :            : 
     626                 :            : static table const dst_table[] =
     627                 :            : {
     628                 :            :   { "DST", tDST, 0 }
     629                 :            : };
     630                 :            : 
     631                 :            : static table const month_and_day_table[] =
     632                 :            : {
     633                 :            :   { "JANUARY",  tMONTH,  1 },
     634                 :            :   { "FEBRUARY", tMONTH,  2 },
     635                 :            :   { "MARCH",    tMONTH,  3 },
     636                 :            :   { "APRIL",    tMONTH,  4 },
     637                 :            :   { "MAY",      tMONTH,  5 },
     638                 :            :   { "JUNE",     tMONTH,  6 },
     639                 :            :   { "JULY",     tMONTH,  7 },
     640                 :            :   { "AUGUST",   tMONTH,  8 },
     641                 :            :   { "SEPTEMBER",tMONTH,  9 },
     642                 :            :   { "SEPT",     tMONTH,  9 },
     643                 :            :   { "OCTOBER",  tMONTH, 10 },
     644                 :            :   { "NOVEMBER", tMONTH, 11 },
     645                 :            :   { "DECEMBER", tMONTH, 12 },
     646                 :            :   { "SUNDAY",   tDAY,    0 },
     647                 :            :   { "MONDAY",   tDAY,    1 },
     648                 :            :   { "TUESDAY",  tDAY,    2 },
     649                 :            :   { "TUES",     tDAY,    2 },
     650                 :            :   { "WEDNESDAY",tDAY,    3 },
     651                 :            :   { "WEDNES",   tDAY,    3 },
     652                 :            :   { "THURSDAY", tDAY,    4 },
     653                 :            :   { "THUR",     tDAY,    4 },
     654                 :            :   { "THURS",    tDAY,    4 },
     655                 :            :   { "FRIDAY",   tDAY,    5 },
     656                 :            :   { "SATURDAY", tDAY,    6 },
     657                 :            :   { NULL, 0, 0 }
     658                 :            : };
     659                 :            : 
     660                 :            : static table const time_units_table[] =
     661                 :            : {
     662                 :            :   { "YEAR",     tYEAR_UNIT,      1 },
     663                 :            :   { "MONTH",    tMONTH_UNIT,     1 },
     664                 :            :   { "FORTNIGHT",tDAY_UNIT,      14 },
     665                 :            :   { "WEEK",     tDAY_UNIT,       7 },
     666                 :            :   { "DAY",      tDAY_UNIT,       1 },
     667                 :            :   { "HOUR",     tHOUR_UNIT,      1 },
     668                 :            :   { "MINUTE",   tMINUTE_UNIT,    1 },
     669                 :            :   { "MIN",      tMINUTE_UNIT,    1 },
     670                 :            :   { "SECOND",   tSEC_UNIT,       1 },
     671                 :            :   { "SEC",      tSEC_UNIT,       1 },
     672                 :            :   { NULL, 0, 0 }
     673                 :            : };
     674                 :            : 
     675                 :            : /* Assorted relative-time words. */
     676                 :            : static table const relative_time_table[] =
     677                 :            : {
     678                 :            :   { "TOMORROW", tDAY_SHIFT,      1 },
     679                 :            :   { "YESTERDAY",tDAY_SHIFT,     -1 },
     680                 :            :   { "TODAY",    tDAY_SHIFT,      0 },
     681                 :            :   { "NOW",      tDAY_SHIFT,      0 },
     682                 :            :   { "LAST",     tORDINAL,       -1 },
     683                 :            :   { "THIS",     tORDINAL,        0 },
     684                 :            :   { "NEXT",     tORDINAL,        1 },
     685                 :            :   { "FIRST",    tORDINAL,        1 },
     686                 :            : /*{ "SECOND",   tORDINAL,        2 }, */
     687                 :            :   { "THIRD",    tORDINAL,        3 },
     688                 :            :   { "FOURTH",   tORDINAL,        4 },
     689                 :            :   { "FIFTH",    tORDINAL,        5 },
     690                 :            :   { "SIXTH",    tORDINAL,        6 },
     691                 :            :   { "SEVENTH",  tORDINAL,        7 },
     692                 :            :   { "EIGHTH",   tORDINAL,        8 },
     693                 :            :   { "NINTH",    tORDINAL,        9 },
     694                 :            :   { "TENTH",    tORDINAL,       10 },
     695                 :            :   { "ELEVENTH", tORDINAL,       11 },
     696                 :            :   { "TWELFTH",  tORDINAL,       12 },
     697                 :            :   { "AGO",      tAGO,            1 },
     698                 :            :   { NULL, 0, 0 }
     699                 :            : };
     700                 :            : 
     701                 :            : /* The universal time zone table.  These labels can be used even for
     702                 :            :    time stamps that would not otherwise be valid, e.g., GMT time
     703                 :            :    stamps in London during summer.  */
     704                 :            : static table const universal_time_zone_table[] =
     705                 :            : {
     706                 :            :   { "GMT",      tZONE,     HOUR ( 0) }, /* Greenwich Mean */
     707                 :            :   { "UT",       tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
     708                 :            :   { "UTC",      tZONE,     HOUR ( 0) },
     709                 :            :   { NULL, 0, 0 }
     710                 :            : };
     711                 :            : 
     712                 :            : /* The time zone table.  This table is necessarily incomplete, as time
     713                 :            :    zone abbreviations are ambiguous; e.g. Australians interpret "EST"
     714                 :            :    as Eastern time in Australia, not as US Eastern Standard Time.
     715                 :            :    You cannot rely on getdate to handle arbitrary time zone
     716                 :            :    abbreviations; use numeric abbreviations like `-0500' instead.  */
     717                 :            : static table const time_zone_table[] =
     718                 :            : {
     719                 :            :   { "WET",      tZONE,     HOUR ( 0) }, /* Western European */
     720                 :            :   { "WEST",     tDAYZONE,  HOUR ( 0) }, /* Western European Summer */
     721                 :            :   { "BST",      tDAYZONE,  HOUR ( 0) }, /* British Summer */
     722                 :            :   { "ART",      tZONE,    -HOUR ( 3) }, /* Argentina */
     723                 :            :   { "BRT",      tZONE,    -HOUR ( 3) }, /* Brazil */
     724                 :            :   { "BRST",     tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
     725                 :            :   { "NST",      tZONE,   -(HOUR ( 3) + 30) },   /* Newfoundland Standard */
     726                 :            :   { "NDT",      tDAYZONE,-(HOUR ( 3) + 30) },   /* Newfoundland Daylight */
     727                 :            :   { "AST",      tZONE,    -HOUR ( 4) }, /* Atlantic Standard */
     728                 :            :   { "ADT",      tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
     729                 :            :   { "CLT",      tZONE,    -HOUR ( 4) }, /* Chile */
     730                 :            :   { "CLST",     tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
     731                 :            :   { "EST",      tZONE,    -HOUR ( 5) }, /* Eastern Standard */
     732                 :            :   { "EDT",      tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
     733                 :            :   { "CST",      tZONE,    -HOUR ( 6) }, /* Central Standard */
     734                 :            :   { "CDT",      tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
     735                 :            :   { "MST",      tZONE,    -HOUR ( 7) }, /* Mountain Standard */
     736                 :            :   { "MDT",      tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
     737                 :            :   { "PST",      tZONE,    -HOUR ( 8) }, /* Pacific Standard */
     738                 :            :   { "PDT",      tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
     739                 :            :   { "AKST",     tZONE,    -HOUR ( 9) }, /* Alaska Standard */
     740                 :            :   { "AKDT",     tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
     741                 :            :   { "HST",      tZONE,    -HOUR (10) }, /* Hawaii Standard */
     742                 :            :   { "HAST",     tZONE,    -HOUR (10) }, /* Hawaii-Aleutian Standard */
     743                 :            :   { "HADT",     tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
     744                 :            :   { "SST",      tZONE,    -HOUR (12) }, /* Samoa Standard */
     745                 :            :   { "WAT",      tZONE,     HOUR ( 1) }, /* West Africa */
     746                 :            :   { "CET",      tZONE,     HOUR ( 1) }, /* Central European */
     747                 :            :   { "CEST",     tDAYZONE,  HOUR ( 1) }, /* Central European Summer */
     748                 :            :   { "MET",      tZONE,     HOUR ( 1) }, /* Middle European */
     749                 :            :   { "MEZ",      tZONE,     HOUR ( 1) }, /* Middle European */
     750                 :            :   { "MEST",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
     751                 :            :   { "MESZ",     tDAYZONE,  HOUR ( 1) }, /* Middle European Summer */
     752                 :            :   { "EET",      tZONE,     HOUR ( 2) }, /* Eastern European */
     753                 :            :   { "EEST",     tDAYZONE,  HOUR ( 2) }, /* Eastern European Summer */
     754                 :            :   { "CAT",      tZONE,     HOUR ( 2) }, /* Central Africa */
     755                 :            :   { "SAST",     tZONE,     HOUR ( 2) }, /* South Africa Standard */
     756                 :            :   { "EAT",      tZONE,     HOUR ( 3) }, /* East Africa */
     757                 :            :   { "MSK",      tZONE,     HOUR ( 3) }, /* Moscow */
     758                 :            :   { "MSD",      tDAYZONE,  HOUR ( 3) }, /* Moscow Daylight */
     759                 :            :   { "IST",      tZONE,    (HOUR ( 5) + 30) },   /* India Standard */
     760                 :            :   { "SGT",      tZONE,     HOUR ( 8) }, /* Singapore */
     761                 :            :   { "KST",      tZONE,     HOUR ( 9) }, /* Korea Standard */
     762                 :            :   { "JST",      tZONE,     HOUR ( 9) }, /* Japan Standard */
     763                 :            :   { "GST",      tZONE,     HOUR (10) }, /* Guam Standard */
     764                 :            :   { "NZST",     tZONE,     HOUR (12) }, /* New Zealand Standard */
     765                 :            :   { "NZDT",     tDAYZONE,  HOUR (12) }, /* New Zealand Daylight */
     766                 :            :   { NULL, 0, 0 }
     767                 :            : };
     768                 :            : 
     769                 :            : /* Military time zone table. */
     770                 :            : static table const military_table[] =
     771                 :            : {
     772                 :            :   { "A", tZONE, -HOUR ( 1) },
     773                 :            :   { "B", tZONE, -HOUR ( 2) },
     774                 :            :   { "C", tZONE, -HOUR ( 3) },
     775                 :            :   { "D", tZONE, -HOUR ( 4) },
     776                 :            :   { "E", tZONE, -HOUR ( 5) },
     777                 :            :   { "F", tZONE, -HOUR ( 6) },
     778                 :            :   { "G", tZONE, -HOUR ( 7) },
     779                 :            :   { "H", tZONE, -HOUR ( 8) },
     780                 :            :   { "I", tZONE, -HOUR ( 9) },
     781                 :            :   { "K", tZONE, -HOUR (10) },
     782                 :            :   { "L", tZONE, -HOUR (11) },
     783                 :            :   { "M", tZONE, -HOUR (12) },
     784                 :            :   { "N", tZONE,  HOUR ( 1) },
     785                 :            :   { "O", tZONE,  HOUR ( 2) },
     786                 :            :   { "P", tZONE,  HOUR ( 3) },
     787                 :            :   { "Q", tZONE,  HOUR ( 4) },
     788                 :            :   { "R", tZONE,  HOUR ( 5) },
     789                 :            :   { "S", tZONE,  HOUR ( 6) },
     790                 :            :   { "T", tZONE,  HOUR ( 7) },
     791                 :            :   { "U", tZONE,  HOUR ( 8) },
     792                 :            :   { "V", tZONE,  HOUR ( 9) },
     793                 :            :   { "W", tZONE,  HOUR (10) },
     794                 :            :   { "X", tZONE,  HOUR (11) },
     795                 :            :   { "Y", tZONE,  HOUR (12) },
     796                 :            :   { "Z", tZONE,  HOUR ( 0) },
     797                 :            :   { NULL, 0, 0 }
     798                 :            : };
     799                 :            : 
     800                 :            : 
     801                 :            : 
     802                 :            : /* Convert a time zone expressed as HH:MM into an integer count of
     803                 :            :    minutes.  If MM is negative, then S is of the form HHMM and needs
     804                 :            :    to be picked apart; otherwise, S is of the form HH.  As specified in
     805                 :            :    http://www.opengroup.org/susv3xbd/xbd_chap08.html#tag_08_03, allow
     806                 :            :    only valid TZ range, and consider first two digits as hours, if no
     807                 :            :    minutes specified.  */
     808                 :            : 
     809                 :            : static long int
     810                 :          0 : time_zone_hhmm (parser_control *pc, textint s, long int mm)
     811                 :            : {
     812                 :            :   long int n_minutes;
     813                 :            : 
     814                 :            :   /* If the length of S is 1 or 2 and no minutes are specified,
     815                 :            :      interpret it as a number of hours.  */
     816 [ #  # ][ #  # ]:          0 :   if (s.digits <= 2 && mm < 0)
     817                 :          0 :     s.value *= 100;
     818                 :            : 
     819         [ #  # ]:          0 :   if (mm < 0)
     820                 :          0 :     n_minutes = (s.value / 100) * 60 + s.value % 100;
     821                 :            :   else
     822         [ #  # ]:          0 :     n_minutes = s.value * 60 + (s.negative ? -mm : mm);
     823                 :            : 
     824                 :            :   /* If the absolute number of minutes is larger than 24 hours,
     825                 :            :      arrange to reject it by incrementing pc->zones_seen.  Thus,
     826                 :            :      we allow only values in the range UTC-24:00 to UTC+24:00.  */
     827         [ #  # ]:          0 :   if (24 * 60 < abs (n_minutes))
     828                 :          0 :     pc->zones_seen++;
     829                 :            : 
     830                 :          0 :   return n_minutes;
     831                 :            : }
     832                 :            : 
     833                 :            : static int
     834                 :          0 : to_hour (long int hours, int meridian)
     835                 :            : {
     836      [ #  #  # ]:          0 :   switch (meridian)
     837                 :            :     {
     838                 :            :     default: /* Pacify GCC.  */
     839                 :            :     case MER24:
     840 [ #  # ][ #  # ]:          0 :       return 0 <= hours && hours < 24 ? hours : -1;
     841                 :            :     case MERam:
     842 [ #  # ][ #  # ]:          0 :       return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
                 [ #  # ]
     843                 :            :     case MERpm:
     844 [ #  # ][ #  # ]:          0 :       return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
                 [ #  # ]
     845                 :            :     }
     846                 :            : }
     847                 :            : 
     848                 :            : static long int
     849                 :          0 : to_year (textint textyear)
     850                 :            : {
     851                 :          0 :   long int year = textyear.value;
     852                 :            : 
     853         [ #  # ]:          0 :   if (year < 0)
     854                 :          0 :     year = -year;
     855                 :            : 
     856                 :            :   /* XPG4 suggests that years 00-68 map to 2000-2068, and
     857                 :            :      years 69-99 map to 1969-1999.  */
     858         [ #  # ]:          0 :   else if (textyear.digits == 2)
     859         [ #  # ]:          0 :     year += year < 69 ? 2000 : 1900;
     860                 :            : 
     861                 :          0 :   return year;
     862                 :            : }
     863                 :            : 
     864                 :            : static table const *
     865                 :          0 : lookup_zone (parser_control const *pc, char const *name)
     866                 :            : {
     867                 :            :   table const *tp;
     868                 :            : 
     869         [ #  # ]:          0 :   for (tp = universal_time_zone_table; tp->name; tp++)
     870         [ #  # ]:          0 :     if (strcmp (name, tp->name) == 0)
     871                 :          0 :       return tp;
     872                 :            : 
     873                 :            :   /* Try local zone abbreviations before those in time_zone_table, as
     874                 :            :      the local ones are more likely to be right.  */
     875         [ #  # ]:          0 :   for (tp = pc->local_time_zone_table; tp->name; tp++)
     876         [ #  # ]:          0 :     if (strcmp (name, tp->name) == 0)
     877                 :          0 :       return tp;
     878                 :            : 
     879         [ #  # ]:          0 :   for (tp = time_zone_table; tp->name; tp++)
     880         [ #  # ]:          0 :     if (strcmp (name, tp->name) == 0)
     881                 :          0 :       return tp;
     882                 :            : 
     883                 :          0 :   return NULL;
     884                 :            : }
     885                 :            : 
     886                 :            : #if ! HAVE_TM_GMTOFF
     887                 :            : /* Yield the difference between *A and *B,
     888                 :            :    measured in seconds, ignoring leap seconds.
     889                 :            :    The body of this function is taken directly from the GNU C Library;
     890                 :            :    see src/strftime.c.  */
     891                 :            : static long int
     892                 :            : tm_diff (struct tm const *a, struct tm const *b)
     893                 :            : {
     894                 :            :   /* Compute intervening leap days correctly even if year is negative.
     895                 :            :      Take care to avoid int overflow in leap day calculations.  */
     896                 :            :   int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
     897                 :            :   int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
     898                 :            :   int a100 = a4 / 25 - (a4 % 25 < 0);
     899                 :            :   int b100 = b4 / 25 - (b4 % 25 < 0);
     900                 :            :   int a400 = SHR (a100, 2);
     901                 :            :   int b400 = SHR (b100, 2);
     902                 :            :   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
     903                 :            :   long int ayear = a->tm_year;
     904                 :            :   long int years = ayear - b->tm_year;
     905                 :            :   long int days = (365 * years + intervening_leap_days
     906                 :            :                    + (a->tm_yday - b->tm_yday));
     907                 :            :   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
     908                 :            :                 + (a->tm_min - b->tm_min))
     909                 :            :           + (a->tm_sec - b->tm_sec));
     910                 :            : }
     911                 :            : #endif /* ! HAVE_TM_GMTOFF */
     912                 :            : 
     913                 :            : static table const *
     914                 :          0 : lookup_word (parser_control const *pc, char *word)
     915                 :            : {
     916                 :            :   char *p;
     917                 :            :   char *q;
     918                 :            :   size_t wordlen;
     919                 :            :   table const *tp;
     920                 :            :   bool period_found;
     921                 :            :   bool abbrev;
     922                 :            : 
     923                 :            :   /* Make it uppercase.  */
     924         [ #  # ]:          0 :   for (p = word; *p; p++)
     925                 :            :     {
     926                 :          0 :       unsigned char ch = *p;
     927                 :          0 :       *p = c_toupper (ch);
     928                 :            :     }
     929                 :            : 
     930         [ #  # ]:          0 :   for (tp = meridian_table; tp->name; tp++)
     931         [ #  # ]:          0 :     if (strcmp (word, tp->name) == 0)
     932                 :          0 :       return tp;
     933                 :            : 
     934                 :            :   /* See if we have an abbreviation for a month. */
     935                 :          0 :   wordlen = strlen (word);
     936 [ #  # ][ #  # ]:          0 :   abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
                 [ #  # ]
     937                 :            : 
     938         [ #  # ]:          0 :   for (tp = month_and_day_table; tp->name; tp++)
     939 [ #  # ][ #  # ]:          0 :     if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
     940                 :          0 :       return tp;
     941                 :            : 
     942         [ #  # ]:          0 :   if ((tp = lookup_zone (pc, word)))
     943                 :          0 :     return tp;
     944                 :            : 
     945         [ #  # ]:          0 :   if (strcmp (word, dst_table[0].name) == 0)
     946                 :          0 :     return dst_table;
     947                 :            : 
     948         [ #  # ]:          0 :   for (tp = time_units_table; tp->name; tp++)
     949         [ #  # ]:          0 :     if (strcmp (word, tp->name) == 0)
     950                 :          0 :       return tp;
     951                 :            : 
     952                 :            :   /* Strip off any plural and try the units table again. */
     953         [ #  # ]:          0 :   if (word[wordlen - 1] == 'S')
     954                 :            :     {
     955                 :          0 :       word[wordlen - 1] = '\0';
     956         [ #  # ]:          0 :       for (tp = time_units_table; tp->name; tp++)
     957         [ #  # ]:          0 :         if (strcmp (word, tp->name) == 0)
     958                 :          0 :           return tp;
     959                 :          0 :       word[wordlen - 1] = 'S';  /* For "this" in relative_time_table.  */
     960                 :            :     }
     961                 :            : 
     962         [ #  # ]:          0 :   for (tp = relative_time_table; tp->name; tp++)
     963         [ #  # ]:          0 :     if (strcmp (word, tp->name) == 0)
     964                 :          0 :       return tp;
     965                 :            : 
     966                 :            :   /* Military time zones. */
     967         [ #  # ]:          0 :   if (wordlen == 1)
     968         [ #  # ]:          0 :     for (tp = military_table; tp->name; tp++)
     969         [ #  # ]:          0 :       if (word[0] == tp->name[0])
     970                 :          0 :         return tp;
     971                 :            : 
     972                 :            :   /* Drop out any periods and try the time zone table again. */
     973         [ #  # ]:          0 :   for (period_found = false, p = q = word; (*p = *q); q++)
     974         [ #  # ]:          0 :     if (*q == '.')
     975                 :          0 :       period_found = true;
     976                 :            :     else
     977                 :          0 :       p++;
     978 [ #  # ][ #  # ]:          0 :   if (period_found && (tp = lookup_zone (pc, word)))
     979                 :          0 :     return tp;
     980                 :            : 
     981                 :          0 :   return NULL;
     982                 :            : }
     983                 :            : 
     984                 :            : static int
     985                 :          0 : yylex (YYSTYPE *lvalp, parser_control *pc)
     986                 :            : {
     987                 :            :   unsigned char c;
     988                 :            :   size_t count;
     989                 :            : 
     990                 :            :   for (;;)
     991                 :            :     {
     992         [ #  # ]:          0 :       while (c = *pc->input, c_isspace (c))
     993                 :          0 :         pc->input++;
     994                 :            : 
     995 [ #  # ][ #  # ]:          0 :       if (ISDIGIT (c) || c == '-' || c == '+')
                 [ #  # ]
     996                 :            :         {
     997                 :            :           char const *p;
     998                 :            :           int sign;
     999                 :            :           unsigned long int value;
    1000 [ #  # ][ #  # ]:          0 :           if (c == '-' || c == '+')
    1001                 :            :             {
    1002         [ #  # ]:          0 :               sign = c == '-' ? -1 : 1;
    1003         [ #  # ]:          0 :               while (c = *++pc->input, c_isspace (c))
    1004                 :          0 :                 continue;
    1005         [ #  # ]:          0 :               if (! ISDIGIT (c))
    1006                 :            :                 /* skip the '-' sign */
    1007                 :          0 :                 continue;
    1008                 :            :             }
    1009                 :            :           else
    1010                 :          0 :             sign = 0;
    1011                 :          0 :           p = pc->input;
    1012                 :          0 :           for (value = 0; ; value *= 10)
    1013                 :            :             {
    1014                 :          0 :               unsigned long int value1 = value + (c - '0');
    1015         [ #  # ]:          0 :               if (value1 < value)
    1016                 :          0 :                 return '?';
    1017                 :          0 :               value = value1;
    1018                 :          0 :               c = *++p;
    1019         [ #  # ]:          0 :               if (! ISDIGIT (c))
    1020                 :            :                 break;
    1021         [ #  # ]:          0 :               if (ULONG_MAX / 10 < value)
    1022                 :          0 :                 return '?';
    1023                 :          0 :             }
    1024 [ #  # ][ #  # ]:          0 :           if ((c == '.' || c == ',') && ISDIGIT (p[1]))
                 [ #  # ]
    1025                 :            :             {
    1026                 :            :               time_t s;
    1027                 :            :               int ns;
    1028                 :            :               int digits;
    1029                 :            :               unsigned long int value1;
    1030                 :            : 
    1031                 :            :               /* Check for overflow when converting value to time_t.  */
    1032         [ #  # ]:          0 :               if (sign < 0)
    1033                 :            :                 {
    1034                 :          0 :                   s = - value;
    1035         [ #  # ]:          0 :                   if (0 < s)
    1036                 :          0 :                     return '?';
    1037                 :          0 :                   value1 = -s;
    1038                 :            :                 }
    1039                 :            :               else
    1040                 :            :                 {
    1041                 :          0 :                   s = value;
    1042         [ #  # ]:          0 :                   if (s < 0)
    1043                 :          0 :                     return '?';
    1044                 :          0 :                   value1 = s;
    1045                 :            :                 }
    1046         [ #  # ]:          0 :               if (value != value1)
    1047                 :          0 :                 return '?';
    1048                 :            : 
    1049                 :            :               /* Accumulate fraction, to ns precision.  */
    1050                 :          0 :               p++;
    1051                 :          0 :               ns = *p++ - '0';
    1052         [ #  # ]:          0 :               for (digits = 2; digits <= LOG10_BILLION; digits++)
    1053                 :            :                 {
    1054                 :          0 :                   ns *= 10;
    1055         [ #  # ]:          0 :                   if (ISDIGIT (*p))
    1056                 :          0 :                     ns += *p++ - '0';
    1057                 :            :                 }
    1058                 :            : 
    1059                 :            :               /* Skip excess digits, truncating toward -Infinity.  */
    1060         [ #  # ]:          0 :               if (sign < 0)
    1061         [ #  # ]:          0 :                 for (; ISDIGIT (*p); p++)
    1062         [ #  # ]:          0 :                   if (*p != '0')
    1063                 :            :                     {
    1064                 :          0 :                       ns++;
    1065                 :          0 :                       break;
    1066                 :            :                     }
    1067         [ #  # ]:          0 :               while (ISDIGIT (*p))
    1068                 :          0 :                 p++;
    1069                 :            : 
    1070                 :            :               /* Adjust to the timespec convention, which is that
    1071                 :            :                  tv_nsec is always a positive offset even if tv_sec is
    1072                 :            :                  negative.  */
    1073 [ #  # ][ #  # ]:          0 :               if (sign < 0 && ns)
    1074                 :            :                 {
    1075                 :          0 :                   s--;
    1076         [ #  # ]:          0 :                   if (! (s < 0))
    1077                 :          0 :                     return '?';
    1078                 :          0 :                   ns = BILLION - ns;
    1079                 :            :                 }
    1080                 :            : 
    1081                 :          0 :               lvalp->timespec.tv_sec = s;
    1082                 :          0 :               lvalp->timespec.tv_nsec = ns;
    1083                 :          0 :               pc->input = p;
    1084         [ #  # ]:          0 :               return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER;
    1085                 :            :             }
    1086                 :            :           else
    1087                 :            :             {
    1088                 :          0 :               lvalp->textintval.negative = sign < 0;
    1089         [ #  # ]:          0 :               if (sign < 0)
    1090                 :            :                 {
    1091                 :          0 :                   lvalp->textintval.value = - value;
    1092         [ #  # ]:          0 :                   if (0 < lvalp->textintval.value)
    1093                 :          0 :                     return '?';
    1094                 :            :                 }
    1095                 :            :               else
    1096                 :            :                 {
    1097                 :          0 :                   lvalp->textintval.value = value;
    1098         [ #  # ]:          0 :                   if (lvalp->textintval.value < 0)
    1099                 :          0 :                     return '?';
    1100                 :            :                 }
    1101                 :          0 :               lvalp->textintval.digits = p - pc->input;
    1102                 :          0 :               pc->input = p;
    1103         [ #  # ]:          0 :               return sign ? tSNUMBER : tUNUMBER;
    1104                 :            :             }
    1105                 :            :         }
    1106                 :            : 
    1107         [ #  # ]:          0 :       if (c_isalpha (c))
    1108                 :            :         {
    1109                 :            :           char buff[20];
    1110                 :          0 :           char *p = buff;
    1111                 :            :           table const *tp;
    1112                 :            : 
    1113                 :            :           do
    1114                 :            :             {
    1115         [ #  # ]:          0 :               if (p < buff + sizeof buff - 1)
    1116                 :          0 :                 *p++ = c;
    1117                 :          0 :               c = *++pc->input;
    1118                 :            :             }
    1119 [ #  # ][ #  # ]:          0 :           while (c_isalpha (c) || c == '.');
    1120                 :            : 
    1121                 :          0 :           *p = '\0';
    1122                 :          0 :           tp = lookup_word (pc, buff);
    1123         [ #  # ]:          0 :           if (! tp)
    1124                 :          0 :             return '?';
    1125                 :          0 :           lvalp->intval = tp->value;
    1126                 :          0 :           return tp->type;
    1127                 :            :         }
    1128                 :            : 
    1129         [ #  # ]:          0 :       if (c != '(')
    1130                 :          0 :         return *pc->input++;
    1131                 :          0 :       count = 0;
    1132                 :            :       do
    1133                 :            :         {
    1134                 :          0 :           c = *pc->input++;
    1135         [ #  # ]:          0 :           if (c == '\0')
    1136                 :          0 :             return c;
    1137         [ #  # ]:          0 :           if (c == '(')
    1138                 :          0 :             count++;
    1139         [ #  # ]:          0 :           else if (c == ')')
    1140                 :          0 :             count--;
    1141                 :            :         }
    1142         [ #  # ]:          0 :       while (count != 0);
    1143                 :          0 :     }
    1144                 :            : }
    1145                 :            : 
    1146                 :            : /* Do nothing if the parser reports an error.  */
    1147                 :            : static int
    1148                 :          0 : yyerror (parser_control const *pc _GL_UNUSED,
    1149                 :            :          char const *s _GL_UNUSED)
    1150                 :            : {
    1151                 :          0 :   return 0;
    1152                 :            : }
    1153                 :            : 
    1154                 :            : /* If *TM0 is the old and *TM1 is the new value of a struct tm after
    1155                 :            :    passing it to mktime, return true if it's OK that mktime returned T.
    1156                 :            :    It's not OK if *TM0 has out-of-range members.  */
    1157                 :            : 
    1158                 :            : static bool
    1159                 :          0 : mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
    1160                 :            : {
    1161         [ #  # ]:          0 :   if (t == (time_t) -1)
    1162                 :            :     {
    1163                 :            :       /* Guard against falsely reporting an error when parsing a time
    1164                 :            :          stamp that happens to equal (time_t) -1, on a host that
    1165                 :            :          supports such a time stamp.  */
    1166                 :          0 :       tm1 = localtime (&t);
    1167         [ #  # ]:          0 :       if (!tm1)
    1168                 :          0 :         return false;
    1169                 :            :     }
    1170                 :            : 
    1171                 :          0 :   return ! ((tm0->tm_sec ^ tm1->tm_sec)
    1172                 :          0 :             | (tm0->tm_min ^ tm1->tm_min)
    1173                 :          0 :             | (tm0->tm_hour ^ tm1->tm_hour)
    1174                 :          0 :             | (tm0->tm_mday ^ tm1->tm_mday)
    1175                 :          0 :             | (tm0->tm_mon ^ tm1->tm_mon)
    1176                 :          0 :             | (tm0->tm_year ^ tm1->tm_year));
    1177                 :            : }
    1178                 :            : 
    1179                 :            : /* A reasonable upper bound for the size of ordinary TZ strings.
    1180                 :            :    Use heap allocation if TZ's length exceeds this.  */
    1181                 :            : enum { TZBUFSIZE = 100 };
    1182                 :            : 
    1183                 :            : /* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
    1184                 :            :    otherwise.  */
    1185                 :            : static char *
    1186                 :          0 : get_tz (char tzbuf[TZBUFSIZE])
    1187                 :            : {
    1188                 :          0 :   char *tz = getenv ("TZ");
    1189         [ #  # ]:          0 :   if (tz)
    1190                 :            :     {
    1191                 :          0 :       size_t tzsize = strlen (tz) + 1;
    1192         [ #  # ]:          0 :       tz = (tzsize <= TZBUFSIZE
    1193                 :          0 :             ? memcpy (tzbuf, tz, tzsize)
    1194                 :          0 :             : xmemdup (tz, tzsize));
    1195                 :            :     }
    1196                 :          0 :   return tz;
    1197                 :            : }
    1198                 :            : 
    1199                 :            : /* Parse a date/time string, storing the resulting time value into *RESULT.
    1200                 :            :    The string itself is pointed to by P.  Return true if successful.
    1201                 :            :    P can be an incomplete or relative time specification; if so, use
    1202                 :            :    *NOW as the basis for the returned time.  */
    1203                 :            : bool
    1204                 :          0 : get_date (struct timespec *result, char const *p, struct timespec const *now)
    1205                 :            : {
    1206                 :            :   time_t Start;
    1207                 :            :   long int Start_ns;
    1208                 :            :   struct tm const *tmp;
    1209                 :            :   struct tm tm;
    1210                 :            :   struct tm tm0;
    1211                 :            :   parser_control pc;
    1212                 :            :   struct timespec gettime_buffer;
    1213                 :            :   unsigned char c;
    1214                 :          0 :   bool tz_was_altered = false;
    1215                 :          0 :   char *tz0 = NULL;
    1216                 :            :   char tz0buf[TZBUFSIZE];
    1217                 :          0 :   bool ok = true;
    1218                 :            : 
    1219         [ #  # ]:          0 :   if (! now)
    1220                 :            :     {
    1221                 :          0 :       gettime (&gettime_buffer);
    1222                 :          0 :       now = &gettime_buffer;
    1223                 :            :     }
    1224                 :            : 
    1225                 :          0 :   Start = now->tv_sec;
    1226                 :          0 :   Start_ns = now->tv_nsec;
    1227                 :            : 
    1228                 :          0 :   tmp = localtime (&now->tv_sec);
    1229         [ #  # ]:          0 :   if (! tmp)
    1230                 :          0 :     return false;
    1231                 :            : 
    1232         [ #  # ]:          0 :   while (c = *p, c_isspace (c))
    1233                 :          0 :     p++;
    1234                 :            : 
    1235         [ #  # ]:          0 :   if (strncmp (p, "TZ=\"", 4) == 0)
    1236                 :            :     {
    1237                 :          0 :       char const *tzbase = p + 4;
    1238                 :          0 :       size_t tzsize = 1;
    1239                 :            :       char const *s;
    1240                 :            : 
    1241         [ #  # ]:          0 :       for (s = tzbase; *s; s++, tzsize++)
    1242         [ #  # ]:          0 :         if (*s == '\\')
    1243                 :            :           {
    1244                 :          0 :             s++;
    1245 [ #  # ][ #  # ]:          0 :             if (! (*s == '\\' || *s == '"'))
    1246                 :          0 :               break;
    1247                 :            :           }
    1248         [ #  # ]:          0 :         else if (*s == '"')
    1249                 :            :           {
    1250                 :            :             char *z;
    1251                 :            :             char *tz1;
    1252                 :            :             char tz1buf[TZBUFSIZE];
    1253                 :          0 :             bool large_tz = TZBUFSIZE < tzsize;
    1254                 :            :             bool setenv_ok;
    1255                 :            :             /* Free tz0, in case this is the 2nd or subsequent time through. */
    1256                 :          0 :             free (tz0);
    1257                 :          0 :             tz0 = get_tz (tz0buf);
    1258         [ #  # ]:          0 :             z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
    1259         [ #  # ]:          0 :             for (s = tzbase; *s != '"'; s++)
    1260                 :          0 :               *z++ = *(s += *s == '\\');
    1261                 :          0 :             *z = '\0';
    1262                 :          0 :             setenv_ok = setenv ("TZ", tz1, 1) == 0;
    1263         [ #  # ]:          0 :             if (large_tz)
    1264                 :          0 :               free (tz1);
    1265         [ #  # ]:          0 :             if (!setenv_ok)
    1266                 :          0 :               goto fail;
    1267                 :          0 :             tz_was_altered = true;
    1268                 :          0 :             p = s + 1;
    1269                 :            :           }
    1270                 :            :     }
    1271                 :            : 
    1272                 :            :   /* As documented, be careful to treat the empty string just like
    1273                 :            :      a date string of "0".  Without this, an empty string would be
    1274                 :            :      declared invalid when parsed during a DST transition.  */
    1275         [ #  # ]:          0 :   if (*p == '\0')
    1276                 :          0 :     p = "0";
    1277                 :            : 
    1278                 :          0 :   pc.input = p;
    1279                 :          0 :   pc.year.value = tmp->tm_year;
    1280                 :          0 :   pc.year.value += TM_YEAR_BASE;
    1281                 :          0 :   pc.year.digits = 0;
    1282                 :          0 :   pc.month = tmp->tm_mon + 1;
    1283                 :          0 :   pc.day = tmp->tm_mday;
    1284                 :          0 :   pc.hour = tmp->tm_hour;
    1285                 :          0 :   pc.minutes = tmp->tm_min;
    1286                 :          0 :   pc.seconds.tv_sec = tmp->tm_sec;
    1287                 :          0 :   pc.seconds.tv_nsec = Start_ns;
    1288                 :          0 :   tm.tm_isdst = tmp->tm_isdst;
    1289                 :            : 
    1290                 :          0 :   pc.meridian = MER24;
    1291                 :          0 :   pc.rel = RELATIVE_TIME_0;
    1292                 :          0 :   pc.timespec_seen = false;
    1293                 :          0 :   pc.rels_seen = false;
    1294                 :          0 :   pc.dates_seen = 0;
    1295                 :          0 :   pc.days_seen = 0;
    1296                 :          0 :   pc.times_seen = 0;
    1297                 :          0 :   pc.local_zones_seen = 0;
    1298                 :          0 :   pc.dsts_seen = 0;
    1299                 :          0 :   pc.zones_seen = 0;
    1300                 :            : 
    1301                 :            : #if HAVE_STRUCT_TM_TM_ZONE
    1302                 :          0 :   pc.local_time_zone_table[0].name = tmp->tm_zone;
    1303                 :          0 :   pc.local_time_zone_table[0].type = tLOCAL_ZONE;
    1304                 :          0 :   pc.local_time_zone_table[0].value = tmp->tm_isdst;
    1305                 :          0 :   pc.local_time_zone_table[1].name = NULL;
    1306                 :            : 
    1307                 :            :   /* Probe the names used in the next three calendar quarters, looking
    1308                 :            :      for a tm_isdst different from the one we already have.  */
    1309                 :            :   {
    1310                 :            :     int quarter;
    1311         [ #  # ]:          0 :     for (quarter = 1; quarter <= 3; quarter++)
    1312                 :            :       {
    1313                 :          0 :         time_t probe = Start + quarter * (90 * 24 * 60 * 60);
    1314                 :          0 :         struct tm const *probe_tm = localtime (&probe);
    1315   [ #  #  #  # ]:          0 :         if (probe_tm && probe_tm->tm_zone
                 [ #  # ]
    1316                 :          0 :             && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
    1317                 :            :           {
    1318                 :            :               {
    1319                 :          0 :                 pc.local_time_zone_table[1].name = probe_tm->tm_zone;
    1320                 :          0 :                 pc.local_time_zone_table[1].type = tLOCAL_ZONE;
    1321                 :          0 :                 pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
    1322                 :          0 :                 pc.local_time_zone_table[2].name = NULL;
    1323                 :            :               }
    1324                 :          0 :             break;
    1325                 :            :           }
    1326                 :            :       }
    1327                 :            :   }
    1328                 :            : #else
    1329                 :            : #if HAVE_TZNAME
    1330                 :            :   {
    1331                 :            : # if !HAVE_DECL_TZNAME
    1332                 :            :     extern char *tzname[];
    1333                 :            : # endif
    1334                 :            :     int i;
    1335                 :            :     for (i = 0; i < 2; i++)
    1336                 :            :       {
    1337                 :            :         pc.local_time_zone_table[i].name = tzname[i];
    1338                 :            :         pc.local_time_zone_table[i].type = tLOCAL_ZONE;
    1339                 :            :         pc.local_time_zone_table[i].value = i;
    1340                 :            :       }
    1341                 :            :     pc.local_time_zone_table[i].name = NULL;
    1342                 :            :   }
    1343                 :            : #else
    1344                 :            :   pc.local_time_zone_table[0].name = NULL;
    1345                 :            : #endif
    1346                 :            : #endif
    1347                 :            : 
    1348 [ #  # ][ #  # ]:          0 :   if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
                 [ #  # ]
    1349                 :          0 :       && ! strcmp (pc.local_time_zone_table[0].name,
    1350                 :            :                    pc.local_time_zone_table[1].name))
    1351                 :            :     {
    1352                 :            :       /* This locale uses the same abbrevation for standard and
    1353                 :            :          daylight times.  So if we see that abbreviation, we don't
    1354                 :            :          know whether it's daylight time.  */
    1355                 :          0 :       pc.local_time_zone_table[0].value = -1;
    1356                 :          0 :       pc.local_time_zone_table[1].name = NULL;
    1357                 :            :     }
    1358                 :            : 
    1359         [ #  # ]:          0 :   if (yyparse (&pc) != 0)
    1360                 :          0 :     goto fail;
    1361                 :            : 
    1362         [ #  # ]:          0 :   if (pc.timespec_seen)
    1363                 :          0 :     *result = pc.seconds;
    1364                 :            :   else
    1365                 :            :     {
    1366         [ #  # ]:          0 :       if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen
    1367                 :          0 :                | (pc.local_zones_seen + pc.zones_seen)))
    1368                 :          0 :         goto fail;
    1369                 :            : 
    1370                 :          0 :       tm.tm_year = to_year (pc.year) - TM_YEAR_BASE;
    1371                 :          0 :       tm.tm_mon = pc.month - 1;
    1372                 :          0 :       tm.tm_mday = pc.day;
    1373   [ #  #  #  # ]:          0 :       if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
         [ #  # ][ #  # ]
    1374                 :            :         {
    1375                 :          0 :           tm.tm_hour = to_hour (pc.hour, pc.meridian);
    1376         [ #  # ]:          0 :           if (tm.tm_hour < 0)
    1377                 :          0 :             goto fail;
    1378                 :          0 :           tm.tm_min = pc.minutes;
    1379                 :          0 :           tm.tm_sec = pc.seconds.tv_sec;
    1380                 :            :         }
    1381                 :            :       else
    1382                 :            :         {
    1383                 :          0 :           tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
    1384                 :          0 :           pc.seconds.tv_nsec = 0;
    1385                 :            :         }
    1386                 :            : 
    1387                 :            :       /* Let mktime deduce tm_isdst if we have an absolute time stamp.  */
    1388         [ #  # ]:          0 :       if (pc.dates_seen | pc.days_seen | pc.times_seen)
    1389                 :          0 :         tm.tm_isdst = -1;
    1390                 :            : 
    1391                 :            :       /* But if the input explicitly specifies local time with or without
    1392                 :            :          DST, give mktime that information.  */
    1393         [ #  # ]:          0 :       if (pc.local_zones_seen)
    1394                 :          0 :         tm.tm_isdst = pc.local_isdst;
    1395                 :            : 
    1396                 :          0 :       tm0 = tm;
    1397                 :            : 
    1398                 :          0 :       Start = mktime (&tm);
    1399                 :            : 
    1400         [ #  # ]:          0 :       if (! mktime_ok (&tm0, &tm, Start))
    1401                 :            :         {
    1402         [ #  # ]:          0 :           if (! pc.zones_seen)
    1403                 :          0 :             goto fail;
    1404                 :            :           else
    1405                 :            :             {
    1406                 :            :               /* Guard against falsely reporting errors near the time_t
    1407                 :            :                  boundaries when parsing times in other time zones.  For
    1408                 :            :                  example, suppose the input string "1969-12-31 23:00:00 -0100",
    1409                 :            :                  the current time zone is 8 hours ahead of UTC, and the min
    1410                 :            :                  time_t value is 1970-01-01 00:00:00 UTC.  Then the min
    1411                 :            :                  localtime value is 1970-01-01 08:00:00, and mktime will
    1412                 :            :                  therefore fail on 1969-12-31 23:00:00.  To work around the
    1413                 :            :                  problem, set the time zone to 1 hour behind UTC temporarily
    1414                 :            :                  by setting TZ="XXX1:00" and try mktime again.  */
    1415                 :            : 
    1416                 :          0 :               long int time_zone = pc.time_zone;
    1417                 :          0 :               long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
    1418                 :          0 :               long int abs_time_zone_hour = abs_time_zone / 60;
    1419                 :          0 :               int abs_time_zone_min = abs_time_zone % 60;
    1420                 :            :               char tz1buf[sizeof "XXX+0:00"
    1421                 :            :                           + sizeof pc.time_zone * CHAR_BIT / 3];
    1422         [ #  # ]:          0 :               if (!tz_was_altered)
    1423                 :          0 :                 tz0 = get_tz (tz0buf);
    1424         [ #  # ]:          0 :               sprintf (tz1buf, "XXX%s%ld:%02d", "-" + (time_zone < 0),
    1425                 :            :                        abs_time_zone_hour, abs_time_zone_min);
    1426         [ #  # ]:          0 :               if (setenv ("TZ", tz1buf, 1) != 0)
    1427                 :          0 :                 goto fail;
    1428                 :          0 :               tz_was_altered = true;
    1429                 :          0 :               tm = tm0;
    1430                 :          0 :               Start = mktime (&tm);
    1431         [ #  # ]:          0 :               if (! mktime_ok (&tm0, &tm, Start))
    1432                 :          0 :                 goto fail;
    1433                 :            :             }
    1434                 :            :         }
    1435                 :            : 
    1436 [ #  # ][ #  # ]:          0 :       if (pc.days_seen && ! pc.dates_seen)
    1437                 :            :         {
    1438                 :          0 :           tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
    1439 [ #  # ][ #  # ]:          0 :                          + 7 * (pc.day_ordinal
    1440                 :            :                                 - (0 < pc.day_ordinal
    1441                 :          0 :                                    && tm.tm_wday != pc.day_number)));
    1442                 :          0 :           tm.tm_isdst = -1;
    1443                 :          0 :           Start = mktime (&tm);
    1444         [ #  # ]:          0 :           if (Start == (time_t) -1)
    1445                 :          0 :             goto fail;
    1446                 :            :         }
    1447                 :            : 
    1448                 :            :       /* Add relative date.  */
    1449         [ #  # ]:          0 :       if (pc.rel.year | pc.rel.month | pc.rel.day)
    1450                 :            :         {
    1451                 :          0 :           int year = tm.tm_year + pc.rel.year;
    1452                 :          0 :           int month = tm.tm_mon + pc.rel.month;
    1453                 :          0 :           int day = tm.tm_mday + pc.rel.day;
    1454         [ #  # ]:          0 :           if (((year < tm.tm_year) ^ (pc.rel.year < 0))
    1455                 :          0 :               | ((month < tm.tm_mon) ^ (pc.rel.month < 0))
    1456                 :          0 :               | ((day < tm.tm_mday) ^ (pc.rel.day < 0)))
    1457                 :          0 :             goto fail;
    1458                 :          0 :           tm.tm_year = year;
    1459                 :          0 :           tm.tm_mon = month;
    1460                 :          0 :           tm.tm_mday = day;
    1461                 :          0 :           tm.tm_hour = tm0.tm_hour;
    1462                 :          0 :           tm.tm_min = tm0.tm_min;
    1463                 :          0 :           tm.tm_sec = tm0.tm_sec;
    1464                 :          0 :           tm.tm_isdst = tm0.tm_isdst;
    1465                 :          0 :           Start = mktime (&tm);
    1466         [ #  # ]:          0 :           if (Start == (time_t) -1)
    1467                 :          0 :             goto fail;
    1468                 :            :         }
    1469                 :            : 
    1470                 :            :       /* The only "output" of this if-block is an updated Start value,
    1471                 :            :          so this block must follow others that clobber Start.  */
    1472         [ #  # ]:          0 :       if (pc.zones_seen)
    1473                 :            :         {
    1474                 :          0 :           long int delta = pc.time_zone * 60;
    1475                 :            :           time_t t1;
    1476                 :            : #ifdef HAVE_TM_GMTOFF
    1477                 :          0 :           delta -= tm.tm_gmtoff;
    1478                 :            : #else
    1479                 :            :           time_t t = Start;
    1480                 :            :           struct tm const *gmt = gmtime (&t);
    1481                 :            :           if (! gmt)
    1482                 :            :             goto fail;
    1483                 :            :           delta -= tm_diff (&tm, gmt);
    1484                 :            : #endif
    1485                 :          0 :           t1 = Start - delta;
    1486         [ #  # ]:          0 :           if ((Start < t1) != (delta < 0))
    1487                 :          0 :             goto fail;  /* time_t overflow */
    1488                 :          0 :           Start = t1;
    1489                 :            :         }
    1490                 :            : 
    1491                 :            :       /* Add relative hours, minutes, and seconds.  On hosts that support
    1492                 :            :          leap seconds, ignore the possibility of leap seconds; e.g.,
    1493                 :            :          "+ 10 minutes" adds 600 seconds, even if one of them is a
    1494                 :            :          leap second.  Typically this is not what the user wants, but it's
    1495                 :            :          too hard to do it the other way, because the time zone indicator
    1496                 :            :          must be applied before relative times, and if mktime is applied
    1497                 :            :          again the time zone will be lost.  */
    1498                 :            :       {
    1499                 :          0 :         long int sum_ns = pc.seconds.tv_nsec + pc.rel.ns;
    1500                 :          0 :         long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION;
    1501                 :          0 :         time_t t0 = Start;
    1502                 :          0 :         long int d1 = 60 * 60 * pc.rel.hour;
    1503                 :          0 :         time_t t1 = t0 + d1;
    1504                 :          0 :         long int d2 = 60 * pc.rel.minutes;
    1505                 :          0 :         time_t t2 = t1 + d2;
    1506                 :          0 :         long_time_t d3 = pc.rel.seconds;
    1507                 :          0 :         long_time_t t3 = t2 + d3;
    1508                 :          0 :         long int d4 = (sum_ns - normalized_ns) / BILLION;
    1509                 :          0 :         long_time_t t4 = t3 + d4;
    1510                 :          0 :         time_t t5 = t4;
    1511                 :            : 
    1512         [ #  # ]:          0 :         if ((d1 / (60 * 60) ^ pc.rel.hour)
    1513                 :          0 :             | (d2 / 60 ^ pc.rel.minutes)
    1514                 :          0 :             | ((t1 < t0) ^ (d1 < 0))
    1515                 :          0 :             | ((t2 < t1) ^ (d2 < 0))
    1516                 :          0 :             | ((t3 < t2) ^ (d3 < 0))
    1517                 :          0 :             | ((t4 < t3) ^ (d4 < 0))
    1518                 :          0 :             | (t5 != t4))
    1519                 :          0 :           goto fail;
    1520                 :            : 
    1521                 :          0 :         result->tv_sec = t5;
    1522                 :          0 :         result->tv_nsec = normalized_ns;
    1523                 :            :       }
    1524                 :            :     }
    1525                 :            : 
    1526                 :          0 :   goto done;
    1527                 :            : 
    1528                 :            :  fail:
    1529                 :          0 :   ok = false;
    1530                 :            :  done:
    1531         [ #  # ]:          0 :   if (tz_was_altered)
    1532         [ #  # ]:          0 :     ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0;
    1533         [ #  # ]:          0 :   if (tz0 != tz0buf)
    1534                 :          0 :     free (tz0);
    1535                 :          0 :   return ok;
    1536                 :            : }
    1537                 :            : 
    1538                 :            : #if TEST
    1539                 :            : 
    1540                 :            : int
    1541                 :            : main (int ac, char **av)
    1542                 :            : {
    1543                 :            :   char buff[BUFSIZ];
    1544                 :            : 
    1545                 :            :   printf ("Enter date, or blank line to exit.\n\t> ");
    1546                 :            :   fflush (stdout);
    1547                 :            : 
    1548                 :            :   buff[BUFSIZ - 1] = '\0';
    1549                 :            :   while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
    1550                 :            :     {
    1551                 :            :       struct timespec d;
    1552                 :            :       struct tm const *tm;
    1553                 :            :       if (! get_date (&d, buff, NULL))
    1554                 :            :         printf ("Bad format - couldn't convert.\n");
    1555                 :            :       else if (! (tm = localtime (&d.tv_sec)))
    1556                 :            :         {
    1557                 :            :           long int sec = d.tv_sec;
    1558                 :            :           printf ("localtime (%ld) failed\n", sec);
    1559                 :            :         }
    1560                 :            :       else
    1561                 :            :         {
    1562                 :            :           int ns = d.tv_nsec;
    1563                 :            :           printf ("%04ld-%02d-%02d %02d:%02d:%02d.%09d\n",
    1564                 :            :                   tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
    1565                 :            :                   tm->tm_hour, tm->tm_min, tm->tm_sec, ns);
    1566                 :            :         }
    1567                 :            :       printf ("\t> ");
    1568                 :            :       fflush (stdout);
    1569                 :            :     }
    1570                 :            :   return 0;
    1571                 :            : }
    1572                 :            : #endif /* TEST */

Generated by: LCOV version 1.8