1 /* NOTE:  This file defines both strftime() and wcsftime().  Take care when
2  * making changes.  See also wcsftime.c, and note the (small) overlap in the
3  * manual description, taking care to edit both as needed.  */
4 /*
5  * strftime.c
6  * Original Author:	G. Haley
7  * Additions from:	Eric Blake, Corinna Vinschen
8  * Changes to allow dual use as wcstime, also:	Craig Howland
9  *
10  * Places characters into the array pointed to by s as controlled by the string
11  * pointed to by format. If the total number of resulting characters including
12  * the terminating null character is not more than maxsize, returns the number
13  * of characters placed into the array pointed to by s (not including the
14  * terminating null character); otherwise zero is returned and the contents of
15  * the array indeterminate.
16  */
17 
18 /*
19 FUNCTION
20 <<strftime>>, <<strftime_l>>---convert date and time to a formatted string
21 
22 INDEX
23 	strftime
24 
25 INDEX
26 	strftime_l
27 
28 SYNOPSIS
29 	#include <time.h>
30 	size_t strftime(char *restrict <[s]>, size_t <[maxsize]>,
31 			const char *restrict <[format]>,
32                         const struct tm *restrict <[timp]>);
33 	size_t strftime_l(char *restrict <[s]>, size_t <[maxsize]>,
34 			  const char *restrict <[format]>,
35 			  const struct tm *restrict <[timp]>,
36 			  locale_t <[locale]>);
37 
38 DESCRIPTION
39 <<strftime>> converts a <<struct tm>> representation of the time (at
40 <[timp]>) into a null-terminated string, starting at <[s]> and occupying
41 no more than <[maxsize]> characters.
42 
43 <<strftime_l>> is like <<strftime>> but creates a string in a format
44 as expected in locale <[locale]>.  If <[locale]> is LC_GLOBAL_LOCALE or
45 not a valid locale object, the behaviour is undefined.
46 
47 You control the format of the output using the string at <[format]>.
48 <<*<[format]>>> can contain two kinds of specifications: text to be
49 copied literally into the formatted string, and time conversion
50 specifications.  Time conversion specifications are two- and
51 three-character sequences beginning with `<<%>>' (use `<<%%>>' to
52 include a percent sign in the output).  Each defined conversion
53 specification selects only the specified field(s) of calendar time
54 data from <<*<[timp]>>>, and converts it to a string in one of the
55 following ways:
56 
57 o+
58 o %a
59 The abbreviated weekday name according to the current locale. [tm_wday]
60 
61 o %A
62 The full weekday name according to the current locale.
63 In the default "C" locale, one of `<<Sunday>>', `<<Monday>>', `<<Tuesday>>',
64 `<<Wednesday>>', `<<Thursday>>', `<<Friday>>', `<<Saturday>>'. [tm_wday]
65 
66 o %b
67 The abbreviated month name according to the current locale. [tm_mon]
68 
69 o %B
70 The full month name according to the current locale.
71 In the default "C" locale, one of `<<January>>', `<<February>>',
72 `<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
73 `<<August>>', `<<September>>', `<<October>>', `<<November>>',
74 `<<December>>'. [tm_mon]
75 
76 o %c
77 The preferred date and time representation for the current locale.
78 [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
79 
80 o %C
81 The century, that is, the year divided by 100 then truncated.  For
82 4-digit years, the result is zero-padded and exactly two characters;
83 but for other years, there may a negative sign or more digits.  In
84 this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
85 
86 o %d
87 The day of the month, formatted with two digits (from `<<01>>' to
88 `<<31>>'). [tm_mday]
89 
90 o %D
91 A string representing the date, in the form `<<"%m/%d/%y">>'.
92 [tm_mday, tm_mon, tm_year]
93 
94 o %e
95 The day of the month, formatted with leading space if single digit
96 (from `<<1>>' to `<<31>>'). [tm_mday]
97 
98 o %E<<x>>
99 In some locales, the E modifier selects alternative representations of
100 certain modifiers <<x>>.  In newlib, it is ignored, and treated as %<<x>>.
101 
102 o %F
103 A string representing the ISO 8601:2000 date format, in the form
104 `<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
105 
106 o %g
107 The last two digits of the week-based year, see specifier %G (from
108 `<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
109 
110 o %G
111 The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
112 includes January 4th, and begin on Mondays. Therefore, if January 1st,
113 2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
114 week of the previous year; and if December 29th, 30th, or 31st falls
115 on Monday, that day and later belong to week 1 of the next year.  For
116 consistency with %Y, it always has at least four characters.
117 Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
118 Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
119 
120 o %h
121 Synonym for "%b". [tm_mon]
122 
123 o %H
124 The hour (on a 24-hour clock), formatted with two digits (from
125 `<<00>>' to `<<23>>'). [tm_hour]
126 
127 o %I
128 The hour (on a 12-hour clock), formatted with two digits (from
129 `<<01>>' to `<<12>>'). [tm_hour]
130 
131 o %j
132 The count of days in the year, formatted with three digits
133 (from `<<001>>' to `<<366>>'). [tm_yday]
134 
135 o %k
136 The hour (on a 24-hour clock), formatted with leading space if single
137 digit (from `<<0>>' to `<<23>>'). Non-POSIX extension (c.p. %I). [tm_hour]
138 
139 o %l
140 The hour (on a 12-hour clock), formatted with leading space if single
141 digit (from `<<1>>' to `<<12>>'). Non-POSIX extension (c.p. %H). [tm_hour]
142 
143 o %m
144 The month number, formatted with two digits (from `<<01>>' to `<<12>>').
145 [tm_mon]
146 
147 o %M
148 The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
149 
150 o %n
151 A newline character (`<<\n>>').
152 
153 o %O<<x>>
154 In some locales, the O modifier selects alternative digit characters
155 for certain modifiers <<x>>.  In newlib, it is ignored, and treated as %<<x>>.
156 
157 o %p
158 Either `<<AM>>' or `<<PM>>' as appropriate, or the corresponding strings for
159 the current locale. [tm_hour]
160 
161 o %P
162 Same as '<<%p>>', but in lowercase.  This is a GNU extension. [tm_hour]
163 
164 o %q
165 Quarter of the year (from `<<1>>' to `<<4>>'), with January starting
166 the first quarter. This is a GNU extension. [tm_mon]
167 
168 o %r
169 Replaced by the time in a.m. and p.m. notation.  In the "C" locale this
170 is equivalent to "%I:%M:%S %p".  In locales which don't define a.m./p.m.
171 notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
172 
173 o %R
174 The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
175 
176 o %s
177 The time elapsed, in seconds, since the start of the Unix epoch at
178 1970-01-01 00:00:00 UTC.
179 
180 o %S
181 The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
182 value 60 accounts for the occasional leap second. [tm_sec]
183 
184 o %t
185 A tab character (`<<\t>>').
186 
187 o %T
188 The 24-hour time, to the second.  Equivalent to "%H:%M:%S". [tm_sec,
189 tm_min, tm_hour]
190 
191 o %u
192 The weekday as a number, 1-based from Monday (from `<<1>>' to
193 `<<7>>'). [tm_wday]
194 
195 o %U
196 The week number, where weeks start on Sunday, week 1 contains the first
197 Sunday in a year, and earlier days are in week 0.  Formatted with two
198 digits (from `<<00>>' to `<<53>>').  See also <<%W>>. [tm_wday, tm_yday]
199 
200 o %V
201 The week number, where weeks start on Monday, week 1 contains January 4th,
202 and earlier days are in the previous year.  Formatted with two digits
203 (from `<<01>>' to `<<53>>').  See also <<%G>>. [tm_year, tm_wday, tm_yday]
204 
205 o %v
206 A string representing the BSD/OSX/Ruby VMS/Oracle date format, in the form
207 "%e-%b-%Y". Non-POSIX extension. [tm_mday, tm_mon, tm_year]
208 
209 o %w
210 The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
211 [tm_wday]
212 
213 o %W
214 The week number, where weeks start on Monday, week 1 contains the first
215 Monday in a year, and earlier days are in week 0.  Formatted with two
216 digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
217 
218 o %x
219 Replaced by the preferred date representation in the current locale.
220 In the "C" locale this is equivalent to "%m/%d/%y".
221 [tm_mon, tm_mday, tm_year]
222 
223 o %X
224 Replaced by the preferred time representation in the current locale.
225 In the "C" locale this is equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
226 
227 o %y
228 The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
229 (Implementation interpretation:  always positive, even for negative years.)
230 
231 o %Y
232 The full year, equivalent to <<%C%y>>.  It will always have at least four
233 characters, but may have more.  The year is accurate even when tm_year
234 added to the offset of 1900 overflows an int. [tm_year]
235 
236 o %z
237 The offset from UTC.  The format consists of a sign (negative is west of
238 Greewich), two characters for hour, then two characters for minutes
239 (-hhmm or +hhmm).  If tm_isdst is negative, the offset is unknown and no
240 output is generated; if it is zero, the offset is the standard offset for
241 the current time zone; and if it is positive, the offset is the daylight
242 savings offset for the current timezone. The offset is determined from
243 the TZ environment variable, as if by calling tzset(). [tm_isdst]
244 
245 o %Z
246 The current time zone abbreviation. If tm_isdst is negative, no output
247 is generated. Otherwise, the time zone abbreviation is based on the TZ
248 environment variable, as if by calling tzset(). [tm_isdst]
249 
250 o %%
251 A single character, `<<%>>'.
252 o-
253 
254 RETURNS
255 When the formatted time takes up no more than <[maxsize]> characters,
256 the result is the length of the formatted string.  Otherwise, if the
257 formatting operation was abandoned due to lack of room, the result is
258 <<0>>, and the string starting at <[s]> corresponds to just those
259 parts of <<*<[format]>>> that could be completely filled in within the
260 <[maxsize]> limit.
261 
262 PORTABILITY
263 ANSI C requires <<strftime>>, but does not specify the contents of
264 <<*<[s]>>> when the formatted string would require more than
265 <[maxsize]> characters.  Unrecognized specifiers and fields of
266 <<timp>> that are out of range cause undefined results.  Since some
267 formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
268 value beforehand to distinguish between failure and an empty string.
269 This implementation does not support <<s>> being NULL, nor overlapping
270 <<s>> and <<format>>.
271 
272 <<strftime_l>> is POSIX-1.2008.
273 
274 <<strftime>> and <<strftime_l>> require no supporting OS subroutines.
275 
276 BUGS
277 (NOT Cygwin:) <<strftime>> ignores the LC_TIME category of the current
278 locale, hard-coding the "C" locale settings.
279 */
280 
281 #define _GNU_SOURCE
282 #include <stddef.h>
283 #include <stdio.h>
284 #include <time.h>
285 #include <string.h>
286 #include <stdlib.h>
287 #include <limits.h>
288 #include <ctype.h>
289 #include <wctype.h>
290 #include <wchar.h>
291 #include "local.h"
292 #include "../locale/setlocale.h"
293 
294 /* Defines to make the file dual use for either strftime() or wcsftime().
295  * To get wcsftime, define MAKE_WCSFTIME.
296  * To get strftime, do not define MAKE_WCSFTIME.
297  * Names are kept friendly to strftime() usage.  The biggest ugliness is the
298  * use of the CQ() macro to make either regular character constants and
299  * string literals or wide-character constants and wide-character-string
300  * literals, as appropriate.  */
301 #if !defined(MAKE_WCSFTIME)
302 #  define CHAR		char		/* string type basis */
303 #  define CQ(a)		a		/* character constant qualifier */
304 #  define t_snprintf	snprintf	/* char equivalent function name */
305 #  define t_strncmp	strncmp		/* char equivalent function name */
306 #  define SFLG				/* %s flag (null for normal char) */
307 #  define _ctloc(x)     (ctloclen = strlen (ctloc = _CurrentTimeLocale->x))
308 #  define TOLOWER(c)	tolower((int)(unsigned char)(c))
309 #  define STRTOUL(c,p,b) strtoul((c),(p),(b))
310 #  define STRCPY(a,b)	strcpy((a),(b))
311 #  define STRCHR(a,b)	strchr((a),(b))
312 #  define STRLEN(a)	strlen(a)
313 # else
314 #  define strftime	wcsftime	/* Alternate function name */
315 #  define strftime_l	wcsftime_l	/* Alternate function name */
316 #  define CHAR		wchar_t		/* string type basis */
317 #  define CQ(a)		L##a		/* character constant qualifier */
318 #  define t_snprintf	swprintf	/* wide-char equivalent function name */
319 #  define t_strncmp	wcsncmp		/* wide-char equivalent function name */
320 #  define TOLOWER(c)	towlower((wint_t)(c))
321 #  define STRTOUL(c,p,b) wcstoul((c),(p),(b))
322 #  define STRCPY(a,b)	wcscpy((a),(b))
323 #  define STRCHR(a,b)	wcschr((a),(b))
324 #  define STRLEN(a)	wcslen(a)
325 #  define SFLG		"l"		/* %s flag (l for wide char) */
326 #  ifdef __HAVE_LOCALE_INFO_EXTENDED__
327 #   define _ctloc(x)    (ctloclen = wcslen (ctloc = _CurrentTimeLocale->w##x))
328 #  else
329 #   define CTLOCBUFLEN   256		/* Arbitrary big buffer size */
330     static const wchar_t *
__ctloc(wchar_t * buf,const char * elem,size_t * len_ret)331     __ctloc (wchar_t *buf, const char *elem, size_t *len_ret)
332     {
333       buf[CTLOCBUFLEN - 1] = L'\0';
334       *len_ret = mbstowcs (buf, elem, CTLOCBUFLEN - 1);
335       if (*len_ret == (size_t) -1 )
336 	*len_ret = 0;
337       return buf;
338     }
339 #   define _ctloc(x)    (ctloc = __ctloc (ctlocbuf, _CurrentTimeLocale->x, \
340 					  &ctloclen))
341 #  endif
342 #endif  /* MAKE_WCSFTIME */
343 
344 #define CHECK_LENGTH()	if (len < 0 || (count += len) >= maxsize) \
345 			  return 0
346 
347 /* Enforce the coding assumptions that YEAR_BASE is positive.  (%C, %Y, etc.) */
348 #if YEAR_BASE < 0
349 #  error "YEAR_BASE < 0"
350 #endif
351 
352 /* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
353    -1, 0, or 1 as the adjustment to add to the year for the ISO week
354    numbering used in "%g%G%V", avoiding overflow.  */
355 static int
iso_year_adjust(const struct tm * tim_p)356 iso_year_adjust (const struct tm *tim_p)
357 {
358   /* Account for fact that tm_year==0 is year 1900.  */
359   int leap = isleap (tim_p->tm_year + (YEAR_BASE
360 				       - (tim_p->tm_year < 0 ? 0 : 2000)));
361 
362   /* Pack the yday, wday, and leap year into a single int since there are so
363      many disparate cases.  */
364 #define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
365   switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
366     {
367     case PACK (0, 5, 0): /* Jan 1 is Fri, not leap.  */
368     case PACK (0, 6, 0): /* Jan 1 is Sat, not leap.  */
369     case PACK (0, 0, 0): /* Jan 1 is Sun, not leap.  */
370     case PACK (0, 5, 1): /* Jan 1 is Fri, leap year.  */
371     case PACK (0, 6, 1): /* Jan 1 is Sat, leap year.  */
372     case PACK (0, 0, 1): /* Jan 1 is Sun, leap year.  */
373     case PACK (1, 6, 0): /* Jan 2 is Sat, not leap.  */
374     case PACK (1, 0, 0): /* Jan 2 is Sun, not leap.  */
375     case PACK (1, 6, 1): /* Jan 2 is Sat, leap year.  */
376     case PACK (1, 0, 1): /* Jan 2 is Sun, leap year.  */
377     case PACK (2, 0, 0): /* Jan 3 is Sun, not leap.  */
378     case PACK (2, 0, 1): /* Jan 3 is Sun, leap year.  */
379       return -1; /* Belongs to last week of previous year.  */
380     case PACK (362, 1, 0): /* Dec 29 is Mon, not leap.  */
381     case PACK (363, 1, 1): /* Dec 29 is Mon, leap year.  */
382     case PACK (363, 1, 0): /* Dec 30 is Mon, not leap.  */
383     case PACK (363, 2, 0): /* Dec 30 is Tue, not leap.  */
384     case PACK (364, 1, 1): /* Dec 30 is Mon, leap year.  */
385     case PACK (364, 2, 1): /* Dec 30 is Tue, leap year.  */
386     case PACK (364, 1, 0): /* Dec 31 is Mon, not leap.  */
387     case PACK (364, 2, 0): /* Dec 31 is Tue, not leap.  */
388     case PACK (364, 3, 0): /* Dec 31 is Wed, not leap.  */
389     case PACK (365, 1, 1): /* Dec 31 is Mon, leap year.  */
390     case PACK (365, 2, 1): /* Dec 31 is Tue, leap year.  */
391     case PACK (365, 3, 1): /* Dec 31 is Wed, leap year.  */
392       return 1; /* Belongs to first week of next year.  */
393     }
394   return 0; /* Belongs to specified year.  */
395 #undef PACK
396 }
397 
398 #ifdef _WANT_C99_TIME_FORMATS
399 typedef struct {
400   int   year;
401   CHAR *era_C;
402   CHAR *era_Y;
403 } era_info_t;
404 
405 static era_info_t *
406 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
get_era_info(const struct tm * tim_p,const wchar_t * era)407 get_era_info (const struct tm *tim_p, const wchar_t *era)
408 #else
409 get_era_info (const struct tm *tim_p, const char *era)
410 #endif
411 {
412 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
413   wchar_t *c;
414   const wchar_t *dir;
415 # define ERA_STRCHR(a,b)	wcschr((a),(b))
416 # define ERA_STRNCPY(a,b,c)	wcsncpy((a),(b),(c))
417 # define ERA_STRTOL(a,b,c)	wcstol((a),(b),(c))
418 #else
419   char *c;
420   const char *dir;
421 # define ERA_STRCHR(a,b)	strchr((a),(b))
422 # define ERA_STRNCPY(a,b,c)	strncpy((a),(b),(c))
423 # define ERA_STRTOL(a,b,c)	strtol((a),(b),(c))
424 #endif
425   long offset;
426   struct tm stm, etm;
427   era_info_t *ei;
428 
429   ei = (era_info_t *) calloc (1, sizeof (era_info_t));
430   if (!ei)
431     return NULL;
432 
433   stm.tm_isdst = etm.tm_isdst = 0;
434   while (era)
435     {
436       dir = era;
437       era += 2;
438       offset = ERA_STRTOL (era, &c, 10);
439       era = c + 1;
440       stm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
441       /* Adjust offset for negative gregorian dates. */
442       if (stm.tm_year <= -YEAR_BASE)
443       	++stm.tm_year;
444       stm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
445       stm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
446       stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
447       era = c + 1;
448       if (era[0] == '-' && era[1] == '*')
449       	{
450 	  etm = stm;
451 	  stm.tm_year = INT_MIN;
452 	  stm.tm_mon = stm.tm_mday = stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
453 	  era += 3;
454 	}
455       else if (era[0] == '+' && era[1] == '*')
456 	{
457 	  etm.tm_year = INT_MAX;
458 	  etm.tm_mon = 11;
459 	  etm.tm_mday = 31;
460 	  etm.tm_hour = 23;
461 	  etm.tm_min = etm.tm_sec = 59;
462 	  era += 3;
463 	}
464       else
465       	{
466 	  etm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
467 	  /* Adjust offset for negative gregorian dates. */
468 	  if (etm.tm_year <= -YEAR_BASE)
469 	    ++etm.tm_year;
470 	  etm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
471 	  etm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
472 	  etm.tm_mday = 31;
473 	  etm.tm_hour = 23;
474 	  etm.tm_min = etm.tm_sec = 59;
475 	  era = c + 1;
476 	}
477       if ((tim_p->tm_year > stm.tm_year
478 	   || (tim_p->tm_year == stm.tm_year
479 	       && (tim_p->tm_mon > stm.tm_mon
480 		   || (tim_p->tm_mon == stm.tm_mon
481 		       && tim_p->tm_mday >= stm.tm_mday))))
482 	  && (tim_p->tm_year < etm.tm_year
483 	      || (tim_p->tm_year == etm.tm_year
484 		  && (tim_p->tm_mon < etm.tm_mon
485 		      || (tim_p->tm_mon == etm.tm_mon
486 			  && tim_p->tm_mday <= etm.tm_mday)))))
487 	{
488 	  /* Gotcha */
489 	  size_t len;
490 
491 	  /* year */
492 	  if (*dir == '+' && stm.tm_year != INT_MIN)
493 	    ei->year = tim_p->tm_year - stm.tm_year + offset;
494 	  else
495 	    ei->year = etm.tm_year - tim_p->tm_year + offset;
496 	  /* era_C */
497 	  c = ERA_STRCHR (era, ':');
498 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
499 	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
500 	  if (len == (size_t) -1)
501 	    {
502 	      free (ei);
503 	      return NULL;
504 	    }
505 #else
506 	  len = c - era;
507 #endif
508 	  ei->era_C = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
509 	  if (!ei->era_C)
510 	    {
511 	      free (ei);
512 	      return NULL;
513 	    }
514 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
515 	  len = mbsnrtowcs (ei->era_C, &era, c - era, len + 1, NULL);
516 #else
517 	  ERA_STRNCPY (ei->era_C, era, len);
518 	  era += len;
519 #endif
520 	  ei->era_C[len] = CQ('\0');
521 	  /* era_Y */
522 	  ++era;
523 	  c = ERA_STRCHR (era, ';');
524 	  if (!c)
525 	    c = ERA_STRCHR (era, '\0');
526 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
527 	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
528 	  if (len == (size_t) -1)
529 	    {
530 	      free (ei->era_C);
531 	      free (ei);
532 	      return NULL;
533 	    }
534 #else
535 	  len = c - era;
536 #endif
537 	  ei->era_Y = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
538 	  if (!ei->era_Y)
539 	    {
540 	      free (ei->era_C);
541 	      free (ei);
542 	      return NULL;
543 	    }
544 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
545 	  len = mbsnrtowcs (ei->era_Y, &era, c - era, len + 1, NULL);
546 #else
547 	  ERA_STRNCPY (ei->era_Y, era, len);
548 	  era += len;
549 #endif
550 	  ei->era_Y[len] = CQ('\0');
551 	  return ei;
552 	}
553       else
554 	era = ERA_STRCHR (era, ';');
555       if (era)
556 	++era;
557     }
558   return NULL;
559 }
560 
561 static void
free_era_info(era_info_t * ei)562 free_era_info (era_info_t *ei)
563 {
564   free (ei->era_C);
565   free (ei->era_Y);
566   free (ei);
567 }
568 
569 typedef struct {
570   size_t num;
571   CHAR **digit;
572   CHAR *buffer;
573 } alt_digits_t;
574 
575 static alt_digits_t *
576 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
get_alt_digits(const wchar_t * alt_digits)577 get_alt_digits (const wchar_t *alt_digits)
578 #else
579 get_alt_digits (const char *alt_digits)
580 #endif
581 {
582   alt_digits_t *adi;
583 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
584   const wchar_t *a, *e;
585 # define ALT_STRCHR(a,b)	wcschr((a),(b))
586 # define ALT_STRCPY(a,b)	wcscpy((a),(b))
587 # define ALT_STRLEN(a)		wcslen(a)
588 #else
589   const char *a, *e;
590 # define ALT_STRCHR(a,b)	strchr((a),(b))
591 # define ALT_STRCPY(a,b)	strcpy((a),(b))
592 # define ALT_STRLEN(a)		strlen(a)
593 #endif
594   CHAR *aa, *ae;
595   size_t len;
596 
597   adi = (alt_digits_t *) calloc (1, sizeof (alt_digits_t));
598   if (!adi)
599     return NULL;
600 
601   /* Compute number of alt_digits. */
602   adi->num = 1;
603   for (a = alt_digits; (e = ALT_STRCHR (a, ';')) != NULL; a = e + 1)
604       ++adi->num;
605   /* Allocate the `digit' array, which is an array of `num' pointers into
606      `buffer'. */
607   adi->digit = (CHAR **) calloc (adi->num, sizeof (CHAR *));
608   if (!adi->digit)
609     {
610       free (adi);
611       return NULL;
612     }
613   /* Compute memory required for `buffer'. */
614 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
615   len = mbstowcs (NULL, alt_digits, 0);
616   if (len == (size_t) -1)
617     {
618       free (adi->digit);
619       free (adi);
620       return NULL;
621     }
622 #else
623   len = ALT_STRLEN (alt_digits);
624 #endif
625   /* Allocate it. */
626   adi->buffer = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
627   if (!adi->buffer)
628     {
629       free (adi->digit);
630       free (adi);
631       return NULL;
632     }
633   /* Store digits in it. */
634 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
635   mbstowcs (adi->buffer, alt_digits, len + 1);
636 #else
637   ALT_STRCPY (adi->buffer, alt_digits);
638 #endif
639   /* Store the pointers into `buffer' into the appropriate `digit' slot. */
640   for (len = 0, aa = adi->buffer; (ae = STRCHR (aa, CQ(';'))) != NULL;
641        ++len, aa = ae + 1)
642     {
643       *ae = '\0';
644       adi->digit[len] = aa;
645     }
646   adi->digit[len] = aa;
647   return adi;
648 }
649 
650 static void
free_alt_digits(alt_digits_t * adi)651 free_alt_digits (alt_digits_t *adi)
652 {
653   free (adi->digit);
654   free (adi->buffer);
655   free (adi);
656 }
657 
658 /* Return 0 if no alt_digit is available for a number.
659    Return -1 if buffer size isn't sufficient to hold alternative digit.
660    Return length of new digit otherwise. */
661 static int
conv_to_alt_digits(CHAR * buf,size_t bufsiz,unsigned num,alt_digits_t * adi)662 conv_to_alt_digits (CHAR *buf, size_t bufsiz, unsigned num, alt_digits_t *adi)
663 {
664   if (num < adi->num)
665     {
666       size_t len = STRLEN (adi->digit[num]);
667       if (bufsiz < len)
668       	return -1;
669       STRCPY (buf, adi->digit[num]);
670       return (int) len;
671     }
672   return 0;
673 }
674 
675 static size_t
__strftime(CHAR * s,size_t maxsize,const CHAR * format,const struct tm * tim_p,struct __locale_t * locale,era_info_t ** era_info,alt_digits_t ** alt_digits)676 __strftime (CHAR *s, size_t maxsize, const CHAR *format,
677 	    const struct tm *tim_p, struct __locale_t *locale,
678 	    era_info_t **era_info, alt_digits_t **alt_digits)
679 #else /* !_WANT_C99_TIME_FORMATS */
680 static size_t
681 __strftime (CHAR *s, size_t maxsize, const CHAR *format,
682 	    const struct tm *tim_p, struct __locale_t *locale)
683 
684 #define __strftime(s,m,f,t,l,e,a)	__strftime((s),(m),(f),(t),(l))
685 #endif /* !_WANT_C99_TIME_FORMATS */
686 {
687   size_t count = 0;
688   int len = 0;
689   const CHAR *ctloc;
690 #if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
691   CHAR ctlocbuf[CTLOCBUFLEN];
692 #endif
693   size_t i, ctloclen;
694   CHAR alt;
695   CHAR pad;
696   unsigned long width;
697   int tzset_called = 0;
698 
699   const struct lc_time_T *_CurrentTimeLocale = __get_time_locale (locale);
700   for (;;)
701     {
702       while (*format && *format != CQ('%'))
703 	{
704 	  if (count < maxsize - 1)
705 	    s[count++] = *format++;
706 	  else
707 	    return 0;
708 	}
709       if (*format == CQ('\0'))
710 	break;
711       format++;
712       pad = '\0';
713       width = 0;
714 
715       /* POSIX-1.2008 feature: '0' and '+' modifiers require 0-padding with
716          slightly different semantics. */
717       if (*format == CQ('0') || *format == CQ('+'))
718 	pad = *format++;
719 
720       /* POSIX-1.2008 feature: A minimum field width can be specified. */
721       if (*format >= CQ('1') && *format <= CQ('9'))
722       	{
723 	  CHAR *fp;
724 	  width = STRTOUL (format, &fp, 10);
725 	  format = fp;
726 	}
727 
728       alt = CQ('\0');
729       if (*format == CQ('E'))
730 	{
731 	  alt = *format++;
732 #ifdef _WANT_C99_TIME_FORMATS
733 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
734 	  if (!*era_info && *_CurrentTimeLocale->wera)
735 	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->wera);
736 #else
737 	  if (!*era_info && *_CurrentTimeLocale->era)
738 	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->era);
739 #endif
740 #endif /* _WANT_C99_TIME_FORMATS */
741 	}
742       else if (*format == CQ('O'))
743 	{
744 	  alt = *format++;
745 #ifdef _WANT_C99_TIME_FORMATS
746 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
747 	  if (!*alt_digits && *_CurrentTimeLocale->walt_digits)
748 	    *alt_digits = get_alt_digits (_CurrentTimeLocale->walt_digits);
749 #else
750 	  if (!*alt_digits && *_CurrentTimeLocale->alt_digits)
751 	    *alt_digits = get_alt_digits (_CurrentTimeLocale->alt_digits);
752 #endif
753 #endif /* _WANT_C99_TIME_FORMATS */
754 	}
755 
756       switch (*format)
757 	{
758 	case CQ('a'):
759 	  _ctloc (wday[tim_p->tm_wday]);
760 	  for (i = 0; i < ctloclen; i++)
761 	    {
762 	      if (count < maxsize - 1)
763 		s[count++] = ctloc[i];
764 	      else
765 		return 0;
766 	    }
767 	  break;
768 	case CQ('A'):
769 	  _ctloc (weekday[tim_p->tm_wday]);
770 	  for (i = 0; i < ctloclen; i++)
771 	    {
772 	      if (count < maxsize - 1)
773 		s[count++] = ctloc[i];
774 	      else
775 		return 0;
776 	    }
777 	  break;
778 	case CQ('b'):
779 	case CQ('h'):
780 	  _ctloc (mon[tim_p->tm_mon]);
781 	  for (i = 0; i < ctloclen; i++)
782 	    {
783 	      if (count < maxsize - 1)
784 		s[count++] = ctloc[i];
785 	      else
786 		return 0;
787 	    }
788 	  break;
789 	case CQ('B'):
790 	  _ctloc (month[tim_p->tm_mon]);
791 	  for (i = 0; i < ctloclen; i++)
792 	    {
793 	      if (count < maxsize - 1)
794 		s[count++] = ctloc[i];
795 	      else
796 		return 0;
797 	    }
798 	  break;
799 	case CQ('c'):
800 #ifdef _WANT_C99_TIME_FORMATS
801 	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_t_fmt)
802 	    _ctloc (era_d_t_fmt);
803 	  else
804 #endif /* _WANT_C99_TIME_FORMATS */
805 	    _ctloc (c_fmt);
806 	  goto recurse;
807 	case CQ('r'):
808 	  _ctloc (ampm_fmt);
809 	  goto recurse;
810 	case CQ('x'):
811 #ifdef _WANT_C99_TIME_FORMATS
812 	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_fmt)
813 	    _ctloc (era_d_fmt);
814 	  else
815 #endif /* _WANT_C99_TIME_FORMATS */
816 	    _ctloc (x_fmt);
817 	  goto recurse;
818 	case CQ('X'):
819 #ifdef _WANT_C99_TIME_FORMATS
820 	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_t_fmt)
821 	    _ctloc (era_t_fmt);
822 	  else
823 #endif /* _WANT_C99_TIME_FORMATS */
824 	    _ctloc (X_fmt);
825 recurse:
826 	  if (*ctloc)
827 	    {
828 	      /* Recurse to avoid need to replicate %Y formation. */
829 	      len = __strftime (&s[count], maxsize - count, ctloc, tim_p,
830 				locale, era_info, alt_digits);
831 	      if (len > 0)
832 		count += len;
833 	      else
834 		return 0;
835 	    }
836 	  break;
837 	case CQ('C'):
838 	  {
839 	    /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
840 	       with 32-bit int.
841 	       %Y		%C		%y
842 	       2147485547	21474855	47
843 	       10000		100		00
844 	       9999		99		99
845 	       0999		09		99
846 	       0099		00		99
847 	       0001		00		01
848 	       0000		00		00
849 	       -001		-0		01
850 	       -099		-0		99
851 	       -999		-9		99
852 	       -1000		-10		00
853 	       -10000		-100		00
854 	       -2147481748	-21474817	48
855 
856 	       Be careful of both overflow and sign adjustment due to the
857 	       asymmetric range of years.
858 	    */
859 #ifdef _WANT_C99_TIME_FORMATS
860 	    if (alt == 'E' && *era_info)
861 	      len = t_snprintf (&s[count], maxsize - count, CQ("%" SFLG "s"),
862 			      (*era_info)->era_C);
863 	    else
864 #endif /* _WANT_C99_TIME_FORMATS */
865 	      {
866 		CHAR *fmt = CQ("%s%.*d");
867 		char *pos = "";
868 		int neg = tim_p->tm_year < -YEAR_BASE;
869 		int century = tim_p->tm_year >= 0
870 		  ? tim_p->tm_year / 100 + YEAR_BASE / 100
871 		  : abs (tim_p->tm_year + YEAR_BASE) / 100;
872 		if (pad) /* '0' or '+' */
873 		  {
874 		    fmt = CQ("%s%0.*d");
875 		    if (century >= 100 && pad == CQ('+'))
876 		      pos = "+";
877 		  }
878 		if (width < 2)
879 		  width = 2;
880 		len = t_snprintf (&s[count], maxsize - count, fmt,
881 				neg ? "-" : pos, width - neg, century);
882 	      }
883             CHECK_LENGTH ();
884 	  }
885 	  break;
886 	case CQ('d'):
887 	case CQ('e'):
888 #ifdef _WANT_C99_TIME_FORMATS
889 	  if (alt == CQ('O') && *alt_digits)
890 	    {
891 	      if (tim_p->tm_mday < 10)
892 	      	{
893 		  if (*format == CQ('d'))
894 		    {
895 		      if (maxsize - count < 2) return 0;
896 		      len = conv_to_alt_digits (&s[count], maxsize - count,
897 						0, *alt_digits);
898 		      CHECK_LENGTH ();
899 		    }
900 		  if (*format == CQ('e') || len == 0)
901 		    s[count++] = CQ(' ');
902 		}
903 	      len = conv_to_alt_digits (&s[count], maxsize - count,
904 					tim_p->tm_mday, *alt_digits);
905 	      CHECK_LENGTH ();
906 	      if (len > 0)
907 		break;
908 	    }
909 #endif /* _WANT_C99_TIME_FORMATS */
910 	  len = t_snprintf (&s[count], maxsize - count,
911 			  *format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
912 			  tim_p->tm_mday);
913 	  CHECK_LENGTH ();
914 	  break;
915 	case CQ('D'):
916 	  /* %m/%d/%y */
917 	  len = t_snprintf (&s[count], maxsize - count,
918 			  CQ("%.2d/%.2d/%.2d"),
919 			  tim_p->tm_mon + 1, tim_p->tm_mday,
920 			  tim_p->tm_year >= 0 ? tim_p->tm_year % 100
921 			  : abs (tim_p->tm_year + YEAR_BASE) % 100);
922           CHECK_LENGTH ();
923 	  break;
924 	case CQ('F'):
925 	  { /* %F is equivalent to "%+4Y-%m-%d", flags and width can change
926 	       that.  Recurse to avoid need to replicate %Y formation. */
927 	    CHAR fmtbuf[32], *fmt = fmtbuf;
928 
929 	    *fmt++ = CQ('%');
930 	    if (pad) /* '0' or '+' */
931 	      *fmt++ = pad;
932 	    else
933 	      *fmt++ = '+';
934 	    if (!pad)
935 	      width = 10;
936 	    if (width < 6)
937 	      width = 6;
938 	    width -= 6;
939 	    if (width)
940 	      {
941 		len = t_snprintf (fmt, fmtbuf + 32 - fmt, CQ("%lu"), width);
942 		if (len > 0)
943 		  fmt += len;
944 	      }
945 	    STRCPY (fmt, CQ("Y-%m-%d"));
946 	    len = __strftime (&s[count], maxsize - count, fmtbuf, tim_p,
947 			      locale, era_info, alt_digits);
948 	    if (len > 0)
949 	      count += len;
950 	    else
951 	      return 0;
952 	  }
953           break;
954 	case CQ('g'):
955 	  /* Be careful of both overflow and negative years, thanks to
956 		 the asymmetric range of years.  */
957 	  {
958 	    int adjust = iso_year_adjust (tim_p);
959 	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
960 		: abs (tim_p->tm_year + YEAR_BASE) % 100;
961 	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
962 		adjust = 1;
963 	    else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
964 		adjust = -1;
965 	    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
966 			    ((year + adjust) % 100 + 100) % 100);
967             CHECK_LENGTH ();
968 	  }
969           break;
970 	case CQ('G'):
971 	  {
972 	    /* See the comments for 'C' and 'Y'; this is a variable length
973 	       field.  Although there is no requirement for a minimum number
974 	       of digits, we use 4 for consistency with 'Y'.  */
975 	    int sign = tim_p->tm_year < -YEAR_BASE;
976 	    int adjust = iso_year_adjust (tim_p);
977 	    int century = tim_p->tm_year >= 0
978 	      ? tim_p->tm_year / 100 + YEAR_BASE / 100
979 	      : abs (tim_p->tm_year + YEAR_BASE) / 100;
980 	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
981 	      : abs (tim_p->tm_year + YEAR_BASE) % 100;
982 	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
983 	      sign = adjust = 1;
984 	    else if (adjust > 0 && sign)
985 	      adjust = -1;
986 	    year += adjust;
987 	    if (year == -1)
988 	      {
989 		year = 99;
990 		--century;
991 	      }
992 	    else if (year == 100)
993 	      {
994 		year = 0;
995 		++century;
996 	      }
997 	    CHAR fmtbuf[10], *fmt = fmtbuf;
998 	    /* int potentially overflows, so use unsigned instead.  */
999 	    unsigned p_year = century * 100 + year;
1000 	    if (sign)
1001 	      *fmt++ = CQ('-');
1002 	    else if (pad == CQ('+') && p_year >= 10000)
1003 	      {
1004 		*fmt++ = CQ('+');
1005 		sign = 1;
1006 	      }
1007 	    if (width && sign)
1008 	      --width;
1009 	    *fmt++ = CQ('%');
1010 	    if (pad)
1011 	      *fmt++ = CQ('0');
1012 	    STRCPY (fmt, CQ(".*u"));
1013 	    len = t_snprintf (&s[count], maxsize - count, fmtbuf, width, p_year);
1014             if (len < 0  ||  (count+=len) >= maxsize)
1015               return 0;
1016 	  }
1017           break;
1018 	case CQ('H'):
1019 #ifdef _WANT_C99_TIME_FORMATS
1020 	  if (alt == CQ('O') && *alt_digits)
1021 	    {
1022 	      len = conv_to_alt_digits (&s[count], maxsize - count,
1023 					tim_p->tm_hour, *alt_digits);
1024 	      CHECK_LENGTH ();
1025 	      if (len > 0)
1026 		break;
1027 	    }
1028 #endif /* _WANT_C99_TIME_FORMATS */
1029 	  __PICOLIBC_FALLTHROUGH;
1030 	case CQ('k'):	/* newlib extension */
1031 	  len = t_snprintf (&s[count], maxsize - count,
1032 			  *format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
1033 			  tim_p->tm_hour);
1034           CHECK_LENGTH ();
1035 	  break;
1036 	case CQ('l'):	/* newlib extension */
1037 	  if (alt == CQ('O'))
1038 	    alt = CQ('\0');
1039 	  __PICOLIBC_FALLTHROUGH;
1040 	case CQ('I'):
1041 	  {
1042 	    register int  h12;
1043 	    h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
1044 						12  :  tim_p->tm_hour % 12;
1045 #ifdef _WANT_C99_TIME_FORMATS
1046 	    if (alt != CQ('O') || !*alt_digits
1047 		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1048 					       h12, *alt_digits)))
1049 #endif /* _WANT_C99_TIME_FORMATS */
1050 	      len = t_snprintf (&s[count], maxsize - count,
1051 			      *format == CQ('I') ? CQ("%.2d") : CQ("%2d"), h12);
1052 	    CHECK_LENGTH ();
1053 	  }
1054 	  break;
1055 	case CQ('j'):
1056 	  len = t_snprintf (&s[count], maxsize - count, CQ("%.3d"),
1057 			  tim_p->tm_yday + 1);
1058           CHECK_LENGTH ();
1059 	  break;
1060 	case CQ('m'):
1061 #ifdef _WANT_C99_TIME_FORMATS
1062 	  if (alt != CQ('O') || !*alt_digits
1063 	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1064 					     tim_p->tm_mon + 1, *alt_digits)))
1065 #endif /* _WANT_C99_TIME_FORMATS */
1066 	    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
1067 			    tim_p->tm_mon + 1);
1068           CHECK_LENGTH ();
1069 	  break;
1070 	case CQ('M'):
1071 #ifdef _WANT_C99_TIME_FORMATS
1072 	  if (alt != CQ('O') || !*alt_digits
1073 	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1074 					     tim_p->tm_min, *alt_digits)))
1075 #endif /* _WANT_C99_TIME_FORMATS */
1076 	    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
1077 			    tim_p->tm_min);
1078           CHECK_LENGTH ();
1079 	  break;
1080 	case CQ('n'):
1081 	  if (count < maxsize - 1)
1082 	    s[count++] = CQ('\n');
1083 	  else
1084 	    return 0;
1085 	  break;
1086 	case CQ('p'):
1087 	case CQ('P'):
1088 	  _ctloc (am_pm[tim_p->tm_hour < 12 ? 0 : 1]);
1089 	  for (i = 0; i < ctloclen; i++)
1090 	    {
1091 	      if (count < maxsize - 1)
1092                 s[count++] = (*format == CQ('P') ? (CHAR) TOLOWER (ctloc[i])
1093 						 : ctloc[i]);
1094 	      else
1095 		return 0;
1096 	    }
1097 	  break;
1098 	case CQ('q'):	/* GNU quarter year */
1099 	  len = t_snprintf (&s[count], maxsize - count, CQ("%.1d"),
1100 			  tim_p->tm_mon / 3 + 1);
1101 	  CHECK_LENGTH ();
1102 	  break;
1103 	case CQ('R'):
1104           len = t_snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
1105 			  tim_p->tm_hour, tim_p->tm_min);
1106           CHECK_LENGTH ();
1107           break;
1108 	case CQ('s'):
1109 /*
1110  * From:
1111  * The Open Group Base Specifications Issue 7
1112  * IEEE Std 1003.1, 2013 Edition
1113  * Copyright (c) 2001-2013 The IEEE and The Open Group
1114  * XBD Base Definitions
1115  * 4. General Concepts
1116  * 4.15 Seconds Since the Epoch
1117  * A value that approximates the number of seconds that have elapsed since the
1118  * Epoch. A Coordinated Universal Time name (specified in terms of seconds
1119  * (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year
1120  * (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time
1121  * represented as seconds since the Epoch, according to the expression below.
1122  * If the year is <1970 or the value is negative, the relationship is undefined.
1123  * If the year is >=1970 and the value is non-negative, the value is related to a
1124  * Coordinated Universal Time name according to the C-language expression, where
1125  * tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all integer types:
1126  * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
1127  *     (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
1128  *     ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
1129  * OR
1130  * ((((tm_year-69)/4 - (tm_year-1)/100 + (tm_year+299)/400 +
1131  *         (tm_year-70)*365 + tm_yday)*24 + tm_hour)*60 + tm_min)*60 + tm_sec
1132  */
1133 /* modified from %z case by hoisting offset outside if block and initializing */
1134 	  {
1135 	    long offset = 0;	/* offset < 0 => W of GMT, > 0 => E of GMT:
1136 				   subtract to get UTC */
1137 
1138 	    if (tim_p->tm_isdst >= 0)
1139 	      {
1140 		TZ_LOCK;
1141 		if (!tzset_called)
1142 		  {
1143 		    _tzset_unlocked ();
1144 		    tzset_called = 1;
1145 		  }
1146 
1147 #if   defined (__TM_GMTOFF)
1148 		offset = tim_p->__TM_GMTOFF;
1149 #else
1150 		__tzinfo_type *tz = __gettzinfo ();
1151 		/* The sign of this is exactly opposite the envvar TZ.  We
1152 		   could directly use the global _timezone for tm_isdst==0,
1153 		   but have to use __tzrule for daylight savings.  */
1154 		offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
1155 #endif
1156 		TZ_UNLOCK;
1157 	      }
1158 	    len = t_snprintf (&s[count], maxsize - count, CQ("%lld"),
1159 			    (((((long long)tim_p->tm_year - 69)/4
1160 				- (tim_p->tm_year - 1)/100
1161 				+ (tim_p->tm_year + 299)/400
1162 				+ (tim_p->tm_year - 70)*365 + tim_p->tm_yday)*24
1163 			      + tim_p->tm_hour)*60 + tim_p->tm_min)*60
1164 			    + tim_p->tm_sec - offset);
1165 	    CHECK_LENGTH ();
1166 	  }
1167           break;
1168 	case CQ('S'):
1169 #ifdef _WANT_C99_TIME_FORMATS
1170 	  if (alt != CQ('O') || !*alt_digits
1171 	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1172 					     tim_p->tm_sec, *alt_digits)))
1173 #endif /* _WANT_C99_TIME_FORMATS */
1174 	    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
1175 			    tim_p->tm_sec);
1176           CHECK_LENGTH ();
1177 	  break;
1178 	case CQ('t'):
1179 	  if (count < maxsize - 1)
1180 	    s[count++] = CQ('\t');
1181 	  else
1182 	    return 0;
1183 	  break;
1184 	case CQ('T'):
1185           len = t_snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
1186 			  tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
1187           CHECK_LENGTH ();
1188           break;
1189 	case CQ('u'):
1190 #ifdef _WANT_C99_TIME_FORMATS
1191 	  if (alt == CQ('O') && *alt_digits)
1192 	    {
1193 	      len = conv_to_alt_digits (&s[count], maxsize - count,
1194 					tim_p->tm_wday == 0 ? 7
1195 							    : tim_p->tm_wday,
1196 					*alt_digits);
1197 	      CHECK_LENGTH ();
1198 	      if (len > 0)
1199 		break;
1200 	    }
1201 #endif /* _WANT_C99_TIME_FORMATS */
1202           if (count < maxsize - 1)
1203             {
1204               if (tim_p->tm_wday == 0)
1205                 s[count++] = CQ('7');
1206               else
1207                 s[count++] = CQ('0') + tim_p->tm_wday;
1208             }
1209           else
1210             return 0;
1211           break;
1212 	case CQ('U'):
1213 #ifdef _WANT_C99_TIME_FORMATS
1214 	  if (alt != CQ('O') || !*alt_digits
1215 	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1216 					     (tim_p->tm_yday + 7 -
1217 					      tim_p->tm_wday) / 7,
1218 					     *alt_digits)))
1219 #endif /* _WANT_C99_TIME_FORMATS */
1220 	    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
1221 			 (tim_p->tm_yday + 7 -
1222 			  tim_p->tm_wday) / 7);
1223           CHECK_LENGTH ();
1224 	  break;
1225 	case CQ('V'):
1226 	  {
1227 	    int adjust = iso_year_adjust (tim_p);
1228 	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1229 	    int week = (tim_p->tm_yday + 10 - wday) / 7;
1230 	    if (adjust > 0)
1231 		week = 1;
1232 	    else if (adjust < 0)
1233 		/* Previous year has 53 weeks if current year starts on
1234 		   Fri, and also if current year starts on Sat and
1235 		   previous year was leap year.  */
1236 		week = 52 + (4 >= (wday - tim_p->tm_yday
1237 				   - isleap (tim_p->tm_year
1238 					     + (YEAR_BASE - 1
1239 						- (tim_p->tm_year < 0
1240 						   ? 0 : 2000)))));
1241 #ifdef _WANT_C99_TIME_FORMATS
1242 	    if (alt != CQ('O') || !*alt_digits
1243 		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1244 					       week, *alt_digits)))
1245 #endif /* _WANT_C99_TIME_FORMATS */
1246 	      len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
1247             CHECK_LENGTH ();
1248 	  }
1249           break;
1250 	case CQ('v'):	/* BSD/OSX/Ruby extension VMS/Oracle date format
1251 			   from Arnold Robbins strftime version 3.0 */
1252 	  { /* %v is equivalent to "%e-%b-%Y", flags and width can change year
1253 	       format. Recurse to avoid need to replicate %b and %Y formation. */
1254 	    CHAR fmtbuf[32], *fmt = fmtbuf;
1255 	    STRCPY (fmt, CQ("%e-%b-%"));
1256 	    fmt += STRLEN (fmt);
1257 	    if (pad) /* '0' or '+' */
1258 	      *fmt++ = pad;
1259 	    else
1260 	      *fmt++ = '+';
1261 	    if (!pad)
1262 	      width = 10;
1263 	    if (width < 6)
1264 	      width = 6;
1265 	    width -= 6;
1266 	    if (width)
1267 	      {
1268 		len = t_snprintf (fmt, fmtbuf + 32 - fmt, CQ("%lu"), width);
1269 		if (len > 0)
1270 		  fmt += len;
1271 	      }
1272 	    STRCPY (fmt, CQ("Y"));
1273 	    len = __strftime (&s[count], maxsize - count, fmtbuf, tim_p,
1274 			      locale, era_info, alt_digits);
1275 	    if (len > 0)
1276 	      count += len;
1277 	    else
1278 	      return 0;
1279 	  }
1280 	  break;
1281 	case CQ('w'):
1282 #ifdef _WANT_C99_TIME_FORMATS
1283 	  if (alt == CQ('O') && *alt_digits)
1284 	    {
1285 	      len = conv_to_alt_digits (&s[count], maxsize - count,
1286 					tim_p->tm_wday, *alt_digits);
1287 	      CHECK_LENGTH ();
1288 	      if (len > 0)
1289 		break;
1290 	    }
1291 #endif /* _WANT_C99_TIME_FORMATS */
1292 	  if (count < maxsize - 1)
1293             s[count++] = CQ('0') + tim_p->tm_wday;
1294 	  else
1295 	    return 0;
1296 	  break;
1297 	case CQ('W'):
1298 	  {
1299 	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1300 	    wday = (tim_p->tm_yday + 7 - wday) / 7;
1301 #ifdef _WANT_C99_TIME_FORMATS
1302 	    if (alt != CQ('O') || !*alt_digits
1303 		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1304 					       wday, *alt_digits)))
1305 #endif /* _WANT_C99_TIME_FORMATS */
1306 	      len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"), wday);
1307             CHECK_LENGTH ();
1308 	  }
1309 	  break;
1310 	case CQ('y'):
1311 	    {
1312 #ifdef _WANT_C99_TIME_FORMATS
1313 	      if (alt == 'E' && *era_info)
1314 		len = t_snprintf (&s[count], maxsize - count, CQ("%d"),
1315 				(*era_info)->year);
1316 	      else
1317 #endif /* _WANT_C99_TIME_FORMATS */
1318 		{
1319 		  /* Be careful of both overflow and negative years, thanks to
1320 		     the asymmetric range of years.  */
1321 		  int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1322 			     : abs (tim_p->tm_year + YEAR_BASE) % 100;
1323 #ifdef _WANT_C99_TIME_FORMATS
1324 		  if (alt != CQ('O') || !*alt_digits
1325 		      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1326 						     year, *alt_digits)))
1327 #endif /* _WANT_C99_TIME_FORMATS */
1328 		    len = t_snprintf (&s[count], maxsize - count, CQ("%.2d"),
1329 				    year);
1330 		}
1331               CHECK_LENGTH ();
1332 	    }
1333 	  break;
1334 	case CQ('Y'):
1335 #ifdef _WANT_C99_TIME_FORMATS
1336 	  if (alt == 'E' && *era_info)
1337 	    {
1338 	      ctloc = (*era_info)->era_Y;
1339 	      goto recurse;
1340 	    }
1341 	  else
1342 #endif /* _WANT_C99_TIME_FORMATS */
1343 	    {
1344 	      CHAR fmtbuf[10], *fmt = fmtbuf;
1345 	      int sign = tim_p->tm_year < -YEAR_BASE;
1346 	      /* int potentially overflows, so use unsigned instead.  */
1347 	      register unsigned year = (unsigned) tim_p->tm_year
1348 				       + (unsigned) YEAR_BASE;
1349 	      if (sign)
1350 		{
1351 		  *fmt++ = CQ('-');
1352 		  year = UINT_MAX - year + 1;
1353 		}
1354 	      else if (pad == CQ('+') && year >= 10000)
1355 		{
1356 		  *fmt++ = CQ('+');
1357 		  sign = 1;
1358 		}
1359 	      if (width && sign)
1360 		--width;
1361 	      *fmt++ = CQ('%');
1362 	      if (pad)
1363 		*fmt++ = CQ('0');
1364 	      STRCPY (fmt, CQ(".*u"));
1365 	      len = t_snprintf (&s[count], maxsize - count, fmtbuf, width,
1366 			      year);
1367 	      CHECK_LENGTH ();
1368 	    }
1369 	  break;
1370 	case CQ('z'):
1371           if (tim_p->tm_isdst >= 0)
1372             {
1373 	      long offset;
1374 
1375 	      TZ_LOCK;
1376 	      if (!tzset_called)
1377 		{
1378 		  _tzset_unlocked ();
1379 		  tzset_called = 1;
1380 		}
1381 
1382 #if   defined (__TM_GMTOFF)
1383 	      offset = tim_p->__TM_GMTOFF;
1384 #else
1385 	      __tzinfo_type *tz = __gettzinfo ();
1386 	      /* The sign of this is exactly opposite the envvar TZ.  We
1387 		 could directly use the global _timezone for tm_isdst==0,
1388 		 but have to use __tzrule for daylight savings.  */
1389 	      offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
1390 #endif
1391 	      TZ_UNLOCK;
1392 	      len = t_snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
1393 			      offset / SECSPERHOUR,
1394 			      labs (offset / SECSPERMIN) % 60L);
1395               CHECK_LENGTH ();
1396             }
1397           break;
1398 	case CQ('Z'):
1399 	  if (tim_p->tm_isdst >= 0)
1400 	    {
1401 	      size_t size;
1402 	      const char *tznam = NULL;
1403 
1404 	      TZ_LOCK;
1405 	      if (!tzset_called)
1406 		{
1407 		  _tzset_unlocked ();
1408 		  tzset_called = 1;
1409 		}
1410 #if   defined (__TM_ZONE)
1411 	      tznam = tim_p->__TM_ZONE;
1412 #endif
1413 	      if (!tznam)
1414 		tznam = tzname[tim_p->tm_isdst > 0];
1415 	      /* Note that in case of wcsftime this loop only works for
1416 	         timezone abbreviations using the portable codeset (aka ASCII).
1417 		 This seems to be the case, but if that ever changes, this
1418 		 loop needs revisiting. */
1419 	      size = strlen (tznam);
1420 	      for (i = 0; i < size; i++)
1421 		{
1422 		  if (count < maxsize - 1)
1423 		    s[count++] = tznam[i];
1424 		  else
1425 		    {
1426 		      TZ_UNLOCK;
1427 		      return 0;
1428 		    }
1429 		}
1430 	      TZ_UNLOCK;
1431 	    }
1432 	  break;
1433 	case CQ('%'):
1434 	  if (count < maxsize - 1)
1435 	    s[count++] = CQ('%');
1436 	  else
1437 	    return 0;
1438 	  break;
1439 	default:
1440 	  return 0;
1441 	}
1442       if (*format)
1443 	format++;
1444       else
1445 	break;
1446     }
1447   if (maxsize)
1448     s[count] = CQ('\0');
1449 
1450   return count;
1451 }
1452 
1453 size_t
strftime(CHAR * __restrict s,size_t maxsize,const CHAR * __restrict format,const struct tm * __restrict tim_p)1454 strftime (CHAR *__restrict s,
1455 	size_t maxsize,
1456 	const CHAR *__restrict format,
1457 	const struct tm *__restrict tim_p)
1458 {
1459 #ifdef _WANT_C99_TIME_FORMATS
1460   era_info_t *era_info = NULL;
1461   alt_digits_t *alt_digits = NULL;
1462   size_t ret = __strftime (s, maxsize, format, tim_p, __get_current_locale (),
1463 			   &era_info, &alt_digits);
1464   if (era_info)
1465     free_era_info (era_info);
1466   if (alt_digits)
1467     free_alt_digits (alt_digits);
1468   return ret;
1469 #else /* !_WANT_C99_TIME_FORMATS */
1470   return __strftime (s, maxsize, format, tim_p, __get_current_locale (),
1471 		     NULL, NULL);
1472 #endif /* !_WANT_C99_TIME_FORMATS */
1473 }
1474 
1475 size_t
strftime_l(CHAR * __restrict s,size_t maxsize,const CHAR * __restrict format,const struct tm * __restrict tim_p,struct __locale_t * locale)1476 strftime_l (CHAR *__restrict s, size_t maxsize, const CHAR *__restrict format,
1477 	    const struct tm *__restrict tim_p, struct __locale_t *locale)
1478 {
1479 #ifdef _WANT_C99_TIME_FORMATS
1480   era_info_t *era_info = NULL;
1481   alt_digits_t *alt_digits = NULL;
1482   size_t ret = __strftime (s, maxsize, format, tim_p, locale,
1483 			   &era_info, &alt_digits);
1484   if (era_info)
1485     free_era_info (era_info);
1486   if (alt_digits)
1487     free_alt_digits (alt_digits);
1488   return ret;
1489 #else /* !_WANT_C99_TIME_FORMATS */
1490   return __strftime (s, maxsize, format, tim_p, locale, NULL, NULL);
1491 #endif /* !_WANT_C99_TIME_FORMATS */
1492 }
1493 
1494 /* The remainder of this file can serve as a regression test.  Compile
1495  *  with -D_REGRESSION_TEST.  */
1496 #if defined(_REGRESSION_TEST)	/* [Test code:  */
1497 
1498 /* This test code relies on ANSI C features, in particular on the ability
1499  * of adjacent strings to be pasted together into one string.  */
1500 
1501 /* Test output buffer size (should be larger than all expected results) */
1502 #define OUTSIZE	256
1503 
1504 struct test {
1505 	CHAR  *fmt;	/* Testing format */
1506 	size_t  max;	/* Testing maxsize */
1507 	size_t	ret;	/* Expected return value */
1508 	CHAR  *out;	/* Expected output string */
1509 	};
1510 struct list {
1511 	const struct tm  *tms;	/* Time used for these vectors */
1512 	const struct test *vec;	/* Test vectors */
1513 	int  cnt;		/* Number of vectors */
1514 	};
1515 
1516 const char  TZ[]="TZ=EST5EDT";
1517 
1518 /* Define list of test inputs and expected outputs, for the given time zone
1519  * and time.  */
1520 const struct tm  tm0 = {
1521 	/* Tue Dec 30 10:53:47 EST 2008 (time_t=1230648827) */
1522 	.tm_sec 	= 47,
1523 	.tm_min 	= 53,
1524 	.tm_hour	= 9,
1525 	.tm_mday	= 30,
1526 	.tm_mon 	= 11,
1527 	.tm_year	= 108,
1528 	.tm_wday	= 2,
1529 	.tm_yday	= 364,
1530 	.tm_isdst	= 0
1531 	};
1532 const struct test  Vec0[] = {
1533 	/* Testing fields one at a time, expecting to pass, using exact
1534 	 * allowed length as what is needed.  */
1535 	/* Using tm0 for time: */
1536 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1537 	{ CQ("%a"), 3+1, EXP(CQ("Tue")) },
1538 	{ CQ("%A"), 7+1, EXP(CQ("Tuesday")) },
1539 	{ CQ("%b"), 3+1, EXP(CQ("Dec")) },
1540 	{ CQ("%B"), 8+1, EXP(CQ("December")) },
1541 	{ CQ("%c"), 24+1, EXP(CQ("Tue Dec 30 09:53:47 2008")) },
1542 	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1543 	{ CQ("%d"), 2+1, EXP(CQ("30")) },
1544 	{ CQ("%D"), 8+1, EXP(CQ("12/30/08")) },
1545 	{ CQ("%e"), 2+1, EXP(CQ("30")) },
1546 	{ CQ("%F"), 10+1, EXP(CQ("2008-12-30")) },
1547 	{ CQ("%g"), 2+1, EXP(CQ("09")) },
1548 	{ CQ("%G"), 4+1, EXP(CQ("2009")) },
1549 	{ CQ("%h"), 3+1, EXP(CQ("Dec")) },
1550 	{ CQ("%H"), 2+1, EXP(CQ("09")) },
1551 	{ CQ("%I"), 2+1, EXP(CQ("09")) },
1552 	{ CQ("%j"), 3+1, EXP(CQ("365")) },
1553 	{ CQ("%k"), 2+1, EXP(CQ(" 9")) },
1554 	{ CQ("%l"), 2+1, EXP(CQ(" 9")) },
1555 	{ CQ("%m"), 2+1, EXP(CQ("12")) },
1556 	{ CQ("%M"), 2+1, EXP(CQ("53")) },
1557 	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1558 	{ CQ("%p"), 2+1, EXP(CQ("AM")) },
1559 	{ CQ("%q"), 1+1, EXP(CQ("4")) },
1560 	{ CQ("%r"), 11+1, EXP(CQ("09:53:47 AM")) },
1561 	{ CQ("%R"), 5+1, EXP(CQ("09:53")) },
1562 	{ CQ("%s"), 2+1, EXP(CQ("1230648827")) },
1563 	{ CQ("%S"), 2+1, EXP(CQ("47")) },
1564 	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1565 	{ CQ("%T"), 8+1, EXP(CQ("09:53:47")) },
1566 	{ CQ("%u"), 1+1, EXP(CQ("2")) },
1567 	{ CQ("%U"), 2+1, EXP(CQ("52")) },
1568 	{ CQ("%V"), 2+1, EXP(CQ("01")) },
1569 	{ CQ("%v"), 11+1, EXP(CQ("30-Dec-2008")) },
1570 	{ CQ("%w"), 1+1, EXP(CQ("2")) },
1571 	{ CQ("%W"), 2+1, EXP(CQ("52")) },
1572 	{ CQ("%x"), 8+1, EXP(CQ("12/30/08")) },
1573 	{ CQ("%X"), 8+1, EXP(CQ("09:53:47")) },
1574 	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1575 	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1576 	{ CQ("%z"), 5+1, EXP(CQ("-0500")) },
1577 	{ CQ("%Z"), 3+1, EXP(CQ("EST")) },
1578 	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1579 	#undef EXP
1580 	};
1581 /* Define list of test inputs and expected outputs, for the given time zone
1582  * and time.  */
1583 const struct tm  tm1 = {
1584 	/* Wed Jul  2 23:01:13 EDT 2008 (time_t=1215054073) */
1585 	.tm_sec 	= 13,
1586 	.tm_min 	= 1,
1587 	.tm_hour	= 23,
1588 	.tm_mday	= 2,
1589 	.tm_mon 	= 6,
1590 	.tm_year	= 108,
1591 	.tm_wday	= 3,
1592 	.tm_yday	= 183,
1593 	.tm_isdst	= 1
1594 	};
1595 const struct test  Vec1[] = {
1596 	/* Testing fields one at a time, expecting to pass, using exact
1597 	 * allowed length as what is needed.  */
1598 	/* Using tm1 for time: */
1599 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1600 	{ CQ("%a"), 3+1, EXP(CQ("Wed")) },
1601 	{ CQ("%A"), 9+1, EXP(CQ("Wednesday")) },
1602 	{ CQ("%b"), 3+1, EXP(CQ("Jul")) },
1603 	{ CQ("%B"), 4+1, EXP(CQ("July")) },
1604 	{ CQ("%c"), 24+1, EXP(CQ("Wed Jul  2 23:01:13 2008")) },
1605 	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1606 	{ CQ("%d"), 2+1, EXP(CQ("02")) },
1607 	{ CQ("%D"), 8+1, EXP(CQ("07/02/08")) },
1608 	{ CQ("%e"), 2+1, EXP(CQ(" 2")) },
1609 	{ CQ("%F"), 10+1, EXP(CQ("2008-07-02")) },
1610 	{ CQ("%g"), 2+1, EXP(CQ("08")) },
1611 	{ CQ("%G"), 4+1, EXP(CQ("2008")) },
1612 	{ CQ("%h"), 3+1, EXP(CQ("Jul")) },
1613 	{ CQ("%H"), 2+1, EXP(CQ("23")) },
1614 	{ CQ("%I"), 2+1, EXP(CQ("11")) },
1615 	{ CQ("%j"), 3+1, EXP(CQ("184")) },
1616 	{ CQ("%k"), 2+1, EXP(CQ("23")) },
1617 	{ CQ("%l"), 2+1, EXP(CQ("11")) },
1618 	{ CQ("%m"), 2+1, EXP(CQ("07")) },
1619 	{ CQ("%M"), 2+1, EXP(CQ("01")) },
1620 	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1621 	{ CQ("%p"), 2+1, EXP(CQ("PM")) },
1622 	{ CQ("%q"), 1+1, EXP(CQ("3")) },
1623 	{ CQ("%r"), 11+1, EXP(CQ("11:01:13 PM")) },
1624 	{ CQ("%R"), 5+1, EXP(CQ("23:01")) },
1625 	{ CQ("%s"), 2+1, EXP(CQ("1215054073")) },
1626 	{ CQ("%S"), 2+1, EXP(CQ("13")) },
1627 	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1628 	{ CQ("%T"), 8+1, EXP(CQ("23:01:13")) },
1629 	{ CQ("%u"), 1+1, EXP(CQ("3")) },
1630 	{ CQ("%U"), 2+1, EXP(CQ("26")) },
1631 	{ CQ("%V"), 2+1, EXP(CQ("27")) },
1632 	{ CQ("%v"), 11+1, EXP(CQ(" 2-Jul-2008")) },
1633 	{ CQ("%w"), 1+1, EXP(CQ("3")) },
1634 	{ CQ("%W"), 2+1, EXP(CQ("26")) },
1635 	{ CQ("%x"), 8+1, EXP(CQ("07/02/08")) },
1636 	{ CQ("%X"), 8+1, EXP(CQ("23:01:13")) },
1637 	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1638 	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1639 	{ CQ("%z"), 5+1, EXP(CQ("-0400")) },
1640 	{ CQ("%Z"), 3+1, EXP(CQ("EDT")) },
1641 	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1642 	#undef EXP
1643 	#define VEC(s)	s, sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1644 	#define EXP(s)	sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1645 	{ VEC(CQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) },
1646 	{ CQ("0123456789%%%h:`~"), EXP(CQ("0123456789%Jul:`~")) },
1647 	{ CQ("%R%h:`~ %x %w"), EXP(CQ("23:01Jul:`~ 07/02/08 3")) },
1648 	#undef VEC
1649 	#undef EXP
1650 	};
1651 
1652 #if YEAR_BASE == 1900  /* ( */
1653 /* Checks for very large years.  YEAR_BASE value relied upon so that the
1654  * answer strings can be predetermined.
1655  * Years more than 4 digits are not mentioned in the standard for %C, so the
1656  * test for those cases are based on the design intent (which is to print the
1657  * whole number, being the century).  */
1658 const struct tm  tmyr0 = {
1659 	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1660 	.tm_sec 	= 13,
1661 	.tm_min 	= 1,
1662 	.tm_hour	= 23,
1663 	.tm_mday	= 2,
1664 	.tm_mon 	= 6,
1665 	.tm_year	= INT_MAX - YEAR_BASE/2,
1666 	.tm_wday	= 3,
1667 	.tm_yday	= 183,
1668 	.tm_isdst	= 1
1669 	};
1670 #if INT_MAX == 32767
1671 #  define YEAR	CQ("33717")		/* INT_MAX + YEAR_BASE/2 */
1672 #  define CENT	CQ("337")
1673 #  define Year	   CQ("17")
1674 # elif INT_MAX == 2147483647
1675 #  define YEAR	CQ("2147484597")
1676 #  define CENT	CQ("21474845")
1677 #  define Year	        CQ("97")
1678 # elif INT_MAX == 9223372036854775807
1679 #  define YEAR	CQ("9223372036854776757")
1680 #  define CENT	CQ("92233720368547777")
1681 #  define Year	                 CQ("57")
1682 # else
1683 #  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1684 #endif
1685 const struct test  Vecyr0[] = {
1686 	/* Testing fields one at a time, expecting to pass, using a larger
1687 	 * allowed length than what is needed.  */
1688 	/* Using tmyr0 for time: */
1689 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1690 	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1691 	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1692 	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1693 	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1694 	{ CQ("%v"), OUTSIZE, EXP(CQ(" 2-Jul-")YEAR) },
1695 	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1696 	{ CQ("%y"), OUTSIZE, EXP(Year) },
1697 	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1698 	#undef EXP
1699 	};
1700 #undef YEAR
1701 #undef CENT
1702 #undef Year
1703 /* Checks for very large negative years.  YEAR_BASE value relied upon so that
1704  * the answer strings can be predetermined.  */
1705 const struct tm  tmyr1 = {
1706 	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1707 	.tm_sec 	= 13,
1708 	.tm_min 	= 1,
1709 	.tm_hour	= 23,
1710 	.tm_mday	= 2,
1711 	.tm_mon 	= 6,
1712 	.tm_year	= INT_MIN,
1713 	.tm_wday	= 3,
1714 	.tm_yday	= 183,
1715 	.tm_isdst	= 1
1716 	};
1717 #if INT_MAX == 32767
1718 #  define YEAR	CQ("-30868")		/* INT_MIN + YEAR_BASE */
1719 #  define CENT	CQ("-308")
1720 #  define Year	    CQ("68")
1721 # elif INT_MAX == 2147483647
1722 #  define YEAR	CQ("-2147481748")
1723 #  define CENT	CQ("-21474817")
1724 #  define Year	         CQ("48")
1725 # elif INT_MAX == 9223372036854775807
1726 #  define YEAR	CQ("-9223372036854773908")
1727 #  define CENT	CQ("-92233720368547739")
1728 #  define Year	                  CQ("08")
1729 # else
1730 #  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1731 #endif
1732 const struct test  Vecyr1[] = {
1733 	/* Testing fields one at a time, expecting to pass, using a larger
1734 	 * allowed length than what is needed.  */
1735 	/* Using tmyr1 for time: */
1736 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1737 	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1738 	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1739 	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1740 	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1741 	{ CQ("%v"), OUTSIZE, EXP(CQ(" 2-Jul-")YEAR) },
1742 	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1743 	{ CQ("%y"), OUTSIZE, EXP(Year) },
1744 	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1745 	#undef EXP
1746 	};
1747 #undef YEAR
1748 #undef CENT
1749 #undef Year
1750 #endif /* YEAR_BASE ) */
1751 
1752 /* Checks for years just over zero (also test for s=60).
1753  * Years less than 4 digits are not mentioned for %Y in the standard, so the
1754  * test for that case is based on the design intent.  */
1755 const struct tm  tmyrzp = {
1756 	/* Wed Jul  2 23:01:60 EDT 0007 */
1757 	.tm_sec 	= 60,
1758 	.tm_min 	= 1,
1759 	.tm_hour	= 23,
1760 	.tm_mday	= 2,
1761 	.tm_mon 	= 6,
1762 	.tm_year	= 7-YEAR_BASE,
1763 	.tm_wday	= 3,
1764 	.tm_yday	= 183,
1765 	.tm_isdst	= 1
1766 	};
1767 #define YEAR	CQ("0007")	/* Design intent:  %Y=%C%y */
1768 #define CENT	CQ("00")
1769 #define Year	  CQ("07")
1770 const struct test  Vecyrzp[] = {
1771 	/* Testing fields one at a time, expecting to pass, using a larger
1772 	 * allowed length than what is needed.  */
1773 	/* Using tmyrzp for time: */
1774 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1775 	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1776 	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:60 ")YEAR) },
1777 	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1778 	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1779 	{ CQ("%v"), OUTSIZE, EXP(CQ(" 2-Jul-")YEAR) },
1780 	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1781 	{ CQ("%y"), OUTSIZE, EXP(Year) },
1782 	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1783 	#undef EXP
1784 	};
1785 #undef YEAR
1786 #undef CENT
1787 #undef Year
1788 /* Checks for years just under zero.
1789  * Negative years are not handled by the standard, so the vectors here are
1790  * verifying the chosen implemtation.  */
1791 const struct tm  tmyrzn = {
1792 	/* Wed Jul  2 23:01:00 EDT -004 */
1793 	.tm_sec 	= 00,
1794 	.tm_min 	= 1,
1795 	.tm_hour	= 23,
1796 	.tm_mday	= 2,
1797 	.tm_mon 	= 6,
1798 	.tm_year	= -4-YEAR_BASE,
1799 	.tm_wday	= 3,
1800 	.tm_yday	= 183,
1801 	.tm_isdst	= 1
1802 	};
1803 #define YEAR	CQ("-004")
1804 #define CENT	CQ("-0")
1805 #define Year	  CQ("04")
1806 const struct test  Vecyrzn[] = {
1807 	/* Testing fields one at a time, expecting to pass, using a larger
1808 	 * allowed length than what is needed.  */
1809 	/* Using tmyrzn for time: */
1810 	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1811 	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1812 	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:00 ")YEAR) },
1813 	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1814 	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1815 	{ CQ("%v"), OUTSIZE, EXP(CQ(" 2-Jul-")YEAR) },
1816 	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1817 	{ CQ("%y"), OUTSIZE, EXP(Year) },
1818 	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1819 	#undef EXP
1820 	};
1821 #undef YEAR
1822 #undef CENT
1823 #undef Year
1824 
1825 const struct list  ListYr[] = {
1826 	{ &tmyrzp, Vecyrzp, sizeof(Vecyrzp)/sizeof(Vecyrzp[0]) },
1827 	{ &tmyrzn, Vecyrzn, sizeof(Vecyrzn)/sizeof(Vecyrzn[0]) },
1828 	#if YEAR_BASE == 1900
1829 	{ &tmyr0, Vecyr0, sizeof(Vecyr0)/sizeof(Vecyr0[0]) },
1830 	{ &tmyr1, Vecyr1, sizeof(Vecyr1)/sizeof(Vecyr1[0]) },
1831 	#endif
1832 	};
1833 
1834 
1835 /* List of tests to be run */
1836 const struct list  List[] = {
1837 	{ &tm0, Vec0, sizeof(Vec0)/sizeof(Vec0[0]) },
1838 	{ &tm1, Vec1, sizeof(Vec1)/sizeof(Vec1[0]) },
1839 	};
1840 
1841 int
main(void)1842 main(void)
1843 {
1844 int  i, l, errr=0, erro=0, tot=0;
1845 const char  *cp;
1846 CHAR  out[OUTSIZE];
1847 size_t  ret;
1848 
1849 /* Set timezone so that %z and %Z tests come out right */
1850 cp = TZ;
1851 if((i=putenv(cp)))  {
1852     printf( "putenv(%s) FAILED, ret %d\n", cp, i);
1853     return(-1);
1854     }
1855 if(strcmp(getenv("TZ"),strchr(TZ,'=')+1))  {
1856     printf( "TZ not set properly in environment\n");
1857     return(-2);
1858     }
1859 tzset();
1860 
1861 #if defined(VERBOSE)
1862 printf("_timezone=%d, _daylight=%d, _tzname[0]=%s, _tzname[1]=%s\n", _timezone, _daylight, _tzname[0], _tzname[1]);
1863 {
1864 long offset;
1865 __tzinfo_type *tz = __gettzinfo ();
1866 /* The sign of this is exactly opposite the envvar TZ.  We
1867    could directly use the global _timezone for tm_isdst==0,
1868    but have to use __tzrule for daylight savings.  */
1869 printf("tz->__tzrule[0].offset=%d, tz->__tzrule[1].offset=%d\n", tz->__tzrule[0].offset, tz->__tzrule[1].offset);
1870 }
1871 #endif
1872 
1873 /* Run all of the exact-length tests as-given--results should match */
1874 for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
1875     const struct list  *test = &List[l];
1876     for(i=0; i<test->cnt; i++)  {
1877 	tot++;	/* Keep track of number of tests */
1878 	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1879 	if(ret != test->vec[i].ret)  {
1880 	    errr++;
1881 	    fprintf(stderr,
1882 		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1883 						ret, test->vec[i].ret, l, i);
1884 	    }
1885 	if(t_strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1886 	    erro++;
1887 	    fprintf(stderr,
1888 		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1889 						out, test->vec[i].out, l, i);
1890 	    }
1891 	}
1892     }
1893 
1894 /* Run all of the exact-length tests with the length made too short--expect to
1895  * fail.  */
1896 for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
1897     const struct list  *test = &List[l];
1898     for(i=0; i<test->cnt; i++)  {
1899 	tot++;	/* Keep track of number of tests */
1900 	ret = strftime(out, test->vec[i].max-1, test->vec[i].fmt, test->tms);
1901 	if(ret != 0)  {
1902 	    errr++;
1903 	    fprintf(stderr,
1904 		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1905 						ret, 0, l, i);
1906 	    }
1907 	/* Almost every conversion puts out as many characters as possible, so
1908 	 * go ahead and test the output even though have failed.  (The test
1909 	 * times chosen happen to not hit any of the cases that fail this, so it
1910 	 * works.)  */
1911 	if(t_strncmp(out, test->vec[i].out, test->vec[i].max-1-1))  {
1912 	    erro++;
1913 	    fprintf(stderr,
1914 		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1915 						out, test->vec[i].out, l, i);
1916 	    }
1917 	}
1918     }
1919 
1920 /* Run all of the special year test cases */
1921 for(l=0; l<sizeof(ListYr)/sizeof(ListYr[0]); l++)  {
1922     const struct list  *test = &ListYr[l];
1923     for(i=0; i<test->cnt; i++)  {
1924 	tot++;	/* Keep track of number of tests */
1925 	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1926 	if(ret != test->vec[i].ret)  {
1927 	    errr++;
1928 	    fprintf(stderr,
1929 		"ERROR:  return %d != %d expected for ListYr[%d].vec[%d]\n",
1930 						ret, test->vec[i].ret, l, i);
1931 	    }
1932 	if(t_strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1933 	    erro++;
1934 	    fprintf(stderr,
1935 		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for ListYr[%d].vec[%d]\n",
1936 						out, test->vec[i].out, l, i);
1937 	    }
1938 	}
1939     }
1940 
1941 #define STRIZE(f)	#f
1942 #define NAME(f)	STRIZE(f)
1943 printf(NAME(strftime) "() test ");
1944 if(errr || erro)  printf("FAILED %d/%d of", errr, erro);
1945   else    printf("passed");
1946 printf(" %d test cases.\n", tot);
1947 
1948 return(errr || erro);
1949 }
1950 #endif /* defined(_REGRESSION_TEST) ] */
1951