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