Ensure we use gnulib mktime rather than glibc's mktime, on hosts
[gnulib.git] / lib / strftime.c
index b9b468a..1adcaa4 100644 (file)
@@ -265,7 +265,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
       int _n = (n);                                                          \
       int _delta = width - _n;                                               \
       int _incr = _n + (_delta > 0 ? _delta : 0);                            \
-      if (i + _incr >= maxsize)                                                      \
+      if ((size_t) _incr >= maxsize - i)                                     \
        return 0;                                                             \
       if (p)                                                                 \
        {                                                                     \
@@ -292,27 +292,19 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
           MEMCPY ((PTR) p, (const PTR) (s), _n))
 
 #ifdef COMPILE_WIDE
-# ifdef USE_IN_EXTENDED_LOCALE_MODEL
-#  define widen(os, ws, l) \
+# ifndef USE_IN_EXTENDED_LOCALE_MODEL
+#  undef __mbsrtowcs_l
+#  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
+# endif
+# define widen(os, ws, l) \
   {                                                                          \
     mbstate_t __st;                                                          \
     const char *__s = os;                                                    \
     memset (&__st, '\0', sizeof (__st));                                     \
     l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                           \
-    ws = alloca ((l + 1) * sizeof (wchar_t));                                \
+    ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                    \
     (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                          \
   }
-# else
-#  define widen(os, ws, l) \
-  {                                                                          \
-    mbstate_t __st;                                                          \
-    const char *__s = os;                                                    \
-    memset (&__st, '\0', sizeof (__st));                                     \
-    l = __mbsrtowcs (NULL, &__s, 0, &__st);                                  \
-    ws = alloca ((l + 1) * sizeof (wchar_t));                                \
-    (void) __mbsrtowcs (ws, &__s, l, &__st);                                 \
-  }
-# endif
 #endif
 
 
@@ -488,8 +480,10 @@ static CHAR_T const month_name[][10] =
 #else
 # ifdef COMPILE_WIDE
 #  define my_strftime wcsftime
+#  define nl_get_alt_digit _nl_get_walt_digit
 # else
 #  define my_strftime strftime
+#  define nl_get_alt_digit _nl_get_alt_digit
 # endif
 # define extra_args
 # define extra_args_spec
@@ -754,8 +748,15 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
          width = 0;
          do
            {
-             width *= 10;
-             width += *f - L_('0');
+             if (width > INT_MAX / 10
+                 || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
+               /* Avoid overflow.  */
+               width = INT_MAX;
+             else
+               {
+                 width *= 10;
+                 width += *f - L_('0');
+               }
              ++f;
            }
          while (ISDIGIT (*f));
@@ -779,10 +780,10 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
       switch (format_char)
        {
 #define DO_NUMBER(d, v) \
-         digits = width == -1 ? d : width;                                   \
+         digits = d > width ? d : width;                                     \
          number_value = v; goto do_number
 #define DO_NUMBER_SPACEPAD(d, v) \
-         digits = width == -1 ? d : width;                                   \
+         digits = d > width ? d : width;                                     \
          number_value = v; goto do_number_spacepad
 
        case L_('%'):
@@ -986,8 +987,8 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
             jump to one of these two labels.  */
 
        do_number_spacepad:
-         /* Force `_' flag unless overwritten by `0' flag.  */
-         if (pad != L_('0'))
+         /* Force `_' flag unless overridden by `0' or `-' flag.  */
+         if (pad != L_('0') && pad != L_('-'))
            pad = L_('_');
 
        do_number:
@@ -998,13 +999,8 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
 #ifdef _NL_CURRENT
              /* Get the locale specific alternate representation of
                 the number NUMBER_VALUE.  If none exist NULL is returned.  */
-# ifdef COMPILE_WIDE
-             const wchar_t *cp = _nl_get_walt_digit (number_value
-                                                     HELPER_LOCALE_ARG);
-# else
-             const char *cp = _nl_get_alt_digit (number_value
-                                                 HELPER_LOCALE_ARG);
-# endif
+             const CHAR_T *cp = nl_get_alt_digit (number_value
+                                                  HELPER_LOCALE_ARG);
 
              if (cp != NULL)
                {
@@ -1044,18 +1040,37 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
              int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
                                      - bufp);
 
-             if (pad == L_('_'))
-               {
-                 while (0 < padding--)
-                   *--bufp = L_(' ');
-               }
-             else
+             if (padding > 0)
                {
-                 bufp += negative_number;
-                 while (0 < padding--)
-                   *--bufp = L_('0');
-                 if (negative_number)
-                   *--bufp = L_('-');
+                 if (pad == L_('_'))
+                   {
+                     if ((size_t) padding >= maxsize - i)
+                       return 0;
+
+                     if (p)
+                       memset_space (p, padding);
+                     i += padding;
+                     width = width > padding ? width - padding : 0;
+                   }
+                 else
+                   {
+                     if ((size_t) digits >= maxsize - i)
+                       return 0;
+
+                     if (negative_number)
+                       {
+                         ++bufp;
+
+                         if (p)
+                           *p++ = L_('-');
+                         ++i;
+                       }
+
+                     if (p)
+                       memset_zero (p, padding);
+                     i += padding;
+                     width = 0;
+                   }
                }
            }