Pádraig Brady wrote:
using PRIuMAX may be best?

That would be too easy :-). I installed the attached.
From 8edebfe6f97d0e378d042accb2475a32a53f100f Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 22 Apr 2017 15:13:24 -0700
Subject: [PATCH] parse-datetime: fix %z and prefer signed int
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

%z problem reported by Pádraig Brady in:
http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00103.html
While fixing it, I decided to prefer signed ints to size_t, as
they are less error-prone (e.g., ubsan catches overflow).
* lib/parse-datetime.y (textint, parser_control, lookup_word, yylex)
(parse_datetime2): Prefer ptrdiff_t to size_t for sizes and object
counts, since signed integers make for better debugging.
(date): Don’t assume %z works in printf formats.
(debug_strfdatetime, debug_strfdate, debug_strftime): Use int for
sizes of buffers known to be small, e.g., because we’re using snprintf.
(parse_datetime2): Simplify call to debug_mktime_not_ok.
---
 ChangeLog            | 15 +++++++++++++
 lib/parse-datetime.y | 60 ++++++++++++++++++++++++++--------------------------
 2 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d44f5d8..bdebb94 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2017-04-22  Paul Eggert  <egg...@cs.ucla.edu>
+
+       parse-datetime: fix %z and prefer signed int
+       %z problem reported by Pádraig Brady in:
+       http://lists.gnu.org/archive/html/bug-gnulib/2017-04/msg00103.html
+       While fixing it, I decided to prefer signed ints to size_t, as
+       they are less error-prone (e.g., ubsan catches overflow).
+       * lib/parse-datetime.y (textint, parser_control, lookup_word, yylex)
+       (parse_datetime2): Prefer ptrdiff_t to size_t for sizes and object
+       counts, since signed integers make for better debugging.
+       (date): Don’t assume %z works in printf formats.
+       (debug_strfdatetime, debug_strfdate, debug_strftime): Use int for
+       sizes of buffers known to be small, e.g., because we’re using snprintf.
+       (parse_datetime2): Simplify call to debug_mktime_not_ok.
+
 2017-04-22  Bruno Haible  <br...@clisp.org>
 
        *printf: Work around rounding bug on Mac OS X.
diff --git a/lib/parse-datetime.y b/lib/parse-datetime.y
index 3b815a9..7161416 100644
--- a/lib/parse-datetime.y
+++ b/lib/parse-datetime.y
@@ -139,7 +139,7 @@ typedef struct
 {
   bool negative;
   intmax_t value;
-  size_t digits;
+  ptrdiff_t digits;
 } textint;
 
 /* An entry in the lexical lookup table.  */
@@ -212,12 +212,12 @@ typedef struct
   /* Presence or counts of nonterminals of various flavors parsed so far.  */
   bool timespec_seen;
   bool rels_seen;
-  size_t dates_seen;
-  size_t days_seen;
-  size_t local_zones_seen;
-  size_t dsts_seen;
-  size_t times_seen;
-  size_t zones_seen;
+  ptrdiff_t dates_seen;
+  ptrdiff_t days_seen;
+  ptrdiff_t local_zones_seen;
+  ptrdiff_t dsts_seen;
+  ptrdiff_t times_seen;
+  ptrdiff_t zones_seen;
   bool year_seen;
 
   /* Print debugging output to stderr.  */
@@ -802,9 +802,12 @@ date:
         if (4 <= $1.digits)
           {
             if (pc->parse_datetime_debug)
-              dbg_printf (_("warning: value %"PRIdMAX" has %zu digits. "
-                            "Assuming YYYY/MM/DD\n"),
-                          $1.value, $1.digits);
+              {
+                intmax_t digits = $1.digits;
+                dbg_printf (_("warning: value %"PRIdMAX" has %"PRIdMAX" 
digits. "
+                              "Assuming YYYY/MM/DD\n"),
+                            $1.value, digits);
+              }
 
             pc->year = $1;
             pc->month = $3.value;
@@ -1328,7 +1331,7 @@ lookup_word (parser_control const *pc, char *word)
 {
   char *p;
   char *q;
-  size_t wordlen;
+  ptrdiff_t wordlen;
   table const *tp;
   bool period_found;
   bool abbrev;
@@ -1395,7 +1398,6 @@ static int
 yylex (union YYSTYPE *lvalp, parser_control *pc)
 {
   unsigned char c;
-  size_t count;
 
   for (;;)
     {
@@ -1516,7 +1518,7 @@ yylex (union YYSTYPE *lvalp, parser_control *pc)
       if (c != '(')
         return to_uchar (*pc->input++);
 
-      count = 0;
+      ptrdiff_t count = 0;
       do
         {
           c = *pc->input++;
@@ -1570,7 +1572,7 @@ mktime_ok (timezone_t tz, struct tm const *tm0, struct tm 
const *tm1, time_t t)
    timezone information into account (if pc != NULL).  */
 static char const *
 debug_strfdatetime (struct tm const *tm, parser_control const *pc,
-                    char *buf, size_t n)
+                    char *buf, int n)
 {
   /* TODO:
      1. find an optimal way to print date string in a clear and unambiguous
@@ -1614,7 +1616,7 @@ debug_strfdatetime (struct tm const *tm, parser_control 
const *pc,
 }
 
 static char const *
-debug_strfdate (struct tm const *tm, char *buf, size_t n)
+debug_strfdate (struct tm const *tm, char *buf, int n)
 {
   char tm_year_buf[TM_YEAR_BUFSIZE];
   snprintf (buf, n, "(Y-M-D) %s-%02d-%02d",
@@ -1624,7 +1626,7 @@ debug_strfdate (struct tm const *tm, char *buf, size_t n)
 }
 
 static char const *
-debug_strftime (struct tm const *tm, char *buf, size_t n)
+debug_strftime (struct tm const *tm, char *buf, int n)
 {
   snprintf (buf, n, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
   return buf;
@@ -1644,7 +1646,7 @@ debug_strftime (struct tm const *tm, char *buf, size_t n)
  */
 static void
 debug_mktime_not_ok (struct tm const *tm0, struct tm const *tm1,
-                     parser_control const *pc,  bool time_zone_seen)
+                     parser_control const *pc, bool time_zone_seen)
 {
   /* TODO: handle t == -1 (as in 'mktime_ok').  */
   char tmp[DBGBUFSIZE];
@@ -1754,7 +1756,7 @@ parse_datetime2 (struct timespec *result, char const *p,
   if (strncmp (p, "TZ=\"", 4) == 0)
     {
       char const *tzbase = p + 4;
-      size_t tzsize = 1;
+      ptrdiff_t tzsize = 1;
       char const *s;
 
       for (s = tzbase; *s; s++, tzsize++)
@@ -2025,12 +2027,9 @@ parse_datetime2 (struct timespec *result, char const *p,
 
       if (! mktime_ok (tz, &tm0, &tm, Start))
         {
-          if (! pc.zones_seen)
-            {
-              debug_mktime_not_ok (&tm0, &tm, &pc, pc.zones_seen);
-              goto fail;
-            }
-          else
+          bool repaired = false;
+          bool time_zone_seen = pc.zones_seen != 0;
+          if (time_zone_seen)
             {
               /* Guard against falsely reporting errors near the time_t
                  boundaries when parsing times in other time zones.  For
@@ -2054,13 +2053,14 @@ parse_datetime2 (struct timespec *result, char const *p,
                 }
               tm = tm0;
               Start = mktime_z (tz2, &tm);
-              bool mktime_failed = !mktime_ok (tz2, &tm0, &tm, Start);
+              repaired = mktime_ok (tz2, &tm0, &tm, Start);
               tzfree (tz2);
-              if (mktime_failed)
-                {
-                  debug_mktime_not_ok (&tm0, &tm, &pc, pc.zones_seen);
-                  goto fail;
-                }
+            }
+
+          if (! repaired)
+            {
+              debug_mktime_not_ok (&tm0, &tm, &pc, time_zone_seen);
+              goto fail;
             }
         }
 
-- 
2.7.4

Reply via email to