X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fstrftime.c;h=1e026649d0c6a568f2a897f1d6cf43c6128aa917;hb=a9b64ea6a96fe625db5332f5e2b3e5f968704af7;hp=9a421df44bbdb1be8ed75f3ae874930952f11e13;hpb=7535c9422de3d94d22a3f0dabbeff9623131417d;p=gnulib.git diff --git a/lib/strftime.c b/lib/strftime.c index 9a421df44..1e026649d 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -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 @@ -168,44 +167,21 @@ extern char *tzname[]; #ifdef _LIBC -# define my_strftime_gmtime_r __gmtime_r -# define my_strftime_localtime_r __localtime_r # define tzname __tzname # define tzset __tzset -#else - -/* If we're a strftime substitute in a GNU program, then prefer gmtime - to gmtime_r, since many gmtime_r implementations are buggy. - Similarly for localtime_r. */ - -# if ! HAVE_TM_GMTOFF -static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *)); -static struct tm * -my_strftime_gmtime_r (t, tp) - const time_t *t; - struct tm *tp; -{ - struct tm *l = gmtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} +#endif -static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *)); -static struct tm * -my_strftime_localtime_r (t, tp) - const time_t *t; - struct tm *tp; -{ - struct tm *l = localtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} -# endif /* ! HAVE_TM_GMTOFF */ -#endif /* ! defined _LIBC */ +#if !HAVE_TM_GMTOFF +/* Portable standalone applications should supply a "time_r.h" that + declares a POSIX-compliant localtime_r, for the benefit of older + implementations that lack localtime_r or have a nonstandard one. + See the gnulib time_r module for one way to implement this. */ +# include "time_r.h" +# undef __gmtime_r +# undef __localtime_r +# define __gmtime_r gmtime_r +# define __localtime_r localtime_r +#endif #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC @@ -265,7 +241,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 +278,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 @@ -493,25 +469,11 @@ static CHAR_T const month_name[][10] = # define ns 0 #endif -#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET - /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime. - Work around this bug by copying *tp before it might be munged. */ - size_t _strftime_copytm __P ((char *, size_t, const char *, - const struct tm * extra_args_spec_iso)); - size_t - my_strftime (s, maxsize, format, tp extra_args) - CHAR_T *s; - size_t maxsize; - const CHAR_T *format; - const struct tm *tp; - extra_args_spec - { - struct tm tmcopy; - tmcopy = *tp; - return _strftime_copytm (s, maxsize, format, &tmcopy extra_args); - } -# undef my_strftime -# define my_strftime _strftime_copytm +#if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST +/* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned + by localtime. On such systems, we must use the tzset and localtime + wrappers to work around the bug. */ +"you must run the autoconf test for a working tzset function" #endif @@ -615,7 +577,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) int pad = 0; /* Padding for number ('-', '_', or 0). */ int modifier; /* Field modifier ('E', 'O', or 0). */ int digits; /* Max digits for numeric format. */ - int number_value; /* Numeric value to be printed. */ + int number_value; /* Numeric value to be printed. */ int negative_number; /* 1 if the number is negative. */ const CHAR_T *subfmt; CHAR_T *bufp; @@ -748,8 +710,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 +742,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 +949,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: @@ -1022,7 +991,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) do *--bufp = u % 10 + L_('0'); while ((u /= 10) != 0); - } + } do_number_sign_and_padding: if (negative_number) @@ -1033,18 +1002,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; + } } } @@ -1145,13 +1133,17 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) goto subformat; case L_('r'): -#ifdef _NL_CURRENT +#if !defined _NL_CURRENT && HAVE_STRFTIME + goto underlying_strftime; +#else +# ifdef _NL_CURRENT if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT_AMPM))) == L_('\0')) -#endif +# endif subfmt = L_("%I:%M:%S %p"); goto subformat; +#endif case L_('S'): if (modifier == L_('E')) @@ -1160,7 +1152,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) DO_NUMBER (2, tp->tm_sec); case L_('s'): /* GNU extension. */ - { + { struct tm ltm; time_t t; @@ -1385,7 +1377,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) occurred. */ struct tm tm; - if (! my_strftime_localtime_r (<, &tm) + if (! __localtime_r (<, &tm) || ((ltm.tm_sec ^ tm.tm_sec) | (ltm.tm_min ^ tm.tm_min) | (ltm.tm_hour ^ tm.tm_hour) @@ -1395,7 +1387,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) break; } - if (! my_strftime_gmtime_r (<, >m)) + if (! __gmtime_r (<, >m)) break; diff = tm_diff (<m, >m);