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