comparison lib/strftime.c @ 691:6813ffe12e6a

(strftime): New version, from GNU libc.
author Jim Meyering <jim@meyering.net>
date Tue, 17 Sep 1996 04:13:22 +0000
parents e46401d63db8
children 8867c987f8cf
comparison
equal deleted inserted replaced
690:47656fb2fcfa 691:6813ffe12e6a
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. 1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
2 2 This file is part of the GNU C Library.
3 NOTE: The canonical source of this file is maintained with the GNU C Library. 3
4 Bugs can be reported to bug-glibc@prep.ai.mit.edu. 4 The GNU C Library is free software; you can redistribute it and/or
5 5 modify it under the terms of the GNU Library General Public License as
6 This program is free software; you can redistribute it and/or modify it 6 published by the Free Software Foundation; either version 2 of the
7 under the terms of the GNU General Public License as published by the 7 License, or (at your option) any later version.
8 Free Software Foundation; either version 2, or (at your option) any 8
9 later version. 9 The GNU C Library is distributed in the hope that it will be useful,
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 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 GNU General Public License for more details. 12 Library General Public License for more details.
15 13
16 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU Library General Public
17 along with this program; if not, write to the Free Software 15 License along with the GNU C Library; see the file COPYING.LIB. If
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 USA. */ 17 Cambridge, MA 02139, USA. */
20 18
21 #ifdef HAVE_CONFIG_H 19 #ifdef HAVE_CONFIG_H
22 # include <config.h> 20 # include <config.h>
23 #endif 21 #endif
24 22
25 #ifdef _LIBC 23 #ifdef _LIBC
26 # define HAVE_LIMITS_H 1 24 # define HAVE_LIMITS_H 1
27 # define HAVE_MBLEN 1 25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_TM_GMTOFF 1
28 # define HAVE_TM_ZONE 1 28 # define HAVE_TM_ZONE 1
29 # define MULTIBYTE_IS_FORMAT_SAFE 1
29 # define STDC_HEADERS 1 30 # define STDC_HEADERS 1
30 # include <ansidecl.h> 31 # include <ansidecl.h>
31 # include "../locale/localeinfo.h" 32 # include "../locale/localeinfo.h"
32 #endif 33 #endif
33 34
34 #include <stdio.h>
35 #include <sys/types.h> /* Some systems define `time_t' here. */ 35 #include <sys/types.h> /* Some systems define `time_t' here. */
36 36
37 #ifdef TIME_WITH_SYS_TIME 37 #ifdef TIME_WITH_SYS_TIME
38 # include <sys/time.h> 38 # include <sys/time.h>
39 # include <time.h> 39 # include <time.h>
43 # else 43 # else
44 # include <time.h> 44 # include <time.h>
45 # endif 45 # endif
46 #endif 46 #endif
47 47
48 #if HAVE_MBLEN 48 /* Do multibyte processing if multibytes are supported, unless
49 # include <ctype.h> 49 multibyte sequences are safe in formats. Multibyte sequences are
50 safe if they cannot contain byte sequences that look like format
51 conversion specifications. The GNU C Library uses UTF8 multibyte
52 encoding, which is safe for formats, but strftime.c can be used
53 with other C libraries that use unsafe encodings. */
54 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
55
56 #if DO_MULTIBYTE
57 # if HAVE_MBRLEN
58 # include <wchar.h>
59 # else
60 /* Simulate mbrlen with mblen as best we can. */
61 # define mbstate_t int
62 # define mbrlen(s, n, ps) mblen (s, n)
63 # define mbsinit(ps) (*(ps) == 0)
64 # endif
65 static const mbstate_t mbstate_zero;
50 #endif 66 #endif
51 67
52 #if HAVE_LIMITS_H 68 #if HAVE_LIMITS_H
53 # include <limits.h> 69 # include <limits.h>
54 #endif 70 #endif
75 #else 91 #else
76 #define PTR char * 92 #define PTR char *
77 #endif 93 #endif
78 #endif 94 #endif
79 95
80 /* Uncomment following line in the production version. */ 96 #ifndef CHAR_BIT
81 /* #define NDEBUG */ 97 #define CHAR_BIT 8
82 #include <assert.h> 98 #endif
83 99
84 static unsigned int week __P ((const struct tm *const, int, int)); 100 #define TYPE_SIGNED(t) ((t) -1 < 0)
101
102 /* Bound on length of the string representing an integer value of type t.
103 Subtract one for the sign bit if t is signed;
104 302 / 1000 is log10 (2) rounded up;
105 add one for integer division truncation;
106 add one more for a minus sign if t is signed. */
107 #define INT_STRLEN_BOUND(t) \
108 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
109
110 #define TM_YEAR_BASE 1900
111
112 #ifndef __isleap
113 /* Nonzero if YEAR is a leap year (every 4 years,
114 except every 100th isn't, and every 400th is). */
115 #define __isleap(year) \
116 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
117 #endif
118
119
120 #ifdef _LIBC
121 # define gmtime_r __gmtime_r
122 # define localtime_r __localtime_r
123 #else
124 # if ! HAVE_LOCALTIME_R
125 # if ! HAVE_TM_GMTOFF
126 /* Approximate gmtime_r as best we can in its absence. */
127 #define gmtime_r my_gmtime_r
128 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
129 static struct tm *
130 gmtime_r (t, tp)
131 const time_t *t;
132 struct tm *tp;
133 {
134 struct tm *l = gmtime (t);
135 if (! l)
136 return 0;
137 *tp = *l;
138 return tp;
139 }
140 # endif /* ! HAVE_TM_GMTOFF */
141
142 /* Approximate localtime_r as best we can in its absence. */
143 #define localtime_r my_localtime_r
144 static struct tm *localtime_r __P ((const time_t *, struct tm *));
145 static struct tm *
146 localtime_r (t, tp)
147 const time_t *t;
148 struct tm *tp;
149 {
150 struct tm *l = localtime (t);
151 if (! l)
152 return 0;
153 *tp = *l;
154 return tp;
155 }
156 # endif /* ! HAVE_LOCALTIME_R */
157 #endif /* ! defined (_LIBC) */
85 158
86 159
87 #define add(n, f) \ 160 #define add(n, f) \
88 do \ 161 do \
89 { \ 162 { \
97 p += (n); \ 170 p += (n); \
98 } \ 171 } \
99 } while (0) 172 } while (0)
100 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n))) 173 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
101 174
102 #ifdef _LIBC 175 #if ! HAVE_TM_GMTOFF
103 #define fmt(n, args) add((n), if (sprintf args != (n)) return 0) 176 /* Yield the difference between *A and *B,
104 #else 177 measured in seconds, ignoring leap seconds. */
105 #define fmt(n, args) add((n), sprintf args; if (strlen (p) != (n)) return 0) 178 static int tm_diff __P ((const struct tm *, const struct tm *));
106 #endif 179 static int
107 180 tm_diff (a, b)
108 181 const struct tm *a;
109 182 const struct tm *b;
110 /* Return the week in the year specified by TP, 183 {
111 with weeks starting on STARTING_DAY. */ 184 int ay = a->tm_year + TM_YEAR_BASE - 1;
112 #ifdef __GNUC__ 185 int by = b->tm_year + TM_YEAR_BASE - 1;
186 /* Divide years by 100, rounding towards minus infinity. */
187 int ac = ay / 100 - (ay % 100 < 0);
188 int bc = by / 100 - (by % 100 < 0);
189 int intervening_leap_days =
190 ((ay >> 2) - (by >> 2)) - (ac - bc) + ((ac >> 2) - (bc >> 2));
191 int years = ay - by;
192 int days = (365 * years + intervening_leap_days
193 + (a->tm_yday - b->tm_yday));
194 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
195 + (a->tm_min - b->tm_min))
196 + (a->tm_sec - b->tm_sec));
197 }
198 #endif /* ! HAVE_TM_GMTOFF */
199
200
201
202 /* The number of days from the first day of the first ISO week of this
203 year to the year day YDAY with week day WDAY. ISO weeks start on
204 Monday; the first ISO week has the year's first Thursday. YDAY may
205 be as small as YDAY_MINIMUM. */
206 #define ISO_WEEK_START_WDAY 1 /* Monday */
207 #define ISO_WEEK1_WDAY 4 /* Thursday */
208 #define YDAY_MINIMUM (-366)
209 static int iso_week_days __P ((int, int));
210 #ifdef __GNUC__
113 inline 211 inline
114 #endif 212 #endif
115 static unsigned int 213 static int
116 week (tp, starting_day, max_preceding) 214 iso_week_days (yday, wday)
117 const struct tm *const tp; 215 int yday;
118 int starting_day; 216 int wday;
119 int max_preceding;
120 { 217 {
121 int wday, dl, base; 218 /* Add enough to the first operand of % to make it nonnegative. */
122 219 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
123 wday = tp->tm_wday - starting_day; 220 return (yday
124 if (wday < 0) 221 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
125 wday += 7; 222 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
126
127 /* Set DL to the day in the year of the first day of the week
128 containing the day specified in TP. */
129 dl = tp->tm_yday - wday;
130
131 /* For the computation following ISO 8601:1988 we set the number of
132 the week containing January 1st to 1 if this week has more than
133 MAX_PRECEDING days in the new year. For ISO 8601 this number is
134 3, for the other representation it is 7 (i.e., not to be
135 fulfilled). */
136 base = ((dl + 7) % 7) > max_preceding ? 1 : 0;
137
138 /* If DL is negative we compute the result as 0 unless we have to
139 compute it according ISO 8601. In this case we have to return 53
140 or 1 if the week containing January 1st has less than 4 days in
141 the new year or not. If DL is not negative we calculate the
142 number of complete weeks for our week (DL / 7) plus 1 (because
143 only for DL < 0 we are in week 0/53 and plus the number of the
144 first week computed in the last step. */
145 return dl < 0 ? (dl < -max_preceding ? 53 : base)
146 : base + 1 + dl / 7;
147 } 223 }
224
148 225
149 #ifndef _NL_CURRENT 226 #ifndef _NL_CURRENT
150 static char const weekday_name[][10] = 227 static char const weekday_name[][10] =
151 { 228 {
152 "Sunday", "Monday", "Tuesday", "Wednesday", 229 "Sunday", "Monday", "Tuesday", "Wednesday",
181 const char *const ampm = _NL_CURRENT (LC_TIME, 258 const char *const ampm = _NL_CURRENT (LC_TIME,
182 hour12 > 11 ? PM_STR : AM_STR); 259 hour12 > 11 ? PM_STR : AM_STR);
183 size_t aw_len = strlen(a_wkday); 260 size_t aw_len = strlen(a_wkday);
184 size_t am_len = strlen(a_month); 261 size_t am_len = strlen(a_month);
185 size_t ap_len = strlen (ampm); 262 size_t ap_len = strlen (ampm);
263
264 const char *alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS);
265 const char *end_alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS + 1);
186 #else 266 #else
187 const char *const f_wkday = weekday_name[tp->tm_wday]; 267 const char *const f_wkday = weekday_name[tp->tm_wday];
188 const char *const f_month = month_name[tp->tm_mon]; 268 const char *const f_month = month_name[tp->tm_mon];
189 const char *const a_wkday = f_wkday; 269 const char *const a_wkday = f_wkday;
190 const char *const a_month = f_month; 270 const char *const a_month = f_month;
193 size_t am_len = 3; 273 size_t am_len = 3;
194 size_t ap_len = 2; 274 size_t ap_len = 2;
195 #endif 275 #endif
196 size_t wkday_len = strlen (f_wkday); 276 size_t wkday_len = strlen (f_wkday);
197 size_t month_len = strlen (f_month); 277 size_t month_len = strlen (f_month);
198 const unsigned int y_week0 = week (tp, 0, 7);
199 const unsigned int y_week1 = week (tp, 1, 7);
200 const unsigned int y_week2 = week (tp, 1, 3);
201 const char *zone; 278 const char *zone;
202 size_t zonelen; 279 size_t zonelen;
203 register size_t i = 0; 280 register size_t i = 0;
204 register char *p = s; 281 register char *p = s;
205 register const char *f; 282 register const char *f;
206 char number_fmt[5];
207
208 /* Initialize the buffer we will use for the sprintf format for numbers. */
209 number_fmt[0] = '%';
210 283
211 zone = 0; 284 zone = 0;
212 #if HAVE_TM_ZONE 285 #if HAVE_TM_ZONE
213 zone = (const char *) tp->tm_zone; 286 zone = (const char *) tp->tm_zone;
214 #endif 287 #endif
215 #if HAVE_TZNAME 288 #if HAVE_TZNAME
216 if (!(zone && *zone) && tp->tm_isdst >= 0) 289 if (!(zone && *zone) && tp->tm_isdst >= 0)
217 zone = tzname[tp->tm_isdst]; 290 zone = tzname[tp->tm_isdst];
218 #endif 291 #endif
219 if (!(zone && *zone)) 292 if (! zone)
220 zone = "???"; 293 zone = ""; /* POSIX.2 requires the empty string here. */
221 294
222 zonelen = strlen (zone); 295 zonelen = strlen (zone);
223 296
224 if (hour12 > 12) 297 if (hour12 > 12)
225 hour12 -= 12; 298 hour12 -= 12;
226 else 299 else
227 if (hour12 == 0) hour12 = 12; 300 if (hour12 == 0) hour12 = 12;
228 301
229 for (f = format; *f != '\0'; ++f) 302 for (f = format; *f != '\0'; ++f)
230 { 303 {
231 enum { pad_zero, pad_space, pad_none } pad; /* Padding for number. */ 304 int pad; /* Padding for number ('-', '_', or 0). */
232 unsigned int maxdigits; /* Max digits for numeric format. */ 305 int modifier; /* Field modifier ('E', 'O', or 0). */
233 unsigned int number_value; /* Numeric value to be printed. */ 306 int digits; /* Max digits for numeric format. */
307 int number_value; /* Numeric value to be printed. */
308 int negative_number; /* 1 if the number is negative. */
234 const char *subfmt; 309 const char *subfmt;
235 310 char *bufp;
236 #if HAVE_MBLEN 311 char buf[1 + (sizeof (int) < sizeof (time_t)
237 if (!isascii (*f)) 312 ? INT_STRLEN_BOUND (time_t)
313 : INT_STRLEN_BOUND (int))];
314
315 #if DO_MULTIBYTE
316
317 switch (*f)
238 { 318 {
239 /* Non-ASCII, may be a multibyte. */ 319 case '%':
240 int len = mblen (f, strlen (f)); 320 break;
241 if (len > 0) 321
242 { 322 case '\a': case '\b': case '\t': case '\n':
243 cpy(len, f); 323 case '\v': case '\f': case '\r':
244 continue; 324 case ' ': case '!': case '"': case '#': case '&': case'\'':
245 } 325 case '(': case ')': case '*': case '+': case ',': case '-':
326 case '.': case '/': case '0': case '1': case '2': case '3':
327 case '4': case '5': case '6': case '7': case '8': case '9':
328 case ':': case ';': case '<': case '=': case '>': case '?':
329 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
330 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
331 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
332 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
333 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
334 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
335 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
336 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
337 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
338 case 'x': case 'y': case 'z': case '{': case '|': case '}':
339 case '~':
340 /* The C Standard requires these 98 characters (plus '%') to
341 be in the basic execution character set. None of these
342 characters can start a multibyte sequence, so they need
343 not be analyzed further. */
344 add (1, *p = *f);
345 continue;
346
347 default:
348 /* Copy this multibyte sequence until we reach its end, find
349 an error, or come back to the initial shift state. */
350 {
351 mbstate_t mbstate = mbstate_zero;
352 size_t len = 0;
353
354 do
355 {
356 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
357
358 if (bytes == 0)
359 break;
360
361 if (bytes == (size_t) -2 || bytes == (size_t) -1)
362 {
363 len++;
364 break;
365 }
366
367 len += bytes;
368 }
369 while (! mbsinit (&mbstate));
370
371 cpy (len, f);
372 continue;
373 }
246 } 374 }
247 #endif 375
248 376 #else /* ! DO_MULTIBYTE */
377
378 /* Either multibyte encodings are not supported, or they are
379 safe for formats, so any non-'%' byte can be copied through. */
249 if (*f != '%') 380 if (*f != '%')
250 { 381 {
251 add (1, *p = *f); 382 add (1, *p = *f);
252 continue; 383 continue;
253 } 384 }
254 385
386 #endif /* ! DO_MULTIBYTE */
387
255 /* Check for flags that can modify a number format. */ 388 /* Check for flags that can modify a number format. */
256 ++f; 389 ++f;
257 switch (*f) 390 switch (*f)
258 { 391 {
259 case '_': 392 case '_':
260 pad = pad_space;
261 ++f;
262 break;
263 case '-': 393 case '-':
264 pad = pad_none; 394 pad = *f++;
265 ++f; 395 break;
266 break; 396
267 default: 397 default:
268 pad = pad_zero; 398 pad = 0;
399 break;
400 }
401
402 /* Check for modifiers. */
403 switch (*f)
404 {
405 case 'E':
406 case 'O':
407 modifier = *f++;
408 break;
409
410 default:
411 modifier = 0;
269 break; 412 break;
270 } 413 }
271 414
272 /* Now do the specified format. */ 415 /* Now do the specified format. */
273 switch (*f) 416 switch (*f)
274 { 417 {
275 case '\0': 418 #define DO_NUMBER(d, v) \
419 digits = d; number_value = v; goto do_number
420 #define DO_NUMBER_SPACEPAD(d, v) \
421 digits = d; number_value = v; goto do_number_spacepad
422
423 case '\0': /* GNU extension: % at end of format. */
424 --f;
425 /* Fall through. */
276 case '%': 426 case '%':
427 if (modifier != 0)
428 goto bad_format;
277 add (1, *p = *f); 429 add (1, *p = *f);
278 break; 430 break;
279 431
280 case 'a': 432 case 'a':
433 if (modifier != 0)
434 goto bad_format;
281 cpy (aw_len, a_wkday); 435 cpy (aw_len, a_wkday);
282 break; 436 break;
283 437
284 case 'A': 438 case 'A':
439 if (modifier != 0)
440 goto bad_format;
285 cpy (wkday_len, f_wkday); 441 cpy (wkday_len, f_wkday);
286 break; 442 break;
287 443
288 case 'b': 444 case 'b':
289 case 'h': /* GNU extension. */ 445 case 'h': /* POSIX.2 extension. */
446 if (modifier != 0)
447 goto bad_format;
290 cpy (am_len, a_month); 448 cpy (am_len, a_month);
291 break; 449 break;
292 450
293 case 'B': 451 case 'B':
452 if (modifier != 0)
453 goto bad_format;
294 cpy (month_len, f_month); 454 cpy (month_len, f_month);
295 break; 455 break;
296 456
297 case 'c': 457 case 'c':
458 if (modifier == 'O')
459 goto bad_format;
298 #ifdef _NL_CURRENT 460 #ifdef _NL_CURRENT
299 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT); 461 if (! (modifier == 'E'
462 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
463 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
300 #else 464 #else
301 subfmt = "%a %b %d %H:%M:%S %Z %Y"; 465 subfmt = "%a %b %e %H:%M:%S %Z %Y";
302 #endif 466 #endif
467
303 subformat: 468 subformat:
304 { 469 {
305 size_t len = strftime (p, maxsize - i, subfmt, tp); 470 size_t len = strftime (p, maxsize - i, subfmt, tp);
306 if (len == 0 && *subfmt) 471 if (len == 0 && *subfmt)
307 return 0; 472 return 0;
308 add (len, ;); 473 add (len, ;);
309 } 474 }
310 break; 475 break;
311 476
312 #define DO_NUMBER(digits, value) \ 477 case 'C': /* POSIX.2 extension. */
313 maxdigits = digits; number_value = value; goto do_number 478 if (modifier == 'O')
314 #define DO_NUMBER_SPACEPAD(digits, value) \ 479 goto bad_format;
315 maxdigits = digits; number_value = value; goto do_number_spacepad 480 #ifdef _NL_CURRENT
316 481 /* XXX %EC is not implemented yet. */
317 case 'C': 482 #endif
318 DO_NUMBER (2, (1900 + tp->tm_year) / 100); 483 {
484 int year = tp->tm_year + TM_YEAR_BASE;
485 DO_NUMBER (1, year / 100 - (year % 100 < 0));
486 }
319 487
320 case 'x': 488 case 'x':
489 if (modifier == 'O')
490 goto bad_format;
321 #ifdef _NL_CURRENT 491 #ifdef _NL_CURRENT
322 subfmt = _NL_CURRENT (LC_TIME, D_FMT); 492 if (! (modifier == 'E'
493 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
494 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
323 goto subformat; 495 goto subformat;
324 #endif 496 #endif
325 /* Fall through. */ 497 /* Fall through. */
326 case 'D': /* GNU extension. */ 498 case 'D': /* POSIX.2 extension. */
499 if (modifier != 0)
500 goto bad_format;
327 subfmt = "%m/%d/%y"; 501 subfmt = "%m/%d/%y";
328 goto subformat; 502 goto subformat;
329 503
330 case 'd': 504 case 'd':
505 if (modifier == 'E')
506 goto bad_format;
507
331 DO_NUMBER (2, tp->tm_mday); 508 DO_NUMBER (2, tp->tm_mday);
332 509
333 case 'e': /* GNU extension: %d, but blank-padded. */ 510 case 'e': /* POSIX.2 extension. */
511 if (modifier == 'E')
512 goto bad_format;
513
334 DO_NUMBER_SPACEPAD (2, tp->tm_mday); 514 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
335 515
336 /* All numeric formats set MAXDIGITS and NUMBER_VALUE and then 516 /* All numeric formats set DIGITS and NUMBER_VALUE and then
337 jump to one of these two labels. */ 517 jump to one of these two labels. */
338 518
339 do_number_spacepad: 519 do_number_spacepad:
340 /* Force `_' flag. */ 520 /* Force `_' flag. */
341 pad = pad_space; 521 pad = '_';
342 522
343 do_number: 523 do_number:
524 /* Format the number according to the MODIFIER flag. */
525
526 #ifdef _NL_CURRENT
527 if (modifier == 'O')
528 {
529 /* ALT_DIGITS is the first entry in an array with
530 alternative digit symbols. We have to find string
531 number NUMBER_VALUE, but must not look beyond
532 END_ALT_DIGITS. */
533 int run = number_value;
534 const char *cp = alt_digits;
535
536 while (run > 0 && cp < end_alt_digits)
537 cp = strchr (cp, '\0') + 1;
538
539 if (cp < end_alt_digits)
540 {
541 size_t digitlen = strlen (cp);
542 if (digitlen != 0)
543 {
544 cpy (digitlen, cp);
545 break;
546 }
547 }
548 }
549 #endif
344 { 550 {
345 /* Format the number according to the PAD flag. */ 551 unsigned int u = number_value;
346 552
347 register char *nf = &number_fmt[1]; 553 bufp = buf + sizeof (buf);
348 int printed = maxdigits; 554 negative_number = number_value < 0;
349 555
350 switch (pad) 556 if (negative_number)
351 { 557 u = -u;
352 case pad_zero: 558
353 *nf++ = '0'; 559 do
354 case pad_space: 560 *--bufp = u % 10 + '0';
355 *nf++ = '0' + maxdigits; 561 while ((u /= 10) != 0);
356 case pad_none: 562 }
357 *nf++ = 'u'; 563
358 *nf = '\0'; 564 do_number_sign_and_padding:
359 } 565 if (negative_number)
360 566 *--bufp = '-';
361 #ifdef _LIBC 567
362 add (maxdigits, printed = sprintf (p, number_fmt, number_value)); 568 if (pad != '-')
363 #else 569 {
364 add (maxdigits, sprintf (p, number_fmt, number_value); 570 int padding = digits - (buf + sizeof (buf) - bufp);
365 printed = strlen (p)); 571
366 #endif 572 if (pad == '_')
367 /* Back up if fewer than MAXDIGITS chars written for pad_none. */ 573 {
368 p -= maxdigits - printed; 574 while (0 < padding--)
369 i -= maxdigits - printed; 575 *--bufp = ' ';
370 576 }
371 break; 577 else
372 } 578 {
579 bufp += negative_number;
580 while (0 < padding--)
581 *--bufp = '0';
582 if (negative_number)
583 *--bufp = '-';
584 }
585 }
586
587 cpy (buf + sizeof (buf) - bufp, bufp);
588 break;
373 589
374 590
375 case 'H': 591 case 'H':
592 if (modifier == 'E')
593 goto bad_format;
594
376 DO_NUMBER (2, tp->tm_hour); 595 DO_NUMBER (2, tp->tm_hour);
377 596
378 case 'I': 597 case 'I':
598 if (modifier == 'E')
599 goto bad_format;
600
379 DO_NUMBER (2, hour12); 601 DO_NUMBER (2, hour12);
380 602
381 case 'k': /* GNU extension. */ 603 case 'k': /* GNU extension. */
604 if (modifier == 'E')
605 goto bad_format;
606
382 DO_NUMBER_SPACEPAD (2, tp->tm_hour); 607 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
383 608
384 case 'l': /* GNU extension. */ 609 case 'l': /* GNU extension. */
610 if (modifier == 'E')
611 goto bad_format;
612
385 DO_NUMBER_SPACEPAD (2, hour12); 613 DO_NUMBER_SPACEPAD (2, hour12);
386 614
387 case 'j': 615 case 'j':
616 if (modifier == 'E')
617 goto bad_format;
618
388 DO_NUMBER (3, 1 + tp->tm_yday); 619 DO_NUMBER (3, 1 + tp->tm_yday);
389 620
390 case 'M': 621 case 'M':
622 if (modifier == 'E')
623 goto bad_format;
624
391 DO_NUMBER (2, tp->tm_min); 625 DO_NUMBER (2, tp->tm_min);
392 626
393 case 'm': 627 case 'm':
628 if (modifier == 'E')
629 goto bad_format;
630
394 DO_NUMBER (2, tp->tm_mon + 1); 631 DO_NUMBER (2, tp->tm_mon + 1);
395 632
396 case 'n': /* GNU extension. */ 633 case 'n': /* POSIX.2 extension. */
397 add (1, *p = '\n'); 634 add (1, *p = '\n');
398 break; 635 break;
399 636
400 case 'p': 637 case 'p':
401 cpy (ap_len, ampm); 638 cpy (ap_len, ampm);
403 640
404 case 'R': /* GNU extension. */ 641 case 'R': /* GNU extension. */
405 subfmt = "%H:%M"; 642 subfmt = "%H:%M";
406 goto subformat; 643 goto subformat;
407 644
408 case 'r': /* GNU extension. */ 645 case 'r': /* POSIX.2 extension. */
646 #ifdef _NL_CURRENT
647 subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM);
648 #else
409 subfmt = "%I:%M:%S %p"; 649 subfmt = "%I:%M:%S %p";
650 #endif
410 goto subformat; 651 goto subformat;
411 652
412 case 'S': 653 case 'S':
654 if (modifier == 'E')
655 return 0;
656
413 DO_NUMBER (2, tp->tm_sec); 657 DO_NUMBER (2, tp->tm_sec);
414 658
415 case 's': /* GNU extension. */ 659 case 's': /* GNU extension. */
416 { 660 {
417 struct tm writable_tm = *tp; 661 struct tm ltm = *tp;
418 unsigned long int num = (unsigned long int) mktime (&writable_tm); 662 time_t t = mktime (&ltm);
419 /* `3 * sizeof (unsigned long int)' is an approximation of 663
420 the size of the decimal representation of NUM, valid 664 /* Generate string value for T using time_t arithmetic;
421 for sizes <= 16. */ 665 this works even if sizeof (long) < sizeof (time_t). */
422 int printed = 3 * sizeof (unsigned long int); 666
423 maxdigits = printed; 667 bufp = buf + sizeof (buf);
424 assert (sizeof (unsigned long int) <= 16); 668 negative_number = t < 0;
425 #ifdef _LIBC 669
426 add (maxdigits, printed = sprintf (p, "%lu", num)); 670 do
427 #else 671 {
428 add (maxdigits, sprintf (p, "%lu", num); printed = strlen (p)); 672 int d = t % 10;
429 #endif 673 t /= 10;
430 /* Back up if fewer than MAXDIGITS chars written for pad_none. */ 674
431 p -= maxdigits - printed; 675 if (negative_number)
432 i -= maxdigits - printed; 676 {
677 d = -d;
678
679 /* Adjust if division truncates to minus infinity. */
680 if (0 < -1 % 10 && d < 0)
681 {
682 t++;
683 d += 10;
684 }
685 }
686
687 *--bufp = d + '0';
688 }
689 while (t != 0);
690
691 digits = 1;
692 goto do_number_sign_and_padding;
433 } 693 }
434 break;
435 694
436 case 'X': 695 case 'X':
696 if (modifier == 'O')
697 goto bad_format;
437 #ifdef _NL_CURRENT 698 #ifdef _NL_CURRENT
438 subfmt = _NL_CURRENT (LC_TIME, T_FMT); 699 if (! (modifier == 'E'
700 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
701 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
439 goto subformat; 702 goto subformat;
440 #endif 703 #endif
441 /* Fall through. */ 704 /* Fall through. */
442 case 'T': /* GNU extension. */ 705 case 'T': /* POSIX.2 extension. */
443 subfmt = "%H:%M:%S"; 706 subfmt = "%H:%M:%S";
444 goto subformat; 707 goto subformat;
445 708
446 case 't': /* GNU extension. */ 709 case 't': /* POSIX.2 extension. */
447 add (1, *p = '\t'); 710 add (1, *p = '\t');
448 break; 711 break;
449 712
713 case 'u': /* POSIX.2 extension. */
714 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
715
450 case 'U': 716 case 'U':
451 DO_NUMBER (2, y_week0); 717 if (modifier == 'E')
718 goto bad_format;
719
720 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
452 721
453 case 'V': 722 case 'V':
454 DO_NUMBER (2, y_week2); 723 case 'g': /* GNU extension. */
724 case 'G': /* GNU extension. */
725 if (modifier == 'E')
726 goto bad_format;
727 {
728 int year = tp->tm_year + TM_YEAR_BASE;
729 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
730
731 if (days < 0)
732 {
733 /* This ISO week belongs to the previous year. */
734 year--;
735 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
736 tp->tm_wday);
737 }
738 else
739 {
740 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
741 tp->tm_wday);
742 if (0 <= d)
743 {
744 /* This ISO week belongs to the next year. */
745 year++;
746 days = d;
747 }
748 }
749
750 switch (*f)
751 {
752 case 'g':
753 DO_NUMBER (2, (year % 100 + 100) % 100);
754
755 case 'G':
756 DO_NUMBER (1, year);
757
758 default:
759 DO_NUMBER (2, days / 7 + 1);
760 }
761 }
455 762
456 case 'W': 763 case 'W':
457 DO_NUMBER (2, y_week1); 764 if (modifier == 'E')
765 goto bad_format;
766
767 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
458 768
459 case 'w': 769 case 'w':
460 DO_NUMBER (2, tp->tm_wday); 770 if (modifier == 'E')
771 goto bad_format;
772
773 DO_NUMBER (1, tp->tm_wday);
461 774
462 case 'Y': 775 case 'Y':
463 DO_NUMBER (4, 1900 + tp->tm_year); 776 #ifdef _NL_CURRENT
777 if (modifier == 'E'
778 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
779 goto subformat;
780 #endif
781 if (modifier == 'O')
782 goto bad_format;
783 else
784 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
464 785
465 case 'y': 786 case 'y':
466 DO_NUMBER (2, tp->tm_year % 100); 787 #ifdef _NL_CURRENT
788 /* XXX %Ey is not implemented yet. */
789 #endif
790 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
467 791
468 case 'Z': 792 case 'Z':
469 cpy(zonelen, zone); 793 cpy(zonelen, zone);
470 break; 794 break;
471 795
472 case 'z': 796 case 'z': /* GNU extension. */
797 if (tp->tm_isdst < 0)
798 break;
799
473 { 800 {
474 struct tm tml = *tp;
475 time_t t = mktime (&tml);
476 struct tm tmg;
477 int diff; 801 int diff;
478 802 #if HAVE_TM_GMTOFF
479 tml = *localtime (&t); /* Canonicalize the local time. */ 803 diff = tp->tm_gmtoff;
480 tmg = *gmtime (&t); 804 #else
481 805 struct tm gtm;
482 /* Compute the difference. */ 806 struct tm ltm = *tp;
483 diff = tml.tm_min - tmg.tm_min; 807 time_t lt = mktime (&ltm);
484 diff += 60 * (tml.tm_hour - tmg.tm_hour); 808
485 809 if (lt == (time_t) -1)
486 if (tml.tm_mon != tmg.tm_mon)
487 { 810 {
488 /* We assume no timezone differs from UTC by more than 811 /* mktime returns -1 for errors, but -1 is also a
489 +- 23 hours. This should be safe. */ 812 valid time_t value. Check whether an error really
490 if (tmg.tm_mday == 1) 813 occurred. */
491 tml.tm_mday = 0; 814 struct tm tm;
492 else /* tml.tm_mday == 1 */ 815 localtime_r (&lt, &tm);
493 tmg.tm_mday = 0; 816
817 if ((ltm.tm_sec ^ tm.tm_sec)
818 | (ltm.tm_min ^ tm.tm_min)
819 | (ltm.tm_hour ^ tm.tm_hour)
820 | (ltm.tm_mday ^ tm.tm_mday)
821 | (ltm.tm_mon ^ tm.tm_mon)
822 | (ltm.tm_year ^ tm.tm_year))
823 break;
494 } 824 }
495 diff += 1440 * (tml.tm_mday - tmg.tm_mday); 825
826 if (! gmtime_r (&lt, &gtm))
827 break;
828
829 diff = tm_diff (&ltm, &gtm);
830 #endif
496 831
497 if (diff < 0) 832 if (diff < 0)
498 { 833 {
499 add (1, *p = '-'); 834 add (1, *p = '-');
500 diff = -diff; 835 diff = -diff;
501 } 836 }
502 else 837 else
503 add (1, *p = '+'); 838 add (1, *p = '+');
504 839
505 pad = pad_zero; 840 diff /= 60;
506 DO_NUMBER (4, ((diff / 60) % 24) * 100 + diff % 60); 841 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
507 } 842 }
508 843
509 default: 844 default:
510 /* Bad format. */ 845 /* Unknown format; output the format, including the '%',
511 add (1, *p = *f); 846 since this is most likely the right thing to do if a
847 multibyte string has been misparsed. */
848 bad_format:
849 {
850 int flen;
851 for (flen = 2; f[1 - flen] != '%'; flen++)
852 continue;
853 cpy (flen, &f[1 - flen]);
854 }
512 break; 855 break;
513 } 856 }
514 } 857 }
515 858
516 if (p) 859 if (p)