Home | History | Annotate | Line # | Download | only in lib
      1  1.1  christos /*	$NetBSD: strftime.c,v 1.1.1.1 2016/01/13 03:15:30 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    NOTE: The canonical source of this file is maintained with the GNU C Library.
      6  1.1  christos    Bugs can be reported to bug-glibc (at) prep.ai.mit.edu.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify it
      9  1.1  christos    under the terms of the GNU General Public License as published by the
     10  1.1  christos    Free Software Foundation; either version 2, or (at your option) any
     11  1.1  christos    later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  1.1  christos    Library General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software
     20  1.1  christos    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
     21  1.1  christos    USA.  */
     22  1.1  christos 
     23  1.1  christos #ifdef HAVE_CONFIG_H
     24  1.1  christos # include <config.h>
     25  1.1  christos #endif
     26  1.1  christos 
     27  1.1  christos #ifdef _LIBC
     28  1.1  christos # define HAVE_LIMITS_H 1
     29  1.1  christos # define HAVE_MBLEN 1
     30  1.1  christos # define HAVE_MBRLEN 1
     31  1.1  christos # define HAVE_STRUCT_ERA_ENTRY 1
     32  1.1  christos # define HAVE_TM_GMTOFF 1
     33  1.1  christos # define HAVE_TM_ZONE 1
     34  1.1  christos # define HAVE_TZNAME 1
     35  1.1  christos # define HAVE_TZSET 1
     36  1.1  christos # define MULTIBYTE_IS_FORMAT_SAFE 1
     37  1.1  christos # define STDC_HEADERS 1
     38  1.1  christos # include "../locale/localeinfo.h"
     39  1.1  christos #endif
     40  1.1  christos 
     41  1.1  christos #if defined emacs && !defined HAVE_BCOPY
     42  1.1  christos # define HAVE_MEMCPY 1
     43  1.1  christos #endif
     44  1.1  christos 
     45  1.1  christos #include <ctype.h>
     46  1.1  christos #include <sys/types.h>		/* Some systems define `time_t' here.  */
     47  1.1  christos 
     48  1.1  christos #ifdef TIME_WITH_SYS_TIME
     49  1.1  christos # include <sys/time.h>
     50  1.1  christos # include <time.h>
     51  1.1  christos #else
     52  1.1  christos # ifdef HAVE_SYS_TIME_H
     53  1.1  christos #  include <sys/time.h>
     54  1.1  christos # else
     55  1.1  christos #  include <time.h>
     56  1.1  christos # endif
     57  1.1  christos #endif
     58  1.1  christos #if HAVE_TZNAME
     59  1.1  christos extern char *tzname[];
     60  1.1  christos #endif
     61  1.1  christos 
     62  1.1  christos /* Do multibyte processing if multibytes are supported, unless
     63  1.1  christos    multibyte sequences are safe in formats.  Multibyte sequences are
     64  1.1  christos    safe if they cannot contain byte sequences that look like format
     65  1.1  christos    conversion specifications.  The GNU C Library uses UTF8 multibyte
     66  1.1  christos    encoding, which is safe for formats, but strftime.c can be used
     67  1.1  christos    with other C libraries that use unsafe encodings.  */
     68  1.1  christos #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
     69  1.1  christos 
     70  1.1  christos #if DO_MULTIBYTE
     71  1.1  christos # if HAVE_MBRLEN
     72  1.1  christos #  include <wchar.h>
     73  1.1  christos # else
     74  1.1  christos    /* Simulate mbrlen with mblen as best we can.  */
     75  1.1  christos #  define mbstate_t int
     76  1.1  christos #  define mbrlen(s, n, ps) mblen (s, n)
     77  1.1  christos #  define mbsinit(ps) (*(ps) == 0)
     78  1.1  christos # endif
     79  1.1  christos   static const mbstate_t mbstate_zero;
     80  1.1  christos #endif
     81  1.1  christos 
     82  1.1  christos #if HAVE_LIMITS_H
     83  1.1  christos # include <limits.h>
     84  1.1  christos #endif
     85  1.1  christos 
     86  1.1  christos #if STDC_HEADERS
     87  1.1  christos # include <stddef.h>
     88  1.1  christos # include <stdlib.h>
     89  1.1  christos # include <string.h>
     90  1.1  christos #else
     91  1.1  christos # ifndef HAVE_MEMCPY
     92  1.1  christos #  define memcpy(d, s, n) bcopy ((s), (d), (n))
     93  1.1  christos # endif
     94  1.1  christos #endif
     95  1.1  christos 
     96  1.1  christos #ifdef COMPILE_WIDE
     97  1.1  christos # include <endian.h>
     98  1.1  christos # define CHAR_T wchar_t
     99  1.1  christos # define UCHAR_T unsigned int
    100  1.1  christos # define L_(Str) L##Str
    101  1.1  christos # define NLW(Sym) _NL_W##Sym
    102  1.1  christos 
    103  1.1  christos # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
    104  1.1  christos # define STRLEN(s) __wcslen (s)
    105  1.1  christos 
    106  1.1  christos #else
    107  1.1  christos # define CHAR_T char
    108  1.1  christos # define UCHAR_T unsigned char
    109  1.1  christos # define L_(Str) Str
    110  1.1  christos # define NLW(Sym) Sym
    111  1.1  christos 
    112  1.1  christos # if !defined STDC_HEADERS && !defined HAVE_MEMCPY
    113  1.1  christos #  define MEMCPY(d, s, n) bcopy ((s), (d), (n))
    114  1.1  christos # else
    115  1.1  christos #  define MEMCPY(d, s, n) memcpy ((d), (s), (n))
    116  1.1  christos # endif
    117  1.1  christos # define STRLEN(s) strlen (s)
    118  1.1  christos 
    119  1.1  christos # ifdef _LIBC
    120  1.1  christos #  define MEMPCPY(d, s, n) __mempcpy (d, s, n)
    121  1.1  christos # else
    122  1.1  christos #  ifndef HAVE_MEMPCPY
    123  1.1  christos #   define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
    124  1.1  christos #  endif
    125  1.1  christos # endif
    126  1.1  christos #endif
    127  1.1  christos 
    128  1.1  christos #ifndef __P
    129  1.1  christos # if defined __GNUC__ || (defined __STDC__ && __STDC__)
    130  1.1  christos #  define __P(args) args
    131  1.1  christos # else
    132  1.1  christos #  define __P(args) ()
    133  1.1  christos # endif  /* GCC.  */
    134  1.1  christos #endif  /* Not __P.  */
    135  1.1  christos 
    136  1.1  christos #ifndef PTR
    137  1.1  christos # ifdef __STDC__
    138  1.1  christos #  define PTR void *
    139  1.1  christos # else
    140  1.1  christos #  define PTR char *
    141  1.1  christos # endif
    142  1.1  christos #endif
    143  1.1  christos 
    144  1.1  christos #ifndef CHAR_BIT
    145  1.1  christos # define CHAR_BIT 8
    146  1.1  christos #endif
    147  1.1  christos 
    148  1.1  christos #ifndef NULL
    149  1.1  christos # define NULL 0
    150  1.1  christos #endif
    151  1.1  christos 
    152  1.1  christos #define TYPE_SIGNED(t) ((t) -1 < 0)
    153  1.1  christos 
    154  1.1  christos /* Bound on length of the string representing an integer value of type t.
    155  1.1  christos    Subtract one for the sign bit if t is signed;
    156  1.1  christos    302 / 1000 is log10 (2) rounded up;
    157  1.1  christos    add one for integer division truncation;
    158  1.1  christos    add one more for a minus sign if t is signed.  */
    159  1.1  christos #define INT_STRLEN_BOUND(t) \
    160  1.1  christos  ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
    161  1.1  christos 
    162  1.1  christos #define TM_YEAR_BASE 1900
    163  1.1  christos 
    164  1.1  christos #ifndef __isleap
    165  1.1  christos /* Nonzero if YEAR is a leap year (every 4 years,
    166  1.1  christos    except every 100th isn't, and every 400th is).  */
    167  1.1  christos # define __isleap(year)	\
    168  1.1  christos   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
    169  1.1  christos #endif
    170  1.1  christos 
    171  1.1  christos 
    172  1.1  christos #ifdef _LIBC
    173  1.1  christos # define my_strftime_gmtime_r __gmtime_r
    174  1.1  christos # define my_strftime_localtime_r __localtime_r
    175  1.1  christos # define tzname __tzname
    176  1.1  christos # define tzset __tzset
    177  1.1  christos #else
    178  1.1  christos 
    179  1.1  christos /* If we're a strftime substitute in a GNU program, then prefer gmtime
    180  1.1  christos    to gmtime_r, since many gmtime_r implementations are buggy.
    181  1.1  christos    Similarly for localtime_r.  */
    182  1.1  christos 
    183  1.1  christos # if ! HAVE_TM_GMTOFF
    184  1.1  christos static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *));
    185  1.1  christos static struct tm *
    186  1.1  christos my_strftime_gmtime_r (t, tp)
    187  1.1  christos      const time_t *t;
    188  1.1  christos      struct tm *tp;
    189  1.1  christos {
    190  1.1  christos   struct tm *l = gmtime (t);
    191  1.1  christos   if (! l)
    192  1.1  christos     return 0;
    193  1.1  christos   *tp = *l;
    194  1.1  christos   return tp;
    195  1.1  christos }
    196  1.1  christos 
    197  1.1  christos static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
    198  1.1  christos static struct tm *
    199  1.1  christos my_strftime_localtime_r (t, tp)
    200  1.1  christos      const time_t *t;
    201  1.1  christos      struct tm *tp;
    202  1.1  christos {
    203  1.1  christos   struct tm *l = localtime (t);
    204  1.1  christos   if (! l)
    205  1.1  christos     return 0;
    206  1.1  christos   *tp = *l;
    207  1.1  christos   return tp;
    208  1.1  christos }
    209  1.1  christos # endif /* ! HAVE_TM_GMTOFF */
    210  1.1  christos #endif /* ! defined _LIBC */
    211  1.1  christos 
    212  1.1  christos 
    213  1.1  christos #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
    214  1.1  christos /* Some systems lack the `memset' function and we don't want to
    215  1.1  christos    introduce additional dependencies.  */
    216  1.1  christos /* The SGI compiler reportedly barfs on the trailing null
    217  1.1  christos    if we use a string constant as the initializer.  28 June 1997, rms.  */
    218  1.1  christos static const CHAR_T spaces[16] = /* "                " */
    219  1.1  christos {
    220  1.1  christos   L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
    221  1.1  christos   L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
    222  1.1  christos };
    223  1.1  christos static const CHAR_T zeroes[16] = /* "0000000000000000" */
    224  1.1  christos {
    225  1.1  christos   L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
    226  1.1  christos   L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
    227  1.1  christos };
    228  1.1  christos 
    229  1.1  christos # define memset_space(P, Len) \
    230  1.1  christos   do {									      \
    231  1.1  christos     int _len = (Len);							      \
    232  1.1  christos 									      \
    233  1.1  christos     do									      \
    234  1.1  christos       {									      \
    235  1.1  christos 	int _this = _len > 16 ? 16 : _len;				      \
    236  1.1  christos 	(P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T));		      \
    237  1.1  christos 	_len -= _this;							      \
    238  1.1  christos       }									      \
    239  1.1  christos     while (_len > 0);							      \
    240  1.1  christos   } while (0)
    241  1.1  christos 
    242  1.1  christos # define memset_zero(P, Len) \
    243  1.1  christos   do {									      \
    244  1.1  christos     int _len = (Len);							      \
    245  1.1  christos 									      \
    246  1.1  christos     do									      \
    247  1.1  christos       {									      \
    248  1.1  christos 	int _this = _len > 16 ? 16 : _len;				      \
    249  1.1  christos 	(P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T));		      \
    250  1.1  christos 	_len -= _this;							      \
    251  1.1  christos       }									      \
    252  1.1  christos     while (_len > 0);							      \
    253  1.1  christos   } while (0)
    254  1.1  christos #else
    255  1.1  christos # ifdef COMPILE_WIDE
    256  1.1  christos #  define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
    257  1.1  christos #  define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
    258  1.1  christos # else
    259  1.1  christos #  define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
    260  1.1  christos #  define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
    261  1.1  christos # endif
    262  1.1  christos #endif
    263  1.1  christos 
    264  1.1  christos #define add(n, f)							      \
    265  1.1  christos   do									      \
    266  1.1  christos     {									      \
    267  1.1  christos       int _n = (n);							      \
    268  1.1  christos       int _delta = width - _n;						      \
    269  1.1  christos       int _incr = _n + (_delta > 0 ? _delta : 0);			      \
    270  1.1  christos       if (i + _incr >= maxsize)						      \
    271  1.1  christos 	return 0;							      \
    272  1.1  christos       if (p)								      \
    273  1.1  christos 	{								      \
    274  1.1  christos 	  if (_delta > 0)						      \
    275  1.1  christos 	    {								      \
    276  1.1  christos 	      if (pad == L_('0'))					      \
    277  1.1  christos 		memset_zero (p, _delta);				      \
    278  1.1  christos 	      else							      \
    279  1.1  christos 		memset_space (p, _delta);				      \
    280  1.1  christos 	    }								      \
    281  1.1  christos 	  f;								      \
    282  1.1  christos 	  p += _n;							      \
    283  1.1  christos 	}								      \
    284  1.1  christos       i += _incr;							      \
    285  1.1  christos     } while (0)
    286  1.1  christos 
    287  1.1  christos #define cpy(n, s) \
    288  1.1  christos     add ((n),								      \
    289  1.1  christos 	 if (to_lowcase)						      \
    290  1.1  christos 	   memcpy_lowcase (p, (s), _n);					      \
    291  1.1  christos 	 else if (to_uppcase)						      \
    292  1.1  christos 	   memcpy_uppcase (p, (s), _n);					      \
    293  1.1  christos 	 else								      \
    294  1.1  christos 	   MEMCPY ((PTR) p, (const PTR) (s), _n))
    295  1.1  christos 
    296  1.1  christos #ifdef COMPILE_WIDE
    297  1.1  christos # define widen(os, ws, l) \
    298  1.1  christos   {									      \
    299  1.1  christos     mbstate_t __st;							      \
    300  1.1  christos     const char *__s = os;						      \
    301  1.1  christos     memset (&__st, '\0', sizeof (__st));				      \
    302  1.1  christos     l = __mbsrtowcs (NULL, &__s, 0, &__st);				      \
    303  1.1  christos     ws = alloca ((l + 1) * sizeof (wchar_t));				      \
    304  1.1  christos     (void) __mbsrtowcs (ws, &__s, l, &__st);				      \
    305  1.1  christos   }
    306  1.1  christos #endif
    307  1.1  christos 
    308  1.1  christos 
    309  1.1  christos #ifdef COMPILE_WIDE
    310  1.1  christos # define TOUPPER(Ch) towupper (Ch)
    311  1.1  christos # define TOLOWER(Ch) towlower (Ch)
    312  1.1  christos #else
    313  1.1  christos # ifdef _LIBC
    314  1.1  christos #  define TOUPPER(Ch) toupper (Ch)
    315  1.1  christos #  define TOLOWER(Ch) tolower (Ch)
    316  1.1  christos # else
    317  1.1  christos #  define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
    318  1.1  christos #  define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
    319  1.1  christos # endif
    320  1.1  christos #endif
    321  1.1  christos /* We don't use `isdigit' here since the locale dependent
    322  1.1  christos    interpretation is not what we want here.  We only need to accept
    323  1.1  christos    the arabic digits in the ASCII range.  One day there is perhaps a
    324  1.1  christos    more reliable way to accept other sets of digits.  */
    325  1.1  christos #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
    326  1.1  christos 
    327  1.1  christos static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
    328  1.1  christos 				    size_t len));
    329  1.1  christos 
    330  1.1  christos static CHAR_T *
    331  1.1  christos memcpy_lowcase (dest, src, len)
    332  1.1  christos      CHAR_T *dest;
    333  1.1  christos      const CHAR_T *src;
    334  1.1  christos      size_t len;
    335  1.1  christos {
    336  1.1  christos   while (len-- > 0)
    337  1.1  christos     dest[len] = TOLOWER ((UCHAR_T) src[len]);
    338  1.1  christos   return dest;
    339  1.1  christos }
    340  1.1  christos 
    341  1.1  christos static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
    342  1.1  christos 				    size_t len));
    343  1.1  christos 
    344  1.1  christos static CHAR_T *
    345  1.1  christos memcpy_uppcase (dest, src, len)
    346  1.1  christos      CHAR_T *dest;
    347  1.1  christos      const CHAR_T *src;
    348  1.1  christos      size_t len;
    349  1.1  christos {
    350  1.1  christos   while (len-- > 0)
    351  1.1  christos     dest[len] = TOUPPER ((UCHAR_T) src[len]);
    352  1.1  christos   return dest;
    353  1.1  christos }
    354  1.1  christos 
    355  1.1  christos 
    356  1.1  christos #if ! HAVE_TM_GMTOFF
    357  1.1  christos /* Yield the difference between *A and *B,
    358  1.1  christos    measured in seconds, ignoring leap seconds.  */
    359  1.1  christos # define tm_diff ftime_tm_diff
    360  1.1  christos static int tm_diff __P ((const struct tm *, const struct tm *));
    361  1.1  christos static int
    362  1.1  christos tm_diff (a, b)
    363  1.1  christos      const struct tm *a;
    364  1.1  christos      const struct tm *b;
    365  1.1  christos {
    366  1.1  christos   /* Compute intervening leap days correctly even if year is negative.
    367  1.1  christos      Take care to avoid int overflow in leap day calculations,
    368  1.1  christos      but it's OK to assume that A and B are close to each other.  */
    369  1.1  christos   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
    370  1.1  christos   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
    371  1.1  christos   int a100 = a4 / 25 - (a4 % 25 < 0);
    372  1.1  christos   int b100 = b4 / 25 - (b4 % 25 < 0);
    373  1.1  christos   int a400 = a100 >> 2;
    374  1.1  christos   int b400 = b100 >> 2;
    375  1.1  christos   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
    376  1.1  christos   int years = a->tm_year - b->tm_year;
    377  1.1  christos   int days = (365 * years + intervening_leap_days
    378  1.1  christos 	      + (a->tm_yday - b->tm_yday));
    379  1.1  christos   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
    380  1.1  christos 		+ (a->tm_min - b->tm_min))
    381  1.1  christos 	  + (a->tm_sec - b->tm_sec));
    382  1.1  christos }
    383  1.1  christos #endif /* ! HAVE_TM_GMTOFF */
    384  1.1  christos 
    385  1.1  christos 
    386  1.1  christos 
    387  1.1  christos /* The number of days from the first day of the first ISO week of this
    388  1.1  christos    year to the year day YDAY with week day WDAY.  ISO weeks start on
    389  1.1  christos    Monday; the first ISO week has the year's first Thursday.  YDAY may
    390  1.1  christos    be as small as YDAY_MINIMUM.  */
    391  1.1  christos #define ISO_WEEK_START_WDAY 1 /* Monday */
    392  1.1  christos #define ISO_WEEK1_WDAY 4 /* Thursday */
    393  1.1  christos #define YDAY_MINIMUM (-366)
    394  1.1  christos static int iso_week_days __P ((int, int));
    395  1.1  christos #ifdef __GNUC__
    396  1.1  christos __inline__
    397  1.1  christos #endif
    398  1.1  christos static int
    399  1.1  christos iso_week_days (yday, wday)
    400  1.1  christos      int yday;
    401  1.1  christos      int wday;
    402  1.1  christos {
    403  1.1  christos   /* Add enough to the first operand of % to make it nonnegative.  */
    404  1.1  christos   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
    405  1.1  christos   return (yday
    406  1.1  christos 	  - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
    407  1.1  christos 	  + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
    408  1.1  christos }
    409  1.1  christos 
    410  1.1  christos 
    411  1.1  christos #if !(defined _NL_CURRENT || HAVE_STRFTIME)
    412  1.1  christos static CHAR_T const weekday_name[][10] =
    413  1.1  christos   {
    414  1.1  christos     L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
    415  1.1  christos     L_("Thursday"), L_("Friday"), L_("Saturday")
    416  1.1  christos   };
    417  1.1  christos static CHAR_T const month_name[][10] =
    418  1.1  christos   {
    419  1.1  christos     L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
    420  1.1  christos     L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
    421  1.1  christos     L_("November"), L_("December")
    422  1.1  christos   };
    423  1.1  christos #endif
    424  1.1  christos 
    425  1.1  christos 
    426  1.1  christos /* When compiling this file, GNU applications can #define my_strftime
    427  1.1  christos    to a symbol (typically nstrftime) to get an extended strftime with
    428  1.1  christos    extra arguments UT and NS.  Emacs is a special case for now, but
    429  1.1  christos    this Emacs-specific code can be removed once Emacs's config.h
    430  1.1  christos    defines my_strftime.  */
    431  1.1  christos #if defined emacs && !defined my_strftime
    432  1.1  christos # define my_strftime nstrftime
    433  1.1  christos #endif
    434  1.1  christos 
    435  1.1  christos #ifdef my_strftime
    436  1.1  christos # define extra_args , ut, ns
    437  1.1  christos # define extra_args_spec int ut; int ns;
    438  1.1  christos # define extra_args_spec_iso , int ut, int ns
    439  1.1  christos #else
    440  1.1  christos # ifdef COMPILE_WIDE
    441  1.1  christos #  define my_strftime wcsftime
    442  1.1  christos # else
    443  1.1  christos #  define my_strftime strftime
    444  1.1  christos # endif
    445  1.1  christos # define extra_args
    446  1.1  christos # define extra_args_spec
    447  1.1  christos # define extra_args_spec_iso
    448  1.1  christos /* We don't have this information in general.  */
    449  1.1  christos # define ut 0
    450  1.1  christos # define ns 0
    451  1.1  christos #endif
    452  1.1  christos 
    453  1.1  christos #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
    454  1.1  christos   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
    455  1.1  christos      Work around this bug by copying *tp before it might be munged.  */
    456  1.1  christos   size_t _strftime_copytm __P ((char *, size_t, const char *,
    457  1.1  christos 			        const struct tm * extra_args_spec_iso));
    458  1.1  christos   size_t
    459  1.1  christos   my_strftime (s, maxsize, format, tp extra_args)
    460  1.1  christos       CHAR_T *s;
    461  1.1  christos       size_t maxsize;
    462  1.1  christos       const CHAR_T *format;
    463  1.1  christos       const struct tm *tp;
    464  1.1  christos       extra_args_spec
    465  1.1  christos   {
    466  1.1  christos     struct tm tmcopy;
    467  1.1  christos     tmcopy = *tp;
    468  1.1  christos     return _strftime_copytm (s, maxsize, format, &tmcopy extra_args);
    469  1.1  christos   }
    470  1.1  christos # undef my_strftime
    471  1.1  christos # define my_strftime _strftime_copytm
    472  1.1  christos #endif
    473  1.1  christos 
    474  1.1  christos 
    475  1.1  christos /* Write information from TP into S according to the format
    476  1.1  christos    string FORMAT, writing no more that MAXSIZE characters
    477  1.1  christos    (including the terminating '\0') and returning number of
    478  1.1  christos    characters written.  If S is NULL, nothing will be written
    479  1.1  christos    anywhere, so to determine how many characters would be
    480  1.1  christos    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
    481  1.1  christos size_t
    482  1.1  christos my_strftime (s, maxsize, format, tp extra_args)
    483  1.1  christos       CHAR_T *s;
    484  1.1  christos       size_t maxsize;
    485  1.1  christos       const CHAR_T *format;
    486  1.1  christos       const struct tm *tp;
    487  1.1  christos       extra_args_spec
    488  1.1  christos {
    489  1.1  christos   int hour12 = tp->tm_hour;
    490  1.1  christos #ifdef _NL_CURRENT
    491  1.1  christos   /* We cannot make the following values variables since we must delay
    492  1.1  christos      the evaluation of these values until really needed since some
    493  1.1  christos      expressions might not be valid in every situation.  The `struct tm'
    494  1.1  christos      might be generated by a strptime() call that initialized
    495  1.1  christos      only a few elements.  Dereference the pointers only if the format
    496  1.1  christos      requires this.  Then it is ok to fail if the pointers are invalid.  */
    497  1.1  christos # define a_wkday \
    498  1.1  christos   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
    499  1.1  christos # define f_wkday \
    500  1.1  christos   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
    501  1.1  christos # define a_month \
    502  1.1  christos   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
    503  1.1  christos # define f_month \
    504  1.1  christos   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
    505  1.1  christos # define ampm \
    506  1.1  christos   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11		      \
    507  1.1  christos 				 ? NLW(PM_STR) : NLW(AM_STR)))
    508  1.1  christos 
    509  1.1  christos # define aw_len STRLEN (a_wkday)
    510  1.1  christos # define am_len STRLEN (a_month)
    511  1.1  christos # define ap_len STRLEN (ampm)
    512  1.1  christos #else
    513  1.1  christos # if !HAVE_STRFTIME
    514  1.1  christos #  define f_wkday (weekday_name[tp->tm_wday])
    515  1.1  christos #  define f_month (month_name[tp->tm_mon])
    516  1.1  christos #  define a_wkday f_wkday
    517  1.1  christos #  define a_month f_month
    518  1.1  christos #  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
    519  1.1  christos 
    520  1.1  christos   size_t aw_len = 3;
    521  1.1  christos   size_t am_len = 3;
    522  1.1  christos   size_t ap_len = 2;
    523  1.1  christos # endif
    524  1.1  christos #endif
    525  1.1  christos   const char *zone;
    526  1.1  christos   size_t i = 0;
    527  1.1  christos   CHAR_T *p = s;
    528  1.1  christos   const CHAR_T *f;
    529  1.1  christos #if DO_MULTIBYTE && !defined COMPILE_WIDE
    530  1.1  christos   const char *format_end = NULL;
    531  1.1  christos #endif
    532  1.1  christos 
    533  1.1  christos   zone = NULL;
    534  1.1  christos #if HAVE_TM_ZONE
    535  1.1  christos   /* The POSIX test suite assumes that setting
    536  1.1  christos      the environment variable TZ to a new value before calling strftime()
    537  1.1  christos      will influence the result (the %Z format) even if the information in
    538  1.1  christos      TP is computed with a totally different time zone.
    539  1.1  christos      This is bogus: though POSIX allows bad behavior like this,
    540  1.1  christos      POSIX does not require it.  Do the right thing instead.  */
    541  1.1  christos   zone = (const char *) tp->tm_zone;
    542  1.1  christos #endif
    543  1.1  christos #if HAVE_TZNAME
    544  1.1  christos   if (ut)
    545  1.1  christos     {
    546  1.1  christos       if (! (zone && *zone))
    547  1.1  christos 	zone = "GMT";
    548  1.1  christos     }
    549  1.1  christos   else
    550  1.1  christos     {
    551  1.1  christos       /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
    552  1.1  christos 	 time zone names contained in the external variable `tzname' shall
    553  1.1  christos 	 be set as if the tzset() function had been called.  */
    554  1.1  christos # if HAVE_TZSET
    555  1.1  christos       tzset ();
    556  1.1  christos # endif
    557  1.1  christos     }
    558  1.1  christos #endif
    559  1.1  christos 
    560  1.1  christos   if (hour12 > 12)
    561  1.1  christos     hour12 -= 12;
    562  1.1  christos   else
    563  1.1  christos     if (hour12 == 0)
    564  1.1  christos       hour12 = 12;
    565  1.1  christos 
    566  1.1  christos   for (f = format; *f != '\0'; ++f)
    567  1.1  christos     {
    568  1.1  christos       int pad = 0;		/* Padding for number ('-', '_', or 0).  */
    569  1.1  christos       int modifier;		/* Field modifier ('E', 'O', or 0).  */
    570  1.1  christos       int digits;		/* Max digits for numeric format.  */
    571  1.1  christos       int number_value; 	/* Numeric value to be printed.  */
    572  1.1  christos       int negative_number;	/* 1 if the number is negative.  */
    573  1.1  christos       const CHAR_T *subfmt;
    574  1.1  christos       CHAR_T *bufp;
    575  1.1  christos       CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
    576  1.1  christos 		      ? INT_STRLEN_BOUND (time_t)
    577  1.1  christos 		      : INT_STRLEN_BOUND (int))];
    578  1.1  christos       int width = -1;
    579  1.1  christos       int to_lowcase = 0;
    580  1.1  christos       int to_uppcase = 0;
    581  1.1  christos       int change_case = 0;
    582  1.1  christos       int format_char;
    583  1.1  christos 
    584  1.1  christos #if DO_MULTIBYTE && !defined COMPILE_WIDE
    585  1.1  christos       switch (*f)
    586  1.1  christos 	{
    587  1.1  christos 	case L_('%'):
    588  1.1  christos 	  break;
    589  1.1  christos 
    590  1.1  christos 	case L_('\b'): case L_('\t'): case L_('\n'):
    591  1.1  christos 	case L_('\v'): case L_('\f'): case L_('\r'):
    592  1.1  christos 	case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
    593  1.1  christos 	case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
    594  1.1  christos 	case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
    595  1.1  christos 	case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
    596  1.1  christos 	case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
    597  1.1  christos 	case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
    598  1.1  christos 	case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
    599  1.1  christos 	case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
    600  1.1  christos 	case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
    601  1.1  christos 	case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
    602  1.1  christos 	case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
    603  1.1  christos 	case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
    604  1.1  christos 	case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
    605  1.1  christos 	case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
    606  1.1  christos 	case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
    607  1.1  christos 	case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
    608  1.1  christos 	case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
    609  1.1  christos 	case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
    610  1.1  christos 	case L_('~'):
    611  1.1  christos 	  /* The C Standard requires these 98 characters (plus '%') to
    612  1.1  christos 	     be in the basic execution character set.  None of these
    613  1.1  christos 	     characters can start a multibyte sequence, so they need
    614  1.1  christos 	     not be analyzed further.  */
    615  1.1  christos 	  add (1, *p = *f);
    616  1.1  christos 	  continue;
    617  1.1  christos 
    618  1.1  christos 	default:
    619  1.1  christos 	  /* Copy this multibyte sequence until we reach its end, find
    620  1.1  christos 	     an error, or come back to the initial shift state.  */
    621  1.1  christos 	  {
    622  1.1  christos 	    mbstate_t mbstate = mbstate_zero;
    623  1.1  christos 	    size_t len = 0;
    624  1.1  christos 	    size_t fsize;
    625  1.1  christos 
    626  1.1  christos 	    if (! format_end)
    627  1.1  christos 	      format_end = f + strlen (f) + 1;
    628  1.1  christos 	    fsize = format_end - f;
    629  1.1  christos 
    630  1.1  christos 	    do
    631  1.1  christos 	      {
    632  1.1  christos 		size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
    633  1.1  christos 
    634  1.1  christos 		if (bytes == 0)
    635  1.1  christos 		  break;
    636  1.1  christos 
    637  1.1  christos 		if (bytes == (size_t) -2)
    638  1.1  christos 		  {
    639  1.1  christos 		    len += strlen (f + len);
    640  1.1  christos 		    break;
    641  1.1  christos 		  }
    642  1.1  christos 
    643  1.1  christos 		if (bytes == (size_t) -1)
    644  1.1  christos 		  {
    645  1.1  christos 		    len++;
    646  1.1  christos 		    break;
    647  1.1  christos 		  }
    648  1.1  christos 
    649  1.1  christos 		len += bytes;
    650  1.1  christos 	      }
    651  1.1  christos 	    while (! mbsinit (&mbstate));
    652  1.1  christos 
    653  1.1  christos 	    cpy (len, f);
    654  1.1  christos 	    f += len - 1;
    655  1.1  christos 	    continue;
    656  1.1  christos 	  }
    657  1.1  christos 	}
    658  1.1  christos 
    659  1.1  christos #else /* ! DO_MULTIBYTE */
    660  1.1  christos 
    661  1.1  christos       /* Either multibyte encodings are not supported, they are
    662  1.1  christos 	 safe for formats, so any non-'%' byte can be copied through,
    663  1.1  christos 	 or this is the wide character version.  */
    664  1.1  christos       if (*f != L_('%'))
    665  1.1  christos 	{
    666  1.1  christos 	  add (1, *p = *f);
    667  1.1  christos 	  continue;
    668  1.1  christos 	}
    669  1.1  christos 
    670  1.1  christos #endif /* ! DO_MULTIBYTE */
    671  1.1  christos 
    672  1.1  christos       /* Check for flags that can modify a format.  */
    673  1.1  christos       while (1)
    674  1.1  christos 	{
    675  1.1  christos 	  switch (*++f)
    676  1.1  christos 	    {
    677  1.1  christos 	      /* This influences the number formats.  */
    678  1.1  christos 	    case L_('_'):
    679  1.1  christos 	    case L_('-'):
    680  1.1  christos 	    case L_('0'):
    681  1.1  christos 	      pad = *f;
    682  1.1  christos 	      continue;
    683  1.1  christos 
    684  1.1  christos 	      /* This changes textual output.  */
    685  1.1  christos 	    case L_('^'):
    686  1.1  christos 	      to_uppcase = 1;
    687  1.1  christos 	      continue;
    688  1.1  christos 	    case L_('#'):
    689  1.1  christos 	      change_case = 1;
    690  1.1  christos 	      continue;
    691  1.1  christos 
    692  1.1  christos 	    default:
    693  1.1  christos 	      break;
    694  1.1  christos 	    }
    695  1.1  christos 	  break;
    696  1.1  christos 	}
    697  1.1  christos 
    698  1.1  christos       /* As a GNU extension we allow to specify the field width.  */
    699  1.1  christos       if (ISDIGIT (*f))
    700  1.1  christos 	{
    701  1.1  christos 	  width = 0;
    702  1.1  christos 	  do
    703  1.1  christos 	    {
    704  1.1  christos 	      width *= 10;
    705  1.1  christos 	      width += *f - L_('0');
    706  1.1  christos 	      ++f;
    707  1.1  christos 	    }
    708  1.1  christos 	  while (ISDIGIT (*f));
    709  1.1  christos 	}
    710  1.1  christos 
    711  1.1  christos       /* Check for modifiers.  */
    712  1.1  christos       switch (*f)
    713  1.1  christos 	{
    714  1.1  christos 	case L_('E'):
    715  1.1  christos 	case L_('O'):
    716  1.1  christos 	  modifier = *f++;
    717  1.1  christos 	  break;
    718  1.1  christos 
    719  1.1  christos 	default:
    720  1.1  christos 	  modifier = 0;
    721  1.1  christos 	  break;
    722  1.1  christos 	}
    723  1.1  christos 
    724  1.1  christos       /* Now do the specified format.  */
    725  1.1  christos       format_char = *f;
    726  1.1  christos       switch (format_char)
    727  1.1  christos 	{
    728  1.1  christos #define DO_NUMBER(d, v) \
    729  1.1  christos 	  digits = width == -1 ? d : width;				      \
    730  1.1  christos 	  number_value = v; goto do_number
    731  1.1  christos #define DO_NUMBER_SPACEPAD(d, v) \
    732  1.1  christos 	  digits = width == -1 ? d : width;				      \
    733  1.1  christos 	  number_value = v; goto do_number_spacepad
    734  1.1  christos 
    735  1.1  christos 	case L_('%'):
    736  1.1  christos 	  if (modifier != 0)
    737  1.1  christos 	    goto bad_format;
    738  1.1  christos 	  add (1, *p = *f);
    739  1.1  christos 	  break;
    740  1.1  christos 
    741  1.1  christos 	case L_('a'):
    742  1.1  christos 	  if (modifier != 0)
    743  1.1  christos 	    goto bad_format;
    744  1.1  christos 	  if (change_case)
    745  1.1  christos 	    {
    746  1.1  christos 	      to_uppcase = 1;
    747  1.1  christos 	      to_lowcase = 0;
    748  1.1  christos 	    }
    749  1.1  christos #if defined _NL_CURRENT || !HAVE_STRFTIME
    750  1.1  christos 	  cpy (aw_len, a_wkday);
    751  1.1  christos 	  break;
    752  1.1  christos #else
    753  1.1  christos 	  goto underlying_strftime;
    754  1.1  christos #endif
    755  1.1  christos 
    756  1.1  christos 	case 'A':
    757  1.1  christos 	  if (modifier != 0)
    758  1.1  christos 	    goto bad_format;
    759  1.1  christos 	  if (change_case)
    760  1.1  christos 	    {
    761  1.1  christos 	      to_uppcase = 1;
    762  1.1  christos 	      to_lowcase = 0;
    763  1.1  christos 	    }
    764  1.1  christos #if defined _NL_CURRENT || !HAVE_STRFTIME
    765  1.1  christos 	  cpy (STRLEN (f_wkday), f_wkday);
    766  1.1  christos 	  break;
    767  1.1  christos #else
    768  1.1  christos 	  goto underlying_strftime;
    769  1.1  christos #endif
    770  1.1  christos 
    771  1.1  christos 	case L_('b'):
    772  1.1  christos 	case L_('h'):		/* POSIX.2 extension.  */
    773  1.1  christos 	  if (change_case)
    774  1.1  christos 	    {
    775  1.1  christos 	      to_uppcase = 1;
    776  1.1  christos 	      to_lowcase = 0;
    777  1.1  christos 	    }
    778  1.1  christos 	  if (modifier != 0)
    779  1.1  christos 	    goto bad_format;
    780  1.1  christos #if defined _NL_CURRENT || !HAVE_STRFTIME
    781  1.1  christos 	  cpy (am_len, a_month);
    782  1.1  christos 	  break;
    783  1.1  christos #else
    784  1.1  christos 	  goto underlying_strftime;
    785  1.1  christos #endif
    786  1.1  christos 
    787  1.1  christos 	case L_('B'):
    788  1.1  christos 	  if (modifier != 0)
    789  1.1  christos 	    goto bad_format;
    790  1.1  christos 	  if (change_case)
    791  1.1  christos 	    {
    792  1.1  christos 	      to_uppcase = 1;
    793  1.1  christos 	      to_lowcase = 0;
    794  1.1  christos 	    }
    795  1.1  christos #if defined _NL_CURRENT || !HAVE_STRFTIME
    796  1.1  christos 	  cpy (STRLEN (f_month), f_month);
    797  1.1  christos 	  break;
    798  1.1  christos #else
    799  1.1  christos 	  goto underlying_strftime;
    800  1.1  christos #endif
    801  1.1  christos 
    802  1.1  christos 	case L_('c'):
    803  1.1  christos 	  if (modifier == L_('O'))
    804  1.1  christos 	    goto bad_format;
    805  1.1  christos #ifdef _NL_CURRENT
    806  1.1  christos 	  if (! (modifier == 'E'
    807  1.1  christos 		 && (*(subfmt =
    808  1.1  christos 		       (const CHAR_T *) _NL_CURRENT (LC_TIME,
    809  1.1  christos 						     NLW(ERA_D_T_FMT)))
    810  1.1  christos 		     != '\0')))
    811  1.1  christos 	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
    812  1.1  christos #else
    813  1.1  christos # if HAVE_STRFTIME
    814  1.1  christos 	  goto underlying_strftime;
    815  1.1  christos # else
    816  1.1  christos 	  subfmt = L_("%a %b %e %H:%M:%S %Y");
    817  1.1  christos # endif
    818  1.1  christos #endif
    819  1.1  christos 
    820  1.1  christos 	subformat:
    821  1.1  christos 	  {
    822  1.1  christos 	    CHAR_T *old_start = p;
    823  1.1  christos 	    size_t len = my_strftime (NULL, (size_t) -1, subfmt,
    824  1.1  christos 				      tp extra_args);
    825  1.1  christos 	    add (len, my_strftime (p, maxsize - i, subfmt,
    826  1.1  christos 				   tp extra_args));
    827  1.1  christos 
    828  1.1  christos 	    if (to_uppcase)
    829  1.1  christos 	      while (old_start < p)
    830  1.1  christos 		{
    831  1.1  christos 		  *old_start = TOUPPER ((UCHAR_T) *old_start);
    832  1.1  christos 		  ++old_start;
    833  1.1  christos 		}
    834  1.1  christos 	  }
    835  1.1  christos 	  break;
    836  1.1  christos 
    837  1.1  christos #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
    838  1.1  christos 	underlying_strftime:
    839  1.1  christos 	  {
    840  1.1  christos 	    /* The relevant information is available only via the
    841  1.1  christos 	       underlying strftime implementation, so use that.  */
    842  1.1  christos 	    char ufmt[4];
    843  1.1  christos 	    char *u = ufmt;
    844  1.1  christos 	    char ubuf[1024]; /* enough for any single format in practice */
    845  1.1  christos 	    size_t len;
    846  1.1  christos 	    /* Make sure we're calling the actual underlying strftime.
    847  1.1  christos 	       In some cases, config.h contains something like
    848  1.1  christos 	       "#define strftime rpl_strftime".  */
    849  1.1  christos # ifdef strftime
    850  1.1  christos #  undef strftime
    851  1.1  christos 	    size_t strftime ();
    852  1.1  christos # endif
    853  1.1  christos 
    854  1.1  christos 	    *u++ = '%';
    855  1.1  christos 	    if (modifier != 0)
    856  1.1  christos 	      *u++ = modifier;
    857  1.1  christos 	    *u++ = format_char;
    858  1.1  christos 	    *u = '\0';
    859  1.1  christos 	    len = strftime (ubuf, sizeof ubuf, ufmt, tp);
    860  1.1  christos 	    if (len == 0 && ubuf[0] != '\0')
    861  1.1  christos 	      return 0;
    862  1.1  christos 	    cpy (len, ubuf);
    863  1.1  christos 	  }
    864  1.1  christos 	  break;
    865  1.1  christos #endif
    866  1.1  christos 
    867  1.1  christos 	case L_('C'):		/* POSIX.2 extension.  */
    868  1.1  christos 	  if (modifier == L_('O'))
    869  1.1  christos 	    goto bad_format;
    870  1.1  christos 	  if (modifier == L_('E'))
    871  1.1  christos 	    {
    872  1.1  christos #if HAVE_STRUCT_ERA_ENTRY
    873  1.1  christos 	      struct era_entry *era = _nl_get_era_entry (tp);
    874  1.1  christos 	      if (era)
    875  1.1  christos 		{
    876  1.1  christos # ifdef COMPILE_WIDE
    877  1.1  christos 		  size_t len = __wcslen (era->era_wname);
    878  1.1  christos 		  cpy (len, era->era_wname);
    879  1.1  christos # else
    880  1.1  christos 		  size_t len = strlen (era->era_name);
    881  1.1  christos 		  cpy (len, era->era_name);
    882  1.1  christos # endif
    883  1.1  christos 		  break;
    884  1.1  christos 		}
    885  1.1  christos #else
    886  1.1  christos # if HAVE_STRFTIME
    887  1.1  christos 	      goto underlying_strftime;
    888  1.1  christos # endif
    889  1.1  christos #endif
    890  1.1  christos 	    }
    891  1.1  christos 
    892  1.1  christos 	  {
    893  1.1  christos 	    int year = tp->tm_year + TM_YEAR_BASE;
    894  1.1  christos 	    DO_NUMBER (1, year / 100 - (year % 100 < 0));
    895  1.1  christos 	  }
    896  1.1  christos 
    897  1.1  christos 	case L_('x'):
    898  1.1  christos 	  if (modifier == L_('O'))
    899  1.1  christos 	    goto bad_format;
    900  1.1  christos #ifdef _NL_CURRENT
    901  1.1  christos 	  if (! (modifier == L_('E')
    902  1.1  christos 		 && (*(subfmt =
    903  1.1  christos 		       (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
    904  1.1  christos 		     != L_('\0'))))
    905  1.1  christos 	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
    906  1.1  christos 	  goto subformat;
    907  1.1  christos #else
    908  1.1  christos # if HAVE_STRFTIME
    909  1.1  christos 	  goto underlying_strftime;
    910  1.1  christos # else
    911  1.1  christos 	  /* Fall through.  */
    912  1.1  christos # endif
    913  1.1  christos #endif
    914  1.1  christos 	case L_('D'):		/* POSIX.2 extension.  */
    915  1.1  christos 	  if (modifier != 0)
    916  1.1  christos 	    goto bad_format;
    917  1.1  christos 	  subfmt = L_("%m/%d/%y");
    918  1.1  christos 	  goto subformat;
    919  1.1  christos 
    920  1.1  christos 	case L_('d'):
    921  1.1  christos 	  if (modifier == L_('E'))
    922  1.1  christos 	    goto bad_format;
    923  1.1  christos 
    924  1.1  christos 	  DO_NUMBER (2, tp->tm_mday);
    925  1.1  christos 
    926  1.1  christos 	case L_('e'):		/* POSIX.2 extension.  */
    927  1.1  christos 	  if (modifier == L_('E'))
    928  1.1  christos 	    goto bad_format;
    929  1.1  christos 
    930  1.1  christos 	  DO_NUMBER_SPACEPAD (2, tp->tm_mday);
    931  1.1  christos 
    932  1.1  christos 	  /* All numeric formats set DIGITS and NUMBER_VALUE and then
    933  1.1  christos 	     jump to one of these two labels.  */
    934  1.1  christos 
    935  1.1  christos 	do_number_spacepad:
    936  1.1  christos 	  /* Force `_' flag unless overwritten by `0' flag.  */
    937  1.1  christos 	  if (pad != L_('0'))
    938  1.1  christos 	    pad = L_('_');
    939  1.1  christos 
    940  1.1  christos 	do_number:
    941  1.1  christos 	  /* Format the number according to the MODIFIER flag.  */
    942  1.1  christos 
    943  1.1  christos 	  if (modifier == L_('O') && 0 <= number_value)
    944  1.1  christos 	    {
    945  1.1  christos #ifdef _NL_CURRENT
    946  1.1  christos 	      /* Get the locale specific alternate representation of
    947  1.1  christos 		 the number NUMBER_VALUE.  If none exist NULL is returned.  */
    948  1.1  christos # ifdef COMPILE_WIDE
    949  1.1  christos 	      const wchar_t *cp = _nl_get_walt_digit (number_value);
    950  1.1  christos # else
    951  1.1  christos 	      const char *cp = _nl_get_alt_digit (number_value);
    952  1.1  christos # endif
    953  1.1  christos 
    954  1.1  christos 	      if (cp != NULL)
    955  1.1  christos 		{
    956  1.1  christos 		  size_t digitlen = STRLEN (cp);
    957  1.1  christos 		  if (digitlen != 0)
    958  1.1  christos 		    {
    959  1.1  christos 		      cpy (digitlen, cp);
    960  1.1  christos 		      break;
    961  1.1  christos 		    }
    962  1.1  christos 		}
    963  1.1  christos #else
    964  1.1  christos # if HAVE_STRFTIME
    965  1.1  christos 	      goto underlying_strftime;
    966  1.1  christos # endif
    967  1.1  christos #endif
    968  1.1  christos 	    }
    969  1.1  christos 	  {
    970  1.1  christos 	    unsigned int u = number_value;
    971  1.1  christos 
    972  1.1  christos 	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
    973  1.1  christos 	    negative_number = number_value < 0;
    974  1.1  christos 
    975  1.1  christos 	    if (negative_number)
    976  1.1  christos 	      u = -u;
    977  1.1  christos 
    978  1.1  christos 	    do
    979  1.1  christos 	      *--bufp = u % 10 + L_('0');
    980  1.1  christos 	    while ((u /= 10) != 0);
    981  1.1  christos   	  }
    982  1.1  christos 
    983  1.1  christos 	do_number_sign_and_padding:
    984  1.1  christos 	  if (negative_number)
    985  1.1  christos 	    *--bufp = L_('-');
    986  1.1  christos 
    987  1.1  christos 	  if (pad != L_('-'))
    988  1.1  christos 	    {
    989  1.1  christos 	      int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
    990  1.1  christos 				      - bufp);
    991  1.1  christos 
    992  1.1  christos 	      if (pad == L_('_'))
    993  1.1  christos 		{
    994  1.1  christos 		  while (0 < padding--)
    995  1.1  christos 		    *--bufp = L_(' ');
    996  1.1  christos 		}
    997  1.1  christos 	      else
    998  1.1  christos 		{
    999  1.1  christos 		  bufp += negative_number;
   1000  1.1  christos 		  while (0 < padding--)
   1001  1.1  christos 		    *--bufp = L_('0');
   1002  1.1  christos 		  if (negative_number)
   1003  1.1  christos 		    *--bufp = L_('-');
   1004  1.1  christos 		}
   1005  1.1  christos 	    }
   1006  1.1  christos 
   1007  1.1  christos 	  cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
   1008  1.1  christos 	  break;
   1009  1.1  christos 
   1010  1.1  christos 	case L_('F'):
   1011  1.1  christos 	  if (modifier != 0)
   1012  1.1  christos 	    goto bad_format;
   1013  1.1  christos 	  subfmt = L_("%Y-%m-%d");
   1014  1.1  christos 	  goto subformat;
   1015  1.1  christos 
   1016  1.1  christos 	case L_('H'):
   1017  1.1  christos 	  if (modifier == L_('E'))
   1018  1.1  christos 	    goto bad_format;
   1019  1.1  christos 
   1020  1.1  christos 	  DO_NUMBER (2, tp->tm_hour);
   1021  1.1  christos 
   1022  1.1  christos 	case L_('I'):
   1023  1.1  christos 	  if (modifier == L_('E'))
   1024  1.1  christos 	    goto bad_format;
   1025  1.1  christos 
   1026  1.1  christos 	  DO_NUMBER (2, hour12);
   1027  1.1  christos 
   1028  1.1  christos 	case L_('k'):		/* GNU extension.  */
   1029  1.1  christos 	  if (modifier == L_('E'))
   1030  1.1  christos 	    goto bad_format;
   1031  1.1  christos 
   1032  1.1  christos 	  DO_NUMBER_SPACEPAD (2, tp->tm_hour);
   1033  1.1  christos 
   1034  1.1  christos 	case L_('l'):		/* GNU extension.  */
   1035  1.1  christos 	  if (modifier == L_('E'))
   1036  1.1  christos 	    goto bad_format;
   1037  1.1  christos 
   1038  1.1  christos 	  DO_NUMBER_SPACEPAD (2, hour12);
   1039  1.1  christos 
   1040  1.1  christos 	case L_('j'):
   1041  1.1  christos 	  if (modifier == L_('E'))
   1042  1.1  christos 	    goto bad_format;
   1043  1.1  christos 
   1044  1.1  christos 	  DO_NUMBER (3, 1 + tp->tm_yday);
   1045  1.1  christos 
   1046  1.1  christos 	case L_('M'):
   1047  1.1  christos 	  if (modifier == L_('E'))
   1048  1.1  christos 	    goto bad_format;
   1049  1.1  christos 
   1050  1.1  christos 	  DO_NUMBER (2, tp->tm_min);
   1051  1.1  christos 
   1052  1.1  christos 	case L_('m'):
   1053  1.1  christos 	  if (modifier == L_('E'))
   1054  1.1  christos 	    goto bad_format;
   1055  1.1  christos 
   1056  1.1  christos 	  DO_NUMBER (2, tp->tm_mon + 1);
   1057  1.1  christos 
   1058  1.1  christos 	case L_('N'):		/* GNU extension.  */
   1059  1.1  christos 	  if (modifier == L_('E'))
   1060  1.1  christos 	    goto bad_format;
   1061  1.1  christos 
   1062  1.1  christos 	  number_value = ns;
   1063  1.1  christos 	  if (width != -1)
   1064  1.1  christos 	    {
   1065  1.1  christos 	      /* Take an explicit width less than 9 as a precision.  */
   1066  1.1  christos 	      int j;
   1067  1.1  christos 	      for (j = width; j < 9; j++)
   1068  1.1  christos 		number_value /= 10;
   1069  1.1  christos 	    }
   1070  1.1  christos 
   1071  1.1  christos 	  DO_NUMBER (9, number_value);
   1072  1.1  christos 
   1073  1.1  christos 	case L_('n'):		/* POSIX.2 extension.  */
   1074  1.1  christos 	  add (1, *p = L_('\n'));
   1075  1.1  christos 	  break;
   1076  1.1  christos 
   1077  1.1  christos 	case L_('P'):
   1078  1.1  christos 	  to_lowcase = 1;
   1079  1.1  christos #if !defined _NL_CURRENT && HAVE_STRFTIME
   1080  1.1  christos 	  format_char = L_('p');
   1081  1.1  christos #endif
   1082  1.1  christos 	  /* FALLTHROUGH */
   1083  1.1  christos 
   1084  1.1  christos 	case L_('p'):
   1085  1.1  christos 	  if (change_case)
   1086  1.1  christos 	    {
   1087  1.1  christos 	      to_uppcase = 0;
   1088  1.1  christos 	      to_lowcase = 1;
   1089  1.1  christos 	    }
   1090  1.1  christos #if defined _NL_CURRENT || !HAVE_STRFTIME
   1091  1.1  christos 	  cpy (ap_len, ampm);
   1092  1.1  christos 	  break;
   1093  1.1  christos #else
   1094  1.1  christos 	  goto underlying_strftime;
   1095  1.1  christos #endif
   1096  1.1  christos 
   1097  1.1  christos 	case L_('R'):		/* ISO C99 extension.  */
   1098  1.1  christos 	  subfmt = L_("%H:%M");
   1099  1.1  christos 	  goto subformat;
   1100  1.1  christos 
   1101  1.1  christos 	case L_('r'):		/* POSIX.2 extension.  */
   1102  1.1  christos #ifdef _NL_CURRENT
   1103  1.1  christos 	  if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
   1104  1.1  christos 						       NLW(T_FMT_AMPM)))
   1105  1.1  christos 	      == L_('\0'))
   1106  1.1  christos #endif
   1107  1.1  christos 	    subfmt = L_("%I:%M:%S %p");
   1108  1.1  christos 	  goto subformat;
   1109  1.1  christos 
   1110  1.1  christos 	case L_('S'):
   1111  1.1  christos 	  if (modifier == L_('E'))
   1112  1.1  christos 	    goto bad_format;
   1113  1.1  christos 
   1114  1.1  christos 	  DO_NUMBER (2, tp->tm_sec);
   1115  1.1  christos 
   1116  1.1  christos 	case L_('s'):		/* GNU extension.  */
   1117  1.1  christos   	  {
   1118  1.1  christos 	    struct tm ltm;
   1119  1.1  christos 	    time_t t;
   1120  1.1  christos 
   1121  1.1  christos 	    ltm = *tp;
   1122  1.1  christos 	    t = mktime (&ltm);
   1123  1.1  christos 
   1124  1.1  christos 	    /* Generate string value for T using time_t arithmetic;
   1125  1.1  christos 	       this works even if sizeof (long) < sizeof (time_t).  */
   1126  1.1  christos 
   1127  1.1  christos 	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
   1128  1.1  christos 	    negative_number = t < 0;
   1129  1.1  christos 
   1130  1.1  christos 	    do
   1131  1.1  christos 	      {
   1132  1.1  christos 		int d = t % 10;
   1133  1.1  christos 		t /= 10;
   1134  1.1  christos 
   1135  1.1  christos 		if (negative_number)
   1136  1.1  christos 		  {
   1137  1.1  christos 		    d = -d;
   1138  1.1  christos 
   1139  1.1  christos 		    /* Adjust if division truncates to minus infinity.  */
   1140  1.1  christos 		    if (0 < -1 % 10 && d < 0)
   1141  1.1  christos 		      {
   1142  1.1  christos 			t++;
   1143  1.1  christos 			d += 10;
   1144  1.1  christos 		      }
   1145  1.1  christos 		  }
   1146  1.1  christos 
   1147  1.1  christos 		*--bufp = d + L_('0');
   1148  1.1  christos 	      }
   1149  1.1  christos 	    while (t != 0);
   1150  1.1  christos 
   1151  1.1  christos 	    digits = 1;
   1152  1.1  christos 	    goto do_number_sign_and_padding;
   1153  1.1  christos 	  }
   1154  1.1  christos 
   1155  1.1  christos 	case L_('X'):
   1156  1.1  christos 	  if (modifier == L_('O'))
   1157  1.1  christos 	    goto bad_format;
   1158  1.1  christos #ifdef _NL_CURRENT
   1159  1.1  christos 	  if (! (modifier == L_('E')
   1160  1.1  christos 		 && (*(subfmt =
   1161  1.1  christos 		       (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
   1162  1.1  christos 		     != L_('\0'))))
   1163  1.1  christos 	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
   1164  1.1  christos 	  goto subformat;
   1165  1.1  christos #else
   1166  1.1  christos # if HAVE_STRFTIME
   1167  1.1  christos 	  goto underlying_strftime;
   1168  1.1  christos # else
   1169  1.1  christos 	  /* Fall through.  */
   1170  1.1  christos # endif
   1171  1.1  christos #endif
   1172  1.1  christos 	case L_('T'):		/* POSIX.2 extension.  */
   1173  1.1  christos 	  subfmt = L_("%H:%M:%S");
   1174  1.1  christos 	  goto subformat;
   1175  1.1  christos 
   1176  1.1  christos 	case L_('t'):		/* POSIX.2 extension.  */
   1177  1.1  christos 	  add (1, *p = L_('\t'));
   1178  1.1  christos 	  break;
   1179  1.1  christos 
   1180  1.1  christos 	case L_('u'):		/* POSIX.2 extension.  */
   1181  1.1  christos 	  DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
   1182  1.1  christos 
   1183  1.1  christos 	case L_('U'):
   1184  1.1  christos 	  if (modifier == L_('E'))
   1185  1.1  christos 	    goto bad_format;
   1186  1.1  christos 
   1187  1.1  christos 	  DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
   1188  1.1  christos 
   1189  1.1  christos 	case L_('V'):
   1190  1.1  christos 	case L_('g'):		/* ISO C99 extension.  */
   1191  1.1  christos 	case L_('G'):		/* ISO C99 extension.  */
   1192  1.1  christos 	  if (modifier == L_('E'))
   1193  1.1  christos 	    goto bad_format;
   1194  1.1  christos 	  {
   1195  1.1  christos 	    int year = tp->tm_year + TM_YEAR_BASE;
   1196  1.1  christos 	    int days = iso_week_days (tp->tm_yday, tp->tm_wday);
   1197  1.1  christos 
   1198  1.1  christos 	    if (days < 0)
   1199  1.1  christos 	      {
   1200  1.1  christos 		/* This ISO week belongs to the previous year.  */
   1201  1.1  christos 		year--;
   1202  1.1  christos 		days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
   1203  1.1  christos 				      tp->tm_wday);
   1204  1.1  christos 	      }
   1205  1.1  christos 	    else
   1206  1.1  christos 	      {
   1207  1.1  christos 		int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
   1208  1.1  christos 				       tp->tm_wday);
   1209  1.1  christos 		if (0 <= d)
   1210  1.1  christos 		  {
   1211  1.1  christos 		    /* This ISO week belongs to the next year.  */
   1212  1.1  christos 		    year++;
   1213  1.1  christos 		    days = d;
   1214  1.1  christos 		  }
   1215  1.1  christos 	      }
   1216  1.1  christos 
   1217  1.1  christos 	    switch (*f)
   1218  1.1  christos 	      {
   1219  1.1  christos 	      case L_('g'):
   1220  1.1  christos 		DO_NUMBER (2, (year % 100 + 100) % 100);
   1221  1.1  christos 
   1222  1.1  christos 	      case L_('G'):
   1223  1.1  christos 		DO_NUMBER (1, year);
   1224  1.1  christos 
   1225  1.1  christos 	      default:
   1226  1.1  christos 		DO_NUMBER (2, days / 7 + 1);
   1227  1.1  christos 	      }
   1228  1.1  christos 	  }
   1229  1.1  christos 
   1230  1.1  christos 	case L_('W'):
   1231  1.1  christos 	  if (modifier == L_('E'))
   1232  1.1  christos 	    goto bad_format;
   1233  1.1  christos 
   1234  1.1  christos 	  DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
   1235  1.1  christos 
   1236  1.1  christos 	case L_('w'):
   1237  1.1  christos 	  if (modifier == L_('E'))
   1238  1.1  christos 	    goto bad_format;
   1239  1.1  christos 
   1240  1.1  christos 	  DO_NUMBER (1, tp->tm_wday);
   1241  1.1  christos 
   1242  1.1  christos 	case L_('Y'):
   1243  1.1  christos 	  if (modifier == 'E')
   1244  1.1  christos 	    {
   1245  1.1  christos #if HAVE_STRUCT_ERA_ENTRY
   1246  1.1  christos 	      struct era_entry *era = _nl_get_era_entry (tp);
   1247  1.1  christos 	      if (era)
   1248  1.1  christos 		{
   1249  1.1  christos # ifdef COMPILE_WIDE
   1250  1.1  christos 		  subfmt = era->era_wformat;
   1251  1.1  christos # else
   1252  1.1  christos 		  subfmt = era->era_format;
   1253  1.1  christos # endif
   1254  1.1  christos 		  goto subformat;
   1255  1.1  christos 		}
   1256  1.1  christos #else
   1257  1.1  christos # if HAVE_STRFTIME
   1258  1.1  christos 	      goto underlying_strftime;
   1259  1.1  christos # endif
   1260  1.1  christos #endif
   1261  1.1  christos 	    }
   1262  1.1  christos 	  if (modifier == L_('O'))
   1263  1.1  christos 	    goto bad_format;
   1264  1.1  christos 	  else
   1265  1.1  christos 	    DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
   1266  1.1  christos 
   1267  1.1  christos 	case L_('y'):
   1268  1.1  christos 	  if (modifier == L_('E'))
   1269  1.1  christos 	    {
   1270  1.1  christos #if HAVE_STRUCT_ERA_ENTRY
   1271  1.1  christos 	      struct era_entry *era = _nl_get_era_entry (tp);
   1272  1.1  christos 	      if (era)
   1273  1.1  christos 		{
   1274  1.1  christos 		  int delta = tp->tm_year - era->start_date[0];
   1275  1.1  christos 		  DO_NUMBER (1, (era->offset
   1276  1.1  christos 				 + delta * era->absolute_direction));
   1277  1.1  christos 		}
   1278  1.1  christos #else
   1279  1.1  christos # if HAVE_STRFTIME
   1280  1.1  christos 	      goto underlying_strftime;
   1281  1.1  christos # endif
   1282  1.1  christos #endif
   1283  1.1  christos 	    }
   1284  1.1  christos 	  DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
   1285  1.1  christos 
   1286  1.1  christos 	case L_('Z'):
   1287  1.1  christos 	  if (change_case)
   1288  1.1  christos 	    {
   1289  1.1  christos 	      to_uppcase = 0;
   1290  1.1  christos 	      to_lowcase = 1;
   1291  1.1  christos 	    }
   1292  1.1  christos 
   1293  1.1  christos #if HAVE_TZNAME
   1294  1.1  christos 	  /* The tzset() call might have changed the value.  */
   1295  1.1  christos 	  if (!(zone && *zone) && tp->tm_isdst >= 0)
   1296  1.1  christos 	    zone = tzname[tp->tm_isdst];
   1297  1.1  christos #endif
   1298  1.1  christos 	  if (! zone)
   1299  1.1  christos 	    zone = "";		/* POSIX.2 requires the empty string here.  */
   1300  1.1  christos 
   1301  1.1  christos #ifdef COMPILE_WIDE
   1302  1.1  christos 	  {
   1303  1.1  christos 	    /* The zone string is always given in multibyte form.  We have
   1304  1.1  christos 	       to transform it first.  */
   1305  1.1  christos 	    wchar_t *wczone;
   1306  1.1  christos 	    size_t len;
   1307  1.1  christos 	    widen (zone, wczone, len);
   1308  1.1  christos 	    cpy (len, wczone);
   1309  1.1  christos 	  }
   1310  1.1  christos #else
   1311  1.1  christos 	  cpy (strlen (zone), zone);
   1312  1.1  christos #endif
   1313  1.1  christos 	  break;
   1314  1.1  christos 
   1315  1.1  christos 	case L_('z'):		/* ISO C99 extension.  */
   1316  1.1  christos 	  if (tp->tm_isdst < 0)
   1317  1.1  christos 	    break;
   1318  1.1  christos 
   1319  1.1  christos 	  {
   1320  1.1  christos 	    int diff;
   1321  1.1  christos #if HAVE_TM_GMTOFF
   1322  1.1  christos 	    diff = tp->tm_gmtoff;
   1323  1.1  christos #else
   1324  1.1  christos 	    if (ut)
   1325  1.1  christos 	      diff = 0;
   1326  1.1  christos 	    else
   1327  1.1  christos 	      {
   1328  1.1  christos 		struct tm gtm;
   1329  1.1  christos 		struct tm ltm;
   1330  1.1  christos 		time_t lt;
   1331  1.1  christos 
   1332  1.1  christos 		ltm = *tp;
   1333  1.1  christos 		lt = mktime (&ltm);
   1334  1.1  christos 
   1335  1.1  christos 		if (lt == (time_t) -1)
   1336  1.1  christos 		  {
   1337  1.1  christos 		    /* mktime returns -1 for errors, but -1 is also a
   1338  1.1  christos 		       valid time_t value.  Check whether an error really
   1339  1.1  christos 		       occurred.  */
   1340  1.1  christos 		    struct tm tm;
   1341  1.1  christos 
   1342  1.1  christos 		    if (! my_strftime_localtime_r (&lt, &tm)
   1343  1.1  christos 			|| ((ltm.tm_sec ^ tm.tm_sec)
   1344  1.1  christos 			    | (ltm.tm_min ^ tm.tm_min)
   1345  1.1  christos 			    | (ltm.tm_hour ^ tm.tm_hour)
   1346  1.1  christos 			    | (ltm.tm_mday ^ tm.tm_mday)
   1347  1.1  christos 			    | (ltm.tm_mon ^ tm.tm_mon)
   1348  1.1  christos 			    | (ltm.tm_year ^ tm.tm_year)))
   1349  1.1  christos 		      break;
   1350  1.1  christos 		  }
   1351  1.1  christos 
   1352  1.1  christos 		if (! my_strftime_gmtime_r (&lt, &gtm))
   1353  1.1  christos 		  break;
   1354  1.1  christos 
   1355  1.1  christos 		diff = tm_diff (&ltm, &gtm);
   1356  1.1  christos 	      }
   1357  1.1  christos #endif
   1358  1.1  christos 
   1359  1.1  christos 	    if (diff < 0)
   1360  1.1  christos 	      {
   1361  1.1  christos 		add (1, *p = L_('-'));
   1362  1.1  christos 		diff = -diff;
   1363  1.1  christos 	      }
   1364  1.1  christos 	    else
   1365  1.1  christos 	      add (1, *p = L_('+'));
   1366  1.1  christos 
   1367  1.1  christos 	    diff /= 60;
   1368  1.1  christos 	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
   1369  1.1  christos 	  }
   1370  1.1  christos 
   1371  1.1  christos 	case L_('\0'):		/* GNU extension: % at end of format.  */
   1372  1.1  christos 	    --f;
   1373  1.1  christos 	    /* Fall through.  */
   1374  1.1  christos 	default:
   1375  1.1  christos 	  /* Unknown format; output the format, including the '%',
   1376  1.1  christos 	     since this is most likely the right thing to do if a
   1377  1.1  christos 	     multibyte string has been misparsed.  */
   1378  1.1  christos 	bad_format:
   1379  1.1  christos 	  {
   1380  1.1  christos 	    int flen;
   1381  1.1  christos 	    for (flen = 1; f[1 - flen] != L_('%'); flen++)
   1382  1.1  christos 	      continue;
   1383  1.1  christos 	    cpy (flen, &f[1 - flen]);
   1384  1.1  christos 	  }
   1385  1.1  christos 	  break;
   1386  1.1  christos 	}
   1387  1.1  christos     }
   1388  1.1  christos 
   1389  1.1  christos   if (p && maxsize != 0)
   1390  1.1  christos     *p = L_('\0');
   1391  1.1  christos   return i;
   1392  1.1  christos }
   1393  1.1  christos 
   1394  1.1  christos 
   1395  1.1  christos #ifdef emacs
   1396  1.1  christos /* For Emacs we have a separate interface which corresponds to the normal
   1397  1.1  christos    strftime function plus the ut argument, but without the ns argument.  */
   1398  1.1  christos size_t
   1399  1.1  christos emacs_strftimeu (s, maxsize, format, tp, ut)
   1400  1.1  christos       char *s;
   1401  1.1  christos       size_t maxsize;
   1402  1.1  christos       const char *format;
   1403  1.1  christos       const struct tm *tp;
   1404  1.1  christos       int ut;
   1405  1.1  christos {
   1406  1.1  christos   return my_strftime (s, maxsize, format, tp, ut, 0);
   1407  1.1  christos }
   1408  1.1  christos #endif
   1409