~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to misc/strftime.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

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