Merge frem coreutils.
[gnulib.git] / lib / strftime.c
index 9a421df..b15dfa9 100644 (file)
@@ -3,20 +3,19 @@
    NOTE: The canonical source of this file is maintained with the GNU C Library.
    Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 
-   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 2, 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 2, or (at your option)
+   any later version.
 
    This program 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
-   Library General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-   USA.  */
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
@@ -265,7 +264,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)                                                                 \
        {                                                                     \
@@ -302,7 +301,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
     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);                          \
   }
 #endif
@@ -748,8 +747,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));
@@ -773,10 +779,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_('%'):
@@ -980,8 +986,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:
@@ -1033,18 +1039,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;
+                   }
                }
            }