Document recent checkins.
[gnulib.git] / lib / getdate.y
index 4b7c2e9..40fd4e0 100644 (file)
@@ -1,6 +1,6 @@
 %{
 /* Parse a string into an internal time stamp.
-   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
-# ifdef HAVE_ALLOCA_H
-#  include <alloca.h>
-# endif
 #endif
 
+#include <alloca.h>
+
 /* Since the code of getdate.y is not included in the Emacs executable
    itself, there is no need to #define static in this file.  Even if
    the code were included in the Emacs executable, it probably
@@ -44,9 +43,7 @@
 
 #include <ctype.h>
 
-#if HAVE_STDLIB_H
-# include <stdlib.h> /* for `free'; used by Bison 1.27 */
-#endif
+#include <stdlib.h> /* for `free'; used by Bison 1.27 */
 
 #if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
 # define IN_CTYPE_DOMAIN(c) 1
    - Its arg may be any int or unsigned int; it need not be an unsigned char.
    - It's guaranteed to evaluate its argument exactly once.
    - It's typically faster.
-   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
-   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
-   it's important to use the locale's definition of `digit' even when the
-   host does not conform to Posix.  */
+   POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
+   ISDIGIT_LOCALE unless it's important to use the locale's definition
+   of `digit' even when the host does not conform to POSIX.  */
 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
 
-#if STDC_HEADERS || HAVE_STRING_H
-# include <string.h>
-#endif
+#include <string.h>
 
 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
 # define __attribute__(x)
@@ -85,7 +79,7 @@
 #define TM_YEAR_BASE 1900
 
 #define HOUR(x) ((x) * 60)
+
 /* An integer value, and the number of digits in its textual
    representation.  */
 typedef struct
@@ -168,7 +162,7 @@ static int yylex ();
 
 /* This grammar has 13 shift/reduce conflicts. */
 %expect 13
+
 %union
 {
   int intval;
@@ -323,6 +317,14 @@ date:
        PC.year.value = -$3.value;
        PC.year.digits = $3.digits;
       }
+  | tMONTH tSNUMBER tSNUMBER
+      {
+       /* e.g. JUN-17-1992.  */
+       PC.month = $1;
+       PC.day = -$2.value;
+       PC.year.value = -$3.value;
+       PC.year.digits = $3.digits;
+      }
   | tMONTH tUNUMBER
       {
        PC.month = $1;
@@ -378,19 +380,19 @@ relunit:
   | tSNUMBER tDAY_UNIT
       { PC.rel_day += $1.value * $2; }
   | tDAY_UNIT
-      { PC.rel_day += $1 }
+      { PC.rel_day += $1; }
   | tUNUMBER tHOUR_UNIT
       { PC.rel_hour += $1.value * $2; }
   | tSNUMBER tHOUR_UNIT
       { PC.rel_hour += $1.value * $2; }
   | tHOUR_UNIT
-      { PC.rel_hour += $1 }
+      { PC.rel_hour += $1; }
   | tUNUMBER tMINUTE_UNIT
       { PC.rel_minutes += $1.value * $2; }
   | tSNUMBER tMINUTE_UNIT
       { PC.rel_minutes += $1.value * $2; }
   | tMINUTE_UNIT
-      { PC.rel_minutes += $1 }
+      { PC.rel_minutes += $1; }
   | tUNUMBER tSEC_UNIT
       { PC.rel_seconds += $1.value * $2; }
   | tSNUMBER tSEC_UNIT
@@ -448,6 +450,7 @@ o_merid:
    may define-away `const'.  We want the prototype for get_date to have
    the same signature as the function definition.  */
 #include "getdate.h"
+#include "unlocked-io.h"
 
 #ifndef gmtime
 struct tm *gmtime ();
@@ -520,10 +523,10 @@ static table const time_units_table[] =
 /* Assorted relative-time words. */
 static table const relative_time_table[] =
 {
-  { "TOMORROW",        tMINUTE_UNIT,   24 * 60 },
-  { "YESTERDAY",tMINUTE_UNIT,  - (24 * 60) },
-  { "TODAY",   tMINUTE_UNIT,    0 },
-  { "NOW",     tMINUTE_UNIT,    0 },
+  { "TOMORROW",        tDAY_UNIT,       1 },
+  { "YESTERDAY",tDAY_UNIT,     -1 },
+  { "TODAY",   tDAY_UNIT,       0 },
+  { "NOW",     tDAY_UNIT,       0 },
   { "LAST",    tUNUMBER,       -1 },
   { "THIS",    tUNUMBER,        0 },
   { "NEXT",    tUNUMBER,        1 },
@@ -908,7 +911,7 @@ get_date (const char *p, const time_t *now)
   pc.local_zones_seen = 0;
   pc.zones_seen = 0;
 
-#if HAVE_TM_ZONE
+#if HAVE_STRUCT_TM_TM_ZONE
   pc.local_time_zone_table[0].name = tmp->tm_zone;
   pc.local_time_zone_table[0].type = tLOCAL_ZONE;
   pc.local_time_zone_table[0].value = tmp->tm_isdst;
@@ -987,13 +990,11 @@ get_date (const char *p, const time_t *now)
     {
       tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
     }
-  tm.tm_hour += pc.rel_hour;
-  tm.tm_min += pc.rel_minutes;
-  tm.tm_sec += pc.rel_seconds;
 
   /* Let mktime deduce tm_isdst if we have an absolute time stamp,
      or if the relative time stamp mentions days, months, or years.  */
-  if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day | pc.rel_month | pc.rel_year)
+  if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day
+      | pc.rel_month | pc.rel_year)
     tm.tm_isdst = -1;
 
   /* But if the input explicitly specifies local time with or without
@@ -1040,6 +1041,7 @@ get_date (const char *p, const time_t *now)
     {
       tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
                     + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+      tm.tm_isdst = -1;
       Start = mktime (&tm);
       if (Start == (time_t) -1)
        return Start;
@@ -1061,6 +1063,29 @@ get_date (const char *p, const time_t *now)
       Start -= delta;
     }
 
+  /* Add relative hours, minutes, and seconds.  Ignore leap seconds;
+     i.e. "+ 10 minutes" means 600 seconds, even if one of them is a
+     leap second.  Typically this is not what the user wants, but it's
+     too hard to do it the other way, because the time zone indicator
+     must be applied before relative times, and if mktime is applied
+     again the time zone will be lost.  */
+  {
+    time_t t0 = Start;
+    long d1 = 60 * 60 * (long) pc.rel_hour;
+    time_t t1 = t0 + d1;
+    long d2 = 60 * (long) pc.rel_minutes;
+    time_t t2 = t1 + d2;
+    int d3 = pc.rel_seconds;
+    time_t t3 = t2 + d3;
+    if ((d1 / (60 * 60) ^ pc.rel_hour)
+       | (d2 / 60 ^ pc.rel_minutes)
+       | ((t0 + d1 < t0) ^ (d1 < 0))
+       | ((t1 + d2 < t1) ^ (d2 < 0))
+       | ((t2 + d3 < t2) ^ (d3 < 0)))
+      return -1;
+    Start = t3;
+  }
+
   return Start;
 }