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