1 /*
2    NOTE: The canonical source of this file is maintained with the GNU C
3    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
4 
5    This program is free software; you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by the
7    Free Software Foundation; either version 2, or (at your option) any
8    later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18    */
19 
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #ifdef _LIBC
25 # define HAVE_LIMITS_H 1
26 # define HAVE_MBLEN 1
27 # define HAVE_MBRLEN 1
28 # define HAVE_STRUCT_ERA_ENTRY 1
29 # define HAVE_TM_GMTOFF 1
30 # define HAVE_TM_ZONE 1
31 # define HAVE_TZNAME 1
32 # define HAVE_TZSET 1
33 # define MULTIBYTE_IS_FORMAT_SAFE 1
34 # define STDC_HEADERS 1
35 # include <ansidecl.h>
36 # include "../locale/localeinfo.h"
37 #endif
38 
39 #include <ctype.h>
40 #include <sys/types.h>          /* Some systems define `time_t' here.  */
41 
42 #ifdef TIME_WITH_SYS_TIME
43 # include <sys/time.h>
44 # include <time.h>
45 #else
46 # ifdef HAVE_SYS_TIME_H
47 #  include <sys/time.h>
48 # else
49 #  include <time.h>
50 # endif
51 #endif
52 #if HAVE_TZNAME
53 extern char *tzname[];
54 #endif
55 
56 /* Do multibyte processing if multibytes are supported, unless
57    multibyte sequences are safe in formats.  Multibyte sequences are
58    safe if they cannot contain byte sequences that look like format
59    conversion specifications.  The GNU C Library uses UTF8 multibyte
60    encoding, which is safe for formats, but strftime.c can be used
61    with other C libraries that use unsafe encodings.  */
62 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
63 
64 #if DO_MULTIBYTE
65 # if HAVE_MBRLEN
66 #  include <wchar.h>
67 # else
68    /* Simulate mbrlen with mblen as best we can.  */
69 #  define mbstate_t int
70 #  define mbrlen(s, n, ps) mblen (s, n)
71 #  define mbsinit(ps) (*(ps) == 0)
72 # endif
73   static const mbstate_t mbstate_zero;
74 #endif
75 
76 #if HAVE_LIMITS_H
77 # include <limits.h>
78 #endif
79 
80 #if STDC_HEADERS
81 # include <stddef.h>
82 # include <stdlib.h>
83 # include <string.h>
84 #else
85 # define memcpy(d, s, n) bcopy ((s), (d), (n))
86 #endif
87 
88 #ifndef __P
89 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
90 #  define __P(args) args
91 # else
92 #  define __P(args) ()
93 # endif  /* GCC.  */
94 #endif  /* Not __P.  */
95 
96 #ifndef PTR
97 # ifdef __STDC__
98 #  define PTR void *
99 # else
100 #  define PTR char *
101 # endif
102 #endif
103 
104 #ifndef CHAR_BIT
105 # define CHAR_BIT 8
106 #endif
107 
108 #ifndef NULL
109 # define NULL 0
110 #endif
111 
112 #define TYPE_SIGNED(t) ((t) -1 < 0)
113 
114 /* Bound on length of the string representing an integer value of type t.
115    Subtract one for the sign bit if t is signed;
116    302 / 1000 is log10 (2) rounded up;
117    add one for integer division truncation;
118    add one more for a minus sign if t is signed.  */
119 #define INT_STRLEN_BOUND(t) \
120   ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
121 
122 #define TM_YEAR_BASE 1900
123 
124 #ifndef __isleap
125 /* Nonzero if YEAR is a leap year (every 4 years,
126    except every 100th isn't, and every 400th is).  */
127 # define __isleap(year) \
128   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
129 #endif
130 
131 
132 #ifdef _LIBC
133 # define gmtime_r __gmtime_r
134 # define localtime_r __localtime_r
135 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
136 # define tzname __tzname
137 # define tzset __tzset
138 #else
139 # if ! HAVE_LOCALTIME_R
140 #  if ! HAVE_TM_GMTOFF
141 /* Approximate gmtime_r as best we can in its absence.  */
142 #  define gmtime_r my_gmtime_r
143 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
144 static struct tm *
gmtime_r(const time_t * t,struct tm * tp)145 gmtime_r (const time_t *t, struct tm *tp)
146 {
147   struct tm *l = gmtime (t);
148   if (! l)
149     return 0;
150   *tp = *l;
151   return tp;
152 }
153 #  endif /* ! HAVE_TM_GMTOFF */
154 
155 /* Approximate localtime_r as best we can in its absence.  */
156 #  define localtime_r my_localtime_r
157 static struct tm *localtime_r __P ((const time_t *, struct tm *));
158 static struct tm *
localtime_r(const time_t * t,struct tm * tp)159 localtime_r (const time_t *t, struct tm *tp)
160 {
161   struct tm *l = localtime (t);
162   if (! l)
163     return 0;
164   *tp = *l;
165   return tp;
166 }
167 # endif /* ! HAVE_LOCALTIME_R */
168 #endif /* ! defined (_LIBC) */
169 
170 
171 #if !defined (memset) && !HAVE_MEMSET && !_LIBC
172 /* Some systems lack the `memset' function and we don't want to
173    introduce additional dependencies.  */
174 static char const spaces[16] = "                ";
175 
176 # define memset_space(P, Len) \
177   do {                                                                        \
178     int _len = (Len);                                                         \
179                                                                               \
180     do                                                                        \
181       {                                                                       \
182         int _this = _len > 16 ? 16 : _len;                                    \
183         memcpy ((P), spaces, (size_t) _this);                                 \
184         (P) += _this;                                                         \
185         _len -= _this;                                                        \
186       }                                                                       \
187     while (_len > 0);                                                         \
188   } while (false)
189 #else
190 # define memset_space(P, Len) memset ((P), ' ', (size_t) (Len))
191 #endif
192 
193 #define add(n, f) \
194   do                                                                          \
195     {                                                                         \
196       int _n = (n);                                                           \
197       int _delta = width - _n;                                                \
198       int _incr = _n + (_delta > 0 ? _delta : 0);                             \
199       if (i + _incr >= maxsize)                                               \
200         return 0;                                                             \
201       if (p)                                                                  \
202         {                                                                     \
203           if (_delta > 0)                                                     \
204             memset_space (p, _delta);                                         \
205           f;                                                                  \
206           p += _n;                                                            \
207         }                                                                     \
208       i += _incr;                                                             \
209     } while (false)
210 
211 #define cpy(n, s) \
212     add ((n),                                                                 \
213          if (to_lowcase)                                                      \
214            memcpy_lowcase (p, (s), (size_t) _n);                              \
215          else if (to_uppcase)                                                 \
216            memcpy_uppcase (p, (s), (size_t) _n);                              \
217          else                                                                 \
218            memcpy ((PTR) p, (PTR) (s), (size_t) _n))
219 
220 
221 
222 #ifdef _LIBC
223 # define TOUPPER(Ch) toupper (Ch)
224 # define TOLOWER(Ch) tolower (Ch)
225 #else
226 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
227 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
228 #endif
229 /* We don't use `isdigit' here since the locale dependent
230    interpretation is not what we want here.  We only need to accept
231    the arabic digits in the ASCII range.  One day there is perhaps a
232    more reliable way to accept other sets of digits.  */
233 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
234 
235 static char *memcpy_lowcase __P ((char *dest, char const *src, size_t len));
236 
237 static char *
memcpy_lowcase(char * dest,char const * src,size_t len)238 memcpy_lowcase (char *dest, char const *src, size_t len)
239 {
240   while (len-- > 0)
241     dest[len] = TOLOWER (src[len]);
242   return dest;
243 }
244 
245 static char *memcpy_uppcase __P ((char *dest, char const *src, size_t len));
246 
247 static char *
memcpy_uppcase(char * dest,char const * src,size_t len)248 memcpy_uppcase (char *dest, char const *src, size_t len)
249 {
250   while (len-- > 0)
251     dest[len] = TOUPPER (src[len]);
252   return dest;
253 }
254 
255 #if ! HAVE_TM_GMTOFF
256 /* Yield the difference between *A and *B,
257    measured in seconds, ignoring leap seconds.  */
258 static int tm_diff __P ((const struct tm *, const struct tm *));
259 static int
tm_diff(const struct tm * a,const struct tm * b)260 tm_diff (const struct tm *a, const struct tm *b)
261 {
262   /* Compute intervening leap days correctly even if year is negative.
263      Take care to avoid int overflow in leap day calculations,
264      but it's OK to assume that A and B are close to each other.  */
265   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
266   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
267   int a100 = a4 / 25 - (a4 % 25 < 0);
268   int b100 = b4 / 25 - (b4 % 25 < 0);
269   int a400 = a100 >> 2;
270   int b400 = b100 >> 2;
271   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
272   int years = a->tm_year - b->tm_year;
273   int days = (365 * years + intervening_leap_days
274               + (a->tm_yday - b->tm_yday));
275   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
276                 + (a->tm_min - b->tm_min))
277           + (a->tm_sec - b->tm_sec));
278 }
279 #endif /* ! HAVE_TM_GMTOFF */
280 
281 
282 
283 /* The number of days from the first day of the first ISO week of this
284    year to the year day YDAY with week day WDAY.  ISO weeks start on
285    Monday; the first ISO week has the year's first Thursday.  YDAY may
286    be as small as YDAY_MINIMUM.  */
287 #define ISO_WEEK_START_WDAY 1 /* Monday */
288 #define ISO_WEEK1_WDAY 4 /* Thursday */
289 #define YDAY_MINIMUM (-366)
290 static int iso_week_days __P ((int, int));
291 #ifdef __GNUC__
292 inline
293 #endif
294 static int
iso_week_days(int yday,int wday)295 iso_week_days (int yday, int wday)
296 {
297   /* Add enough to the first operand of % to make it nonnegative.  */
298   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
299   return (yday
300           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
301           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
302 }
303 
304 
305 #ifndef _NL_CURRENT
306 static char const weekday_name[][10] =
307   {
308     "Sunday", "Monday", "Tuesday", "Wednesday",
309     "Thursday", "Friday", "Saturday"
310   };
311 static char const month_name[][10] =
312   {
313     "January", "February", "March", "April", "May", "June",
314     "July", "August", "September", "October", "November", "December"
315   };
316 #endif
317 
318 
319 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
320   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
321      Work around this bug by copying *tp before it might be munged.  */
322   size_t _strftime_copytm __P ((char *, size_t, char const *,
323                                 const struct tm *));
324   size_t
strftime(s,maxsize,format,tp)325   strftime (s, maxsize, format, tp)
326       char *s;
327       size_t maxsize;
328       char const *format;
329       const struct tm *tp;
330   {
331     struct tm tmcopy;
332     tmcopy = *tp;
333     return _strftime_copytm (s, maxsize, format, &tmcopy);
334 }
335 # ifdef strftime
336 #  undef strftime
337 # endif
338 # define strftime _strftime_copytm
339 #endif
340 
341 
342 
343 /* Write information from TP into S according to the format
344    string FORMAT, writing no more that MAXSIZE characters
345    (including the terminating '\0') and returning number of
346    characters written.  If S is NULL, nothing will be written
347    anywhere, so to determine how many characters would be
348    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
349 size_t
strftime(char * s,size_t maxsize,char const * format,const struct tm * tp)350 strftime (char *s, size_t maxsize, char const *format, const struct tm *tp)
351 {
352   int hour12 = tp->tm_hour;
353 #ifdef _NL_CURRENT
354   char const *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
355   char const *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
356   char const *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
357   char const *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
358   char const *const ampm = _NL_CURRENT (LC_TIME,
359                                         hour12 > 11 ? PM_STR : AM_STR);
360   size_t aw_len = strlen (a_wkday);
361   size_t am_len = strlen (a_month);
362   size_t ap_len = strlen (ampm);
363 #else
364   char const *const f_wkday = weekday_name[tp->tm_wday];
365   char const *const f_month = month_name[tp->tm_mon];
366   char const *const a_wkday = f_wkday;
367   char const *const a_month = f_month;
368   char const *const ampm = "AMPM" + 2 * (hour12 > 11);
369   size_t aw_len = 3;
370   size_t am_len = 3;
371   size_t ap_len = 2;
372 #endif
373   size_t wkday_len = strlen (f_wkday);
374   size_t month_len = strlen (f_month);
375   char const *zone;
376   size_t zonelen;
377   size_t i = 0;
378   char *p = s;
379   char const *f;
380 
381   zone = NULL;
382 #if !defined _LIBC && HAVE_TM_ZONE
383   /* XXX We have some problems here.  First, the string pointed to by
384      tm_zone is dynamically allocated while loading the zone data.  But
385      when another zone is loaded since the information in TP were
386      computed this would be a stale pointer.
387      The second problem is the POSIX test suite which assumes setting
388      the environment variable TZ to a new value before calling strftime()
389      will influence the result (the %Z format) even if the information in
390      TP is computed with a totally different time zone.  --drepper@gnu  */
391   zone = (char const *) tp->tm_zone;
392 #endif
393 #if HAVE_TZNAME
394   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
395      time zone names contained in the external variable `tzname' shall
396      be set as if the tzset() function had been called.  */
397 # if HAVE_TZSET
398   tzset ();
399 # endif
400 
401   if (!(zone && *zone) && tp->tm_isdst >= 0)
402     zone = tzname[tp->tm_isdst];
403 #endif
404   if (! zone)
405     zone = "";          /* POSIX.2 requires the empty string here.  */
406 
407   zonelen = strlen (zone);
408 
409   if (hour12 > 12)
410     hour12 -= 12;
411   else
412     if (hour12 == 0) hour12 = 12;
413 
414   for (f = format; *f != '\0'; ++f)
415     {
416       int pad;                  /* Padding for number ('-', '_', or 0).  */
417       int modifier;             /* Field modifier ('E', 'O', or 0).  */
418       int digits;               /* Max digits for numeric format.  */
419       int number_value;         /* Numeric value to be printed.  */
420       int negative_number;      /* 1 if the number is negative.  */
421       char const *subfmt;
422       char *bufp;
423       char buf[1 + (sizeof (int) < sizeof (time_t)
424                     ? INT_STRLEN_BOUND (time_t)
425                     : INT_STRLEN_BOUND (int))];
426       int width = -1;
427       int to_lowcase = 0;
428       int to_uppcase = 0;
429 
430 #if DO_MULTIBYTE
431 
432        switch (*f)
433         {
434         case '%':
435           break;
436 
437 #if __STDC__
438         case '\a':
439 #else
440         case 7:                 /* '\a' is ASCII decimal value 7. */
441 #endif
442         case '\b': case '\t': case '\n':
443         case '\v': case '\f': case '\r':
444         case ' ': case '!': case '"': case '#': case '&': case'\'':
445         case '(': case ')': case '*': case '+': case ',': case '-':
446         case '.': case '/': case '0': case '1': case '2': case '3':
447         case '4': case '5': case '6': case '7': case '8': case '9':
448         case ':': case ';': case '<': case '=': case '>': case '?':
449         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
450         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
451         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
452         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
453         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
454         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
455         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
456         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
457         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
458         case 'x': case 'y': case 'z': case '{': case '|': case '}':
459         case '~':
460           /* The C Standard requires these 98 characters (plus '%') to
461              be in the basic execution character set.  None of these
462              characters can start a multibyte sequence, so they need
463              not be analyzed further.  */
464           add (1, *p = *f);
465           continue;
466 
467         default:
468           /* Copy this multibyte sequence until we reach its end, find
469              an error, or come back to the initial shift state.  */
470           {
471             mbstate_t mbstate = mbstate_zero;
472             size_t len = 0;
473 
474             do
475               {
476                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
477 
478                 if (bytes == 0)
479                   break;
480 
481                 if (bytes == (size_t) -2 || bytes == (size_t) -1)
482                   {
483                     len++;
484                     break;
485                   }
486 
487                 len += bytes;
488               }
489             while (! mbsinit (&mbstate));
490 
491             cpy (len, f);
492             continue;
493           }
494         }
495 
496 #else /* ! DO_MULTIBYTE */
497 
498       /* Either multibyte encodings are not supported, or they are
499          safe for formats, so any non-'%' byte can be copied through.  */
500       if (*f != '%')
501         {
502           add (1, *p = *f);
503           continue;
504         }
505 
506 #endif /* ! DO_MULTIBYTE */
507 
508       /* Check for flags that can modify a format.  */
509       pad = 0;
510       while (1)
511         {
512           switch (*++f)
513             {
514               /* This influences the number formats.  */
515             case '_':
516             case '-':
517             case '0':
518               pad = *f;
519               continue;
520 
521               /* This changes textual output.  */
522             case '^':
523               to_uppcase = 1;
524               continue;
525 
526             default:
527               break;
528             }
529           break;
530         }
531 
532       /* As a GNU extension we allow to specify the field width.  */
533       if (ISDIGIT (*f))
534         {
535           width = 0;
536           do
537             {
538               width *= 10;
539               width += *f - '0';
540               ++f;
541             }
542           while (ISDIGIT (*f));
543         }
544 
545       /* Check for modifiers.  */
546       switch (*f)
547         {
548         case 'E':
549         case 'O':
550           modifier = *f++;
551           break;
552 
553         default:
554           modifier = 0;
555           break;
556         }
557 
558       /* Now do the specified format.  */
559       switch (*f)
560         {
561 #define DO_NUMBER(d, v) \
562           digits = d; number_value = v; goto do_number
563 #define DO_NUMBER_SPACEPAD(d, v) \
564           digits = d; number_value = v; goto do_number_spacepad
565 
566         case '%':
567           if (modifier != 0)
568             goto bad_format;
569           add (1, *p = *f);
570           break;
571 
572         case 'a':
573           if (modifier != 0)
574             goto bad_format;
575           cpy (aw_len, a_wkday);
576           break;
577 
578         case 'A':
579           if (modifier != 0)
580             goto bad_format;
581           cpy (wkday_len, f_wkday);
582           break;
583 
584         case 'b':
585         case 'h':               /* POSIX.2 extension.  */
586           if (modifier != 0)
587             goto bad_format;
588           cpy (am_len, a_month);
589           break;
590 
591         case 'B':
592           if (modifier != 0)
593             goto bad_format;
594           cpy (month_len, f_month);
595           break;
596 
597         case 'c':
598           if (modifier == 'O')
599             goto bad_format;
600 #ifdef _NL_CURRENT
601           if (! (modifier == 'E'
602                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
603             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
604 #else
605           subfmt = "%a %b %e %H:%M:%S %Y";
606 #endif
607 
608         subformat:
609           {
610             char *old_start = p;
611             size_t len = strftime (NULL, maxsize - i, subfmt, tp);
612             if (len == 0 && *subfmt)
613               return 0;
614             add (len, strftime (p, maxsize - i, subfmt, tp));
615 
616             if (to_uppcase)
617               while (old_start < p)
618                 {
619                   *old_start = TOUPPER (*old_start);
620                   ++old_start;
621                 }
622           }
623           break;
624 
625         case 'C':               /* POSIX.2 extension.  */
626           if (modifier == 'O')
627             goto bad_format;
628 #if HAVE_STRUCT_ERA_ENTRY
629           if (modifier == 'E')
630             {
631               struct era_entry *era = _nl_get_era_entry (tp);
632               if (era)
633                 {
634                   size_t len = strlen (era->name_fmt);
635                   cpy (len, era->name_fmt);
636                   break;
637                 }
638             }
639 #endif
640           {
641             int year = tp->tm_year + TM_YEAR_BASE;
642             DO_NUMBER (1, year / 100 - (year % 100 < 0));
643           }
644 
645         case 'x':
646           if (modifier == 'O')
647             goto bad_format;
648 #ifdef _NL_CURRENT
649           if (! (modifier == 'E'
650                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
651             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
652           goto subformat;
653 #endif
654           /* Fall through.  */
655         case 'D':               /* POSIX.2 extension.  */
656           if (modifier != 0)
657             goto bad_format;
658           subfmt = "%m/%d/%y";
659           goto subformat;
660 
661         case 'd':
662           if (modifier == 'E')
663             goto bad_format;
664 
665           DO_NUMBER (2, tp->tm_mday);
666 
667         case 'e':               /* POSIX.2 extension.  */
668           if (modifier == 'E')
669             goto bad_format;
670 
671           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
672 
673           /* All numeric formats set DIGITS and NUMBER_VALUE and then
674              jump to one of these two labels.  */
675 
676         do_number_spacepad:
677           /* Force `_' flag unless overwritten by `0' flag.  */
678           if (pad != '0')
679             pad = '_';
680 
681         do_number:
682           /* Format the number according to the MODIFIER flag.  */
683 
684 #ifdef _NL_CURRENT
685           if (modifier == 'O' && 0 <= number_value)
686             {
687               /* Get the locale specific alternate representation of
688                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
689               char const *cp = _nl_get_alt_digit (number_value);
690 
691               if (cp != NULL)
692                 {
693                   size_t digitlen = strlen (cp);
694                   if (digitlen != 0)
695                     {
696                       cpy (digitlen, cp);
697                       break;
698                     }
699                 }
700             }
701 #endif
702           {
703             unsigned int u = number_value;
704 
705             bufp = buf + sizeof (buf);
706             negative_number = number_value < 0;
707 
708             if (negative_number)
709               u = -u;
710 
711             do
712               *--bufp = u % 10 + '0';
713             while ((u /= 10) != 0);
714           }
715 
716         do_number_sign_and_padding:
717           if (negative_number)
718             *--bufp = '-';
719 
720           if (pad != '-')
721             {
722               int padding = digits - (buf + sizeof (buf) - bufp);
723 
724               if (pad == '_')
725                 {
726                   while (0 < padding--)
727                     *--bufp = ' ';
728                 }
729               else
730                 {
731                   bufp += negative_number;
732                   while (0 < padding--)
733                     *--bufp = '0';
734                   if (negative_number)
735                     *--bufp = '-';
736                 }
737             }
738 
739           cpy (buf + sizeof (buf) - bufp, bufp);
740           break;
741 
742 
743         case 'H':
744           if (modifier == 'E')
745             goto bad_format;
746 
747           DO_NUMBER (2, tp->tm_hour);
748 
749         case 'I':
750           if (modifier == 'E')
751             goto bad_format;
752 
753           DO_NUMBER (2, hour12);
754 
755         case 'k':               /* GNU extension.  */
756           if (modifier == 'E')
757             goto bad_format;
758 
759           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
760 
761         case 'l':               /* GNU extension.  */
762           if (modifier == 'E')
763             goto bad_format;
764 
765           DO_NUMBER_SPACEPAD (2, hour12);
766 
767         case 'j':
768           if (modifier == 'E')
769             goto bad_format;
770 
771           DO_NUMBER (3, 1 + tp->tm_yday);
772 
773         case 'M':
774           if (modifier == 'E')
775             goto bad_format;
776 
777           DO_NUMBER (2, tp->tm_min);
778 
779         case 'm':
780           if (modifier == 'E')
781             goto bad_format;
782 
783           DO_NUMBER (2, tp->tm_mon + 1);
784 
785         case 'n':               /* POSIX.2 extension.  */
786           add (1, *p = '\n');
787           break;
788 
789         case 'P':
790           to_lowcase = 1;
791           /* FALLTHROUGH */
792 
793         case 'p':
794           cpy (ap_len, ampm);
795           break;
796 
797         case 'R':               /* GNU extension.  */
798           subfmt = "%H:%M";
799           goto subformat;
800 
801         case 'r':               /* POSIX.2 extension.  */
802 #ifdef _NL_CURRENT
803           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
804 #endif
805             subfmt = "%I:%M:%S %p";
806           goto subformat;
807 
808         case 'S':
809           if (modifier == 'E')
810             goto bad_format;
811 
812           DO_NUMBER (2, tp->tm_sec);
813 
814         case 's':               /* GNU extension.  */
815           {
816             struct tm ltm;
817             time_t t;
818 
819             ltm = *tp;
820             t = mktime (&ltm);
821 
822             /* Generate string value for T using time_t arithmetic;
823                this works even if sizeof (long) < sizeof (time_t).  */
824 
825             bufp = buf + sizeof (buf);
826             negative_number = t < 0;
827 
828             do
829               {
830                 int d = t % 10;
831                 t /= 10;
832 
833                 if (negative_number)
834                   {
835                     d = -d;
836 
837                     /* Adjust if division truncates to minus infinity.  */
838                     if (0 < -1 % 10 && d < 0)
839                       {
840                         t++;
841                         d += 10;
842                       }
843                   }
844 
845                 *--bufp = d + '0';
846               }
847             while (t != 0);
848 
849             digits = 1;
850             goto do_number_sign_and_padding;
851           }
852 
853         case 'X':
854           if (modifier == 'O')
855             goto bad_format;
856 #ifdef _NL_CURRENT
857           if (! (modifier == 'E'
858                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
859             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
860           goto subformat;
861 #endif
862           /* Fall through.  */
863         case 'T':               /* POSIX.2 extension.  */
864           subfmt = "%H:%M:%S";
865           goto subformat;
866 
867         case 't':               /* POSIX.2 extension.  */
868           add (1, *p = '\t');
869           break;
870 
871         case 'u':               /* POSIX.2 extension.  */
872           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
873 
874         case 'U':
875           if (modifier == 'E')
876             goto bad_format;
877 
878           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
879 
880         case 'V':
881         case 'g':               /* GNU extension.  */
882         case 'G':               /* GNU extension.  */
883           if (modifier == 'E')
884             goto bad_format;
885           {
886             int year = tp->tm_year + TM_YEAR_BASE;
887             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
888 
889             if (days < 0)
890               {
891                 /* This ISO week belongs to the previous year.  */
892                 year--;
893                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
894                                       tp->tm_wday);
895               }
896             else
897               {
898                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
899                                        tp->tm_wday);
900                 if (0 <= d)
901                   {
902                     /* This ISO week belongs to the next year.  */
903                     year++;
904                     days = d;
905                   }
906               }
907 
908             switch (*f)
909               {
910               case 'g':
911                 DO_NUMBER (2, (year % 100 + 100) % 100);
912 
913               case 'G':
914                 DO_NUMBER (1, year);
915 
916               default:
917                 DO_NUMBER (2, days / 7 + 1);
918               }
919           }
920 
921         case 'W':
922           if (modifier == 'E')
923             goto bad_format;
924 
925           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
926 
927         case 'w':
928           if (modifier == 'E')
929             goto bad_format;
930 
931           DO_NUMBER (1, tp->tm_wday);
932 
933         case 'Y':
934 #if HAVE_STRUCT_ERA_ENTRY
935           if (modifier == 'E')
936             {
937               struct era_entry *era = _nl_get_era_entry (tp);
938               if (era)
939                 {
940                   subfmt = strchr (era->name_fmt, '\0') + 1;
941                   goto subformat;
942                 }
943             }
944 #endif
945           if (modifier == 'O')
946             goto bad_format;
947           else
948             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
949 
950         case 'y':
951 #if HAVE_STRUCT_ERA_ENTRY
952           if (modifier == 'E')
953             {
954               struct era_entry *era = _nl_get_era_entry (tp);
955               if (era)
956                 {
957                   int delta = tp->tm_year - era->start_date[0];
958                   DO_NUMBER (1, (era->offset
959                                  + (era->direction == '-' ? -delta : delta)));
960                 }
961             }
962 #endif
963           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
964 
965         case 'Z':
966           cpy (zonelen, zone);
967           break;
968 
969         case 'z':               /* GNU extension.  */
970           if (tp->tm_isdst < 0)
971             break;
972 
973           {
974             int diff;
975 #if HAVE_TM_GMTOFF
976             diff = tp->tm_gmtoff;
977 #else
978             struct tm gtm;
979             struct tm ltm;
980             time_t lt;
981 
982             ltm = *tp;
983             lt = mktime (&ltm);
984 
985             if (lt == (time_t) -1)
986               {
987                 /* mktime returns -1 for errors, but -1 is also a
988                    valid time_t value.  Check whether an error really
989                    occurred.  */
990                 struct tm tm;
991                 localtime_r (&lt, &tm);
992 
993                 if ((ltm.tm_sec ^ tm.tm_sec)
994                     | (ltm.tm_min ^ tm.tm_min)
995                     | (ltm.tm_hour ^ tm.tm_hour)
996                     | (ltm.tm_mday ^ tm.tm_mday)
997                     | (ltm.tm_mon ^ tm.tm_mon)
998                     | (ltm.tm_year ^ tm.tm_year))
999                   break;
1000               }
1001 
1002             if (! gmtime_r (&lt, &gtm))
1003               break;
1004 
1005             diff = tm_diff (&ltm, &gtm);
1006 #endif
1007 
1008             if (diff < 0)
1009               {
1010                 add (1, *p = '-');
1011                 diff = -diff;
1012               }
1013             else
1014               add (1, *p = '+');
1015 
1016             diff /= 60;
1017             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1018           }
1019 
1020         case '\0':              /* GNU extension: % at end of format.  */
1021             --f;
1022             /* Fall through.  */
1023         default:
1024           /* Unknown format; output the format, including the '%',
1025              since this is most likely the right thing to do if a
1026              multibyte string has been misparsed.  */
1027         bad_format:
1028           {
1029             int flen;
1030             for (flen = 1; f[1 - flen] != '%'; flen++)
1031               continue;
1032             cpy (flen, &f[1 - flen]);
1033           }
1034           break;
1035         }
1036     }
1037 
1038   if (p)
1039     *p = '\0';
1040   return i;
1041 }
1042 
1043 /*
1044  * Local Variables:
1045  * mode: C
1046  * c-file-style: "stroustrup"
1047  * indent-tabs-mode: nil
1048  * End:
1049  * end of compat/strftime.c */
1050