OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [newlib/] [libc/] [time/] [strftime.c] - Blame information for rev 277

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/* NOTE:  This file defines both strftime() and wcsftime().  Take care when
2
 * making changes.  See also wcsftime.c, and note the (small) overlap in the
3
 * manual description, taking care to edit both as needed.  */
4
/*
5
 * strftime.c
6
 * Original Author:     G. Haley
7
 * Additions from:      Eric Blake
8
 * Changes to allow dual use as wcstime, also:  Craig Howland
9
 *
10
 * Places characters into the array pointed to by s as controlled by the string
11
 * pointed to by format. If the total number of resulting characters including
12
 * the terminating null character is not more than maxsize, returns the number
13
 * of characters placed into the array pointed to by s (not including the
14
 * terminating null character); otherwise zero is returned and the contents of
15
 * the array indeterminate.
16
 */
17
 
18
/*
19
FUNCTION
20
<<strftime>>---convert date and time to a formatted string
21
 
22
INDEX
23
        strftime
24
 
25
ANSI_SYNOPSIS
26
        #include <time.h>
27
        size_t strftime(char *<[s]>, size_t <[maxsize]>,
28
                        const char *<[format]>, const struct tm *<[timp]>);
29
 
30
TRAD_SYNOPSIS
31
        #include <time.h>
32
        size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
33
        char *<[s]>;
34
        size_t <[maxsize]>;
35
        char *<[format]>;
36
        struct tm *<[timp]>;
37
 
38
DESCRIPTION
39
<<strftime>> converts a <<struct tm>> representation of the time (at
40
<[timp]>) into a null-terminated string, starting at <[s]> and occupying
41
no more than <[maxsize]> characters.
42
 
43
You control the format of the output using the string at <[format]>.
44
<<*<[format]>>> can contain two kinds of specifications: text to be
45
copied literally into the formatted string, and time conversion
46
specifications.  Time conversion specifications are two- and
47
three-character sequences beginning with `<<%>>' (use `<<%%>>' to
48
include a percent sign in the output).  Each defined conversion
49
specification selects only the specified field(s) of calendar time
50
data from <<*<[timp]>>>, and converts it to a string in one of the
51
following ways:
52
 
53
o+
54
o %a
55
A three-letter abbreviation for the day of the week. [tm_wday]
56
 
57
o %A
58
The full name for the day of the week, one of `<<Sunday>>',
59
`<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>',
60
`<<Friday>>', or `<<Saturday>>'. [tm_wday]
61
 
62
o %b
63
A three-letter abbreviation for the month name. [tm_mon]
64
 
65
o %B
66
The full name of the month, one of `<<January>>', `<<February>>',
67
`<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
68
`<<August>>', `<<September>>', `<<October>>', `<<November>>',
69
`<<December>>'. [tm_mon]
70
 
71
o %c
72
A string representing the complete date and time, in the form
73
`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13
74
1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
75
 
76
o %C
77
The century, that is, the year divided by 100 then truncated.  For
78
4-digit years, the result is zero-padded and exactly two characters;
79
but for other years, there may a negative sign or more digits.  In
80
this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
81
 
82
o %d
83
The day of the month, formatted with two digits (from `<<01>>' to
84
`<<31>>'). [tm_mday]
85
 
86
o %D
87
A string representing the date, in the form `<<"%m/%d/%y">>'.
88
[tm_mday, tm_mon, tm_year]
89
 
90
o %e
91
The day of the month, formatted with leading space if single digit
92
(from `<<1>>' to `<<31>>'). [tm_mday]
93
 
94
o %E<<x>>
95
In some locales, the E modifier selects alternative representations of
96
certain modifiers <<x>>.  But in the "C" locale supported by newlib,
97
it is ignored, and treated as %<<x>>.
98
 
99
o %F
100
A string representing the ISO 8601:2000 date format, in the form
101
`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
102
 
103
o %g
104
The last two digits of the week-based year, see specifier %G (from
105
`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
106
 
107
o %G
108
The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
109
includes January 4th, and begin on Mondays. Therefore, if January 1st,
110
2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
111
week of the previous year; and if December 29th, 30th, or 31st falls
112
on Monday, that day and later belong to week 1 of the next year.  For
113
consistency with %Y, it always has at least four characters.
114
Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
115
Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
116
 
117
o %h
118
A three-letter abbreviation for the month name (synonym for
119
"%b"). [tm_mon]
120
 
121
o %H
122
The hour (on a 24-hour clock), formatted with two digits (from
123
`<<00>>' to `<<23>>'). [tm_hour]
124
 
125
o %I
126
The hour (on a 12-hour clock), formatted with two digits (from
127
`<<01>>' to `<<12>>'). [tm_hour]
128
 
129
o %j
130
The count of days in the year, formatted with three digits
131
(from `<<001>>' to `<<366>>'). [tm_yday]
132
 
133
o %k
134
The hour (on a 24-hour clock), formatted with leading space if single
135
digit (from `<<0>>' to `<<23>>'). Non-POSIX extension (c.p. %I). [tm_hour]
136
 
137
o %l
138
The hour (on a 12-hour clock), formatted with leading space if single
139
digit (from `<<1>>' to `<<12>>'). Non-POSIX extension (c.p. %H). [tm_hour]
140
 
141
o %m
142
The month number, formatted with two digits (from `<<01>>' to `<<12>>').
143
[tm_mon]
144
 
145
o %M
146
The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
147
 
148
o %n
149
A newline character (`<<\n>>').
150
 
151
o %O<<x>>
152
In some locales, the O modifier selects alternative digit characters
153
for certain modifiers <<x>>.  But in the "C" locale supported by newlib, it
154
is ignored, and treated as %<<x>>.
155
 
156
o %p
157
Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour]
158
 
159
o %r
160
The 12-hour time, to the second.  Equivalent to "%I:%M:%S %p". [tm_sec,
161
tm_min, tm_hour]
162
 
163
o %R
164
The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
165
 
166
o %S
167
The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
168
value 60 accounts for the occasional leap second. [tm_sec]
169
 
170
o %t
171
A tab character (`<<\t>>').
172
 
173
o %T
174
The 24-hour time, to the second.  Equivalent to "%H:%M:%S". [tm_sec,
175
tm_min, tm_hour]
176
 
177
o %u
178
The weekday as a number, 1-based from Monday (from `<<1>>' to
179
`<<7>>'). [tm_wday]
180
 
181
o %U
182
The week number, where weeks start on Sunday, week 1 contains the first
183
Sunday in a year, and earlier days are in week 0.  Formatted with two
184
digits (from `<<00>>' to `<<53>>').  See also <<%W>>. [tm_wday, tm_yday]
185
 
186
o %V
187
The week number, where weeks start on Monday, week 1 contains January 4th,
188
and earlier days are in the previous year.  Formatted with two digits
189
(from `<<01>>' to `<<53>>').  See also <<%G>>. [tm_year, tm_wday, tm_yday]
190
 
191
o %w
192
The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
193
[tm_wday]
194
 
195
o %W
196
The week number, where weeks start on Monday, week 1 contains the first
197
Monday in a year, and earlier days are in week 0.  Formatted with two
198
digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
199
 
200
o %x
201
A string representing the complete date, equivalent to "%m/%d/%y".
202
[tm_mon, tm_mday, tm_year]
203
 
204
o %X
205
A string representing the full time of day (hours, minutes, and
206
seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
207
 
208
o %y
209
The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
210
(Implementation interpretation:  always positive, even for negative years.)
211
 
212
o %Y
213
The full year, equivalent to <<%C%y>>.  It will always have at least four
214
characters, but may have more.  The year is accurate even when tm_year
215
added to the offset of 1900 overflows an int. [tm_year]
216
 
217
o %z
218
The offset from UTC.  The format consists of a sign (negative is west of
219
Greewich), two characters for hour, then two characters for minutes
220
(-hhmm or +hhmm).  If tm_isdst is negative, the offset is unknown and no
221
output is generated; if it is zero, the offset is the standard offset for
222
the current time zone; and if it is positive, the offset is the daylight
223
savings offset for the current timezone. The offset is determined from
224
the TZ environment variable, as if by calling tzset(). [tm_isdst]
225
 
226
o %Z
227
The time zone name.  If tm_isdst is negative, no output is generated.
228
Otherwise, the time zone name is based on the TZ environment variable,
229
as if by calling tzset(). [tm_isdst]
230
 
231
o %%
232
A single character, `<<%>>'.
233
o-
234
 
235
RETURNS
236
When the formatted time takes up no more than <[maxsize]> characters,
237
the result is the length of the formatted string.  Otherwise, if the
238
formatting operation was abandoned due to lack of room, the result is
239
<<0>>, and the string starting at <[s]> corresponds to just those
240
parts of <<*<[format]>>> that could be completely filled in within the
241
<[maxsize]> limit.
242
 
243
PORTABILITY
244
ANSI C requires <<strftime>>, but does not specify the contents of
245
<<*<[s]>>> when the formatted string would require more than
246
<[maxsize]> characters.  Unrecognized specifiers and fields of
247
<<timp>> that are out of range cause undefined results.  Since some
248
formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
249
value beforehand to distinguish between failure and an empty string.
250
This implementation does not support <<s>> being NULL, nor overlapping
251
<<s>> and <<format>>.
252
 
253
<<strftime>> requires no supporting OS subroutines.
254
 
255
BUGS
256
<<strftime>> ignores the LC_TIME category of the current locale, hard-coding
257
the "C" locale settings.
258
*/
259
 
260
#include <stddef.h>
261
#include <stdio.h>
262
#include <time.h>
263
#include <string.h>
264
#include <stdlib.h>
265
#include <limits.h>
266
#include "local.h"
267
 
268
/* Defines to make the file dual use for either strftime() or wcsftime().
269
 * To get wcsftime, define MAKE_WCSFTIME.
270
 * To get strftime, do not define MAKE_WCSFTIME.
271
 * Names are kept friendly to strftime() usage.  The biggest ugliness is the
272
 * use of the CQ() macro to make either regular character constants and
273
 * string literals or wide-character constants and wide-character-string
274
 * literals, as appropriate.  */
275
#if !defined(MAKE_WCSFTIME)
276
#  define CHAR          char            /* string type basis */
277
#  define CQ(a)         a               /* character constant qualifier */
278
#  define SFLG                          /* %s flag (null for normal char) */
279
# else
280
#  define strftime      wcsftime        /* Alternate function name */
281
#  define CHAR          wchar_t         /* string type basis */
282
#  define CQ(a)         L##a            /* character constant qualifier */
283
#  define snprintf      swprintf        /* wide-char equivalent function name */
284
#  define strncmp       wcsncmp         /* wide-char equivalent function name */
285
#  define SFLG          "l"             /* %s flag (l for wide char) */
286
#endif  /* MAKE_WCSFTIME */
287
 
288
/* Enforce the coding assumptions that YEAR_BASE is positive.  (%C, %Y, etc.) */
289
#if YEAR_BASE < 0
290
#  error "YEAR_BASE < 0"
291
#endif
292
 
293
static _CONST int dname_len[7] =
294
{6, 6, 7, 9, 8, 6, 8};
295
 
296
static _CONST CHAR *_CONST dname[7] =
297
{CQ("Sunday"), CQ("Monday"), CQ("Tuesday"), CQ("Wednesday"),
298
 CQ("Thursday"), CQ("Friday"), CQ("Saturday")};
299
 
300
static _CONST int mname_len[12] =
301
{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8};
302
 
303
static _CONST CHAR *_CONST mname[12] =
304
{CQ("January"), CQ("February"), CQ("March"), CQ("April"),
305
 CQ("May"), CQ("June"), CQ("July"), CQ("August"),
306
 CQ("September"), CQ("October"), CQ("November"), CQ("December")};
307
 
308
/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
309
   -1, 0, or 1 as the adjustment to add to the year for the ISO week
310
   numbering used in "%g%G%V", avoiding overflow.  */
311
static int
312
_DEFUN (iso_year_adjust, (tim_p),
313
        _CONST struct tm *tim_p)
314
{
315
  /* Account for fact that tm_year==0 is year 1900.  */
316
  int leap = isleap (tim_p->tm_year + (YEAR_BASE
317
                                       - (tim_p->tm_year < 0 ? 0 : 2000)));
318
 
319
  /* Pack the yday, wday, and leap year into a single int since there are so
320
     many disparate cases.  */
321
#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
322
  switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
323
    {
324
    case PACK (0, 5, 0): /* Jan 1 is Fri, not leap.  */
325
    case PACK (0, 6, 0): /* Jan 1 is Sat, not leap.  */
326
    case PACK (0, 0, 0): /* Jan 1 is Sun, not leap.  */
327
    case PACK (0, 5, 1): /* Jan 1 is Fri, leap year.  */
328
    case PACK (0, 6, 1): /* Jan 1 is Sat, leap year.  */
329
    case PACK (0, 0, 1): /* Jan 1 is Sun, leap year.  */
330
    case PACK (1, 6, 0): /* Jan 2 is Sat, not leap.  */
331
    case PACK (1, 0, 0): /* Jan 2 is Sun, not leap.  */
332
    case PACK (1, 6, 1): /* Jan 2 is Sat, leap year.  */
333
    case PACK (1, 0, 1): /* Jan 2 is Sun, leap year.  */
334
    case PACK (2, 0, 0): /* Jan 3 is Sun, not leap.  */
335
    case PACK (2, 0, 1): /* Jan 3 is Sun, leap year.  */
336
      return -1; /* Belongs to last week of previous year.  */
337
    case PACK (362, 1, 0): /* Dec 29 is Mon, not leap.  */
338
    case PACK (363, 1, 1): /* Dec 29 is Mon, leap year.  */
339
    case PACK (363, 1, 0): /* Dec 30 is Mon, not leap.  */
340
    case PACK (363, 2, 0): /* Dec 30 is Tue, not leap.  */
341
    case PACK (364, 1, 1): /* Dec 30 is Mon, leap year.  */
342
    case PACK (364, 2, 1): /* Dec 30 is Tue, leap year.  */
343
    case PACK (364, 1, 0): /* Dec 31 is Mon, not leap.  */
344
    case PACK (364, 2, 0): /* Dec 31 is Tue, not leap.  */
345
    case PACK (364, 3, 0): /* Dec 31 is Wed, not leap.  */
346
    case PACK (365, 1, 1): /* Dec 31 is Mon, leap year.  */
347
    case PACK (365, 2, 1): /* Dec 31 is Tue, leap year.  */
348
    case PACK (365, 3, 1): /* Dec 31 is Wed, leap year.  */
349
      return 1; /* Belongs to first week of next year.  */
350
    }
351
  return 0; /* Belongs to specified year.  */
352
#undef PACK
353
}
354
 
355
size_t
356
_DEFUN (strftime, (s, maxsize, format, tim_p),
357
        CHAR *s _AND
358
        size_t maxsize _AND
359
        _CONST CHAR *format _AND
360
        _CONST struct tm *tim_p)
361
{
362
  size_t count = 0;
363
  int i, len;
364
 
365
  for (;;)
366
    {
367
      while (*format && *format != CQ('%'))
368
        {
369
          if (count < maxsize - 1)
370
            s[count++] = *format++;
371
          else
372
            return 0;
373
        }
374
 
375
      if (*format == CQ('\0'))
376
        break;
377
 
378
      format++;
379
      if (*format == CQ('E') || *format == CQ('O'))
380
        format++;
381
 
382
      switch (*format)
383
        {
384
        case CQ('a'):
385
          for (i = 0; i < 3; i++)
386
            {
387
              if (count < maxsize - 1)
388
                s[count++] =
389
                  dname[tim_p->tm_wday][i];
390
              else
391
                return 0;
392
            }
393
          break;
394
        case CQ('A'):
395
          for (i = 0; i < dname_len[tim_p->tm_wday]; i++)
396
            {
397
              if (count < maxsize - 1)
398
                s[count++] =
399
                  dname[tim_p->tm_wday][i];
400
              else
401
                return 0;
402
            }
403
          break;
404
        case CQ('b'):
405
        case CQ('h'):
406
          for (i = 0; i < 3; i++)
407
            {
408
              if (count < maxsize - 1)
409
                s[count++] =
410
                  mname[tim_p->tm_mon][i];
411
              else
412
                return 0;
413
            }
414
          break;
415
        case CQ('B'):
416
          for (i = 0; i < mname_len[tim_p->tm_mon]; i++)
417
            {
418
              if (count < maxsize - 1)
419
                s[count++] =
420
                  mname[tim_p->tm_mon][i];
421
              else
422
                return 0;
423
            }
424
          break;
425
        case CQ('c'):
426
          {
427
            /* Recurse to avoid need to replicate %Y formation. */
428
            size_t adjust = strftime (&s[count], maxsize - count,
429
                                      CQ("%a %b %e %H:%M:%S %Y"), tim_p);
430
            if (adjust > 0)
431
              count += adjust;
432
            else
433
              return 0;
434
          }
435
          break;
436
        case CQ('C'):
437
          {
438
            /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
439
               with 32-bit int.
440
               %Y               %C              %y
441
               2147485547       21474855        47
442
               10000            100             00
443
               9999             99              99
444
               0999             09              99
445
               0099             00              99
446
               0001             00              01
447
               0000             00              00
448
               -001             -0              01
449
               -099             -0              99
450
               -999             -9              99
451
               -1000            -10             00
452
               -10000           -100            00
453
               -2147481748      -21474817       48
454
 
455
               Be careful of both overflow and sign adjustment due to the
456
               asymmetric range of years.
457
            */
458
            int neg = tim_p->tm_year < -YEAR_BASE;
459
            int century = tim_p->tm_year >= 0
460
              ? tim_p->tm_year / 100 + YEAR_BASE / 100
461
              : abs (tim_p->tm_year + YEAR_BASE) / 100;
462
            len = snprintf (&s[count], maxsize - count, CQ("%s%.*d"),
463
                               neg ? CQ("-") : CQ(""), 2 - neg, century);
464
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
465
          }
466
          break;
467
        case CQ('d'):
468
        case CQ('e'):
469
          len = snprintf (&s[count], maxsize - count,
470
                        *format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
471
                        tim_p->tm_mday);
472
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
473
          break;
474
        case CQ('D'):
475
        case CQ('x'):
476
          /* %m/%d/%y */
477
          len = snprintf (&s[count], maxsize - count,
478
                        CQ("%.2d/%.2d/%.2d"),
479
                        tim_p->tm_mon + 1, tim_p->tm_mday,
480
                        tim_p->tm_year >= 0 ? tim_p->tm_year % 100
481
                        : abs (tim_p->tm_year + YEAR_BASE) % 100);
482
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
483
          break;
484
        case CQ('F'):
485
          { /* %F is equivalent to "%Y-%m-%d" */
486
            /* Recurse to avoid need to replicate %Y formation. */
487
            size_t adjust = strftime (&s[count], maxsize - count,
488
                                      CQ("%Y-%m-%d"), tim_p);
489
            if (adjust > 0)
490
              count += adjust;
491
            else
492
              return 0;
493
          }
494
          break;
495
        case CQ('g'):
496
          /* Be careful of both overflow and negative years, thanks to
497
                 the asymmetric range of years.  */
498
          {
499
            int adjust = iso_year_adjust (tim_p);
500
            int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
501
                : abs (tim_p->tm_year + YEAR_BASE) % 100;
502
            if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
503
                adjust = 1;
504
            else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
505
                adjust = -1;
506
            len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
507
                       ((year + adjust) % 100 + 100) % 100);
508
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
509
          }
510
          break;
511
        case CQ('G'):
512
          {
513
            /* See the comments for 'C' and 'Y'; this is a variable length
514
               field.  Although there is no requirement for a minimum number
515
               of digits, we use 4 for consistency with 'Y'.  */
516
            int neg = tim_p->tm_year < -YEAR_BASE;
517
            int adjust = iso_year_adjust (tim_p);
518
            int century = tim_p->tm_year >= 0
519
              ? tim_p->tm_year / 100 + YEAR_BASE / 100
520
              : abs (tim_p->tm_year + YEAR_BASE) / 100;
521
            int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
522
              : abs (tim_p->tm_year + YEAR_BASE) % 100;
523
            if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
524
              neg = adjust = 1;
525
            else if (adjust > 0 && neg)
526
              adjust = -1;
527
            year += adjust;
528
            if (year == -1)
529
              {
530
                year = 99;
531
                --century;
532
              }
533
            else if (year == 100)
534
              {
535
                year = 0;
536
                ++century;
537
              }
538
            len = snprintf (&s[count], maxsize - count, CQ("%s%.*d%.2d"),
539
                               neg ? CQ("-") : CQ(""), 2 - neg, century, year);
540
            if (len < 0  ||  (count+=len) >= maxsize)
541
              return 0;
542
          }
543
          break;
544
        case CQ('H'):
545
        case CQ('k'):   /* newlib extension */
546
          len = snprintf (&s[count], maxsize - count,
547
                        *format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
548
                        tim_p->tm_hour);
549
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
550
          break;
551
        case CQ('I'):
552
        case CQ('l'):   /* newlib extension */
553
          {
554
            register int  h12;
555
            h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
556
                                                12  :  tim_p->tm_hour % 12;
557
            len = snprintf (&s[count], maxsize - count,
558
                        *format == CQ('I') ? CQ("%.2d") : CQ("%2d"),
559
                        h12);
560
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
561
          }
562
          break;
563
        case CQ('j'):
564
          len = snprintf (&s[count], maxsize - count, CQ("%.3d"),
565
                        tim_p->tm_yday + 1);
566
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
567
          break;
568
        case CQ('m'):
569
          len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
570
                        tim_p->tm_mon + 1);
571
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
572
          break;
573
        case CQ('M'):
574
          len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
575
                        tim_p->tm_min);
576
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
577
          break;
578
        case CQ('n'):
579
          if (count < maxsize - 1)
580
            s[count++] = CQ('\n');
581
          else
582
            return 0;
583
          break;
584
        case CQ('p'):
585
          if (count < maxsize - 1)
586
            {
587
              if (tim_p->tm_hour < 12)
588
                s[count++] = CQ('A');
589
              else
590
                s[count++] = CQ('P');
591
            }
592
          if (count < maxsize - 1)
593
            {
594
              s[count++] = CQ('M');
595
            }
596
          else
597
            return 0;
598
          break;
599
        case CQ('r'):
600
          {
601
            register int  h12;
602
            h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
603
                                                12  :  tim_p->tm_hour % 12;
604
            len = snprintf (&s[count], maxsize - count,
605
                        CQ("%.2d:%.2d:%.2d %cM"),
606
                        h12,
607
                        tim_p->tm_min,
608
                        tim_p->tm_sec,
609
                        (tim_p->tm_hour < 12)  ?  CQ('A') :  CQ('P'));
610
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
611
          }
612
          break;
613
        case CQ('R'):
614
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
615
                        tim_p->tm_hour, tim_p->tm_min);
616
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
617
          break;
618
        case CQ('S'):
619
          len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
620
                        tim_p->tm_sec);
621
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
622
          break;
623
        case CQ('t'):
624
          if (count < maxsize - 1)
625
            s[count++] = CQ('\t');
626
          else
627
            return 0;
628
          break;
629
        case CQ('T'):
630
        case CQ('X'):
631
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
632
                        tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
633
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
634
          break;
635
        case CQ('u'):
636
          if (count < maxsize - 1)
637
            {
638
              if (tim_p->tm_wday == 0)
639
                s[count++] = CQ('7');
640
              else
641
                s[count++] = CQ('0') + tim_p->tm_wday;
642
            }
643
          else
644
            return 0;
645
          break;
646
        case CQ('U'):
647
          len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
648
                       (tim_p->tm_yday + 7 -
649
                        tim_p->tm_wday) / 7);
650
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
651
          break;
652
        case CQ('V'):
653
          {
654
            int adjust = iso_year_adjust (tim_p);
655
            int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
656
            int week = (tim_p->tm_yday + 10 - wday) / 7;
657
            if (adjust > 0)
658
                week = 1;
659
            else if (adjust < 0)
660
                /* Previous year has 53 weeks if current year starts on
661
                   Fri, and also if current year starts on Sat and
662
                   previous year was leap year.  */
663
                week = 52 + (4 >= (wday - tim_p->tm_yday
664
                                   - isleap (tim_p->tm_year
665
                                             + (YEAR_BASE - 1
666
                                                - (tim_p->tm_year < 0
667
                                                   ? 0 : 2000)))));
668
            len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
669
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
670
          }
671
          break;
672
        case CQ('w'):
673
          if (count < maxsize - 1)
674
            s[count++] = CQ('0') + tim_p->tm_wday;
675
          else
676
            return 0;
677
          break;
678
        case CQ('W'):
679
          {
680
            int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
681
            len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
682
                        (tim_p->tm_yday + 7 - wday) / 7);
683
            if (len < 0  ||  (count+=len) >= maxsize)  return 0;
684
          }
685
          break;
686
        case CQ('y'):
687
            {
688
              /* Be careful of both overflow and negative years, thanks to
689
                 the asymmetric range of years.  */
690
              int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
691
                : abs (tim_p->tm_year + YEAR_BASE) % 100;
692
              len = snprintf (&s[count], maxsize - count, CQ("%.2d"), year);
693
              if (len < 0  ||  (count+=len) >= maxsize)  return 0;
694
            }
695
          break;
696
        case CQ('Y'):
697
          /* An implementation choice is to have %Y match %C%y, so that it
698
           * gives at least 4 digits, with leading zeros as needed.  */
699
          if(tim_p->tm_year <= INT_MAX-YEAR_BASE)  {
700
            /* For normal, non-overflow case.  */
701
            len = snprintf (&s[count], maxsize - count, CQ("%04d"),
702
                                tim_p->tm_year + YEAR_BASE);
703
          }
704
          else  {
705
            /* int would overflow, so use unsigned instead.  */
706
            register unsigned year;
707
            year = (unsigned) tim_p->tm_year + (unsigned) YEAR_BASE;
708
            len = snprintf (&s[count], maxsize - count, CQ("%04u"),
709
                                tim_p->tm_year + YEAR_BASE);
710
          }
711
          if (len < 0  ||  (count+=len) >= maxsize)  return 0;
712
          break;
713
        case CQ('z'):
714
          if (tim_p->tm_isdst >= 0)
715
            {
716
              long offset;
717
              __tzinfo_type *tz = __gettzinfo ();
718
              TZ_LOCK;
719
              /* The sign of this is exactly opposite the envvar TZ.  We
720
                 could directly use the global _timezone for tm_isdst==0,
721
                 but have to use __tzrule for daylight savings.  */
722
              offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
723
              TZ_UNLOCK;
724
              len = snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
725
                        offset / SECSPERHOUR,
726
                        labs (offset / SECSPERMIN) % 60L);
727
              if (len < 0  ||  (count+=len) >= maxsize)  return 0;
728
            }
729
          break;
730
        case CQ('Z'):
731
          if (tim_p->tm_isdst >= 0)
732
            {
733
              int size;
734
              TZ_LOCK;
735
              size = strlen(_tzname[tim_p->tm_isdst > 0]);
736
              for (i = 0; i < size; i++)
737
                {
738
                  if (count < maxsize - 1)
739
                    s[count++] = _tzname[tim_p->tm_isdst > 0][i];
740
                  else
741
                    {
742
                      TZ_UNLOCK;
743
                      return 0;
744
                    }
745
                }
746
              TZ_UNLOCK;
747
            }
748
          break;
749
        case CQ('%'):
750
          if (count < maxsize - 1)
751
            s[count++] = CQ('%');
752
          else
753
            return 0;
754
          break;
755
        }
756
      if (*format)
757
        format++;
758
      else
759
        break;
760
    }
761
  if (maxsize)
762
    s[count] = CQ('\0');
763
 
764
  return count;
765
}
766
 
767
/* The remainder of this file can serve as a regression test.  Compile
768
 *  with -D_REGRESSION_TEST.  */
769
#if defined(_REGRESSION_TEST)   /* [Test code:  */
770
 
771
/* This test code relies on ANSI C features, in particular on the ability
772
 * of adjacent strings to be pasted together into one string.  */
773
 
774
/* Test output buffer size (should be larger than all expected results) */
775
#define OUTSIZE 256
776
 
777
struct test {
778
        CHAR  *fmt;     /* Testing format */
779
        size_t  max;    /* Testing maxsize */
780
        size_t  ret;    /* Expected return value */
781
        CHAR  *out;     /* Expected output string */
782
        };
783
struct list {
784
        const struct tm  *tms;  /* Time used for these vectors */
785
        const struct test *vec; /* Test vectors */
786
        int  cnt;               /* Number of vectors */
787
        };
788
 
789
const char  TZ[]="TZ=EST5EDT";
790
 
791
/* Define list of test inputs and expected outputs, for the given time zone
792
 * and time.  */
793
const struct tm  tm0 = {
794
        /* Tue Dec 30 10:53:47 EST 2008 (time_t=1230648827) */
795
        .tm_sec         = 47,
796
        .tm_min         = 53,
797
        .tm_hour        = 9,
798
        .tm_mday        = 30,
799
        .tm_mon         = 11,
800
        .tm_year        = 108,
801
        .tm_wday        = 2,
802
        .tm_yday        = 364,
803
        .tm_isdst       = 0
804
        };
805
const struct test  Vec0[] = {
806
        /* Testing fields one at a time, expecting to pass, using exact
807
         * allowed length as what is needed.  */
808
        /* Using tm0 for time: */
809
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
810
        { CQ("%a"), 3+1, EXP(CQ("Tue")) },
811
        { CQ("%A"), 7+1, EXP(CQ("Tuesday")) },
812
        { CQ("%b"), 3+1, EXP(CQ("Dec")) },
813
        { CQ("%B"), 8+1, EXP(CQ("December")) },
814
        { CQ("%c"), 24+1, EXP(CQ("Tue Dec 30 09:53:47 2008")) },
815
        { CQ("%C"), 2+1, EXP(CQ("20")) },
816
        { CQ("%d"), 2+1, EXP(CQ("30")) },
817
        { CQ("%D"), 8+1, EXP(CQ("12/30/08")) },
818
        { CQ("%e"), 2+1, EXP(CQ("30")) },
819
        { CQ("%F"), 10+1, EXP(CQ("2008-12-30")) },
820
        { CQ("%g"), 2+1, EXP(CQ("09")) },
821
        { CQ("%G"), 4+1, EXP(CQ("2009")) },
822
        { CQ("%h"), 3+1, EXP(CQ("Dec")) },
823
        { CQ("%H"), 2+1, EXP(CQ("09")) },
824
        { CQ("%I"), 2+1, EXP(CQ("09")) },
825
        { CQ("%j"), 3+1, EXP(CQ("365")) },
826
        { CQ("%k"), 2+1, EXP(CQ(" 9")) },
827
        { CQ("%l"), 2+1, EXP(CQ(" 9")) },
828
        { CQ("%m"), 2+1, EXP(CQ("12")) },
829
        { CQ("%M"), 2+1, EXP(CQ("53")) },
830
        { CQ("%n"), 1+1, EXP(CQ("\n")) },
831
        { CQ("%p"), 2+1, EXP(CQ("AM")) },
832
        { CQ("%r"), 11+1, EXP(CQ("09:53:47 AM")) },
833
        { CQ("%R"), 5+1, EXP(CQ("09:53")) },
834
        { CQ("%S"), 2+1, EXP(CQ("47")) },
835
        { CQ("%t"), 1+1, EXP(CQ("\t")) },
836
        { CQ("%T"), 8+1, EXP(CQ("09:53:47")) },
837
        { CQ("%u"), 1+1, EXP(CQ("2")) },
838
        { CQ("%U"), 2+1, EXP(CQ("52")) },
839
        { CQ("%V"), 2+1, EXP(CQ("01")) },
840
        { CQ("%w"), 1+1, EXP(CQ("2")) },
841
        { CQ("%W"), 2+1, EXP(CQ("52")) },
842
        { CQ("%x"), 8+1, EXP(CQ("12/30/08")) },
843
        { CQ("%X"), 8+1, EXP(CQ("09:53:47")) },
844
        { CQ("%y"), 2+1, EXP(CQ("08")) },
845
        { CQ("%Y"), 4+1, EXP(CQ("2008")) },
846
        { CQ("%z"), 5+1, EXP(CQ("-0500")) },
847
        { CQ("%Z"), 3+1, EXP(CQ("EST")) },
848
        { CQ("%%"), 1+1, EXP(CQ("%")) },
849
        #undef EXP
850
        };
851
/* Define list of test inputs and expected outputs, for the given time zone
852
 * and time.  */
853
const struct tm  tm1 = {
854
        /* Wed Jul  2 23:01:13 EDT 2008 (time_t=1215054073) */
855
        .tm_sec         = 13,
856
        .tm_min         = 1,
857
        .tm_hour        = 23,
858
        .tm_mday        = 2,
859
        .tm_mon         = 6,
860
        .tm_year        = 108,
861
        .tm_wday        = 3,
862
        .tm_yday        = 183,
863
        .tm_isdst       = 1
864
        };
865
const struct test  Vec1[] = {
866
        /* Testing fields one at a time, expecting to pass, using exact
867
         * allowed length as what is needed.  */
868
        /* Using tm1 for time: */
869
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
870
        { CQ("%a"), 3+1, EXP(CQ("Wed")) },
871
        { CQ("%A"), 9+1, EXP(CQ("Wednesday")) },
872
        { CQ("%b"), 3+1, EXP(CQ("Jul")) },
873
        { CQ("%B"), 4+1, EXP(CQ("July")) },
874
        { CQ("%c"), 24+1, EXP(CQ("Wed Jul  2 23:01:13 2008")) },
875
        { CQ("%C"), 2+1, EXP(CQ("20")) },
876
        { CQ("%d"), 2+1, EXP(CQ("02")) },
877
        { CQ("%D"), 8+1, EXP(CQ("07/02/08")) },
878
        { CQ("%e"), 2+1, EXP(CQ(" 2")) },
879
        { CQ("%F"), 10+1, EXP(CQ("2008-07-02")) },
880
        { CQ("%g"), 2+1, EXP(CQ("08")) },
881
        { CQ("%G"), 4+1, EXP(CQ("2008")) },
882
        { CQ("%h"), 3+1, EXP(CQ("Jul")) },
883
        { CQ("%H"), 2+1, EXP(CQ("23")) },
884
        { CQ("%I"), 2+1, EXP(CQ("11")) },
885
        { CQ("%j"), 3+1, EXP(CQ("184")) },
886
        { CQ("%k"), 2+1, EXP(CQ("23")) },
887
        { CQ("%l"), 2+1, EXP(CQ("11")) },
888
        { CQ("%m"), 2+1, EXP(CQ("07")) },
889
        { CQ("%M"), 2+1, EXP(CQ("01")) },
890
        { CQ("%n"), 1+1, EXP(CQ("\n")) },
891
        { CQ("%p"), 2+1, EXP(CQ("PM")) },
892
        { CQ("%r"), 11+1, EXP(CQ("11:01:13 PM")) },
893
        { CQ("%R"), 5+1, EXP(CQ("23:01")) },
894
        { CQ("%S"), 2+1, EXP(CQ("13")) },
895
        { CQ("%t"), 1+1, EXP(CQ("\t")) },
896
        { CQ("%T"), 8+1, EXP(CQ("23:01:13")) },
897
        { CQ("%u"), 1+1, EXP(CQ("3")) },
898
        { CQ("%U"), 2+1, EXP(CQ("26")) },
899
        { CQ("%V"), 2+1, EXP(CQ("27")) },
900
        { CQ("%w"), 1+1, EXP(CQ("3")) },
901
        { CQ("%W"), 2+1, EXP(CQ("26")) },
902
        { CQ("%x"), 8+1, EXP(CQ("07/02/08")) },
903
        { CQ("%X"), 8+1, EXP(CQ("23:01:13")) },
904
        { CQ("%y"), 2+1, EXP(CQ("08")) },
905
        { CQ("%Y"), 4+1, EXP(CQ("2008")) },
906
        { CQ("%z"), 5+1, EXP(CQ("-0400")) },
907
        { CQ("%Z"), 3+1, EXP(CQ("EDT")) },
908
        { CQ("%%"), 1+1, EXP(CQ("%")) },
909
        #undef EXP
910
        #define VEC(s)  s, sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
911
        #define EXP(s)  sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
912
        { VEC(CQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) },
913
        { CQ("0123456789%%%h:`~"), EXP(CQ("0123456789%Jul:`~")) },
914
        { CQ("%R%h:`~ %x %w"), EXP(CQ("23:01Jul:`~ 07/02/08 3")) },
915
        #undef VEC
916
        #undef EXP
917
        };
918
 
919
#if YEAR_BASE == 1900  /* ( */
920
/* Checks for very large years.  YEAR_BASE value relied upon so that the
921
 * answer strings can be predetermined.
922
 * Years more than 4 digits are not mentioned in the standard for %C, so the
923
 * test for those cases are based on the design intent (which is to print the
924
 * whole number, being the century).  */
925
const struct tm  tmyr0 = {
926
        /* Wed Jul  2 23:01:13 EDT [HUGE#] */
927
        .tm_sec         = 13,
928
        .tm_min         = 1,
929
        .tm_hour        = 23,
930
        .tm_mday        = 2,
931
        .tm_mon         = 6,
932
        .tm_year        = INT_MAX - YEAR_BASE/2,
933
        .tm_wday        = 3,
934
        .tm_yday        = 183,
935
        .tm_isdst       = 1
936
        };
937
#if INT_MAX == 32767
938
#  define YEAR  CQ("33717")             /* INT_MAX + YEAR_BASE/2 */
939
#  define CENT  CQ("337")
940
#  define Year     CQ("17")
941
# elif INT_MAX == 2147483647
942
#  define YEAR  CQ("2147484597")
943
#  define CENT  CQ("21474845")
944
#  define Year          CQ("97")
945
# elif INT_MAX == 9223372036854775807
946
#  define YEAR  CQ("9223372036854776757")
947
#  define CENT  CQ("92233720368547777")
948
#  define Year                   CQ("57")
949
# else
950
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
951
#endif
952
const struct test  Vecyr0[] = {
953
        /* Testing fields one at a time, expecting to pass, using a larger
954
         * allowed length than what is needed.  */
955
        /* Using tmyr0 for time: */
956
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
957
        { CQ("%C"), OUTSIZE, EXP(CENT) },
958
        { CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
959
        { CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
960
        { CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
961
        { CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
962
        { CQ("%y"), OUTSIZE, EXP(Year) },
963
        { CQ("%Y"), OUTSIZE, EXP(YEAR) },
964
        #undef EXP
965
        };
966
#undef YEAR
967
#undef CENT
968
#undef Year
969
/* Checks for very large negative years.  YEAR_BASE value relied upon so that
970
 * the answer strings can be predetermined.  */
971
const struct tm  tmyr1 = {
972
        /* Wed Jul  2 23:01:13 EDT [HUGE#] */
973
        .tm_sec         = 13,
974
        .tm_min         = 1,
975
        .tm_hour        = 23,
976
        .tm_mday        = 2,
977
        .tm_mon         = 6,
978
        .tm_year        = INT_MIN,
979
        .tm_wday        = 3,
980
        .tm_yday        = 183,
981
        .tm_isdst       = 1
982
        };
983
#if INT_MAX == 32767
984
#  define YEAR  CQ("-30868")            /* INT_MIN + YEAR_BASE */
985
#  define CENT  CQ("-308")
986
#  define Year      CQ("68")
987
# elif INT_MAX == 2147483647
988
#  define YEAR  CQ("-2147481748")
989
#  define CENT  CQ("-21474817")
990
#  define Year           CQ("48")
991
# elif INT_MAX == 9223372036854775807
992
#  define YEAR  CQ("-9223372036854773908")
993
#  define CENT  CQ("-92233720368547739")
994
#  define Year                    CQ("08")
995
# else
996
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
997
#endif
998
const struct test  Vecyr1[] = {
999
        /* Testing fields one at a time, expecting to pass, using a larger
1000
         * allowed length than what is needed.  */
1001
        /* Using tmyr1 for time: */
1002
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
1003
        { CQ("%C"), OUTSIZE, EXP(CENT) },
1004
        { CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1005
        { CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1006
        { CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1007
        { CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1008
        { CQ("%y"), OUTSIZE, EXP(Year) },
1009
        { CQ("%Y"), OUTSIZE, EXP(YEAR) },
1010
        #undef EXP
1011
        };
1012
#undef YEAR
1013
#undef CENT
1014
#undef Year
1015
#endif /* YEAR_BASE ) */
1016
 
1017
/* Checks for years just over zero (also test for s=60).
1018
 * Years less than 4 digits are not mentioned for %Y in the standard, so the
1019
 * test for that case is based on the design intent.  */
1020
const struct tm  tmyrzp = {
1021
        /* Wed Jul  2 23:01:60 EDT 0007 */
1022
        .tm_sec         = 60,
1023
        .tm_min         = 1,
1024
        .tm_hour        = 23,
1025
        .tm_mday        = 2,
1026
        .tm_mon         = 6,
1027
        .tm_year        = 7-YEAR_BASE,
1028
        .tm_wday        = 3,
1029
        .tm_yday        = 183,
1030
        .tm_isdst       = 1
1031
        };
1032
#define YEAR    CQ("0007")      /* Design intent:  %Y=%C%y */
1033
#define CENT    CQ("00")
1034
#define Year      CQ("07")
1035
const struct test  Vecyrzp[] = {
1036
        /* Testing fields one at a time, expecting to pass, using a larger
1037
         * allowed length than what is needed.  */
1038
        /* Using tmyrzp for time: */
1039
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
1040
        { CQ("%C"), OUTSIZE, EXP(CENT) },
1041
        { CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:60 ")YEAR) },
1042
        { CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1043
        { CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1044
        { CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1045
        { CQ("%y"), OUTSIZE, EXP(Year) },
1046
        { CQ("%Y"), OUTSIZE, EXP(YEAR) },
1047
        #undef EXP
1048
        };
1049
#undef YEAR
1050
#undef CENT
1051
#undef Year
1052
/* Checks for years just under zero.
1053
 * Negative years are not handled by the standard, so the vectors here are
1054
 * verifying the chosen implemtation.  */
1055
const struct tm  tmyrzn = {
1056
        /* Wed Jul  2 23:01:00 EDT -004 */
1057
        .tm_sec         = 00,
1058
        .tm_min         = 1,
1059
        .tm_hour        = 23,
1060
        .tm_mday        = 2,
1061
        .tm_mon         = 6,
1062
        .tm_year        = -4-YEAR_BASE,
1063
        .tm_wday        = 3,
1064
        .tm_yday        = 183,
1065
        .tm_isdst       = 1
1066
        };
1067
#define YEAR    CQ("-004")
1068
#define CENT    CQ("-0")
1069
#define Year      CQ("04")
1070
const struct test  Vecyrzn[] = {
1071
        /* Testing fields one at a time, expecting to pass, using a larger
1072
         * allowed length than what is needed.  */
1073
        /* Using tmyrzn for time: */
1074
        #define EXP(s)  sizeof(s)/sizeof(CHAR)-1, s
1075
        { CQ("%C"), OUTSIZE, EXP(CENT) },
1076
        { CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:00 ")YEAR) },
1077
        { CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1078
        { CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1079
        { CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1080
        { CQ("%y"), OUTSIZE, EXP(Year) },
1081
        { CQ("%Y"), OUTSIZE, EXP(YEAR) },
1082
        #undef EXP
1083
        };
1084
#undef YEAR
1085
#undef CENT
1086
#undef Year
1087
 
1088
const struct list  ListYr[] = {
1089
        { &tmyrzp, Vecyrzp, sizeof(Vecyrzp)/sizeof(Vecyrzp[0]) },
1090
        { &tmyrzn, Vecyrzn, sizeof(Vecyrzn)/sizeof(Vecyrzn[0]) },
1091
        #if YEAR_BASE == 1900
1092
        { &tmyr0, Vecyr0, sizeof(Vecyr0)/sizeof(Vecyr0[0]) },
1093
        { &tmyr1, Vecyr1, sizeof(Vecyr1)/sizeof(Vecyr1[0]) },
1094
        #endif
1095
        };
1096
 
1097
 
1098
/* List of tests to be run */
1099
const struct list  List[] = {
1100
        { &tm0, Vec0, sizeof(Vec0)/sizeof(Vec0[0]) },
1101
        { &tm1, Vec1, sizeof(Vec1)/sizeof(Vec1[0]) },
1102
        };
1103
 
1104
#if defined(STUB_getenv_r)
1105
char *
1106
_getenv_r(struct _reent *p, const char *cp) { return getenv(cp); }
1107
#endif
1108
 
1109
int
1110
main(void)
1111
{
1112
int  i, l, errr=0, erro=0, tot=0;
1113
const char  *cp;
1114
CHAR  out[OUTSIZE];
1115
size_t  ret;
1116
 
1117
/* Set timezone so that %z and %Z tests come out right */
1118
cp = TZ;
1119
if((i=putenv(cp)))  {
1120
    printf( "putenv(%s) FAILED, ret %d\n", cp, i);
1121
    return(-1);
1122
    }
1123
if(strcmp(getenv("TZ"),strchr(TZ,'=')+1))  {
1124
    printf( "TZ not set properly in environment\n");
1125
    return(-2);
1126
    }
1127
tzset();
1128
 
1129
#if defined(VERBOSE)
1130
printf("_timezone=%d, _daylight=%d, _tzname[0]=%s, _tzname[1]=%s\n", _timezone, _daylight, _tzname[0], _tzname[1]);
1131
{
1132
long offset;
1133
__tzinfo_type *tz = __gettzinfo ();
1134
/* The sign of this is exactly opposite the envvar TZ.  We
1135
   could directly use the global _timezone for tm_isdst==0,
1136
   but have to use __tzrule for daylight savings.  */
1137
printf("tz->__tzrule[0].offset=%d, tz->__tzrule[1].offset=%d\n", tz->__tzrule[0].offset, tz->__tzrule[1].offset);
1138
}
1139
#endif
1140
 
1141
/* Run all of the exact-length tests as-given--results should match */
1142
for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
1143
    const struct list  *test = &List[l];
1144
    for(i=0; i<test->cnt; i++)  {
1145
        tot++;  /* Keep track of number of tests */
1146
        ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1147
        if(ret != test->vec[i].ret)  {
1148
            errr++;
1149
            fprintf(stderr,
1150
                "ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1151
                                                ret, test->vec[i].ret, l, i);
1152
            }
1153
        if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1154
            erro++;
1155
            fprintf(stderr,
1156
                "ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1157
                                                out, test->vec[i].out, l, i);
1158
            }
1159
        }
1160
    }
1161
 
1162
/* Run all of the exact-length tests with the length made too short--expect to
1163
 * fail.  */
1164
for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
1165
    const struct list  *test = &List[l];
1166
    for(i=0; i<test->cnt; i++)  {
1167
        tot++;  /* Keep track of number of tests */
1168
        ret = strftime(out, test->vec[i].max-1, test->vec[i].fmt, test->tms);
1169
        if(ret != 0)  {
1170
            errr++;
1171
            fprintf(stderr,
1172
                "ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1173
                                                ret, 0, l, i);
1174
            }
1175
        /* Almost every conversion puts out as many characters as possible, so
1176
         * go ahead and test the output even though have failed.  (The test
1177
         * times chosen happen to not hit any of the cases that fail this, so it
1178
         * works.)  */
1179
        if(strncmp(out, test->vec[i].out, test->vec[i].max-1-1))  {
1180
            erro++;
1181
            fprintf(stderr,
1182
                "ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1183
                                                out, test->vec[i].out, l, i);
1184
            }
1185
        }
1186
    }
1187
 
1188
/* Run all of the special year test cases */
1189
for(l=0; l<sizeof(ListYr)/sizeof(ListYr[0]); l++)  {
1190
    const struct list  *test = &ListYr[l];
1191
    for(i=0; i<test->cnt; i++)  {
1192
        tot++;  /* Keep track of number of tests */
1193
        ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1194
        if(ret != test->vec[i].ret)  {
1195
            errr++;
1196
            fprintf(stderr,
1197
                "ERROR:  return %d != %d expected for ListYr[%d].vec[%d]\n",
1198
                                                ret, test->vec[i].ret, l, i);
1199
            }
1200
        if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1201
            erro++;
1202
            fprintf(stderr,
1203
                "ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for ListYr[%d].vec[%d]\n",
1204
                                                out, test->vec[i].out, l, i);
1205
            }
1206
        }
1207
    }
1208
 
1209
#define STRIZE(f)       #f
1210
#define NAME(f) STRIZE(f)
1211
printf(NAME(strftime) "() test ");
1212
if(errr || erro)  printf("FAILED %d/%d of", errr, erro);
1213
  else    printf("passed");
1214
printf(" %d test cases.\n", tot);
1215
 
1216
return(errr || erro);
1217
}
1218
#endif /* defined(_REGRESSION_TEST) ] */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.