bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Merge strftime.c changes from glibc


From: Paul Eggert
Subject: [PATCH] Merge strftime.c changes from glibc
Date: Sat, 12 Nov 2016 17:28:07 -0800

This incorporates:
2007-10-16 [BZ #5184] Add tzset_called argument
2008-06-13 [BZ #6612] pass reference to tzset_called around
2009-10-30 Implement Burmese language locale for Myanmar
2010-01-09 Add support for XPG7 testing
2015-09-26 [BZ #18985] out of range data to strftime() causes a segfault
2015-10-20 Convert miscellaneous function definitions to prototype style
* lib/strftime.c: Copy glibc license, since gnulib-tool rewrites
it anyway and this lessens the difference between gnulib and glibc.
(USE_IN_EXTENDED_LOCALE_MODEL) [_LIBC]: Define.
(__THROW): Define if standard headers do not.
(LOCALE_PARAM): Rename from LOCALE_PARAM_PROTO.  All uses changed.
(memcpy_locase, memcpy_uppcase, tm_diff, __strftime_internal):
Declare with __THROW.
(__strftime_internal): Rename from strftime_case_. Add arg for
whether tzset is called.  All uses changed.  Call tzset at most
once.  Allow %OC, for Burmese.
(a_wkday, f_wkday, a_month, f_month) [_NL_CURRENT]:
Don't assume values are in range.
---
 ChangeLog      |  23 ++++++++
 lib/strftime.c | 162 ++++++++++++++++++++++++++++++++++-----------------------
 2 files changed, 121 insertions(+), 64 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dec04d9..a748d7a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2016-11-12  Paul Eggert  <address@hidden>
+
+       Merge strftime.c changes from glibc
+       This incorporates:
+       2007-10-16 [BZ #5184] Add tzset_called argument
+       2008-06-13 [BZ #6612] pass reference to tzset_called around
+       2009-10-30 Implement Burmese language locale for Myanmar
+       2010-01-09 Add support for XPG7 testing
+       2015-09-26 [BZ #18985] out of range data to strftime() causes a segfault
+       2015-10-20 Convert miscellaneous function definitions to prototype style
+       * lib/strftime.c: Copy glibc license, since gnulib-tool rewrites
+       it anyway and this lessens the difference between gnulib and glibc.
+       (USE_IN_EXTENDED_LOCALE_MODEL) [_LIBC]: Define.
+       (__THROW): Define if standard headers do not.
+       (LOCALE_PARAM): Rename from LOCALE_PARAM_PROTO.  All uses changed.
+       (memcpy_locase, memcpy_uppcase, tm_diff, __strftime_internal):
+       Declare with __THROW.
+       (__strftime_internal): Rename from strftime_case_. Add arg for
+       whether tzset is called.  All uses changed.  Call tzset at most
+       once.  Allow %OC, for Burmese.
+       (a_wkday, f_wkday, a_month, f_month) [_NL_CURRENT]:
+       Don't assume values are in range.
+
 2016-11-12  Eric Blake  <address@hidden>
 
        strerror_r-posix: Fix override of AC_FUNC_STRERROR_R
diff --git a/lib/strftime.c b/lib/strftime.c
index 564e819..00870f6 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -1,22 +1,22 @@
-/* Copyright (C) 1991-2001, 2003-2007, 2009-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-   NOTE: The canonical source of this file is maintained with the GNU C 
Library.
-   Bugs can be reported to address@hidden
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
+   The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #ifdef _LIBC
+# define USE_IN_EXTENDED_LOCALE_MODEL 1
 # define HAVE_STRUCT_ERA_ENTRY 1
 # define HAVE_TM_GMTOFF 1
 # define HAVE_TM_ZONE 1
@@ -63,10 +63,10 @@ extern char *tzname[];
 #endif
 
 #include <limits.h>
-#include <stdbool.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 
 #ifdef COMPILE_WIDE
 # include <endian.h>
@@ -89,6 +89,10 @@ extern char *tzname[];
 
 #endif
 
+#ifndef __THROW
+# define __THROW
+#endif
+
 /* Shift A right by B bits portably, by dividing A by 2**B and
    truncating towards minus infinity.  A and B should be free of side
    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
@@ -247,11 +251,11 @@ extern char *tzname[];
 # undef _NL_CURRENT
 # define _NL_CURRENT(category, item) \
   (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_PARAM , __locale_t loc
 # define LOCALE_ARG , loc
-# define LOCALE_PARAM_PROTO , __locale_t loc
 # define HELPER_LOCALE_ARG  , current
 #else
-# define LOCALE_PARAM_PROTO
+# define LOCALE_PARAM
 # define LOCALE_ARG
 # ifdef _LIBC
 #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
@@ -304,18 +308,22 @@ fwrite_uppcase (FILE *fp, const CHAR_T *src, size_t len)
     }
 }
 #else
+static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
+                               size_t len LOCALE_PARAM) __THROW;
+
 static CHAR_T *
-memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
-                size_t len LOCALE_PARAM_PROTO)
+memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
 {
   while (len-- > 0)
     dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
   return dest;
 }
 
+static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
+                               size_t len LOCALE_PARAM) __THROW;
+
 static CHAR_T *
-memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
-                size_t len LOCALE_PARAM_PROTO)
+memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
 {
   while (len-- > 0)
     dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
@@ -328,6 +336,7 @@ memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
 /* Yield the difference between *A and *B,
    measured in seconds, ignoring leap seconds.  */
 # define tm_diff ftime_tm_diff
+static int tm_diff (const struct tm *, const struct tm *) __THROW;
 static int
 tm_diff (const struct tm *a, const struct tm *b)
 {
@@ -359,6 +368,7 @@ tm_diff (const struct tm *a, const struct tm *b)
 #define ISO_WEEK_START_WDAY 1 /* Monday */
 #define ISO_WEEK1_WDAY 4 /* Thursday */
 #define YDAY_MINIMUM (-366)
+static int iso_week_days (int, int) __THROW;
 #ifdef __GNUC__
 __inline__
 #endif
@@ -401,17 +411,41 @@ iso_week_days (int yday, int wday)
 # define ns 0
 #endif
 
+static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
+                                   const CHAR_T *, const struct tm *,
+                                   bool, bool *
+                                   extra_args_spec LOCALE_PARAM) __THROW;
 
-/* Just like my_strftime, below, but with one more parameter, UPCASE,
-   to indicate that the result should be converted to upper case.  */
+/* Write information from TP into S according to the format
+   string FORMAT, writing no more that MAXSIZE characters
+   (including the terminating '\0') and returning number of
+   characters written.  If S is NULL, nothing will be written
+   anywhere, so to determine how many characters would be
+   written, use NULL for S and (size_t) -1 for MAXSIZE.  */
+size_t
+my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
+             const CHAR_T *format,
+             const struct tm *tp extra_args_spec LOCALE_PARAM)
+{
+  bool tzset_called = false;
+  return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp,
+                              false, &tzset_called extra_args LOCALE_ARG);
+}
+#if defined _LIBC && ! FPRINTFTIME
+libc_hidden_def (my_strftime)
+#endif
+
+/* Just like my_strftime, above, but with two more parameters.
+   UPCASE indicate that the result should be converted to upper case,
+   and *TZSET_CALLED indicates whether tzset has been called here.  */
 static size_t
-strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
-                STRFTIME_ARG (size_t maxsize)
-                const CHAR_T *format,
-                const struct tm *tp extra_args_spec LOCALE_PARAM_PROTO)
+__strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
+                     const CHAR_T *format,
+                     const struct tm *tp, bool upcase, bool *tzset_called
+                     extra_args_spec LOCALE_PARAM)
 {
 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
-  struct locale_data *const current = loc->__locales[LC_TIME];
+  struct __locale_data *const current = loc->__locales[LC_TIME];
 #endif
 #if FPRINTFTIME
   size_t maxsize = (size_t) -1;
@@ -426,13 +460,17 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
      only a few elements.  Dereference the pointers only if the format
      requires this.  Then it is ok to fail if the pointers are invalid.  */
 # define a_wkday \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
+  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
+                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + 
tp->tm_wday)))
 # define f_wkday \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
+  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
+                     ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
 # define a_month \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
+  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
+                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
 # define f_month \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
+  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
+                     ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
 # define ampm \
   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \
                                  ? NLW(PM_STR) : NLW(AM_STR)))
@@ -483,15 +521,21 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
       /* Infer the zone name from *TZ instead of from TZNAME.  */
       tzname_vec = tz->tzname_copy;
 # endif
+    }
+  /* The tzset() call might have changed the value.  */
+  if (!(zone && *zone) && tp->tm_isdst >= 0)
+    {
       /* POSIX.1 requires that local time zone information be used as
          though strftime called tzset.  */
 # if HAVE_TZSET
-      tzset ();
+      if (!*tzset_called)
+        {
+          tzset ();
+          *tzset_called = true;
+        }
 # endif
+      zone = tzname_vec[tp->tm_isdst != 0];
     }
-  /* The tzset() call might have changed the value.  */
-  if (!(zone && *zone) && tp->tm_isdst >= 0)
-    zone = tzname_vec[tp->tm_isdst != 0];
 #endif
   if (! zone)
     zone = "";
@@ -801,14 +845,15 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 
         subformat:
           {
-            size_t len = strftime_case_ (to_uppcase,
-                                         NULL, STRFTIME_ARG ((size_t) -1)
-                                         subfmt,
-                                         tp extra_args LOCALE_ARG);
-            add (len, strftime_case_ (to_uppcase, p,
-                                      STRFTIME_ARG (maxsize - i)
-                                      subfmt,
-                                      tp extra_args LOCALE_ARG));
+            size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
+                                              subfmt,
+                                              tp, to_uppcase, tzset_called
+                                              extra_args LOCALE_ARG);
+            add (len, __strftime_internal (p,
+                                           STRFTIME_ARG (maxsize - i)
+                                           subfmt,
+                                           tp, to_uppcase, tzset_called
+                                           extra_args LOCALE_ARG));
           }
           break;
 
@@ -845,8 +890,6 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 #endif
 
         case L_('C'):
-          if (modifier == L_('O'))
-            goto bad_format;
           if (modifier == L_('E'))
             {
 #if HAVE_STRUCT_ERA_ENTRY
@@ -1368,6 +1411,16 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                 struct tm ltm;
                 time_t lt;
 
+                /* POSIX.1 requires that local time zone information be used as
+                   though strftime called tzset.  */
+# if HAVE_TZSET
+                if (!*tzset_called)
+                  {
+                    tzset ();
+                    *tzset_called = true;
+                  }
+# endif
+
                 ltm = *tp;
                 lt = mktime_z (tz, &ltm);
 
@@ -1448,22 +1501,3 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 
   return i;
 }
-
-/* Write information from TP into S according to the format
-   string FORMAT, writing no more that MAXSIZE characters
-   (including the terminating '\0') and returning number of
-   characters written.  If S is NULL, nothing will be written
-   anywhere, so to determine how many characters would be
-   written, use NULL for S and (size_t) -1 for MAXSIZE.  */
-size_t
-my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
-             const CHAR_T *format,
-             const struct tm *tp extra_args_spec LOCALE_PARAM_PROTO)
-{
-  return strftime_case_ (false, s, STRFTIME_ARG (maxsize)
-                         format, tp extra_args LOCALE_ARG);
-}
-
-#if defined _LIBC && ! FPRINTFTIME
-libc_hidden_def (my_strftime)
-#endif
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]