/[emacs]/emacs/src/strftime.c
ViewVC logotype

Diff of /emacs/src/strftime.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.28 by monnier, Sun May 25 17:44:14 2003 UTC revision 1.29 by fx, Tue Jun 24 09:42:14 2003 UTC
# Line 1  Line 1 
1  /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2003  /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2003
2               Free Software Foundation, Inc.               Free Software Foundation, Inc.
3    
4       NOTE: The canonical source of this file is maintained with gnulib.
5       Bugs can be reported to bug-gnulib@gnu.org.
6    
7     This file is part of the GNU Emacs.     This file is part of the GNU Emacs.
8    
9     The GNU C Library is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU Library General Public License as     modify it under the terms of the GNU Library General Public License
11     published by the Free Software Foundation; either version 2 of the     as published by the Free Software Foundation; either version 2, or
12     License, or (at your option) any later version.     (at your option) any later version.
13    
14     The GNU C Library is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     Library General Public License for more details.     Library General Public License for more details.
# Line 36  Line 39 
39  # include "../locale/localeinfo.h"  # include "../locale/localeinfo.h"
40  #endif  #endif
41    
 #if defined emacs && !defined HAVE_BCOPY  
 # define HAVE_MEMCPY 1  
 #endif  
   
42  #include <ctype.h>  #include <ctype.h>
43  #include <sys/types.h>          /* Some systems define `time_t' here.  */  #include <sys/types.h>          /* Some systems define `time_t' here.  */
44    
45  #ifdef TIME_WITH_SYS_TIME  #ifdef TIME_WITH_SYS_TIME
46  # include <sys/time.h>  # include <sys/time.h>
# Line 70  extern char *tzname[]; Line 69  extern char *tzname[];
69  #if DO_MULTIBYTE  #if DO_MULTIBYTE
70  # if HAVE_MBRLEN  # if HAVE_MBRLEN
71  #  include <wchar.h>  #  include <wchar.h>
72  #   if __hpux  #   ifdef HAVE_SYS__MBSTATE_H   /* previously tested __hpux */
73  #     include <sys/_mbstate_t.h>  #     include <sys/_mbstate_t.h>
74  #   endif  #   endif
75  #  if !defined (mbsinit) && !defined (HAVE_MBSINIT)  #  if !defined (mbsinit) && !defined (HAVE_MBSINIT)
# Line 92  extern char *tzname[]; Line 91  extern char *tzname[];
91  #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
92  # include <stddef.h>  # include <stddef.h>
93  # include <stdlib.h>  # include <stdlib.h>
94    # include <string.h>
95  #else  #else
96  # ifndef HAVE_MEMCPY  # ifndef HAVE_MEMCPY
97  #  define memcpy(d, s, n) bcopy ((s), (d), (n))  #  define memcpy(d, s, n) bcopy ((s), (d), (n))
# Line 131  extern char *tzname[]; Line 131  extern char *tzname[];
131  #endif  #endif
132    
133  #ifndef __P  #ifndef __P
134  # if defined emacs && defined PROTOTYPES  # if defined __GNUC__ || (defined __STDC__ && __STDC__) || defined (PROTOTYPES)
 #  define __P(args) args  
 # elif defined __GNUC__ || (defined __STDC__ && __STDC__)  
135  #  define __P(args) args  #  define __P(args) args
136  # else  # else
137  #  define __P(args) ()  #  define __P(args) ()
# Line 171  extern char *tzname[]; Line 169  extern char *tzname[];
169  #ifndef __isleap  #ifndef __isleap
170  /* Nonzero if YEAR is a leap year (every 4 years,  /* Nonzero if YEAR is a leap year (every 4 years,
171     except every 100th isn't, and every 400th is).  */     except every 100th isn't, and every 400th is).  */
172  # define __isleap(year) \  # define __isleap(year) \
173    ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))    ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
174  #endif  #endif
175    
# Line 214  my_strftime_localtime_r (t, tp) Line 212  my_strftime_localtime_r (t, tp)
212    return tp;    return tp;
213  }  }
214  # endif /* ! HAVE_TM_GMTOFF */  # endif /* ! HAVE_TM_GMTOFF */
   
215  #endif /* ! defined _LIBC */  #endif /* ! defined _LIBC */
216    
217    
# Line 235  static const CHAR_T zeroes[16] = /* "000 Line 232  static const CHAR_T zeroes[16] = /* "000
232  };  };
233    
234  # define memset_space(P, Len) \  # define memset_space(P, Len) \
235    do {                                                                        \    do {                                                                        \
236      int _len = (Len);                                                         \      int _len = (Len);                                                         \
237                                                                                \                                                                                \
238      do                                                                        \      do                                                                        \
239        {                                                                       \        {                                                                       \
240          int _this = _len > 16 ? 16 : _len;                                    \          int _this = _len > 16 ? 16 : _len;                                    \
241          (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T));                 \          (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T));                 \
242          _len -= _this;                                                        \          _len -= _this;                                                        \
243        }                                                                       \        }                                                                       \
244      while (_len > 0);                                                         \      while (_len > 0);                                                         \
245    } while (0)    } while (0)
246    
247  # define memset_zero(P, Len) \  # define memset_zero(P, Len) \
248    do {                                                                        \    do {                                                                        \
249      int _len = (Len);                                                         \      int _len = (Len);                                                         \
250                                                                                \                                                                                \
251      do                                                                        \      do                                                                        \
252        {                                                                       \        {                                                                       \
253          int _this = _len > 16 ? 16 : _len;                                    \          int _this = _len > 16 ? 16 : _len;                                    \
254          (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T));                 \          (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T));                 \
255          _len -= _this;                                                        \          _len -= _this;                                                        \
256        }                                                                       \        }                                                                       \
257      while (_len > 0);                                                         \      while (_len > 0);                                                         \
258    } while (0)    } while (0)
259  #else  #else
260  # ifdef COMPILE_WIDE  # ifdef COMPILE_WIDE
# Line 269  static const CHAR_T zeroes[16] = /* "000 Line 266  static const CHAR_T zeroes[16] = /* "000
266  # endif  # endif
267  #endif  #endif
268    
269  #define add(n, f)                                                             \  #define add(n, f)                                                             \
270    do                                                                          \    do                                                                          \
271      {                                                                         \      {                                                                         \
272        int _n = (n);                                                           \        int _n = (n);                                                           \
273        int _delta = width - _n;                                                \        int _delta = width - _n;                                                \
274        int _incr = _n + (_delta > 0 ? _delta : 0);                             \        int _incr = _n + (_delta > 0 ? _delta : 0);                             \
275        if (i + _incr >= maxsize)                                               \        if ((size_t) _incr >= maxsize - i)                                      \
276          return 0;                                                             \          return 0;                                                             \
277        if (p)                                                                  \        if (p)                                                                  \
278          {                                                                     \          {                                                                     \
279            if (_delta > 0)                                                     \            if (_delta > 0)                                                     \
280              {                                                                 \              {                                                                 \
281                if (pad == L_('0'))                                             \                if (pad == L_('0'))                                             \
282                  memset_zero (p, _delta);                                      \                  memset_zero (p, _delta);                                      \
283                else                                                            \                else                                                            \
284                  memset_space (p, _delta);                                     \                  memset_space (p, _delta);                                     \
285              }                                                                 \              }                                                                 \
286            f;                                                                  \            f;                                                                  \
287            p += _n;                                                            \            p += _n;                                                            \
288          }                                                                     \          }                                                                     \
289        i += _incr;                                                             \        i += _incr;                                                             \
290      } while (0)      } while (0)
291    
292  #define cpy(n, s) \  #define cpy(n, s) \
293      add ((n),                                                                 \      add ((n),                                                                 \
294           if (to_lowcase)                                                      \           if (to_lowcase)                                                      \
295             memcpy_lowcase (p, (s), _n);                                       \             memcpy_lowcase (p, (s), _n LOCALE_ARG);                            \
296           else if (to_uppcase)                                                 \           else if (to_uppcase)                                                 \
297             memcpy_uppcase (p, (s), _n);                                       \             memcpy_uppcase (p, (s), _n LOCALE_ARG);                            \
298           else                                                                 \           else                                                                 \
299             MEMCPY ((PTR) p, (PTR) (s), _n))             MEMCPY ((PTR) p, (const PTR) (s), _n))
300    
301  #ifdef COMPILE_WIDE  #ifdef COMPILE_WIDE
302    # ifndef USE_IN_EXTENDED_LOCALE_MODEL
303    #  undef __mbsrtowcs_l
304    #  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
305    # endif
306  # define widen(os, ws, l) \  # define widen(os, ws, l) \
307    {                                                                           \    {                                                                           \
308      mbstate_t __st;                                                           \      mbstate_t __st;                                                           \
309      const char *__s = os;                                                     \      const char *__s = os;                                                     \
310      memset (&__st, '\0', sizeof (__st));                                      \      memset (&__st, '\0', sizeof (__st));                                      \
311      l = __mbsrtowcs (NULL, &__s, 0, &__st);                                   \      l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                            \
312      ws = alloca ((l + 1) * sizeof (wchar_t));                                 \      ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                     \
313      (void) __mbsrtowcs (ws, &__s, l, &__st);                                  \      (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                           \
314    }    }
315  #endif  #endif
316    
317    
318    #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
319    /* We use this code also for the extended locale handling where the
320       function gets as an additional argument the locale which has to be
321       used.  To access the values we have to redefine the _NL_CURRENT
322       macro.  */
323    # define strftime               __strftime_l
324    # define wcsftime               __wcsftime_l
325    # undef _NL_CURRENT
326    # define _NL_CURRENT(category, item) \
327      (current->values[_NL_ITEM_INDEX (item)].string)
328    # define LOCALE_PARAM , loc
329    # define LOCALE_ARG , loc
330    # define LOCALE_PARAM_DECL  __locale_t loc;
331    # define LOCALE_PARAM_PROTO , __locale_t loc
332    # define HELPER_LOCALE_ARG  , current
333    #else
334    # define LOCALE_PARAM
335    # define LOCALE_PARAM_PROTO
336    # define LOCALE_ARG
337    # define LOCALE_PARAM_DECL
338    # ifdef _LIBC
339    #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
340    # else
341    #  define HELPER_LOCALE_ARG
342    # endif
343    #endif
344    
345  #ifdef COMPILE_WIDE  #ifdef COMPILE_WIDE
346  # define TOUPPER(Ch) towupper (Ch)  # ifdef USE_IN_EXTENDED_LOCALE_MODEL
347  # define TOLOWER(Ch) towlower (Ch)  #  define TOUPPER(Ch, L) __towupper_l (Ch, L)
348    #  define TOLOWER(Ch, L) __towlower_l (Ch, L)
349    # else
350    #  define TOUPPER(Ch, L) towupper (Ch)
351    #  define TOLOWER(Ch, L) towlower (Ch)
352    # endif
353  #else  #else
354  # ifdef _LIBC  # ifdef _LIBC
355  #  define TOUPPER(Ch) toupper (Ch)  #  ifdef USE_IN_EXTENDED_LOCALE_MODEL
356  #  define TOLOWER(Ch) tolower (Ch)  #   define TOUPPER(Ch, L) __toupper_l (Ch, L)
357    #   define TOLOWER(Ch, L) __tolower_l (Ch, L)
358    #  else
359    #   define TOUPPER(Ch, L) toupper (Ch)
360    #   define TOLOWER(Ch, L) tolower (Ch)
361    #  endif
362  # else  # else
363  #  define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))  #  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
364  #  define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))  #  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
365  # endif  # endif
366  #endif  #endif
367  /* We don't use `isdigit' here since the locale dependent  /* We don't use `isdigit' here since the locale dependent
# Line 333  static const CHAR_T zeroes[16] = /* "000 Line 371  static const CHAR_T zeroes[16] = /* "000
371  #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)  #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
372    
373  static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,  static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
374                                      size_t len));                                      size_t len LOCALE_PARAM_PROTO));
375    
376  static CHAR_T *  static CHAR_T *
377  memcpy_lowcase (dest, src, len)  memcpy_lowcase (dest, src, len LOCALE_PARAM)
378       CHAR_T *dest;       CHAR_T *dest;
379       const CHAR_T *src;       const CHAR_T *src;
380       size_t len;       size_t len;
381         LOCALE_PARAM_DECL
382  {  {
383    while (len-- > 0)    while (len-- > 0)
384      dest[len] = TOLOWER ((UCHAR_T) src[len]);      dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
385    return dest;    return dest;
386  }  }
387    
388  static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,  static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
389                                      size_t len));                                      size_t len LOCALE_PARAM_PROTO));
390    
391  static CHAR_T *  static CHAR_T *
392  memcpy_uppcase (dest, src, len)  memcpy_uppcase (dest, src, len LOCALE_PARAM)
393       CHAR_T *dest;       CHAR_T *dest;
394       const CHAR_T *src;       const CHAR_T *src;
395       size_t len;       size_t len;
396         LOCALE_PARAM_DECL
397  {  {
398    while (len-- > 0)    while (len-- > 0)
399      dest[len] = TOUPPER ((UCHAR_T) src[len]);      dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
400    return dest;    return dest;
401  }  }
402    
# Line 383  tm_diff (a, b) Line 423  tm_diff (a, b)
423    int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);    int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
424    int years = a->tm_year - b->tm_year;    int years = a->tm_year - b->tm_year;
425    int days = (365 * years + intervening_leap_days    int days = (365 * years + intervening_leap_days
426                + (a->tm_yday - b->tm_yday));                + (a->tm_yday - b->tm_yday));
427    return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))    return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
428                  + (a->tm_min - b->tm_min))                  + (a->tm_min - b->tm_min))
429            + (a->tm_sec - b->tm_sec));            + (a->tm_sec - b->tm_sec));
430  }  }
431  #endif /* ! HAVE_TM_GMTOFF */  #endif /* ! HAVE_TM_GMTOFF */
432    
# Line 411  iso_week_days (yday, wday) Line 451  iso_week_days (yday, wday)
451    /* Add enough to the first operand of % to make it nonnegative.  */    /* Add enough to the first operand of % to make it nonnegative.  */
452    int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;    int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
453    return (yday    return (yday
454            - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7            - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
455            + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);            + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
456  }  }
457    
458    
# Line 431  static CHAR_T const month_name[][10] = Line 471  static CHAR_T const month_name[][10] =
471  #endif  #endif
472    
473    
474  #ifdef emacs  /* When compiling this file, GNU applications can #define my_strftime
475  # define my_strftime emacs_strftimeu     to a symbol (typically nstrftime) to get an extended strftime with
476  # define ut_argument , ut     extra arguments UT and NS.  */
477  # define ut_argument_spec int ut;  
478  # define ut_argument_spec_iso , int ut  #ifdef my_strftime
479    # define extra_args , ut, ns
480    # define extra_args_spec int ut; int ns;
481    # define extra_args_spec_iso , int ut, int ns
482  #else  #else
483  # ifdef COMPILE_WIDE  # ifdef COMPILE_WIDE
484  #  define my_strftime wcsftime  #  define my_strftime wcsftime
485    #  define nl_get_alt_digit _nl_get_walt_digit
486  # else  # else
487  #  define my_strftime strftime  #  define my_strftime strftime
488    #  define nl_get_alt_digit _nl_get_alt_digit
489  # endif  # endif
490  # define ut_argument  # define extra_args
491  # define ut_argument_spec  # define extra_args_spec
492  # define ut_argument_spec_iso  # define extra_args_spec_iso
493  /* We don't have this information in general.  */  /* We don't have this information in general.  */
494  # define ut 0  # define ut 0
495    # define ns 0
496  #endif  #endif
497    
498  #if !defined _LIBC && !defined(WINDOWSNT) && HAVE_TZNAME && HAVE_TZSET  #if !defined _LIBC && !defined(WINDOWSNT) && HAVE_TZNAME && HAVE_TZSET
499    /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.    /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
500       Work around this bug by copying *tp before it might be munged.  */       Work around this bug by copying *tp before it might be munged.  */
501    size_t _strftime_copytm __P ((char *, size_t, const char *,    size_t _strftime_copytm __P ((char *, size_t, const char *,
502                                  const struct tm * ut_argument_spec_iso));                                  const struct tm * extra_args_spec_iso));
503    size_t    size_t
504    my_strftime (s, maxsize, format, tp ut_argument)    my_strftime (s, maxsize, format, tp extra_args)
505        CHAR_T *s;        CHAR_T *s;
506        size_t maxsize;        size_t maxsize;
507        const CHAR_T *format;        const CHAR_T *format;
508        const struct tm *tp;        const struct tm *tp;
509        ut_argument_spec        extra_args_spec
510    {    {
511      struct tm tmcopy;      struct tm tmcopy;
512      tmcopy = *tp;      tmcopy = *tp;
513      return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);      return _strftime_copytm (s, maxsize, format, &tmcopy extra_args);
514    }    }
515  # undef my_strftime  # undef my_strftime
516  # define my_strftime _strftime_copytm  # define my_strftime _strftime_copytm
# Line 478  static CHAR_T const month_name[][10] = Line 524  static CHAR_T const month_name[][10] =
524     anywhere, so to determine how many characters would be     anywhere, so to determine how many characters would be
525     written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */     written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
526  size_t  size_t
527  my_strftime (s, maxsize, format, tp ut_argument)  my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
528        CHAR_T *s;        CHAR_T *s;
529        size_t maxsize;        size_t maxsize;
530        const CHAR_T *format;        const CHAR_T *format;
531        const struct tm *tp;        const struct tm *tp;
532        ut_argument_spec        extra_args_spec
533          LOCALE_PARAM_DECL
534  {  {
535    #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
536      struct locale_data *const current = loc->__locales[LC_TIME];
537    #endif
538    
539    int hour12 = tp->tm_hour;    int hour12 = tp->tm_hour;
540  #ifdef _NL_CURRENT  #ifdef _NL_CURRENT
541    /* We cannot make the following values variables since we must delay    /* We cannot make the following values variables since we must delay
# Line 502  my_strftime (s, maxsize, format, tp ut_a Line 553  my_strftime (s, maxsize, format, tp ut_a
553  # define f_month \  # define f_month \
554    ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))    ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
555  # define ampm \  # define ampm \
556    ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \    ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \
557                                   ? NLW(PM_STR) : NLW(AM_STR)))                                   ? NLW(PM_STR) : NLW(AM_STR)))
558    
559  # define aw_len STRLEN (a_wkday)  # define aw_len STRLEN (a_wkday)
560  # define am_len STRLEN (a_month)  # define am_len STRLEN (a_month)
# Line 525  my_strftime (s, maxsize, format, tp ut_a Line 576  my_strftime (s, maxsize, format, tp ut_a
576    size_t i = 0;    size_t i = 0;
577    CHAR_T *p = s;    CHAR_T *p = s;
578    const CHAR_T *f;    const CHAR_T *f;
579    #if DO_MULTIBYTE && !defined COMPILE_WIDE
580      const char *format_end = NULL;
581    #endif
582    
583    zone = NULL;    zone = NULL;
584  #if HAVE_TM_ZONE  #if HAVE_TM_ZONE
# Line 540  my_strftime (s, maxsize, format, tp ut_a Line 594  my_strftime (s, maxsize, format, tp ut_a
594    if (ut)    if (ut)
595      {      {
596        if (! (zone && *zone))        if (! (zone && *zone))
597          zone = "UTC";          zone = "GMT";
598      }      }
599    else    else
600      {      {
601        /* POSIX.1 8.1.1 requires that whenever strftime() is called, the        /* POSIX.1 requires that local time zone information be used as
602           time zone names contained in the external variable `tzname' shall           though strftime called tzset.  */
          be set as if the tzset() function had been called.  */  
603  # if HAVE_TZSET  # if HAVE_TZSET
604        tzset ();        tzset ();
605  # endif  # endif
# Line 561  my_strftime (s, maxsize, format, tp ut_a Line 614  my_strftime (s, maxsize, format, tp ut_a
614    
615    for (f = format; *f != '\0'; ++f)    for (f = format; *f != '\0'; ++f)
616      {      {
617        int pad = 0;              /* Padding for number ('-', '_', or 0).  */        int pad = 0;              /* Padding for number ('-', '_', or 0).  */
618        int modifier;             /* Field modifier ('E', 'O', or 0).  */        int modifier;             /* Field modifier ('E', 'O', or 0).  */
619        int digits;               /* Max digits for numeric format.  */        int digits;               /* Max digits for numeric format.  */
620        int number_value;         /* Numeric value to be printed.  */        int number_value;         /* Numeric value to be printed.  */
621        int negative_number;      /* 1 if the number is negative.  */        int negative_number;      /* 1 if the number is negative.  */
622        const CHAR_T *subfmt;        const CHAR_T *subfmt;
623        CHAR_T *bufp;        CHAR_T *bufp;
624        CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)        CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
625                        ? INT_STRLEN_BOUND (time_t)                        ? INT_STRLEN_BOUND (time_t)
626                        : INT_STRLEN_BOUND (int))];                        : INT_STRLEN_BOUND (int))];
627        int width = -1;        int width = -1;
628        int to_lowcase = 0;        int to_lowcase = 0;
629        int to_uppcase = 0;        int to_uppcase = 0;
# Line 579  my_strftime (s, maxsize, format, tp ut_a Line 632  my_strftime (s, maxsize, format, tp ut_a
632    
633  #if DO_MULTIBYTE && !defined COMPILE_WIDE  #if DO_MULTIBYTE && !defined COMPILE_WIDE
634        switch (*f)        switch (*f)
635          {          {
636          case L_('%'):          case L_('%'):
637            break;            break;
638    
639          case L_('\b'): case L_('\t'): case L_('\n'):          case L_('\b'): case L_('\t'): case L_('\n'):
640          case L_('\v'): case L_('\f'): case L_('\r'):          case L_('\v'): case L_('\f'): case L_('\r'):
641          case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):          case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
642          case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):          case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
643          case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):          case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
644          case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):          case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
645          case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):          case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
646          case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):          case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
647          case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):          case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
648          case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):          case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
649          case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):          case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
650          case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):          case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
651          case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):          case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
652          case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):          case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
653          case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):          case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
654          case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):          case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
655          case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):          case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
656          case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):          case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
657          case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):          case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
658          case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):          case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
659          case L_('~'):          case L_('~'):
660            /* The C Standard requires these 97 characters (plus '%', `\a') to            /* The C Standard requires these 98 characters (plus '%') to
661               be in the basic execution character set.  None of these               be in the basic execution character set.  None of these
662               characters can start a multibyte sequence, so they need               characters can start a multibyte sequence, so they need
663               not be analyzed further.  Some old compilers object to               not be analyzed further.  */
664               `\a', so don't bother optimizing for it.  */            add (1, *p = *f);
665            add (1, *p = *f);            continue;
666            continue;  
667            default:
668          default:            /* Copy this multibyte sequence until we reach its end, find
669            /* Copy this multibyte sequence until we reach its end, find               an error, or come back to the initial shift state.  */
670               an error, or come back to the initial shift state.  */            {
671            {              mbstate_t mbstate = mbstate_zero;
672              mbstate_t mbstate = mbstate_zero;              size_t len = 0;
673              size_t len = 0;              size_t fsize;
674    
675              do              if (! format_end)
676                {                format_end = f + strlen (f) + 1;
677                  size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);              fsize = format_end - f;
678    
679                  if (bytes == 0)              do
680                    break;                {
681                    size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
682                  if (bytes == (size_t) -2)  
683                    {                  if (bytes == 0)
684                      len += strlen (f + len);                    break;
685                      break;  
686                    }                  if (bytes == (size_t) -2)
687                      {
688                  if (bytes == (size_t) -1)                      len += strlen (f + len);
689                    {                      break;
690                      len++;                    }
691                      break;  
692                    }                  if (bytes == (size_t) -1)
693                      {
694                  len += bytes;                      len++;
695                }                      break;
696              while (! mbsinit (&mbstate));                    }
697    
698              cpy (len, f);                  len += bytes;
699              f += len - 1;                }
700              continue;              while (! mbsinit (&mbstate));
701            }  
702          }              cpy (len, f);
703                f += len - 1;
704                continue;
705              }
706            }
707    
708  #else /* ! DO_MULTIBYTE */  #else /* ! DO_MULTIBYTE */
709    
710        /* Either multibyte encodings are not supported, they are        /* Either multibyte encodings are not supported, they are
711           safe for formats, so any non-'%' byte can be copied through,           safe for formats, so any non-'%' byte can be copied through,
712           or this is the wide character version.  */           or this is the wide character version.  */
713        if (*f != L_('%'))        if (*f != L_('%'))
714          {          {
715            add (1, *p = *f);            add (1, *p = *f);
716            continue;            continue;
717          }          }
718    
719  #endif /* ! DO_MULTIBYTE */  #endif /* ! DO_MULTIBYTE */
720    
721        /* Check for flags that can modify a format.  */        /* Check for flags that can modify a format.  */
722        while (1)        while (1)
723          {          {
724            switch (*++f)            switch (*++f)
725              {              {
726                /* This influences the number formats.  */                /* This influences the number formats.  */
727              case L_('_'):              case L_('_'):
728              case L_('-'):              case L_('-'):
729              case L_('0'):              case L_('0'):
730                pad = *f;                pad = *f;
731                continue;                continue;
732    
733                /* This changes textual output.  */                /* This changes textual output.  */
734              case L_('^'):              case L_('^'):
735                to_uppcase = 1;                to_uppcase = 1;
736                continue;                continue;
737              case L_('#'):              case L_('#'):
738                change_case = 1;                change_case = 1;
739                continue;                continue;
740    
741              default:              default:
742                break;                break;
743              }              }
744            break;            break;
745          }          }
746    
747        /* As a GNU extension we allow to specify the field width.  */        /* As a GNU extension we allow to specify the field width.  */
748        if (ISDIGIT (*f))        if (ISDIGIT (*f))
749          {          {
750            width = 0;            width = 0;
751            do            do
752              {              {
753                width *= 10;                if (width > INT_MAX / 10
754                width += *f - L_('0');                    || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
755                ++f;                  /* Avoid overflow.  */
756              }                  width = INT_MAX;
757            while (ISDIGIT (*f));                else
758          }                  {
759                      width *= 10;
760                      width += *f - L_('0');
761                    }
762                  ++f;
763                }
764              while (ISDIGIT (*f));
765            }
766    
767        /* Check for modifiers.  */        /* Check for modifiers.  */
768        switch (*f)        switch (*f)
769          {          {
770          case L_('E'):          case L_('E'):
771          case L_('O'):          case L_('O'):
772            modifier = *f++;            modifier = *f++;
773            break;            break;
774    
775          default:          default:
776            modifier = 0;            modifier = 0;
777            break;            break;
778          }          }
779    
780        /* Now do the specified format.  */        /* Now do the specified format.  */
781        format_char = *f;        format_char = *f;
782        switch (format_char)        switch (format_char)
783          {          {
784  #define DO_NUMBER(d, v) \  #define DO_NUMBER(d, v) \
785            digits = width == -1 ? d : width;                                   \            digits = d > width ? d : width;                                     \
786            number_value = v; goto do_number            number_value = v; goto do_number
787  #define DO_NUMBER_SPACEPAD(d, v) \  #define DO_NUMBER_SPACEPAD(d, v) \
788            digits = width == -1 ? d : width;                                   \            digits = d > width ? d : width;                                     \
789            number_value = v; goto do_number_spacepad            number_value = v; goto do_number_spacepad
   
         case L_('%'):  
           if (modifier != 0)  
             goto bad_format;  
           add (1, *p = *f);  
           break;  
790    
791          case L_('a'):          case L_('%'):
792            if (modifier != 0)            if (modifier != 0)
793              goto bad_format;              goto bad_format;
794            if (change_case)            add (1, *p = *f);
795              {            break;
796                to_uppcase = 1;  
797                to_lowcase = 0;          case L_('a'):
798              }            if (modifier != 0)
799                goto bad_format;
800              if (change_case)
801                {
802                  to_uppcase = 1;
803                  to_lowcase = 0;
804                }
805  #if defined _NL_CURRENT || !HAVE_STRFTIME  #if defined _NL_CURRENT || !HAVE_STRFTIME
806            cpy (aw_len, a_wkday);            cpy (aw_len, a_wkday);
807            break;            break;
808  #else  #else
809            goto underlying_strftime;            goto underlying_strftime;
810  #endif  #endif
811    
812          case 'A':          case 'A':
813            if (modifier != 0)            if (modifier != 0)
814              goto bad_format;              goto bad_format;
815            if (change_case)            if (change_case)
816              {              {
817                to_uppcase = 1;                to_uppcase = 1;
818                to_lowcase = 0;                to_lowcase = 0;
819              }              }
820  #if defined _NL_CURRENT || !HAVE_STRFTIME  #if defined _NL_CURRENT || !HAVE_STRFTIME
821            cpy (STRLEN (f_wkday), f_wkday);            cpy (STRLEN (f_wkday), f_wkday);
822            break;            break;
823  #else  #else
824            goto underlying_strftime;            goto underlying_strftime;
825  #endif  #endif
826    
827          case L_('b'):          case L_('b'):
828          case L_('h'):           /* POSIX.2 extension.  */          case L_('h'):
829            if (change_case)            if (change_case)
830              {              {
831                to_uppcase = 1;                to_uppcase = 1;
832                to_lowcase = 0;                to_lowcase = 0;
833              }              }
834            if (modifier != 0)            if (modifier != 0)
835              goto bad_format;              goto bad_format;
836  #if defined _NL_CURRENT || !HAVE_STRFTIME  #if defined _NL_CURRENT || !HAVE_STRFTIME
837            cpy (am_len, a_month);            cpy (am_len, a_month);
838            break;            break;
839  #else  #else
840            goto underlying_strftime;            goto underlying_strftime;
841  #endif  #endif
842    
843          case L_('B'):          case L_('B'):
844            if (modifier != 0)            if (modifier != 0)
845              goto bad_format;              goto bad_format;
846            if (change_case)            if (change_case)
847              {              {
848                to_uppcase = 1;                to_uppcase = 1;
849                to_lowcase = 0;                to_lowcase = 0;
850              }              }
851  #if defined _NL_CURRENT || !HAVE_STRFTIME  #if defined _NL_CURRENT || !HAVE_STRFTIME
852            cpy (STRLEN (f_month), f_month);            cpy (STRLEN (f_month), f_month);
853            break;            break;
854  #else  #else
855            goto underlying_strftime;            goto underlying_strftime;
856  #endif  #endif
857    
858          case L_('c'):          case L_('c'):
859            if (modifier == L_('O'))            if (modifier == L_('O'))
860              goto bad_format;              goto bad_format;
861  #ifdef _NL_CURRENT  #ifdef _NL_CURRENT
862            if (! (modifier == 'E'            if (! (modifier == 'E'
863                   && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,                   && (*(subfmt =
864                                                          NLW(ERA_D_T_FMT)))                         (const CHAR_T *) _NL_CURRENT (LC_TIME,
865                       != '\0')))                                                       NLW(ERA_D_T_FMT)))
866              subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));                       != '\0')))
867                subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
868  #else  #else
869  # if HAVE_STRFTIME  # if HAVE_STRFTIME
870            goto underlying_strftime;            goto underlying_strftime;
871  # else  # else
872            subfmt = L_("%a %b %e %H:%M:%S %Y");            subfmt = L_("%a %b %e %H:%M:%S %Y");
873  # endif  # endif
874  #endif  #endif
875    
876          subformat:          subformat:
877            {            {
878              CHAR_T *old_start = p;              CHAR_T *old_start = p;
879              size_t len = my_strftime (NULL, (size_t) -1, subfmt, tp, 0);              size_t len = my_strftime (NULL, (size_t) -1, subfmt,
880              add (len, my_strftime (p, maxsize - i, subfmt, tp, 0));                                        tp extra_args LOCALE_ARG);
881                add (len, my_strftime (p, maxsize - i, subfmt,
882              if (to_uppcase)                                     tp extra_args LOCALE_ARG));
883                while (old_start < p)  
884                  {              if (to_uppcase)
885                    *old_start = TOUPPER ((UCHAR_T) *old_start);                while (old_start < p)
886                    ++old_start;                  {
887                  }                    *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
888            }                    ++old_start;
889            break;                  }
890              }
891              break;
892    
893  #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)  #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
894          underlying_strftime:          underlying_strftime:
895            {            {
896              /* The relevant information is available only via the              /* The relevant information is available only via the
897                 underlying strftime implementation, so use that.  */                 underlying strftime implementation, so use that.  */
898              char ufmt[4];              char ufmt[4];
899              char *u = ufmt;              char *u = ufmt;
900              char ubuf[1024]; /* enough for any single format in practice */              char ubuf[1024]; /* enough for any single format in practice */
901              size_t len;              size_t len;
902              /* Make sure we're calling the actual underlying strftime.              /* Make sure we're calling the actual underlying strftime.
903                 In some cases, config.h contains something like                 In some cases, config.h contains something like
904                 "#define strftime rpl_strftime".  */                 "#define strftime rpl_strftime".  */
905  # ifdef strftime  # ifdef strftime
906  #  undef strftime  #  undef strftime
907              size_t strftime ();              size_t strftime ();
908  # endif  # endif
909    
910  #ifdef STRFTIME_NO_POSIX2  #ifdef STRFTIME_NO_POSIX2
# Line 860  my_strftime (s, maxsize, format, tp ut_a Line 927  my_strftime (s, maxsize, format, tp ut_a
927            break;            break;
928  #endif  #endif
929    
930          case L_('C'):           /* POSIX.2 extension.  */          case L_('C'):
931            if (modifier == L_('O'))            if (modifier == L_('O'))
932              goto bad_format;              goto bad_format;
933            if (modifier == L_('E'))            if (modifier == L_('E'))
934              {              {
935  #if HAVE_STRUCT_ERA_ENTRY  #if HAVE_STRUCT_ERA_ENTRY
936                struct era_entry *era = _nl_get_era_entry (tp);                struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
937                if (era)                if (era)
938                  {                  {
939  # ifdef COMPILE_WIDE  # ifdef COMPILE_WIDE
940                    size_t len = __wcslen (era->era_wname);                    size_t len = __wcslen (era->era_wname);
941                    cpy (len, era->era_wname);                    cpy (len, era->era_wname);
942  # else  # else
943                    size_t len = strlen (era->era_name);                    size_t len = strlen (era->era_name);
944                    cpy (len, era->era_name);                    cpy (len, era->era_name);
945  # endif  # endif
946                    break;                    break;
947                  }                  }
948  #else  #else
949  # if HAVE_STRFTIME  # if HAVE_STRFTIME
950                goto underlying_strftime;                goto underlying_strftime;
951  # endif  # endif
952  #endif  #endif
953              }              }
954    
955            {            {
956              int year = tp->tm_year + TM_YEAR_BASE;              int year = tp->tm_year + TM_YEAR_BASE;
957              DO_NUMBER (1, year / 100 - (year % 100 < 0));              DO_NUMBER (1, year / 100 - (year % 100 < 0));
958            }            }
959    
960          case L_('x'):          case L_('x'):
961            if (modifier == L_('O'))            if (modifier == L_('O'))
962              goto bad_format;              goto bad_format;
963  #ifdef _NL_CURRENT  #ifdef _NL_CURRENT
964            if (! (modifier == L_('E')            if (! (modifier == L_('E')
965                   && (*(subfmt = (CHAR_T *)_NL_CURRENT (LC_TIME,                   && (*(subfmt =
966                                                         NLW(ERA_D_FMT)))                         (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
967                       != L_('\0'))))                       != L_('\0'))))
968              subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));              subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
969            goto subformat;            goto subformat;
970  #else  #else
971  # if HAVE_STRFTIME  # if HAVE_STRFTIME
972            goto underlying_strftime;            goto underlying_strftime;
973  # else  # else
974            /* Fall through.  */            /* Fall through.  */
975  # endif  # endif
976  #endif  #endif
977          case L_('D'):           /* POSIX.2 extension.  */          case L_('D'):
978            if (modifier != 0)            if (modifier != 0)
979              goto bad_format;              goto bad_format;
980            subfmt = L_("%m/%d/%y");            subfmt = L_("%m/%d/%y");
981            goto subformat;            goto subformat;
982    
983          case L_('d'):          case L_('d'):
984            if (modifier == L_('E'))            if (modifier == L_('E'))
985              goto bad_format;              goto bad_format;
986    
987            DO_NUMBER (2, tp->tm_mday);            DO_NUMBER (2, tp->tm_mday);
988    
989          case L_('e'):           /* POSIX.2 extension.  */          case L_('e'):
990            if (modifier == L_('E'))            if (modifier == L_('E'))
991              goto bad_format;              goto bad_format;
992    
993            DO_NUMBER_SPACEPAD (2, tp->tm_mday);            DO_NUMBER_SPACEPAD (2, tp->tm_mday);
994    
995            /* All numeric formats set DIGITS and NUMBER_VALUE and then            /* All numeric formats set DIGITS and NUMBER_VALUE and then
996               jump to one of these two labels.  */               jump to one of these two labels.  */
997    
998          do_number_spacepad:          do_number_spacepad:
999            /* Force `_' flag unless overwritten by `0' flag.  */            /* Force `_' flag unless overridden by `0' or `-' flag.  */
1000            if (pad != L_('0'))            if (pad != L_('0') && pad != L_('-'))
1001              pad = L_('_');              pad = L_('_');
1002    
1003          do_number:          do_number:
1004            /* Format the number according to the MODIFIER flag.  */            /* Format the number according to the MODIFIER flag.  */
1005    
1006            if (modifier == L_('O') && 0 <= number_value)            if (modifier == L_('O') && 0 <= number_value)
1007              {              {
1008  #ifdef _NL_CURRENT  #ifdef _NL_CURRENT
1009                /* Get the locale specific alternate representation of                /* Get the locale specific alternate representation of
1010                   the number NUMBER_VALUE.  If none exist NULL is returned.  */                   the number NUMBER_VALUE.  If none exist NULL is returned.  */
1011  # ifdef COMPILE_WIDE                const CHAR_T *cp = nl_get_alt_digit (number_value
1012                const wchar_t *cp = _nl_get_walt_digit (number_value);                                                     HELPER_LOCALE_ARG);
1013  # else  
1014                const char *cp = _nl_get_alt_digit (number_value);                if (cp != NULL)
1015  # endif                  {
1016                      size_t digitlen = STRLEN (cp);
1017                if (cp != NULL)                    if (digitlen != 0)
1018                  {                      {
1019                    size_t digitlen = STRLEN (cp);                        cpy (digitlen, cp);
1020                    if (digitlen != 0)                        break;
1021                      {                      }
1022                        cpy (digitlen, cp);                  }
                       break;  
                     }  
                 }  
1023  #else  #else
1024  # if HAVE_STRFTIME  # if HAVE_STRFTIME
1025                goto underlying_strftime;                goto underlying_strftime;
1026  # endif  # endif
1027  #endif  #endif
1028              }              }
1029            {            {
1030              unsigned int u = number_value;              unsigned int u = number_value;
1031    
1032              bufp = buf + sizeof (buf) / sizeof (buf[0]);              bufp = buf + sizeof (buf) / sizeof (buf[0]);
1033              negative_number = number_value < 0;              negative_number = number_value < 0;
1034    
1035              if (negative_number)              if (negative_number)
1036                u = -u;                u = -u;
1037    
1038              do              do
1039                *--bufp = u % 10 + L_('0');                *--bufp = u % 10 + L_('0');
1040              while ((u /= 10) != 0);              while ((u /= 10) != 0);
1041            }            }
1042    
1043          do_number_sign_and_padding:          do_number_sign_and_padding:
1044            if (negative_number)            if (negative_number)
1045              *--bufp = L_('-');              *--bufp = L_('-');
1046    
1047            if (pad != L_('-'))            if (pad != L_('-'))
1048              {              {
1049                int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))                int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
1050                                        - bufp);                                        - bufp);
1051    
1052                if (pad == L_('_'))                if (padding > 0)
1053                  {                  {
1054                    while (0 < padding--)                    if (pad == L_('_'))
1055                      *--bufp = L_(' ');                      {
1056                  }                        if ((size_t) padding >= maxsize - i)
1057                else                          return 0;
                 {  
                   bufp += negative_number;  
                   while (0 < padding--)  
                     *--bufp = L_('0');  
                   if (negative_number)  
                     *--bufp = L_('-');  
                 }  
             }  
1058    
1059            cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);                        if (p)
1060            break;                          memset_space (p, padding);
1061                          i += padding;
1062                          width = width > padding ? width - padding : 0;
1063                        }
1064                      else
1065                        {
1066                          if ((size_t) digits >= maxsize - i)
1067                            return 0;
1068    
1069          case L_('F'):                        if (negative_number)
1070            if (modifier != 0)                          {
1071              goto bad_format;                            ++bufp;
           subfmt = L_("%Y-%m-%d");  
           goto subformat;  
1072    
1073          case L_('H'):                            if (p)
1074            if (modifier == L_('E'))                              *p++ = L_('-');
1075              goto bad_format;                            ++i;
1076                            }
1077    
1078            DO_NUMBER (2, tp->tm_hour);                        if (p)
1079                            memset_zero (p, padding);
1080                          i += padding;
1081                          width = 0;
1082                        }
1083                    }
1084                }
1085    
1086          case L_('I'):            cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
1087            if (modifier == L_('E'))            break;
             goto bad_format;  
1088    
1089            DO_NUMBER (2, hour12);          case L_('F'):
1090              if (modifier != 0)
1091                goto bad_format;
1092              subfmt = L_("%Y-%m-%d");
1093              goto subformat;
1094    
1095          case L_('k'):           /* GNU extension.  */          case L_('H'):
1096            if (modifier == L_('E'))            if (modifier == L_('E'))
1097              goto bad_format;              goto bad_format;
1098    
1099            DO_NUMBER_SPACEPAD (2, tp->tm_hour);            DO_NUMBER (2, tp->tm_hour);
1100    
1101          case L_('l'):           /* GNU extension.  */          case L_('I'):
1102            if (modifier == L_('E'))            if (modifier == L_('E'))
1103              goto bad_format;              goto bad_format;
1104    
1105            DO_NUMBER_SPACEPAD (2, hour12);            DO_NUMBER (2, hour12);
1106    
1107          case L_('j'):          case L_('k'):           /* GNU extension.  */
1108            if (modifier == L_('E'))            if (modifier == L_('E'))
1109              goto bad_format;              goto bad_format;
1110    
1111            DO_NUMBER (3, 1 + tp->tm_yday);            DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1112    
1113          case L_('M'):          case L_('l'):           /* GNU extension.  */
1114            if (modifier == L_('E'))            if (modifier == L_('E'))
1115              goto bad_format;              goto bad_format;
1116    
1117            DO_NUMBER (2, tp->tm_min);            DO_NUMBER_SPACEPAD (2, hour12);
1118    
1119          case L_('m'):          case L_('j'):
1120            if (modifier == L_('E'))            if (modifier == L_('E'))
1121              goto bad_format;              goto bad_format;
1122    
1123            DO_NUMBER (2, tp->tm_mon + 1);            DO_NUMBER (3, 1 + tp->tm_yday);
1124    
1125          case L_('n'):           /* POSIX.2 extension.  */          case L_('M'):
1126            add (1, *p = L_('\n'));            if (modifier == L_('E'))
1127            break;              goto bad_format;
1128    
1129          case L_('P'):            DO_NUMBER (2, tp->tm_min);
           to_lowcase = 1;  
 #if !defined _NL_CURRENT && HAVE_STRFTIME  
           format_char = L_('p');  
 #endif  
           /* FALLTHROUGH */  
1130    
1131          case L_('p'):          case L_('m'):
1132            if (change_case)            if (modifier == L_('E'))
1133              {              goto bad_format;
               to_uppcase = 0;  
               to_lowcase = 1;  
             }  
 #if defined _NL_CURRENT || !HAVE_STRFTIME  
           cpy (ap_len, ampm);  
           break;  
 #else  
           goto underlying_strftime;  
 #endif  
1134    
1135          case L_('R'):           /* GNU extension.  */            DO_NUMBER (2, tp->tm_mon + 1);
           subfmt = L_("%H:%M");  
           goto subformat;  
1136    
1137          case L_('r'):           /* POSIX.2 extension.  */  #ifndef _LIBC
1138  #ifdef _NL_CURRENT          case L_('N'):           /* GNU extension.  */
1139            if (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,            if (modifier == L_('E'))
1140                                                   NLW(T_FMT_AMPM))) == L_('\0'))              goto bad_format;
1141    
1142              number_value = ns;
1143              if (width != -1)
1144                {
1145                  /* Take an explicit width less than 9 as a precision.  */
1146                  int j;
1147                  for (j = width; j < 9; j++)
1148                    number_value /= 10;
1149                }
1150    
1151              DO_NUMBER (9, number_value);
1152  #endif  #endif
             subfmt = L_("%I:%M:%S %p");  
           goto subformat;  
1153    
1154          case L_('S'):          case L_('n'):
1155            if (modifier == L_('E'))            add (1, *p = L_('\n'));
1156              goto bad_format;            break;
1157    
1158            DO_NUMBER (2, tp->tm_sec);          case L_('P'):
1159              to_lowcase = 1;
1160    #if !defined _NL_CURRENT && HAVE_STRFTIME
1161              format_char = L_('p');
1162    #endif
1163              /* FALLTHROUGH */
1164    
1165          case L_('s'):           /* GNU extension.  */          case L_('p'):
1166            {            if (change_case)
1167              struct tm ltm;              {
1168              time_t t;                to_uppcase = 0;
1169                  to_lowcase = 1;
1170              ltm = *tp;              }
1171              t = mktime (&ltm);  #if defined _NL_CURRENT || !HAVE_STRFTIME
1172              cpy (ap_len, ampm);
1173              /* Generate string value for T using time_t arithmetic;            break;
1174                 this works even if sizeof (long) < sizeof (time_t).  */  #else
1175              goto underlying_strftime;
1176              bufp = buf + sizeof (buf) / sizeof (buf[0]);  #endif
             negative_number = t < 0;  
   
             do  
               {  
                 int d = t % 10;  
                 t /= 10;  
   
                 if (negative_number)  
                   {  
                     d = -d;  
   
                     /* Adjust if division truncates to minus infinity.  */  
                     if (0 < -1 % 10 && d < 0)  
                       {  
                         t++;  
                         d += 10;  
                       }  
                   }  
   
                 *--bufp = d + L_('0');  
               }  
             while (t != 0);  
1177    
1178              digits = 1;          case L_('R'):
1179              goto do_number_sign_and_padding;            subfmt = L_("%H:%M");
1180            }            goto subformat;
1181    
1182          case L_('X'):          case L_('r'):
           if (modifier == L_('O'))  
             goto bad_format;  
1183  #ifdef _NL_CURRENT  #ifdef _NL_CURRENT
1184            if (! (modifier == L_('E')            if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1185                   && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,                                                         NLW(T_FMT_AMPM)))
1186                                                          NLW(ERA_T_FMT)))                == L_('\0'))
1187                       != L_('\0'))))  #endif
1188              subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));              subfmt = L_("%I:%M:%S %p");
1189            goto subformat;            goto subformat;
1190    
1191            case L_('S'):
1192              if (modifier == L_('E'))
1193                goto bad_format;
1194    
1195              DO_NUMBER (2, tp->tm_sec);
1196    
1197            case L_('s'):           /* GNU extension.  */
1198              {
1199                struct tm ltm;
1200                time_t t;
1201    
1202                ltm = *tp;
1203                t = mktime (&ltm);
1204    
1205                /* Generate string value for T using time_t arithmetic;
1206                   this works even if sizeof (long) < sizeof (time_t).  */
1207    
1208                bufp = buf + sizeof (buf) / sizeof (buf[0]);
1209                negative_number = t < 0;
1210    
1211                do
1212                  {
1213                    int d = t % 10;
1214                    t /= 10;
1215    
1216                    if (negative_number)
1217                      {
1218                        d = -d;
1219    
1220                        /* Adjust if division truncates to minus infinity.  */
1221                        if (0 < -1 % 10 && d < 0)
1222                          {
1223                            t++;
1224                            d += 10;
1225                          }
1226                      }
1227    
1228                    *--bufp = d + L_('0');
1229                  }
1230                while (t != 0);
1231    
1232                digits = 1;
1233                goto do_number_sign_and_padding;
1234              }
1235    
1236            case L_('X'):
1237              if (modifier == L_('O'))
1238                goto bad_format;
1239    #ifdef _NL_CURRENT
1240              if (! (modifier == L_('E')
1241                     && (*(subfmt =
1242                           (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1243                         != L_('\0'))))
1244                subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1245              goto subformat;
1246  #else  #else
1247  # if HAVE_STRFTIME  # if HAVE_STRFTIME
1248            goto underlying_strftime;            goto underlying_strftime;
1249  # else  # else
1250            /* Fall through.  */            /* Fall through.  */
1251  # endif  # endif
1252  #endif  #endif
1253          case L_('T'):           /* POSIX.2 extension.  */          case L_('T'):
1254            subfmt = L_("%H:%M:%S");            subfmt = L_("%H:%M:%S");
1255            goto subformat;            goto subformat;
1256    
1257          case L_('t'):           /* POSIX.2 extension.  */          case L_('t'):
1258            add (1, *p = L_('\t'));            add (1, *p = L_('\t'));
1259            break;            break;
1260    
1261          case L_('u'):           /* POSIX.2 extension.  */          case L_('u'):
1262            DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);            DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1263    
1264          case L_('U'):          case L_('U'):
1265            if (modifier == L_('E'))            if (modifier == L_('E'))
1266              goto bad_format;              goto bad_format;
1267    
1268            DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);            DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1269    
1270          case L_('V'):          case L_('V'):
1271          case L_('g'):           /* GNU extension.  */          case L_('g'):
1272          case L_('G'):           /* GNU extension.  */          case L_('G'):
1273            if (modifier == L_('E'))            if (modifier == L_('E'))
1274              goto bad_format;              goto bad_format;
1275            {            {
1276              int year = tp->tm_year + TM_YEAR_BASE;              int year = tp->tm_year + TM_YEAR_BASE;
1277              int days = iso_week_days (tp->tm_yday, tp->tm_wday);              int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1278    
1279              if (days < 0)              if (days < 0)
1280                {                {
1281                  /* This ISO week belongs to the previous year.  */                  /* This ISO week belongs to the previous year.  */
1282                  year--;                  year--;
1283                  days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),                  days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1284                                        tp->tm_wday);                                        tp->tm_wday);
1285                }                }
1286              else              else
1287                {                {
1288                  int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),                  int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1289                                         tp->tm_wday);                                         tp->tm_wday);
1290                  if (0 <= d)                  if (0 <= d)
1291                    {                    {
1292                      /* This ISO week belongs to the next year.  */                      /* This ISO week belongs to the next year.  */
1293                      year++;                      year++;
1294                      days = d;                      days = d;
1295                    }                    }
1296                }                }
1297    
1298              switch (*f)              switch (*f)
1299                {                {
1300                case L_('g'):                case L_('g'):
1301                  DO_NUMBER (2, (year % 100 + 100) % 100);                  DO_NUMBER (2, (year % 100 + 100) % 100);
1302    
1303                case L_('G'):                case L_('G'):
1304                  DO_NUMBER (1, year);                  DO_NUMBER (1, year);
1305    
1306                default:                default:
1307                  DO_NUMBER (2, days / 7 + 1);                  DO_NUMBER (2, days / 7 + 1);
1308                }                }
1309            }            }
1310    
1311          case L_('W'):          case L_('W'):
1312            if (modifier == L_('E'))            if (modifier == L_('E'))
1313              goto bad_format;              goto bad_format;
1314    
1315            DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);            DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1316    
1317          case L_('w'):          case L_('w'):
1318            if (modifier == L_('E'))            if (modifier == L_('E'))
1319              goto bad_format;              goto bad_format;
1320    
1321            DO_NUMBER (1, tp->tm_wday);            DO_NUMBER (1, tp->tm_wday);
1322    
1323          case L_('Y'):          case L_('Y'):
1324            if (modifier == 'E')            if (modifier == 'E')
1325              {              {
1326  #if HAVE_STRUCT_ERA_ENTRY  #if HAVE_STRUCT_ERA_ENTRY
1327                struct era_entry *era = _nl_get_era_entry (tp);                struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1328                if (era)                if (era)
1329                  {                  {
1330  # ifdef COMPILE_WIDE  # ifdef COMPILE_WIDE
1331                    subfmt = era->era_wformat;                    subfmt = era->era_wformat;
1332  # else  # else
1333                    subfmt = era->era_format;                    subfmt = era->era_format;
1334  # endif  # endif
1335                    goto subformat;                    goto subformat;
1336                  }                  }
1337  #else  #else
1338  # if HAVE_STRFTIME  # if HAVE_STRFTIME
1339                goto underlying_strftime;                goto underlying_strftime;
1340  # endif  # endif
1341  #endif  #endif
1342              }              }
1343            if (modifier == L_('O'))            if (modifier == L_('O'))
1344              goto bad_format;              goto bad_format;
1345            else            else
1346              DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);              DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1347    
1348          case L_('y'):          case L_('y'):
1349            if (modifier == L_('E'))            if (modifier == L_('E'))
1350              {              {
1351  #if HAVE_STRUCT_ERA_ENTRY  #if HAVE_STRUCT_ERA_ENTRY
1352                struct era_entry *era = _nl_get_era_entry (tp);                struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1353                if (era)                if (era)
1354                  {                  {
1355                    int delta = tp->tm_year - era->start_date[0];                    int delta = tp->tm_year - era->start_date[0];
1356                    DO_NUMBER (1, (era->offset                    DO_NUMBER (1, (era->offset
1357                                   + delta * era->absolute_direction));                                   + delta * era->absolute_direction));
1358                  }                  }
1359  #else  #else
1360  # if HAVE_STRFTIME  # if HAVE_STRFTIME
1361                goto underlying_strftime;                goto underlying_strftime;
1362  # endif  # endif
1363  #endif  #endif
1364              }              }
1365            DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);            DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1366    
1367          case L_('Z'):          case L_('Z'):
1368            if (change_case)            if (change_case)
1369              {              {
1370                to_uppcase = 0;                to_uppcase = 0;
1371                to_lowcase = 1;                to_lowcase = 1;
1372              }              }
1373    
1374  #if HAVE_TZNAME  #if HAVE_TZNAME
1375            /* The tzset() call might have changed the value.  */            /* The tzset() call might have changed the value.  */
1376            if (!(zone && *zone) && tp->tm_isdst >= 0)            if (!(zone && *zone) && tp->tm_isdst >= 0)
1377              zone = tzname[tp->tm_isdst];              zone = tzname[tp->tm_isdst];
1378  #endif  #endif
1379            if (! zone)            if (! zone)
1380              zone = "";          /* POSIX.2 requires the empty string here.  */              zone = "";
1381    
1382  #ifdef COMPILE_WIDE  #ifdef COMPILE_WIDE
1383            {            {
1384              /* The zone string is always given in multibyte form.  We have              /* The zone string is always given in multibyte form.  We have
1385                 to transform it first.  */                 to transform it first.  */
1386              wchar_t *wczone;              wchar_t *wczone;
1387              size_t len;              size_t len;
1388              widen (zone, wczone, len);              widen (zone, wczone, len);
1389              cpy (len, wczone);              cpy (len, wczone);
1390            }            }
1391  #else  #else
1392            cpy (strlen (zone), zone);            cpy (strlen (zone), zone);
1393  #endif  #endif
1394            break;            break;
1395    
1396          case L_('z'):           /* GNU extension.  */          case L_('z'):
1397            if (tp->tm_isdst < 0)            if (tp->tm_isdst < 0)
1398              break;              break;
1399    
1400            {            {
1401              int diff;              int diff;
1402  #if HAVE_TM_GMTOFF  #if HAVE_TM_GMTOFF
1403              diff = tp->tm_gmtoff;              diff = tp->tm_gmtoff;
1404  #else  #else
1405              if (ut)              if (ut)
1406                diff = 0;                diff = 0;
1407              else              else
1408                {                {
1409                  struct tm gtm;                  struct tm gtm;
1410                  struct tm ltm;                  struct tm ltm;
1411                  time_t lt;                  time_t lt;
1412    
1413                  ltm = *tp;                  ltm = *tp;
1414                  lt = mktime (&ltm);                  lt = mktime (&ltm);
1415    
1416                  if (lt == (time_t) -1)                  if (lt == (time_t) -1)
1417                    {                    {
1418                      /* mktime returns -1 for errors, but -1 is also a                      /* mktime returns -1 for errors, but -1 is also a
1419                         valid time_t value.  Check whether an error really                         valid time_t value.  Check whether an error really
1420                         occurred.  */                         occurred.  */
1421                      struct tm tm;                      struct tm tm;
1422    
1423                      if (! my_strftime_localtime_r (&lt, &tm)                      if (! my_strftime_localtime_r (&lt, &tm)
1424                          || ((ltm.tm_sec ^ tm.tm_sec)                          || ((ltm.tm_sec ^ tm.tm_sec)
1425                              | (ltm.tm_min ^ tm.tm_min)                              | (ltm.tm_min ^ tm.tm_min)
1426                              | (ltm.tm_hour ^ tm.tm_hour)                              | (ltm.tm_hour ^ tm.tm_hour)
1427                              | (ltm.tm_mday ^ tm.tm_mday)                              | (ltm.tm_mday ^ tm.tm_mday)
1428                              | (ltm.tm_mon ^ tm.tm_mon)                              | (ltm.tm_mon ^ tm.tm_mon)
1429                              | (ltm.tm_year ^ tm.tm_year)))                              | (ltm.tm_year ^ tm.tm_year)))
1430                        break;                        break;
1431                    }                    }
1432    
1433                  if (! my_strftime_gmtime_r (&lt, &gtm))                  if (! my_strftime_gmtime_r (&lt, &gtm))
1434                    break;                    break;
1435    
1436                  diff = tm_diff (&ltm, &gtm);                  diff = tm_diff (&ltm, &gtm);
1437                }                }
1438  #endif  #endif
1439    
1440              if (diff < 0)              if (diff < 0)
1441                {                {
1442                  add (1, *p = L_('-'));                  add (1, *p = L_('-'));
1443                  diff = -diff;                  diff = -diff;
1444                }                }
1445              else              else
1446                add (1, *p = L_('+'));                add (1, *p = L_('+'));
1447    
1448              diff /= 60;              diff /= 60;
1449              DO_NUMBER (4, (diff / 60) * 100 + diff % 60);              DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1450            }            }
1451    
1452          case L_('\0'):          /* GNU extension: % at end of format.  */          case L_('\0'):          /* GNU extension: % at end of format.  */
1453              --f;              --f;
1454              /* Fall through.  */              /* Fall through.  */
1455          default:          default:
1456            /* Unknown format; output the format, including the '%',            /* Unknown format; output the format, including the '%',
1457               since this is most likely the right thing to do if a               since this is most likely the right thing to do if a
1458               multibyte string has been misparsed.  */               multibyte string has been misparsed.  */
1459          bad_format:          bad_format:
1460            {            {
1461              int flen;              int flen;
1462              for (flen = 1; f[1 - flen] != L_('%'); flen++)              for (flen = 1; f[1 - flen] != L_('%'); flen++)
1463                continue;                continue;
1464              cpy (flen, &f[1 - flen]);              cpy (flen, &f[1 - flen]);
1465            }            }
1466            break;            break;
1467          }          }
1468      }      }
1469    
1470    if (p && maxsize != 0)    if (p && maxsize != 0)
1471      *p = L_('\0');      *p = L_('\0');
1472    return i;    return i;
1473  }  }
1474    #ifdef _LIBC
1475    libc_hidden_def (my_strftime)
1476    #endif
1477    
1478    
1479  #ifdef emacs  #ifdef emacs
1480    #undef ut
1481  /* For Emacs we have a separate interface which corresponds to the normal  /* For Emacs we have a separate interface which corresponds to the normal
1482     strftime function and does not have the extra information whether the     strftime function plus the ut argument, but without the ns argument.  */
    TP arguments comes from a `gmtime' call or not.  */  
1483  size_t  size_t
1484  emacs_strftime (s, maxsize, format, tp)  emacs_strftimeu (s, maxsize, format, tp, ut)
1485        char *s;        char *s;
1486        size_t maxsize;        size_t maxsize;
1487        const char *format;        const char *format;
1488        const struct tm *tp;        const struct tm *tp;
1489          int ut;
1490  {  {
1491    return my_strftime (s, maxsize, format, tp, 0);    return my_strftime (s, maxsize, format, tp, ut, 0);
1492  }  }
1493  #endif  #endif
   

Legend:
Removed from v.1.28  
changed lines
  Added in v.1.29

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26