Subversion Repositories Kolibri OS

Rev

Rev 4921 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4921 Rev 6099
1
/* NOTE:  This file defines both strftime() and wcsftime().  Take care when
1
/* 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
2
 * making changes.  See also wcsftime.c, and note the (small) overlap in the
3
 * manual description, taking care to edit both as needed.  */
3
 * manual description, taking care to edit both as needed.  */
4
/*
4
/*
5
 * strftime.c
5
 * strftime.c
6
 * Original Author:	G. Haley
6
 * Original Author:	G. Haley
7
 * Additions from:	Eric Blake
7
 * Additions from:	Eric Blake
8
 * Changes to allow dual use as wcstime, also:	Craig Howland
8
 * Changes to allow dual use as wcstime, also:	Craig Howland
9
 *
9
 *
10
 * Places characters into the array pointed to by s as controlled by the string
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
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
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
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
14
 * terminating null character); otherwise zero is returned and the contents of
15
 * the array indeterminate.
15
 * the array indeterminate.
16
 */
16
 */
17
 
17
 
18
/*
18
/*
19
FUNCTION
19
FUNCTION
20
<>---convert date and time to a formatted string
20
<>---convert date and time to a formatted string
21
 
21
 
22
INDEX
22
INDEX
23
	strftime
23
	strftime
24
 
24
 
25
ANSI_SYNOPSIS
25
ANSI_SYNOPSIS
26
	#include 
26
	#include 
27
	size_t strftime(char *restrict <[s]>, size_t <[maxsize]>,
27
	size_t strftime(char *restrict <[s]>, size_t <[maxsize]>,
28
			const char *restrict <[format]>,
28
			const char *restrict <[format]>,
29
                        const struct tm *restrict <[timp]>);
29
                        const struct tm *restrict <[timp]>);
30
 
30
 
31
TRAD_SYNOPSIS
31
TRAD_SYNOPSIS
32
	#include 
32
	#include 
33
	size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
33
	size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
34
	char *<[s]>;
34
	char *<[s]>;
35
	size_t <[maxsize]>;
35
	size_t <[maxsize]>;
36
	char *<[format]>;
36
	char *<[format]>;
37
	struct tm *<[timp]>;
37
	struct tm *<[timp]>;
38
 
38
 
39
DESCRIPTION
39
DESCRIPTION
40
<> converts a <> representation of the time (at
40
<> converts a <> representation of the time (at
41
<[timp]>) into a null-terminated string, starting at <[s]> and occupying
41
<[timp]>) into a null-terminated string, starting at <[s]> and occupying
42
no more than <[maxsize]> characters.
42
no more than <[maxsize]> characters.
43
 
43
 
44
You control the format of the output using the string at <[format]>.
44
You control the format of the output using the string at <[format]>.
45
<<*<[format]>>> can contain two kinds of specifications: text to be
45
<<*<[format]>>> can contain two kinds of specifications: text to be
46
copied literally into the formatted string, and time conversion
46
copied literally into the formatted string, and time conversion
47
specifications.  Time conversion specifications are two- and
47
specifications.  Time conversion specifications are two- and
48
three-character sequences beginning with `<<%>>' (use `<<%%>>' to
48
three-character sequences beginning with `<<%>>' (use `<<%%>>' to
49
include a percent sign in the output).  Each defined conversion
49
include a percent sign in the output).  Each defined conversion
50
specification selects only the specified field(s) of calendar time
50
specification selects only the specified field(s) of calendar time
51
data from <<*<[timp]>>>, and converts it to a string in one of the
51
data from <<*<[timp]>>>, and converts it to a string in one of the
52
following ways:
52
following ways:
53
 
53
 
54
o+
54
o+
55
o %a
55
o %a
56
The abbreviated weekday name according to the current locale. [tm_wday]
56
The abbreviated weekday name according to the current locale. [tm_wday]
57
 
57
 
58
o %A
58
o %A
59
The full weekday name according to the current locale.
59
The full weekday name according to the current locale.
60
In the default "C" locale, one of `<>', `<>', `<>',
60
In the default "C" locale, one of `<>', `<>', `<>',
61
`<>', `<>', `<>', `<>'. [tm_wday]
61
`<>', `<>', `<>', `<>'. [tm_wday]
62
 
62
 
63
o %b
63
o %b
64
The abbreviated month name according to the current locale. [tm_mon]
64
The abbreviated month name according to the current locale. [tm_mon]
65
 
65
 
66
o %B
66
o %B
67
The full month name according to the current locale.
67
The full month name according to the current locale.
68
In the default "C" locale, one of `<>', `<>',
68
In the default "C" locale, one of `<>', `<>',
69
`<>', `<>', `<>', `<>', `<>',
69
`<>', `<>', `<>', `<>', `<>',
70
`<>', `<>', `<>', `<>',
70
`<>', `<>', `<>', `<>',
71
`<>'. [tm_mon]
71
`<>'. [tm_mon]
72
 
72
 
73
o %c
73
o %c
74
The preferred date and time representation for the current locale.
74
The preferred date and time representation for the current locale.
75
[tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
75
[tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
76
 
76
 
77
o %C
77
o %C
78
The century, that is, the year divided by 100 then truncated.  For
78
The century, that is, the year divided by 100 then truncated.  For
79
4-digit years, the result is zero-padded and exactly two characters;
79
4-digit years, the result is zero-padded and exactly two characters;
80
but for other years, there may a negative sign or more digits.  In
80
but for other years, there may a negative sign or more digits.  In
81
this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
81
this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
82
 
82
 
83
o %d
83
o %d
84
The day of the month, formatted with two digits (from `<<01>>' to
84
The day of the month, formatted with two digits (from `<<01>>' to
85
`<<31>>'). [tm_mday]
85
`<<31>>'). [tm_mday]
86
 
86
 
87
o %D
87
o %D
88
A string representing the date, in the form `<<"%m/%d/%y">>'.
88
A string representing the date, in the form `<<"%m/%d/%y">>'.
89
[tm_mday, tm_mon, tm_year]
89
[tm_mday, tm_mon, tm_year]
90
 
90
 
91
o %e
91
o %e
92
The day of the month, formatted with leading space if single digit
92
The day of the month, formatted with leading space if single digit
93
(from `<<1>>' to `<<31>>'). [tm_mday]
93
(from `<<1>>' to `<<31>>'). [tm_mday]
94
 
94
 
95
o %E<>
95
o %E<>
96
In some locales, the E modifier selects alternative representations of
96
In some locales, the E modifier selects alternative representations of
97
certain modifiers <>.  In newlib, it is ignored, and treated as %<>.
97
certain modifiers <>.  In newlib, it is ignored, and treated as %<>.
98
 
98
 
99
o %F
99
o %F
100
A string representing the ISO 8601:2000 date format, in the form
100
A string representing the ISO 8601:2000 date format, in the form
101
`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
101
`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
102
 
102
 
103
o %g
103
o %g
104
The last two digits of the week-based year, see specifier %G (from
104
The last two digits of the week-based year, see specifier %G (from
105
`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
105
`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
106
 
106
 
107
o %G
107
o %G
108
The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
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,
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
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
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
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.
113
consistency with %Y, it always has at least four characters.
114
Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
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]
115
Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
116
 
116
 
117
o %h
117
o %h
118
Synonym for "%b". [tm_mon]
118
Synonym for "%b". [tm_mon]
119
 
119
 
120
o %H
120
o %H
121
The hour (on a 24-hour clock), formatted with two digits (from
121
The hour (on a 24-hour clock), formatted with two digits (from
122
`<<00>>' to `<<23>>'). [tm_hour]
122
`<<00>>' to `<<23>>'). [tm_hour]
123
 
123
 
124
o %I
124
o %I
125
The hour (on a 12-hour clock), formatted with two digits (from
125
The hour (on a 12-hour clock), formatted with two digits (from
126
`<<01>>' to `<<12>>'). [tm_hour]
126
`<<01>>' to `<<12>>'). [tm_hour]
127
 
127
 
128
o %j
128
o %j
129
The count of days in the year, formatted with three digits
129
The count of days in the year, formatted with three digits
130
(from `<<001>>' to `<<366>>'). [tm_yday]
130
(from `<<001>>' to `<<366>>'). [tm_yday]
131
 
131
 
132
o %k
132
o %k
133
The hour (on a 24-hour clock), formatted with leading space if single
133
The hour (on a 24-hour clock), formatted with leading space if single
134
digit (from `<<0>>' to `<<23>>'). Non-POSIX extension (c.p. %I). [tm_hour]
134
digit (from `<<0>>' to `<<23>>'). Non-POSIX extension (c.p. %I). [tm_hour]
135
 
135
 
136
o %l
136
o %l
137
The hour (on a 12-hour clock), formatted with leading space if single
137
The hour (on a 12-hour clock), formatted with leading space if single
138
digit (from `<<1>>' to `<<12>>'). Non-POSIX extension (c.p. %H). [tm_hour]
138
digit (from `<<1>>' to `<<12>>'). Non-POSIX extension (c.p. %H). [tm_hour]
139
 
139
 
140
o %m
140
o %m
141
The month number, formatted with two digits (from `<<01>>' to `<<12>>').
141
The month number, formatted with two digits (from `<<01>>' to `<<12>>').
142
[tm_mon]
142
[tm_mon]
143
 
143
 
144
o %M
144
o %M
145
The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
145
The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
146
 
146
 
147
o %n
147
o %n
148
A newline character (`<<\n>>').
148
A newline character (`<<\n>>').
149
 
149
 
150
o %O<>
150
o %O<>
151
In some locales, the O modifier selects alternative digit characters
151
In some locales, the O modifier selects alternative digit characters
152
for certain modifiers <>.  In newlib, it is ignored, and treated as %<>.
152
for certain modifiers <>.  In newlib, it is ignored, and treated as %<>.
153
 
153
 
154
o %p
154
o %p
155
Either `<>' or `<>' as appropriate, or the corresponding strings for
155
Either `<>' or `<>' as appropriate, or the corresponding strings for
156
the current locale. [tm_hour]
156
the current locale. [tm_hour]
157
 
157
 
158
o %P
158
o %P
159
Same as '<<%p>>', but in lowercase.  This is a GNU extension. [tm_hour]
159
Same as '<<%p>>', but in lowercase.  This is a GNU extension. [tm_hour]
160
 
160
 
161
o %r
161
o %r
162
Replaced by the time in a.m. and p.m. notation.  In the "C" locale this
162
Replaced by the time in a.m. and p.m. notation.  In the "C" locale this
163
is equivalent to "%I:%M:%S %p".  In locales which don't define a.m./p.m.
163
is equivalent to "%I:%M:%S %p".  In locales which don't define a.m./p.m.
164
notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
164
notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
165
 
165
 
166
o %R
166
o %R
167
The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
167
The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
-
 
168
 
-
 
169
o %s
-
 
170
The time elapsed, in seconds, since the start of the Unix epoch at
-
 
171
1970-01-01 00:00:00 UTC.
168
 
172
 
169
o %S
173
o %S
170
The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
174
The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
171
value 60 accounts for the occasional leap second. [tm_sec]
175
value 60 accounts for the occasional leap second. [tm_sec]
172
 
176
 
173
o %t
177
o %t
174
A tab character (`<<\t>>').
178
A tab character (`<<\t>>').
175
 
179
 
176
o %T
180
o %T
177
The 24-hour time, to the second.  Equivalent to "%H:%M:%S". [tm_sec,
181
The 24-hour time, to the second.  Equivalent to "%H:%M:%S". [tm_sec,
178
tm_min, tm_hour]
182
tm_min, tm_hour]
179
 
183
 
180
o %u
184
o %u
181
The weekday as a number, 1-based from Monday (from `<<1>>' to
185
The weekday as a number, 1-based from Monday (from `<<1>>' to
182
`<<7>>'). [tm_wday]
186
`<<7>>'). [tm_wday]
183
 
187
 
184
o %U
188
o %U
185
The week number, where weeks start on Sunday, week 1 contains the first
189
The week number, where weeks start on Sunday, week 1 contains the first
186
Sunday in a year, and earlier days are in week 0.  Formatted with two
190
Sunday in a year, and earlier days are in week 0.  Formatted with two
187
digits (from `<<00>>' to `<<53>>').  See also <<%W>>. [tm_wday, tm_yday]
191
digits (from `<<00>>' to `<<53>>').  See also <<%W>>. [tm_wday, tm_yday]
188
 
192
 
189
o %V
193
o %V
190
The week number, where weeks start on Monday, week 1 contains January 4th,
194
The week number, where weeks start on Monday, week 1 contains January 4th,
191
and earlier days are in the previous year.  Formatted with two digits
195
and earlier days are in the previous year.  Formatted with two digits
192
(from `<<01>>' to `<<53>>').  See also <<%G>>. [tm_year, tm_wday, tm_yday]
196
(from `<<01>>' to `<<53>>').  See also <<%G>>. [tm_year, tm_wday, tm_yday]
193
 
197
 
194
o %w
198
o %w
195
The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
199
The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
196
[tm_wday]
200
[tm_wday]
197
 
201
 
198
o %W
202
o %W
199
The week number, where weeks start on Monday, week 1 contains the first
203
The week number, where weeks start on Monday, week 1 contains the first
200
Monday in a year, and earlier days are in week 0.  Formatted with two
204
Monday in a year, and earlier days are in week 0.  Formatted with two
201
digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
205
digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
202
 
206
 
203
o %x
207
o %x
204
Replaced by the preferred date representation in the current locale.
208
Replaced by the preferred date representation in the current locale.
205
In the "C" locale this is equivalent to "%m/%d/%y".
209
In the "C" locale this is equivalent to "%m/%d/%y".
206
[tm_mon, tm_mday, tm_year]
210
[tm_mon, tm_mday, tm_year]
207
 
211
 
208
o %X
212
o %X
209
Replaced by the preferred time representation in the current locale.
213
Replaced by the preferred time representation in the current locale.
210
In the "C" locale this is equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
214
In the "C" locale this is equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
211
 
215
 
212
o %y
216
o %y
213
The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
217
The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
214
(Implementation interpretation:  always positive, even for negative years.)
218
(Implementation interpretation:  always positive, even for negative years.)
215
 
219
 
216
o %Y
220
o %Y
217
The full year, equivalent to <<%C%y>>.  It will always have at least four
221
The full year, equivalent to <<%C%y>>.  It will always have at least four
218
characters, but may have more.  The year is accurate even when tm_year
222
characters, but may have more.  The year is accurate even when tm_year
219
added to the offset of 1900 overflows an int. [tm_year]
223
added to the offset of 1900 overflows an int. [tm_year]
220
 
224
 
221
o %z
225
o %z
222
The offset from UTC.  The format consists of a sign (negative is west of
226
The offset from UTC.  The format consists of a sign (negative is west of
223
Greewich), two characters for hour, then two characters for minutes
227
Greewich), two characters for hour, then two characters for minutes
224
(-hhmm or +hhmm).  If tm_isdst is negative, the offset is unknown and no
228
(-hhmm or +hhmm).  If tm_isdst is negative, the offset is unknown and no
225
output is generated; if it is zero, the offset is the standard offset for
229
output is generated; if it is zero, the offset is the standard offset for
226
the current time zone; and if it is positive, the offset is the daylight
230
the current time zone; and if it is positive, the offset is the daylight
227
savings offset for the current timezone. The offset is determined from
231
savings offset for the current timezone. The offset is determined from
228
the TZ environment variable, as if by calling tzset(). [tm_isdst]
232
the TZ environment variable, as if by calling tzset(). [tm_isdst]
229
 
233
 
230
o %Z
234
o %Z
231
The time zone name.  If tm_isdst is negative, no output is generated.
235
The time zone name.  If tm_isdst is negative, no output is generated.
232
Otherwise, the time zone name is based on the TZ environment variable,
236
Otherwise, the time zone name is based on the TZ environment variable,
233
as if by calling tzset(). [tm_isdst]
237
as if by calling tzset(). [tm_isdst]
234
 
238
 
235
o %%
239
o %%
236
A single character, `<<%>>'.
240
A single character, `<<%>>'.
237
o-
241
o-
238
 
242
 
239
RETURNS
243
RETURNS
240
When the formatted time takes up no more than <[maxsize]> characters,
244
When the formatted time takes up no more than <[maxsize]> characters,
241
the result is the length of the formatted string.  Otherwise, if the
245
the result is the length of the formatted string.  Otherwise, if the
242
formatting operation was abandoned due to lack of room, the result is
246
formatting operation was abandoned due to lack of room, the result is
243
<<0>>, and the string starting at <[s]> corresponds to just those
247
<<0>>, and the string starting at <[s]> corresponds to just those
244
parts of <<*<[format]>>> that could be completely filled in within the
248
parts of <<*<[format]>>> that could be completely filled in within the
245
<[maxsize]> limit.
249
<[maxsize]> limit.
246
 
250
 
247
PORTABILITY
251
PORTABILITY
248
ANSI C requires <>, but does not specify the contents of
252
ANSI C requires <>, but does not specify the contents of
249
<<*<[s]>>> when the formatted string would require more than
253
<<*<[s]>>> when the formatted string would require more than
250
<[maxsize]> characters.  Unrecognized specifiers and fields of
254
<[maxsize]> characters.  Unrecognized specifiers and fields of
251
<> that are out of range cause undefined results.  Since some
255
<> that are out of range cause undefined results.  Since some
252
formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
256
formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
253
value beforehand to distinguish between failure and an empty string.
257
value beforehand to distinguish between failure and an empty string.
254
This implementation does not support <> being NULL, nor overlapping
258
This implementation does not support <> being NULL, nor overlapping
255
<> and <>.
259
<> and <>.
256
 
260
 
257
<> requires no supporting OS subroutines.
261
<> requires no supporting OS subroutines.
258
 
262
 
259
BUGS
263
BUGS
260
<> ignores the LC_TIME category of the current locale, hard-coding
264
<> ignores the LC_TIME category of the current locale, hard-coding
261
the "C" locale settings.
265
the "C" locale settings.
262
*/
266
*/
263
 
267
 
264
#include 
268
#include 
265
#include 
269
#include 
266
#include 
270
#include 
267
#include 
271
#include 
268
#include 
272
#include 
269
#include 
273
#include 
270
#include 
274
#include 
271
#include 
275
#include 
272
#include 
276
#include 
273
#include 
277
#include 
274
#include "local.h"
278
#include "local.h"
275
#include "../locale/timelocal.h"
279
#include "../locale/timelocal.h"
276
 
280
 
277
/* Defines to make the file dual use for either strftime() or wcsftime().
281
/* Defines to make the file dual use for either strftime() or wcsftime().
278
 * To get wcsftime, define MAKE_WCSFTIME.
282
 * To get wcsftime, define MAKE_WCSFTIME.
279
 * To get strftime, do not define MAKE_WCSFTIME.
283
 * To get strftime, do not define MAKE_WCSFTIME.
280
 * Names are kept friendly to strftime() usage.  The biggest ugliness is the
284
 * Names are kept friendly to strftime() usage.  The biggest ugliness is the
281
 * use of the CQ() macro to make either regular character constants and
285
 * use of the CQ() macro to make either regular character constants and
282
 * string literals or wide-character constants and wide-character-string
286
 * string literals or wide-character constants and wide-character-string
283
 * literals, as appropriate.  */
287
 * literals, as appropriate.  */
284
#if !defined(MAKE_WCSFTIME)
288
#if !defined(MAKE_WCSFTIME)
285
#  define CHAR      char        /* string type basis */
289
#  define CHAR		char		/* string type basis */
286
#  define CQ(a)     a       /* character constant qualifier */
290
#  define CQ(a)		a		/* character constant qualifier */
287
#  define SFLG              /* %s flag (null for normal char) */
291
#  define SFLG				/* %s flag (null for normal char) */
288
#  define _ctloc(x) (ctloclen = strlen (ctloc = _CurrentTimeLocale->x), ctloc)
292
#  define _ctloc(x) (ctloclen = strlen (ctloc = _CurrentTimeLocale->x), ctloc)
289
#  define snprintf	sniprintf	/* avoid to pull in FP functions. */
293
#  define snprintf	sniprintf	/* avoid to pull in FP functions. */
290
#  define TOLOWER(c)    tolower((int)(unsigned char)(c))
294
#  define TOLOWER(c)	tolower((int)(unsigned char)(c))
291
#  define STRTOUL(c,p,b) strtoul((c),(p),(b))
295
#  define STRTOUL(c,p,b) strtoul((c),(p),(b))
292
#  define STRCPY(a,b)   strcpy((a),(b))
296
#  define STRCPY(a,b)	strcpy((a),(b))
293
#  define STRCHR(a,b)   strchr((a),(b))
297
#  define STRCHR(a,b)	strchr((a),(b))
294
#  define STRLEN(a) strlen(a)
298
#  define STRLEN(a)	strlen(a)
295
# else
299
# else
296
#  define strftime  wcsftime    /* Alternate function name */
300
#  define strftime	wcsftime	/* Alternate function name */
297
#  define CHAR      wchar_t     /* string type basis */
301
#  define CHAR		wchar_t		/* string type basis */
298
#  define CQ(a)     L##a        /* character constant qualifier */
302
#  define CQ(a)		L##a		/* character constant qualifier */
299
#  define snprintf  swprintf    /* wide-char equivalent function name */
303
#  define snprintf	swprintf	/* wide-char equivalent function name */
300
#  define strncmp   wcsncmp     /* wide-char equivalent function name */
304
#  define strncmp	wcsncmp		/* wide-char equivalent function name */
301
#  define TOLOWER(c)    towlower((wint_t)(c))
305
#  define TOLOWER(c)	towlower((wint_t)(c))
302
#  define STRTOUL(c,p,b) wcstoul((c),(p),(b))
306
#  define STRTOUL(c,p,b) wcstoul((c),(p),(b))
303
#  define STRCPY(a,b)   wcscpy((a),(b))
307
#  define STRCPY(a,b)	wcscpy((a),(b))
304
#  define STRCHR(a,b)   wcschr((a),(b))
308
#  define STRCHR(a,b)	wcschr((a),(b))
305
#  define STRLEN(a) wcslen(a)
309
#  define STRLEN(a)	wcslen(a)
306
#  define SFLG      "l"     /* %s flag (l for wide char) */
310
#  define SFLG		"l"		/* %s flag (l for wide char) */
307
#  ifdef __HAVE_LOCALE_INFO_EXTENDED__
311
#  ifdef __HAVE_LOCALE_INFO_EXTENDED__
308
#   define _ctloc(x) (ctloclen = wcslen (ctloc = _CurrentTimeLocale->w##x), \
312
#   define _ctloc(x) (ctloclen = wcslen (ctloc = _CurrentTimeLocale->w##x), \
309
              ctloc)
313
		      ctloc)
310
#  else
314
#  else
311
#   define CTLOCBUFLEN   256        /* Arbitrary big buffer size */
315
#   define CTLOCBUFLEN   256		/* Arbitrary big buffer size */
312
    const wchar_t *
316
    const wchar_t *
313
    __ctloc (wchar_t *buf, const char *elem, size_t *len_ret)
317
    __ctloc (wchar_t *buf, const char *elem, size_t *len_ret)
314
    {
318
    {
315
      buf[CTLOCBUFLEN - 1] = L'\0';
319
      buf[CTLOCBUFLEN - 1] = L'\0';
316
      *len_ret = mbstowcs (buf, elem, CTLOCBUFLEN - 1);
320
      *len_ret = mbstowcs (buf, elem, CTLOCBUFLEN - 1);
317
      if (*len_ret == (size_t) -1 )
321
      if (*len_ret == (size_t) -1 )
318
    *len_ret = 0;
322
	*len_ret = 0;
319
      return buf;
323
      return buf;
320
    }
324
    }
321
#   define _ctloc(x) (ctloc = __ctloc (ctlocbuf, _CurrentTimeLocale->x, \
325
#   define _ctloc(x) (ctloc = __ctloc (ctlocbuf, _CurrentTimeLocale->x, \
322
              &ctloclen))
326
		      &ctloclen))
323
#  endif
327
#  endif
324
#endif  /* MAKE_WCSFTIME */
328
#endif  /* MAKE_WCSFTIME */
325
 
329
 
326
#define CHECK_LENGTH()	if (len < 0 || (count += len) >= maxsize) \
330
#define CHECK_LENGTH()	if (len < 0 || (count += len) >= maxsize) \
327
			  return 0
331
			  return 0
328
 
332
 
329
/* Enforce the coding assumptions that YEAR_BASE is positive.  (%C, %Y, etc.) */
333
/* Enforce the coding assumptions that YEAR_BASE is positive.  (%C, %Y, etc.) */
330
#if YEAR_BASE < 0
334
#if YEAR_BASE < 0
331
#  error "YEAR_BASE < 0"
335
#  error "YEAR_BASE < 0"
332
#endif
336
#endif
333
 
337
 
334
static _CONST int dname_len[7] =
338
static _CONST int dname_len[7] =
335
{6, 6, 7, 9, 8, 6, 8};
339
{6, 6, 7, 9, 8, 6, 8};
336
 
340
 
337
/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
341
/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
338
   -1, 0, or 1 as the adjustment to add to the year for the ISO week
342
   -1, 0, or 1 as the adjustment to add to the year for the ISO week
339
   numbering used in "%g%G%V", avoiding overflow.  */
343
   numbering used in "%g%G%V", avoiding overflow.  */
340
static int
344
static int
341
_DEFUN (iso_year_adjust, (tim_p),
345
_DEFUN (iso_year_adjust, (tim_p),
342
	_CONST struct tm *tim_p)
346
	_CONST struct tm *tim_p)
343
{
347
{
344
  /* Account for fact that tm_year==0 is year 1900.  */
348
  /* Account for fact that tm_year==0 is year 1900.  */
345
  int leap = isleap (tim_p->tm_year + (YEAR_BASE
349
  int leap = isleap (tim_p->tm_year + (YEAR_BASE
346
				       - (tim_p->tm_year < 0 ? 0 : 2000)));
350
				       - (tim_p->tm_year < 0 ? 0 : 2000)));
347
 
351
 
348
  /* Pack the yday, wday, and leap year into a single int since there are so
352
  /* Pack the yday, wday, and leap year into a single int since there are so
349
     many disparate cases.  */
353
     many disparate cases.  */
350
#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
354
#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
351
  switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
355
  switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
352
    {
356
    {
353
    case PACK (0, 5, 0): /* Jan 1 is Fri, not leap.  */
357
    case PACK (0, 5, 0): /* Jan 1 is Fri, not leap.  */
354
    case PACK (0, 6, 0): /* Jan 1 is Sat, not leap.  */
358
    case PACK (0, 6, 0): /* Jan 1 is Sat, not leap.  */
355
    case PACK (0, 0, 0): /* Jan 1 is Sun, not leap.  */
359
    case PACK (0, 0, 0): /* Jan 1 is Sun, not leap.  */
356
    case PACK (0, 5, 1): /* Jan 1 is Fri, leap year.  */
360
    case PACK (0, 5, 1): /* Jan 1 is Fri, leap year.  */
357
    case PACK (0, 6, 1): /* Jan 1 is Sat, leap year.  */
361
    case PACK (0, 6, 1): /* Jan 1 is Sat, leap year.  */
358
    case PACK (0, 0, 1): /* Jan 1 is Sun, leap year.  */
362
    case PACK (0, 0, 1): /* Jan 1 is Sun, leap year.  */
359
    case PACK (1, 6, 0): /* Jan 2 is Sat, not leap.  */
363
    case PACK (1, 6, 0): /* Jan 2 is Sat, not leap.  */
360
    case PACK (1, 0, 0): /* Jan 2 is Sun, not leap.  */
364
    case PACK (1, 0, 0): /* Jan 2 is Sun, not leap.  */
361
    case PACK (1, 6, 1): /* Jan 2 is Sat, leap year.  */
365
    case PACK (1, 6, 1): /* Jan 2 is Sat, leap year.  */
362
    case PACK (1, 0, 1): /* Jan 2 is Sun, leap year.  */
366
    case PACK (1, 0, 1): /* Jan 2 is Sun, leap year.  */
363
    case PACK (2, 0, 0): /* Jan 3 is Sun, not leap.  */
367
    case PACK (2, 0, 0): /* Jan 3 is Sun, not leap.  */
364
    case PACK (2, 0, 1): /* Jan 3 is Sun, leap year.  */
368
    case PACK (2, 0, 1): /* Jan 3 is Sun, leap year.  */
365
      return -1; /* Belongs to last week of previous year.  */
369
      return -1; /* Belongs to last week of previous year.  */
366
    case PACK (362, 1, 0): /* Dec 29 is Mon, not leap.  */
370
    case PACK (362, 1, 0): /* Dec 29 is Mon, not leap.  */
367
    case PACK (363, 1, 1): /* Dec 29 is Mon, leap year.  */
371
    case PACK (363, 1, 1): /* Dec 29 is Mon, leap year.  */
368
    case PACK (363, 1, 0): /* Dec 30 is Mon, not leap.  */
372
    case PACK (363, 1, 0): /* Dec 30 is Mon, not leap.  */
369
    case PACK (363, 2, 0): /* Dec 30 is Tue, not leap.  */
373
    case PACK (363, 2, 0): /* Dec 30 is Tue, not leap.  */
370
    case PACK (364, 1, 1): /* Dec 30 is Mon, leap year.  */
374
    case PACK (364, 1, 1): /* Dec 30 is Mon, leap year.  */
371
    case PACK (364, 2, 1): /* Dec 30 is Tue, leap year.  */
375
    case PACK (364, 2, 1): /* Dec 30 is Tue, leap year.  */
372
    case PACK (364, 1, 0): /* Dec 31 is Mon, not leap.  */
376
    case PACK (364, 1, 0): /* Dec 31 is Mon, not leap.  */
373
    case PACK (364, 2, 0): /* Dec 31 is Tue, not leap.  */
377
    case PACK (364, 2, 0): /* Dec 31 is Tue, not leap.  */
374
    case PACK (364, 3, 0): /* Dec 31 is Wed, not leap.  */
378
    case PACK (364, 3, 0): /* Dec 31 is Wed, not leap.  */
375
    case PACK (365, 1, 1): /* Dec 31 is Mon, leap year.  */
379
    case PACK (365, 1, 1): /* Dec 31 is Mon, leap year.  */
376
    case PACK (365, 2, 1): /* Dec 31 is Tue, leap year.  */
380
    case PACK (365, 2, 1): /* Dec 31 is Tue, leap year.  */
377
    case PACK (365, 3, 1): /* Dec 31 is Wed, leap year.  */
381
    case PACK (365, 3, 1): /* Dec 31 is Wed, leap year.  */
378
      return 1; /* Belongs to first week of next year.  */
382
      return 1; /* Belongs to first week of next year.  */
379
    }
383
    }
380
  return 0; /* Belongs to specified year.  */
384
  return 0; /* Belongs to specified year.  */
381
#undef PACK
385
#undef PACK
382
}
386
}
383
 
387
 
384
#ifdef _WANT_C99_TIME_FORMATS
388
#ifdef _WANT_C99_TIME_FORMATS
385
typedef struct {
389
typedef struct {
386
  int   year;
390
  int   year;
387
  CHAR *era_C;
391
  CHAR *era_C;
388
  CHAR *era_Y;
392
  CHAR *era_Y;
389
} era_info_t;
393
} era_info_t;
390
 
394
 
391
static era_info_t *
395
static era_info_t *
392
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
396
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
393
get_era_info (const struct tm *tim_p, const wchar_t *era)
397
get_era_info (const struct tm *tim_p, const wchar_t *era)
394
#else
398
#else
395
get_era_info (const struct tm *tim_p, const char *era)
399
get_era_info (const struct tm *tim_p, const char *era)
396
#endif
400
#endif
397
{
401
{
398
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
402
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
399
  wchar_t *c;
403
  wchar_t *c;
400
  const wchar_t *dir;
404
  const wchar_t *dir;
401
# define ERA_STRCHR(a,b)	wcschr((a),(b))
405
# define ERA_STRCHR(a,b)	wcschr((a),(b))
402
# define ERA_STRNCPY(a,b,c)	wcsncpy((a),(b),(c))
406
# define ERA_STRNCPY(a,b,c)	wcsncpy((a),(b),(c))
403
# define ERA_STRTOL(a,b,c)	wcstol((a),(b),(c))
407
# define ERA_STRTOL(a,b,c)	wcstol((a),(b),(c))
404
#else
408
#else
405
  char *c;
409
  char *c;
406
  const char *dir;
410
  const char *dir;
407
# define ERA_STRCHR(a,b)	strchr((a),(b))
411
# define ERA_STRCHR(a,b)	strchr((a),(b))
408
# define ERA_STRNCPY(a,b,c)	strncpy((a),(b),(c))
412
# define ERA_STRNCPY(a,b,c)	strncpy((a),(b),(c))
409
# define ERA_STRTOL(a,b,c)	strtol((a),(b),(c))
413
# define ERA_STRTOL(a,b,c)	strtol((a),(b),(c))
410
#endif
414
#endif
411
  long offset;
415
  long offset;
412
  struct tm stm, etm;
416
  struct tm stm, etm;
413
  era_info_t *ei;
417
  era_info_t *ei;
414
 
418
 
415
  ei = (era_info_t *) calloc (1, sizeof (era_info_t));
419
  ei = (era_info_t *) calloc (1, sizeof (era_info_t));
416
  if (!ei)
420
  if (!ei)
417
    return NULL;
421
    return NULL;
418
 
422
 
419
  stm.tm_isdst = etm.tm_isdst = 0;
423
  stm.tm_isdst = etm.tm_isdst = 0;
420
  while (era)
424
  while (era)
421
    {
425
    {
422
      dir = era;
426
      dir = era;
423
      era += 2;
427
      era += 2;
424
      offset = ERA_STRTOL (era, &c, 10);
428
      offset = ERA_STRTOL (era, &c, 10);
425
      era = c + 1;
429
      era = c + 1;
426
      stm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
430
      stm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
427
      /* Adjust offset for negative gregorian dates. */
431
      /* Adjust offset for negative gregorian dates. */
428
      if (stm.tm_year <= -YEAR_BASE)
432
      if (stm.tm_year <= -YEAR_BASE)
429
      	++stm.tm_year;
433
      	++stm.tm_year;
430
      stm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
434
      stm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
431
      stm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
435
      stm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
432
      stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
436
      stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
433
      era = c + 1;
437
      era = c + 1;
434
      if (era[0] == '-' && era[1] == '*')
438
      if (era[0] == '-' && era[1] == '*')
435
      	{
439
      	{
436
	  etm = stm;
440
	  etm = stm;
437
	  stm.tm_year = INT_MIN;
441
	  stm.tm_year = INT_MIN;
438
	  stm.tm_mon = stm.tm_mday = stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
442
	  stm.tm_mon = stm.tm_mday = stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
439
	  era += 3;
443
	  era += 3;
440
	}
444
	}
441
      else if (era[0] == '+' && era[1] == '*')
445
      else if (era[0] == '+' && era[1] == '*')
442
	{
446
	{
443
	  etm.tm_year = INT_MAX;
447
	  etm.tm_year = INT_MAX;
444
	  etm.tm_mon = 11;
448
	  etm.tm_mon = 11;
445
	  etm.tm_mday = 31;
449
	  etm.tm_mday = 31;
446
	  etm.tm_hour = 23;
450
	  etm.tm_hour = 23;
447
	  etm.tm_min = etm.tm_sec = 59;
451
	  etm.tm_min = etm.tm_sec = 59;
448
	  era += 3;
452
	  era += 3;
449
	}
453
	}
450
      else
454
      else
451
      	{
455
      	{
452
	  etm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
456
	  etm.tm_year = ERA_STRTOL (era, &c, 10) - YEAR_BASE;
453
	  /* Adjust offset for negative gregorian dates. */
457
	  /* Adjust offset for negative gregorian dates. */
454
	  if (etm.tm_year <= -YEAR_BASE)
458
	  if (etm.tm_year <= -YEAR_BASE)
455
	    ++etm.tm_year;
459
	    ++etm.tm_year;
456
	  etm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
460
	  etm.tm_mon = ERA_STRTOL (c + 1, &c, 10) - 1;
457
	  etm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
461
	  etm.tm_mday = ERA_STRTOL (c + 1, &c, 10);
458
	  etm.tm_mday = 31;
462
	  etm.tm_mday = 31;
459
	  etm.tm_hour = 23;
463
	  etm.tm_hour = 23;
460
	  etm.tm_min = etm.tm_sec = 59;
464
	  etm.tm_min = etm.tm_sec = 59;
461
	  era = c + 1;
465
	  era = c + 1;
462
	}
466
	}
463
      if ((tim_p->tm_year > stm.tm_year
467
      if ((tim_p->tm_year > stm.tm_year
464
	   || (tim_p->tm_year == stm.tm_year
468
	   || (tim_p->tm_year == stm.tm_year
465
	       && (tim_p->tm_mon > stm.tm_mon
469
	       && (tim_p->tm_mon > stm.tm_mon
466
		   || (tim_p->tm_mon == stm.tm_mon
470
		   || (tim_p->tm_mon == stm.tm_mon
467
		       && tim_p->tm_mday >= stm.tm_mday))))
471
		       && tim_p->tm_mday >= stm.tm_mday))))
468
	  && (tim_p->tm_year < etm.tm_year
472
	  && (tim_p->tm_year < etm.tm_year
469
	      || (tim_p->tm_year == etm.tm_year
473
	      || (tim_p->tm_year == etm.tm_year
470
		  && (tim_p->tm_mon < etm.tm_mon
474
		  && (tim_p->tm_mon < etm.tm_mon
471
		      || (tim_p->tm_mon == etm.tm_mon
475
		      || (tim_p->tm_mon == etm.tm_mon
472
			  && tim_p->tm_mday <= etm.tm_mday)))))
476
			  && tim_p->tm_mday <= etm.tm_mday)))))
473
	{
477
	{
474
	  /* Gotcha */
478
	  /* Gotcha */
475
	  size_t len;
479
	  size_t len;
476
 
480
 
477
	  /* year */
481
	  /* year */
478
	  if (*dir == '+' && stm.tm_year != INT_MIN)
482
	  if (*dir == '+' && stm.tm_year != INT_MIN)
479
	    ei->year = tim_p->tm_year - stm.tm_year + offset;
483
	    ei->year = tim_p->tm_year - stm.tm_year + offset;
480
	  else
484
	  else
481
	    ei->year = etm.tm_year - tim_p->tm_year + offset;
485
	    ei->year = etm.tm_year - tim_p->tm_year + offset;
482
	  /* era_C */
486
	  /* era_C */
483
	  c = ERA_STRCHR (era, ':');
487
	  c = ERA_STRCHR (era, ':');
484
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
488
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
485
	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
489
	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
486
	  if (len == (size_t) -1)
490
	  if (len == (size_t) -1)
487
	    {
491
	    {
488
	      free (ei);
492
	      free (ei);
489
	      return NULL;
493
	      return NULL;
490
	    }
494
	    }
491
#else
495
#else
492
	  len = c - era;
496
	  len = c - era;
493
#endif
497
#endif
494
	  ei->era_C = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
498
	  ei->era_C = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
495
	  if (!ei->era_C)
499
	  if (!ei->era_C)
496
	    {
500
	    {
497
	      free (ei);
501
	      free (ei);
498
	      return NULL;
502
	      return NULL;
499
	    }
503
	    }
500
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
504
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
501
	  len = mbsnrtowcs (ei->era_C, &era, c - era, len + 1, NULL);
505
	  len = mbsnrtowcs (ei->era_C, &era, c - era, len + 1, NULL);
502
#else
506
#else
503
	  ERA_STRNCPY (ei->era_C, era, len);
507
	  ERA_STRNCPY (ei->era_C, era, len);
504
	  era += len;
508
	  era += len;
505
#endif
509
#endif
506
	  ei->era_C[len] = CQ('\0');
510
	  ei->era_C[len] = CQ('\0');
507
	  /* era_Y */
511
	  /* era_Y */
508
	  ++era;
512
	  ++era;
509
	  c = ERA_STRCHR (era, ';');
513
	  c = ERA_STRCHR (era, ';');
510
	  if (!c)
514
	  if (!c)
511
	    c = ERA_STRCHR (era, '\0');
515
	    c = ERA_STRCHR (era, '\0');
512
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
516
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
513
	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
517
	  len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
514
	  if (len == (size_t) -1)
518
	  if (len == (size_t) -1)
515
	    {
519
	    {
516
	      free (ei->era_C);
520
	      free (ei->era_C);
517
	      free (ei);
521
	      free (ei);
518
	      return NULL;
522
	      return NULL;
519
	    }
523
	    }
520
#else
524
#else
521
	  len = c - era;
525
	  len = c - era;
522
#endif
526
#endif
523
	  ei->era_Y = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
527
	  ei->era_Y = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
524
	  if (!ei->era_Y)
528
	  if (!ei->era_Y)
525
	    {
529
	    {
526
	      free (ei->era_C);
530
	      free (ei->era_C);
527
	      free (ei);
531
	      free (ei);
528
	      return NULL;
532
	      return NULL;
529
	    }
533
	    }
530
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
534
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
531
	  len = mbsnrtowcs (ei->era_Y, &era, c - era, len + 1, NULL);
535
	  len = mbsnrtowcs (ei->era_Y, &era, c - era, len + 1, NULL);
532
#else
536
#else
533
	  ERA_STRNCPY (ei->era_Y, era, len);
537
	  ERA_STRNCPY (ei->era_Y, era, len);
534
	  era += len;
538
	  era += len;
535
#endif
539
#endif
536
	  ei->era_Y[len] = CQ('\0');
540
	  ei->era_Y[len] = CQ('\0');
537
	  return ei;
541
	  return ei;
538
	}
542
	}
539
      else
543
      else
540
	era = ERA_STRCHR (era, ';');
544
	era = ERA_STRCHR (era, ';');
541
      if (era)
545
      if (era)
542
	++era;
546
	++era;
543
    }
547
    }
544
  return NULL;
548
  return NULL;
545
}
549
}
546
 
550
 
547
static void
551
static void
548
free_era_info (era_info_t *ei)
552
free_era_info (era_info_t *ei)
549
{
553
{
550
  free (ei->era_C);
554
  free (ei->era_C);
551
  free (ei->era_Y);
555
  free (ei->era_Y);
552
  free (ei);
556
  free (ei);
553
}
557
}
554
 
558
 
555
typedef struct {
559
typedef struct {
556
  size_t num;
560
  size_t num;
557
  CHAR **digit;
561
  CHAR **digit;
558
  CHAR *buffer;
562
  CHAR *buffer;
559
} alt_digits_t;
563
} alt_digits_t;
560
 
564
 
561
static alt_digits_t *
565
static alt_digits_t *
562
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
566
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
563
get_alt_digits (const wchar_t *alt_digits)
567
get_alt_digits (const wchar_t *alt_digits)
564
#else
568
#else
565
get_alt_digits (const char *alt_digits)
569
get_alt_digits (const char *alt_digits)
566
#endif
570
#endif
567
{
571
{
568
  alt_digits_t *adi;
572
  alt_digits_t *adi;
569
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
573
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
570
  const wchar_t *a, *e;
574
  const wchar_t *a, *e;
571
# define ALT_STRCHR(a,b)	wcschr((a),(b))
575
# define ALT_STRCHR(a,b)	wcschr((a),(b))
572
# define ALT_STRCPY(a,b)	wcscpy((a),(b))
576
# define ALT_STRCPY(a,b)	wcscpy((a),(b))
573
# define ALT_STRLEN(a)		wcslen(a)
577
# define ALT_STRLEN(a)		wcslen(a)
574
#else
578
#else
575
  const char *a, *e;
579
  const char *a, *e;
576
# define ALT_STRCHR(a,b)	strchr((a),(b))
580
# define ALT_STRCHR(a,b)	strchr((a),(b))
577
# define ALT_STRCPY(a,b)	strcpy((a),(b))
581
# define ALT_STRCPY(a,b)	strcpy((a),(b))
578
# define ALT_STRLEN(a)		strlen(a)
582
# define ALT_STRLEN(a)		strlen(a)
579
#endif
583
#endif
580
  CHAR *aa, *ae;
584
  CHAR *aa, *ae;
581
  size_t len;
585
  size_t len;
582
 
586
 
583
  adi = (alt_digits_t *) calloc (1, sizeof (alt_digits_t));
587
  adi = (alt_digits_t *) calloc (1, sizeof (alt_digits_t));
584
  if (!adi)
588
  if (!adi)
585
    return NULL;
589
    return NULL;
586
 
590
 
587
  /* Compute number of alt_digits. */
591
  /* Compute number of alt_digits. */
588
  adi->num = 1;
592
  adi->num = 1;
589
  for (a = alt_digits; (e = ALT_STRCHR (a, ';')) != NULL; a = e + 1)
593
  for (a = alt_digits; (e = ALT_STRCHR (a, ';')) != NULL; a = e + 1)
590
      ++adi->num;
594
      ++adi->num;
591
  /* Allocate the `digit' array, which is an array of `num' pointers into
595
  /* Allocate the `digit' array, which is an array of `num' pointers into
592
     `buffer'. */
596
     `buffer'. */
593
  adi->digit = (CHAR **) calloc (adi->num, sizeof (CHAR **));
597
  adi->digit = (CHAR **) calloc (adi->num, sizeof (CHAR **));
594
  if (!adi->digit)
598
  if (!adi->digit)
595
    {
599
    {
596
      free (adi);
600
      free (adi);
597
      return NULL;
601
      return NULL;
598
    }
602
    }
599
  /* Compute memory required for `buffer'. */
603
  /* Compute memory required for `buffer'. */
600
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
604
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
601
  len = mbstowcs (NULL, alt_digits, 0);
605
  len = mbstowcs (NULL, alt_digits, 0);
602
  if (len == (size_t) -1)
606
  if (len == (size_t) -1)
603
    {
607
    {
604
      free (adi->digit);
608
      free (adi->digit);
605
      free (adi);
609
      free (adi);
606
      return NULL;
610
      return NULL;
607
    }
611
    }
608
#else
612
#else
609
  len = ALT_STRLEN (alt_digits);
613
  len = ALT_STRLEN (alt_digits);
610
#endif
614
#endif
611
  /* Allocate it. */
615
  /* Allocate it. */
612
  adi->buffer = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
616
  adi->buffer = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
613
  if (!adi->buffer)
617
  if (!adi->buffer)
614
    {
618
    {
615
      free (adi->digit);
619
      free (adi->digit);
616
      free (adi);
620
      free (adi);
617
      return NULL;
621
      return NULL;
618
    }
622
    }
619
  /* Store digits in it. */
623
  /* Store digits in it. */
620
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
624
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
621
  mbstowcs (adi->buffer, alt_digits, len + 1);
625
  mbstowcs (adi->buffer, alt_digits, len + 1);
622
#else
626
#else
623
  ALT_STRCPY (adi->buffer, alt_digits);
627
  ALT_STRCPY (adi->buffer, alt_digits);
624
#endif
628
#endif
625
  /* Store the pointers into `buffer' into the appropriate `digit' slot. */
629
  /* Store the pointers into `buffer' into the appropriate `digit' slot. */
626
  for (len = 0, aa = adi->buffer; (ae = STRCHR (aa, CQ(';'))) != NULL;
630
  for (len = 0, aa = adi->buffer; (ae = STRCHR (aa, CQ(';'))) != NULL;
627
       ++len, aa = ae + 1)
631
       ++len, aa = ae + 1)
628
    {
632
    {
629
      *ae = '\0';
633
      *ae = '\0';
630
      adi->digit[len] = aa;
634
      adi->digit[len] = aa;
631
    }
635
    }
632
  adi->digit[len] = aa;
636
  adi->digit[len] = aa;
633
  return adi;
637
  return adi;
634
}
638
}
635
 
639
 
636
static void
640
static void
637
free_alt_digits (alt_digits_t *adi)
641
free_alt_digits (alt_digits_t *adi)
638
{
642
{
639
  free (adi->digit);
643
  free (adi->digit);
640
  free (adi->buffer);
644
  free (adi->buffer);
641
  free (adi);
645
  free (adi);
642
}
646
}
643
 
647
 
644
/* Return 0 if no alt_digit is available for a number.
648
/* Return 0 if no alt_digit is available for a number.
645
   Return -1 if buffer size isn't sufficient to hold alternative digit.
649
   Return -1 if buffer size isn't sufficient to hold alternative digit.
646
   Return length of new digit otherwise. */
650
   Return length of new digit otherwise. */
647
static int
651
static int
648
conv_to_alt_digits (CHAR *buf, size_t bufsiz, unsigned num, alt_digits_t *adi)
652
conv_to_alt_digits (CHAR *buf, size_t bufsiz, unsigned num, alt_digits_t *adi)
649
{
653
{
650
  if (num < adi->num)
654
  if (num < adi->num)
651
    {
655
    {
652
      size_t len = STRLEN (adi->digit[num]);
656
      size_t len = STRLEN (adi->digit[num]);
653
      if (bufsiz < len)
657
      if (bufsiz < len)
654
      	return -1;
658
      	return -1;
655
      STRCPY (buf, adi->digit[num]);
659
      STRCPY (buf, adi->digit[num]);
656
      return (int) len;
660
      return (int) len;
657
    }
661
    }
658
  return 0;
662
  return 0;
659
}
663
}
660
 
664
 
661
static size_t __strftime (CHAR *, size_t, const CHAR *, const struct tm *,
665
static size_t __strftime (CHAR *, size_t, const CHAR *, const struct tm *,
662
			  era_info_t **, alt_digits_t **);
666
			  era_info_t **, alt_digits_t **);
663
 
667
 
664
size_t
668
size_t
665
_DEFUN (strftime, (s, maxsize, format, tim_p),
669
_DEFUN (strftime, (s, maxsize, format, tim_p),
666
	CHAR *__restrict s _AND
670
	CHAR *__restrict s _AND
667
	size_t maxsize _AND
671
	size_t maxsize _AND
668
	_CONST CHAR *__restrict format _AND
672
	_CONST CHAR *__restrict format _AND
669
	_CONST struct tm *__restrict tim_p)
673
	_CONST struct tm *__restrict tim_p)
670
{
674
{
671
  era_info_t *era_info = NULL;
675
  era_info_t *era_info = NULL;
672
  alt_digits_t *alt_digits = NULL;
676
  alt_digits_t *alt_digits = NULL;
673
  size_t ret = __strftime (s, maxsize, format, tim_p, &era_info, &alt_digits);
677
  size_t ret = __strftime (s, maxsize, format, tim_p, &era_info, &alt_digits);
674
  if (era_info)
678
  if (era_info)
675
    free_era_info (era_info);
679
    free_era_info (era_info);
676
  if (alt_digits)
680
  if (alt_digits)
677
    free_alt_digits (alt_digits);
681
    free_alt_digits (alt_digits);
678
  return ret;
682
  return ret;
679
}
683
}
680
 
684
 
681
static size_t
685
static size_t
682
__strftime (CHAR *s, size_t maxsize, const CHAR *format,
686
__strftime (CHAR *s, size_t maxsize, const CHAR *format,
683
	    const struct tm *tim_p, era_info_t **era_info,
687
	    const struct tm *tim_p, era_info_t **era_info,
684
	    alt_digits_t **alt_digits)
688
	    alt_digits_t **alt_digits)
685
#else /* !_WANT_C99_TIME_FORMATS */
689
#else /* !_WANT_C99_TIME_FORMATS */
686
# define __strftime(s,m,f,t,e,a)	strftime((s),(m),(f),(t))
690
# define __strftime(s,m,f,t,e,a)	strftime((s),(m),(f),(t))
687
 
691
 
688
size_t
692
size_t
689
_DEFUN (strftime, (s, maxsize, format, tim_p),
693
_DEFUN (strftime, (s, maxsize, format, tim_p),
690
	CHAR *__restrict s _AND
694
	CHAR *__restrict s _AND
691
	size_t maxsize _AND
695
	size_t maxsize _AND
692
	_CONST CHAR *__restrict format _AND
696
	_CONST CHAR *__restrict format _AND
693
	_CONST struct tm *__restrict tim_p)
697
	_CONST struct tm *__restrict tim_p)
694
#endif /* !_WANT_C99_TIME_FORMATS */
698
#endif /* !_WANT_C99_TIME_FORMATS */
695
{
699
{
696
  size_t count = 0;
700
  size_t count = 0;
697
  int i, len = 0;
701
  int len = 0;
698
  const CHAR *ctloc;
702
  const CHAR *ctloc;
699
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
703
#if defined (MAKE_WCSFTIME) && !defined (__HAVE_LOCALE_INFO_EXTENDED__)
700
  CHAR ctlocbuf[CTLOCBUFLEN];
704
  CHAR ctlocbuf[CTLOCBUFLEN];
701
#endif
705
#endif
702
  size_t ctloclen;
706
  size_t i, ctloclen;
703
  CHAR alt;
707
  CHAR alt;
704
  CHAR pad;
708
  CHAR pad;
705
  unsigned long width;
709
  unsigned long width;
-
 
710
  int tzset_called = 0;
706
 
711
 
707
  struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale ();
712
  struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale ();
708
  for (;;)
713
  for (;;)
709
    {
714
    {
710
      while (*format && *format != CQ('%'))
715
      while (*format && *format != CQ('%'))
711
	{
716
	{
712
	  if (count < maxsize - 1)
717
	  if (count < maxsize - 1)
713
	    s[count++] = *format++;
718
	    s[count++] = *format++;
714
	  else
719
	  else
715
	    return 0;
720
	    return 0;
716
	}
721
	}
717
      if (*format == CQ('\0'))
722
      if (*format == CQ('\0'))
718
	break;
723
	break;
719
      format++;
724
      format++;
720
      pad = '\0';
725
      pad = '\0';
721
      width = 0;
726
      width = 0;
722
 
727
 
723
      /* POSIX-1.2008 feature: '0' and '+' modifiers require 0-padding with
728
      /* POSIX-1.2008 feature: '0' and '+' modifiers require 0-padding with
724
         slightly different semantics. */
729
         slightly different semantics. */
725
      if (*format == CQ('0') || *format == CQ('+'))
730
      if (*format == CQ('0') || *format == CQ('+'))
726
	pad = *format++;
731
	pad = *format++;
727
 
732
 
728
      /* POSIX-1.2008 feature: A minimum field width can be specified. */
733
      /* POSIX-1.2008 feature: A minimum field width can be specified. */
729
      if (*format >= CQ('1') && *format <= CQ('9'))
734
      if (*format >= CQ('1') && *format <= CQ('9'))
730
      	{
735
      	{
731
	  CHAR *fp;
736
	  CHAR *fp;
732
	  width = STRTOUL (format, &fp, 10);
737
	  width = STRTOUL (format, &fp, 10);
733
	  format = fp;
738
	  format = fp;
734
	}
739
	}
735
 
740
 
736
      alt = CQ('\0');
741
      alt = CQ('\0');
737
      if (*format == CQ('E'))
742
      if (*format == CQ('E'))
738
	{
743
	{
739
	  alt = *format++;
744
	  alt = *format++;
740
#ifdef _WANT_C99_TIME_FORMATS      
745
#ifdef _WANT_C99_TIME_FORMATS
741
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
746
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
742
	  if (!*era_info && *_CurrentTimeLocale->wera)
747
	  if (!*era_info && *_CurrentTimeLocale->wera)
743
	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->wera);
748
	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->wera);
744
#else
749
#else
745
	  if (!*era_info && *_CurrentTimeLocale->era)
750
	  if (!*era_info && *_CurrentTimeLocale->era)
746
	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->era);
751
	    *era_info = get_era_info (tim_p, _CurrentTimeLocale->era);
747
#endif
752
#endif
748
#endif /* _WANT_C99_TIME_FORMATS */
753
#endif /* _WANT_C99_TIME_FORMATS */
749
	}
754
	}
750
      else if (*format == CQ('O'))
755
      else if (*format == CQ('O'))
751
	{
756
	{
752
	  alt = *format++;
757
	  alt = *format++;
753
#ifdef _WANT_C99_TIME_FORMATS      
758
#ifdef _WANT_C99_TIME_FORMATS
754
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
759
#if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
755
	  if (!*alt_digits && *_CurrentTimeLocale->walt_digits)
760
	  if (!*alt_digits && *_CurrentTimeLocale->walt_digits)
756
	    *alt_digits = get_alt_digits (_CurrentTimeLocale->walt_digits);
761
	    *alt_digits = get_alt_digits (_CurrentTimeLocale->walt_digits);
757
#else
762
#else
758
	  if (!*alt_digits && *_CurrentTimeLocale->alt_digits)
763
	  if (!*alt_digits && *_CurrentTimeLocale->alt_digits)
759
	    *alt_digits = get_alt_digits (_CurrentTimeLocale->alt_digits);
764
	    *alt_digits = get_alt_digits (_CurrentTimeLocale->alt_digits);
760
#endif
765
#endif
761
#endif /* _WANT_C99_TIME_FORMATS */
766
#endif /* _WANT_C99_TIME_FORMATS */
762
	}
767
	}
763
 
768
 
764
      switch (*format)
769
      switch (*format)
765
	{
770
	{
766
	case CQ('a'):
771
	case CQ('a'):
767
	  _ctloc (wday[tim_p->tm_wday]);
772
	  _ctloc (wday[tim_p->tm_wday]);
768
	  for (i = 0; i < ctloclen; i++)
773
	  for (i = 0; i < ctloclen; i++)
769
	    {
774
	    {
770
	      if (count < maxsize - 1)
775
	      if (count < maxsize - 1)
771
		s[count++] = ctloc[i];
776
		s[count++] = ctloc[i];
772
	      else
777
	      else
773
		return 0;
778
		return 0;
774
	    }
779
	    }
775
	  break;
780
	  break;
776
	case CQ('A'):
781
	case CQ('A'):
777
	  _ctloc (weekday[tim_p->tm_wday]);
782
	  _ctloc (weekday[tim_p->tm_wday]);
778
	  for (i = 0; i < ctloclen; i++)
783
	  for (i = 0; i < ctloclen; i++)
779
	    {
784
	    {
780
	      if (count < maxsize - 1)
785
	      if (count < maxsize - 1)
781
		s[count++] = ctloc[i];
786
		s[count++] = ctloc[i];
782
	      else
787
	      else
783
		return 0;
788
		return 0;
784
	    }
789
	    }
785
	  break;
790
	  break;
786
	case CQ('b'):
791
	case CQ('b'):
787
	case CQ('h'):
792
	case CQ('h'):
788
	  _ctloc (mon[tim_p->tm_mon]);
793
	  _ctloc (mon[tim_p->tm_mon]);
789
	  for (i = 0; i < ctloclen; i++)
794
	  for (i = 0; i < ctloclen; i++)
790
	    {
795
	    {
791
	      if (count < maxsize - 1)
796
	      if (count < maxsize - 1)
792
		s[count++] = ctloc[i];
797
		s[count++] = ctloc[i];
793
	      else
798
	      else
794
		return 0;
799
		return 0;
795
	    }
800
	    }
796
	  break;
801
	  break;
797
	case CQ('B'):
802
	case CQ('B'):
798
	  _ctloc (month[tim_p->tm_mon]);
803
	  _ctloc (month[tim_p->tm_mon]);
799
	  for (i = 0; i < ctloclen; i++)
804
	  for (i = 0; i < ctloclen; i++)
800
	    {
805
	    {
801
	      if (count < maxsize - 1)
806
	      if (count < maxsize - 1)
802
		s[count++] = ctloc[i];
807
		s[count++] = ctloc[i];
803
	      else
808
	      else
804
		return 0;
809
		return 0;
805
	    }
810
	    }
806
	  break;
811
	  break;
807
	case CQ('c'):
812
	case CQ('c'):
808
#ifdef _WANT_C99_TIME_FORMATS
813
#ifdef _WANT_C99_TIME_FORMATS
809
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_t_fmt)
814
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_t_fmt)
810
	    _ctloc (era_d_t_fmt);
815
	    _ctloc (era_d_t_fmt);
811
	  else
816
	  else
812
#endif /* _WANT_C99_TIME_FORMATS */
817
#endif /* _WANT_C99_TIME_FORMATS */
813
	    _ctloc (c_fmt);
818
	    _ctloc (c_fmt);
814
	  goto recurse;
819
	  goto recurse;
815
	case CQ('r'):
820
	case CQ('r'):
816
	  _ctloc (ampm_fmt);
821
	  _ctloc (ampm_fmt);
817
	  goto recurse;
822
	  goto recurse;
818
	case CQ('x'):
823
	case CQ('x'):
819
#ifdef _WANT_C99_TIME_FORMATS
824
#ifdef _WANT_C99_TIME_FORMATS
820
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_fmt)
825
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_fmt)
821
	    _ctloc (era_d_fmt);
826
	    _ctloc (era_d_fmt);
822
	  else
827
	  else
823
#endif /* _WANT_C99_TIME_FORMATS */
828
#endif /* _WANT_C99_TIME_FORMATS */
824
	    _ctloc (x_fmt);
829
	    _ctloc (x_fmt);
825
	  goto recurse;
830
	  goto recurse;
826
	case CQ('X'):
831
	case CQ('X'):
827
#ifdef _WANT_C99_TIME_FORMATS
832
#ifdef _WANT_C99_TIME_FORMATS
828
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_t_fmt)
833
	  if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_t_fmt)
829
	    _ctloc (era_t_fmt);
834
	    _ctloc (era_t_fmt);
830
	  else
835
	  else
831
#endif /* _WANT_C99_TIME_FORMATS */
836
#endif /* _WANT_C99_TIME_FORMATS */
832
	    _ctloc (X_fmt);
837
	    _ctloc (X_fmt);
833
recurse:
838
recurse:
834
	  if (*ctloc)
839
	  if (*ctloc)
835
	    {
840
	    {
836
	      /* Recurse to avoid need to replicate %Y formation. */
841
	      /* Recurse to avoid need to replicate %Y formation. */
837
	      len = __strftime (&s[count], maxsize - count, ctloc, tim_p,
842
	      len = __strftime (&s[count], maxsize - count, ctloc, tim_p,
838
				era_info, alt_digits);
843
				era_info, alt_digits);
839
	      if (len > 0)
844
	      if (len > 0)
840
		count += len;
845
		count += len;
841
	      else
846
	      else
842
		return 0;
847
		return 0;
843
	    }
848
	    }
844
	  break;
849
	  break;
845
	case CQ('C'):
850
	case CQ('C'):
846
	  {
851
	  {
847
	    /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
852
	    /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
848
	       with 32-bit int.
853
	       with 32-bit int.
849
	       %Y		%C		%y
854
	       %Y		%C		%y
850
	       2147485547	21474855	47
855
	       2147485547	21474855	47
851
	       10000		100		00
856
	       10000		100		00
852
	       9999		99		99
857
	       9999		99		99
853
	       0999		09		99
858
	       0999		09		99
854
	       0099		00		99
859
	       0099		00		99
855
	       0001		00		01
860
	       0001		00		01
856
	       0000		00		00
861
	       0000		00		00
857
	       -001		-0		01
862
	       -001		-0		01
858
	       -099		-0		99
863
	       -099		-0		99
859
	       -999		-9		99
864
	       -999		-9		99
860
	       -1000		-10		00
865
	       -1000		-10		00
861
	       -10000		-100		00
866
	       -10000		-100		00
862
	       -2147481748	-21474817	48
867
	       -2147481748	-21474817	48
863
 
868
 
864
	       Be careful of both overflow and sign adjustment due to the
869
	       Be careful of both overflow and sign adjustment due to the
865
	       asymmetric range of years.
870
	       asymmetric range of years.
866
	    */
871
	    */
867
#ifdef _WANT_C99_TIME_FORMATS
872
#ifdef _WANT_C99_TIME_FORMATS
868
	    if (alt == 'E' && *era_info)
873
	    if (alt == 'E' && *era_info)
869
	      len = snprintf (&s[count], maxsize - count, CQ("%" SFLG "s"),
874
	      len = snprintf (&s[count], maxsize - count, CQ("%" SFLG "s"),
870
			      (*era_info)->era_C);
875
			      (*era_info)->era_C);
871
	    else
876
	    else
872
#endif /* _WANT_C99_TIME_FORMATS */
877
#endif /* _WANT_C99_TIME_FORMATS */
873
	      {
878
	      {
874
		CHAR *fmt = CQ("%s%.*d");
879
		CHAR *fmt = CQ("%s%.*d");
875
		char *pos = "";
880
		char *pos = "";
876
		int neg = tim_p->tm_year < -YEAR_BASE;
881
		int neg = tim_p->tm_year < -YEAR_BASE;
877
		int century = tim_p->tm_year >= 0
882
		int century = tim_p->tm_year >= 0
878
		  ? tim_p->tm_year / 100 + YEAR_BASE / 100
883
		  ? tim_p->tm_year / 100 + YEAR_BASE / 100
879
		  : abs (tim_p->tm_year + YEAR_BASE) / 100;
884
		  : abs (tim_p->tm_year + YEAR_BASE) / 100;
880
		if (pad) /* '0' or '+' */
885
		if (pad) /* '0' or '+' */
881
		  {
886
		  {
882
		    fmt = CQ("%s%0.*d");
887
		    fmt = CQ("%s%0.*d");
883
		    if (century >= 100 && pad == CQ('+'))
888
		    if (century >= 100 && pad == CQ('+'))
884
		      pos = "+";
889
		      pos = "+";
885
		  }
890
		  }
886
		if (width < 2)
891
		if (width < 2)
887
		  width = 2;
892
		  width = 2;
888
		len = snprintf (&s[count], maxsize - count, fmt,
893
		len = snprintf (&s[count], maxsize - count, fmt,
889
				neg ? "-" : pos, width - neg, century);
894
				neg ? "-" : pos, width - neg, century);
890
	      }
895
	      }
891
            CHECK_LENGTH ();
896
            CHECK_LENGTH ();
892
	  }
897
	  }
893
	  break;
898
	  break;
894
	case CQ('d'):
899
	case CQ('d'):
895
	case CQ('e'):
900
	case CQ('e'):
896
#ifdef _WANT_C99_TIME_FORMATS
901
#ifdef _WANT_C99_TIME_FORMATS
897
	  if (alt == CQ('O') && *alt_digits)
902
	  if (alt == CQ('O') && *alt_digits)
898
	    {
903
	    {
899
	      if (tim_p->tm_mday < 10)
904
	      if (tim_p->tm_mday < 10)
900
	      	{
905
	      	{
901
		  if (*format == CQ('d'))
906
		  if (*format == CQ('d'))
902
		    {
907
		    {
903
		      if (maxsize - count < 2) return 0;
908
		      if (maxsize - count < 2) return 0;
904
		      len = conv_to_alt_digits (&s[count], maxsize - count,
909
		      len = conv_to_alt_digits (&s[count], maxsize - count,
905
						0, *alt_digits);
910
						0, *alt_digits);
906
		      CHECK_LENGTH ();
911
		      CHECK_LENGTH ();
907
		    }
912
		    }
908
		  if (*format == CQ('e') || len == 0)
913
		  if (*format == CQ('e') || len == 0)
909
		    s[count++] = CQ(' ');
914
		    s[count++] = CQ(' ');
910
		}
915
		}
911
	      len = conv_to_alt_digits (&s[count], maxsize - count,
916
	      len = conv_to_alt_digits (&s[count], maxsize - count,
912
					tim_p->tm_mday, *alt_digits);
917
					tim_p->tm_mday, *alt_digits);
913
	      CHECK_LENGTH ();
918
	      CHECK_LENGTH ();
914
	      if (len > 0)
919
	      if (len > 0)
915
		break;
920
		break;
916
	    }
921
	    }
917
#endif /* _WANT_C99_TIME_FORMATS */
922
#endif /* _WANT_C99_TIME_FORMATS */
918
	  len = snprintf (&s[count], maxsize - count,
923
	  len = snprintf (&s[count], maxsize - count,
919
			  *format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
924
			  *format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
920
			  tim_p->tm_mday);
925
			  tim_p->tm_mday);
921
	  CHECK_LENGTH ();
926
	  CHECK_LENGTH ();
922
	  break;
927
	  break;
923
	case CQ('D'):
928
	case CQ('D'):
924
	  /* %m/%d/%y */
929
	  /* %m/%d/%y */
925
	  len = snprintf (&s[count], maxsize - count,
930
	  len = snprintf (&s[count], maxsize - count,
926
			  CQ("%.2d/%.2d/%.2d"),
931
			  CQ("%.2d/%.2d/%.2d"),
927
			  tim_p->tm_mon + 1, tim_p->tm_mday,
932
			  tim_p->tm_mon + 1, tim_p->tm_mday,
928
			  tim_p->tm_year >= 0 ? tim_p->tm_year % 100
933
			  tim_p->tm_year >= 0 ? tim_p->tm_year % 100
929
			  : abs (tim_p->tm_year + YEAR_BASE) % 100);
934
			  : abs (tim_p->tm_year + YEAR_BASE) % 100);
930
          CHECK_LENGTH ();
935
          CHECK_LENGTH ();
931
	  break;
936
	  break;
932
	case CQ('F'):
937
	case CQ('F'):
933
	  { /* %F is equivalent to "%+4Y-%m-%d", flags and width can change
938
	  { /* %F is equivalent to "%+4Y-%m-%d", flags and width can change
934
	       that.  Recurse to avoid need to replicate %Y formation. */
939
	       that.  Recurse to avoid need to replicate %Y formation. */
935
	    CHAR fmtbuf[32], *fmt = fmtbuf;
940
	    CHAR fmtbuf[32], *fmt = fmtbuf;
936
	    
941
 
937
	    *fmt++ = CQ('%');
942
	    *fmt++ = CQ('%');
938
	    if (pad) /* '0' or '+' */
943
	    if (pad) /* '0' or '+' */
939
	      *fmt++ = pad;
944
	      *fmt++ = pad;
940
	    else
945
	    else
941
	      *fmt++ = '+';
946
	      *fmt++ = '+';
942
	    if (!pad)
947
	    if (!pad)
943
	      width = 10;
948
	      width = 10;
944
	    if (width < 6)
949
	    if (width < 6)
945
	      width = 6;
950
	      width = 6;
946
	    width -= 6;
951
	    width -= 6;
947
	    if (width)
952
	    if (width)
948
	      {
953
	      {
949
		len = snprintf (fmt, fmtbuf + 32 - fmt, CQ("%lu"), width);
954
		len = snprintf (fmt, fmtbuf + 32 - fmt, CQ("%lu"), width);
950
		if (len > 0)
955
		if (len > 0)
951
		  fmt += len;
956
		  fmt += len;
952
	      }
957
	      }
953
	    STRCPY (fmt, CQ("Y-%m-%d"));
958
	    STRCPY (fmt, CQ("Y-%m-%d"));
954
	    len = __strftime (&s[count], maxsize - count, fmtbuf, tim_p,
959
	    len = __strftime (&s[count], maxsize - count, fmtbuf, tim_p,
955
			      era_info, alt_digits);
960
			      era_info, alt_digits);
956
	    if (len > 0)
961
	    if (len > 0)
957
	      count += len;
962
	      count += len;
958
	    else
963
	    else
959
	      return 0;
964
	      return 0;
960
	  }
965
	  }
961
          break;
966
          break;
962
	case CQ('g'):
967
	case CQ('g'):
963
	  /* Be careful of both overflow and negative years, thanks to
968
	  /* Be careful of both overflow and negative years, thanks to
964
		 the asymmetric range of years.  */
969
		 the asymmetric range of years.  */
965
	  {
970
	  {
966
	    int adjust = iso_year_adjust (tim_p);
971
	    int adjust = iso_year_adjust (tim_p);
967
	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
972
	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
968
		: abs (tim_p->tm_year + YEAR_BASE) % 100;
973
		: abs (tim_p->tm_year + YEAR_BASE) % 100;
969
	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
974
	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
970
		adjust = 1;
975
		adjust = 1;
971
	    else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
976
	    else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
972
		adjust = -1;
977
		adjust = -1;
973
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
978
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
974
			    ((year + adjust) % 100 + 100) % 100);
979
			    ((year + adjust) % 100 + 100) % 100);
975
            CHECK_LENGTH ();
980
            CHECK_LENGTH ();
976
	  }
981
	  }
977
          break;
982
          break;
978
	case CQ('G'):
983
	case CQ('G'):
979
	  {
984
	  {
980
	    /* See the comments for 'C' and 'Y'; this is a variable length
985
	    /* See the comments for 'C' and 'Y'; this is a variable length
981
	       field.  Although there is no requirement for a minimum number
986
	       field.  Although there is no requirement for a minimum number
982
	       of digits, we use 4 for consistency with 'Y'.  */
987
	       of digits, we use 4 for consistency with 'Y'.  */
983
	    int sign = tim_p->tm_year < -YEAR_BASE;
988
	    int sign = tim_p->tm_year < -YEAR_BASE;
984
	    int adjust = iso_year_adjust (tim_p);
989
	    int adjust = iso_year_adjust (tim_p);
985
	    int century = tim_p->tm_year >= 0
990
	    int century = tim_p->tm_year >= 0
986
	      ? tim_p->tm_year / 100 + YEAR_BASE / 100
991
	      ? tim_p->tm_year / 100 + YEAR_BASE / 100
987
	      : abs (tim_p->tm_year + YEAR_BASE) / 100;
992
	      : abs (tim_p->tm_year + YEAR_BASE) / 100;
988
	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
993
	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
989
	      : abs (tim_p->tm_year + YEAR_BASE) % 100;
994
	      : abs (tim_p->tm_year + YEAR_BASE) % 100;
990
	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
995
	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
991
	      sign = adjust = 1;
996
	      sign = adjust = 1;
992
	    else if (adjust > 0 && sign)
997
	    else if (adjust > 0 && sign)
993
	      adjust = -1;
998
	      adjust = -1;
994
	    year += adjust;
999
	    year += adjust;
995
	    if (year == -1)
1000
	    if (year == -1)
996
	      {
1001
	      {
997
		year = 99;
1002
		year = 99;
998
		--century;
1003
		--century;
999
	      }
1004
	      }
1000
	    else if (year == 100)
1005
	    else if (year == 100)
1001
	      {
1006
	      {
1002
		year = 0;
1007
		year = 0;
1003
		++century;
1008
		++century;
1004
	      }
1009
	      }
1005
	    CHAR fmtbuf[10], *fmt = fmtbuf;
1010
	    CHAR fmtbuf[10], *fmt = fmtbuf;
1006
	    /* int potentially overflows, so use unsigned instead.  */
1011
	    /* int potentially overflows, so use unsigned instead.  */
1007
	    unsigned p_year = century * 100 + year;
1012
	    unsigned p_year = century * 100 + year;
1008
	    if (sign)
1013
	    if (sign)
1009
	      *fmt++ = CQ('-');
1014
	      *fmt++ = CQ('-');
1010
	    else if (pad == CQ('+') && p_year >= 10000)
1015
	    else if (pad == CQ('+') && p_year >= 10000)
1011
	      {
1016
	      {
1012
		*fmt++ = CQ('+');
1017
		*fmt++ = CQ('+');
1013
		sign = 1;
1018
		sign = 1;
1014
	      }
1019
	      }
1015
	    if (width && sign)
1020
	    if (width && sign)
1016
	      --width;
1021
	      --width;
1017
	    *fmt++ = CQ('%');
1022
	    *fmt++ = CQ('%');
1018
	    if (pad)
1023
	    if (pad)
1019
	      *fmt++ = CQ('0');
1024
	      *fmt++ = CQ('0');
1020
	    STRCPY (fmt, CQ(".*u"));
1025
	    STRCPY (fmt, CQ(".*u"));
1021
	    len = snprintf (&s[count], maxsize - count, fmtbuf, width, p_year);
1026
	    len = snprintf (&s[count], maxsize - count, fmtbuf, width, p_year);
1022
            if (len < 0  ||  (count+=len) >= maxsize)
1027
            if (len < 0  ||  (count+=len) >= maxsize)
1023
              return 0;
1028
              return 0;
1024
	  }
1029
	  }
1025
          break;
1030
          break;
1026
	case CQ('H'):
1031
	case CQ('H'):
1027
#ifdef _WANT_C99_TIME_FORMATS
1032
#ifdef _WANT_C99_TIME_FORMATS
1028
	  if (alt == CQ('O') && *alt_digits)
1033
	  if (alt == CQ('O') && *alt_digits)
1029
	    {
1034
	    {
1030
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1035
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1031
					tim_p->tm_hour, *alt_digits);
1036
					tim_p->tm_hour, *alt_digits);
1032
	      CHECK_LENGTH ();
1037
	      CHECK_LENGTH ();
1033
	      if (len > 0)
1038
	      if (len > 0)
1034
		break;
1039
		break;
1035
	    }
1040
	    }
1036
#endif /* _WANT_C99_TIME_FORMATS */
1041
#endif /* _WANT_C99_TIME_FORMATS */
1037
	  /*FALLTHRU*/
1042
	  /*FALLTHRU*/
1038
	case CQ('k'):	/* newlib extension */
1043
	case CQ('k'):	/* newlib extension */
1039
	  len = snprintf (&s[count], maxsize - count,
1044
	  len = snprintf (&s[count], maxsize - count,
1040
			  *format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
1045
			  *format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
1041
			  tim_p->tm_hour);
1046
			  tim_p->tm_hour);
1042
          CHECK_LENGTH ();
1047
          CHECK_LENGTH ();
1043
	  break;
1048
	  break;
1044
	case CQ('l'):	/* newlib extension */
1049
	case CQ('l'):	/* newlib extension */
1045
	  if (alt == CQ('O'))
1050
	  if (alt == CQ('O'))
1046
	    alt = CQ('\0');
1051
	    alt = CQ('\0');
1047
	  /*FALLTHRU*/
1052
	  /*FALLTHRU*/
1048
	case CQ('I'):
1053
	case CQ('I'):
1049
	  {
1054
	  {
1050
	    register int  h12;
1055
	    register int  h12;
1051
	    h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
1056
	    h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
1052
						12  :  tim_p->tm_hour % 12;
1057
						12  :  tim_p->tm_hour % 12;
1053
#ifdef _WANT_C99_TIME_FORMATS
1058
#ifdef _WANT_C99_TIME_FORMATS
1054
	    if (alt != CQ('O') || !*alt_digits
1059
	    if (alt != CQ('O') || !*alt_digits
1055
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1060
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1056
					       h12, *alt_digits)))
1061
					       h12, *alt_digits)))
1057
#endif /* _WANT_C99_TIME_FORMATS */
1062
#endif /* _WANT_C99_TIME_FORMATS */
1058
	      len = snprintf (&s[count], maxsize - count,
1063
	      len = snprintf (&s[count], maxsize - count,
1059
			      *format == CQ('I') ? CQ("%.2d") : CQ("%2d"), h12);
1064
			      *format == CQ('I') ? CQ("%.2d") : CQ("%2d"), h12);
1060
	    CHECK_LENGTH ();
1065
	    CHECK_LENGTH ();
1061
	  }
1066
	  }
1062
	  break;
1067
	  break;
1063
	case CQ('j'):
1068
	case CQ('j'):
1064
	  len = snprintf (&s[count], maxsize - count, CQ("%.3d"),
1069
	  len = snprintf (&s[count], maxsize - count, CQ("%.3d"),
1065
			  tim_p->tm_yday + 1);
1070
			  tim_p->tm_yday + 1);
1066
          CHECK_LENGTH ();
1071
          CHECK_LENGTH ();
1067
	  break;
1072
	  break;
1068
	case CQ('m'):
1073
	case CQ('m'):
1069
#ifdef _WANT_C99_TIME_FORMATS
1074
#ifdef _WANT_C99_TIME_FORMATS
1070
	  if (alt != CQ('O') || !*alt_digits
1075
	  if (alt != CQ('O') || !*alt_digits
1071
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1076
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1072
					     tim_p->tm_mon + 1, *alt_digits)))
1077
					     tim_p->tm_mon + 1, *alt_digits)))
1073
#endif /* _WANT_C99_TIME_FORMATS */
1078
#endif /* _WANT_C99_TIME_FORMATS */
1074
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1079
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1075
			    tim_p->tm_mon + 1);
1080
			    tim_p->tm_mon + 1);
1076
          CHECK_LENGTH ();
1081
          CHECK_LENGTH ();
1077
	  break;
1082
	  break;
1078
	case CQ('M'):
1083
	case CQ('M'):
1079
#ifdef _WANT_C99_TIME_FORMATS
1084
#ifdef _WANT_C99_TIME_FORMATS
1080
	  if (alt != CQ('O') || !*alt_digits
1085
	  if (alt != CQ('O') || !*alt_digits
1081
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1086
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1082
					     tim_p->tm_min, *alt_digits)))
1087
					     tim_p->tm_min, *alt_digits)))
1083
#endif /* _WANT_C99_TIME_FORMATS */
1088
#endif /* _WANT_C99_TIME_FORMATS */
1084
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1089
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1085
			    tim_p->tm_min);
1090
			    tim_p->tm_min);
1086
          CHECK_LENGTH ();
1091
          CHECK_LENGTH ();
1087
	  break;
1092
	  break;
1088
	case CQ('n'):
1093
	case CQ('n'):
1089
	  if (count < maxsize - 1)
1094
	  if (count < maxsize - 1)
1090
	    s[count++] = CQ('\n');
1095
	    s[count++] = CQ('\n');
1091
	  else
1096
	  else
1092
	    return 0;
1097
	    return 0;
1093
	  break;
1098
	  break;
1094
	case CQ('p'):
1099
	case CQ('p'):
1095
	case CQ('P'):
1100
	case CQ('P'):
1096
	  _ctloc (am_pm[tim_p->tm_hour < 12 ? 0 : 1]);
1101
	  _ctloc (am_pm[tim_p->tm_hour < 12 ? 0 : 1]);
1097
	  for (i = 0; i < ctloclen; i++)
1102
	  for (i = 0; i < ctloclen; i++)
1098
	    {
1103
	    {
1099
	      if (count < maxsize - 1)
1104
	      if (count < maxsize - 1)
1100
		s[count++] = (*format == CQ('P') ? TOLOWER (ctloc[i])
1105
		s[count++] = (*format == CQ('P') ? TOLOWER (ctloc[i])
1101
						 : ctloc[i]);
1106
						 : ctloc[i]);
1102
	      else
1107
	      else
1103
		return 0;
1108
		return 0;
1104
	    }
1109
	    }
1105
	  break;
1110
	  break;
1106
	case CQ('R'):
1111
	case CQ('R'):
1107
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
1112
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
1108
			  tim_p->tm_hour, tim_p->tm_min);
1113
			  tim_p->tm_hour, tim_p->tm_min);
1109
          CHECK_LENGTH ();
1114
          CHECK_LENGTH ();
1110
          break;
1115
          break;
-
 
1116
	case CQ('s'):
-
 
1117
/*
-
 
1118
 * From:
-
 
1119
 * The Open Group Base Specifications Issue 7
-
 
1120
 * IEEE Std 1003.1, 2013 Edition
-
 
1121
 * Copyright (c) 2001-2013 The IEEE and The Open Group
-
 
1122
 * XBD Base Definitions
-
 
1123
 * 4. General Concepts
-
 
1124
 * 4.15 Seconds Since the Epoch
-
 
1125
 * A value that approximates the number of seconds that have elapsed since the
-
 
1126
 * Epoch. A Coordinated Universal Time name (specified in terms of seconds
-
 
1127
 * (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year
-
 
1128
 * (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time
-
 
1129
 * represented as seconds since the Epoch, according to the expression below.
-
 
1130
 * If the year is <1970 or the value is negative, the relationship is undefined.
-
 
1131
 * If the year is >=1970 and the value is non-negative, the value is related to a
-
 
1132
 * Coordinated Universal Time name according to the C-language expression, where
-
 
1133
 * tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all integer types:
-
 
1134
 * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
-
 
1135
 *     (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
-
 
1136
 *     ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
-
 
1137
 * OR
-
 
1138
 * ((((tm_year-69)/4 - (tm_year-1)/100 + (tm_year+299)/400 +
-
 
1139
 *         (tm_year-70)*365 + tm_yday)*24 + tm_hour)*60 + tm_min)*60 + tm_sec
-
 
1140
 */
-
 
1141
/* modified from %z case by hoisting offset outside if block and initializing */
-
 
1142
	  {
-
 
1143
	    long offset = 0;	/* offset < 0 => W of GMT, > 0 => E of GMT:
-
 
1144
				   subtract to get UTC */
-
 
1145
 
-
 
1146
	    if (tim_p->tm_isdst >= 0)
-
 
1147
	      {
-
 
1148
		TZ_LOCK;
-
 
1149
		if (!tzset_called)
-
 
1150
		  {
-
 
1151
		    _tzset_unlocked ();
-
 
1152
		    tzset_called = 1;
-
 
1153
		  }
-
 
1154
 
-
 
1155
#if defined (__CYGWIN__)
-
 
1156
		/* Cygwin must check if the application has been built with or
-
 
1157
		   without the extra tm members for backward compatibility, and
-
 
1158
		   then use either that or the old method fetching from tzinfo.
-
 
1159
		   Rather than pulling in the version check infrastructure, we
-
 
1160
		   just call a Cygwin function. */
-
 
1161
		extern long __cygwin_gettzoffset (const struct tm *tmp);
-
 
1162
		offset = __cygwin_gettzoffset (tim_p);
-
 
1163
#elif defined (__TM_GMTOFF)
-
 
1164
		offset = tim_p->__TM_GMTOFF;
-
 
1165
#else
-
 
1166
		__tzinfo_type *tz = __gettzinfo ();
-
 
1167
		/* The sign of this is exactly opposite the envvar TZ.  We
-
 
1168
		   could directly use the global _timezone for tm_isdst==0,
-
 
1169
		   but have to use __tzrule for daylight savings.  */
-
 
1170
		offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
-
 
1171
#endif
-
 
1172
		TZ_UNLOCK;
-
 
1173
	      }
-
 
1174
	    len = snprintf (&s[count], maxsize - count, CQ("%lld"),
-
 
1175
			    (((((long long)tim_p->tm_year - 69)/4
-
 
1176
				- (tim_p->tm_year - 1)/100
-
 
1177
				+ (tim_p->tm_year + 299)/400
-
 
1178
				+ (tim_p->tm_year - 70)*365 + tim_p->tm_yday)*24
-
 
1179
			      + tim_p->tm_hour)*60 + tim_p->tm_min)*60
-
 
1180
			    + tim_p->tm_sec - offset);
-
 
1181
	    CHECK_LENGTH ();
-
 
1182
	  }
-
 
1183
          break;
1111
	case CQ('S'):
1184
	case CQ('S'):
1112
#ifdef _WANT_C99_TIME_FORMATS
1185
#ifdef _WANT_C99_TIME_FORMATS
1113
	  if (alt != CQ('O') || !*alt_digits
1186
	  if (alt != CQ('O') || !*alt_digits
1114
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1187
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1115
					     tim_p->tm_sec, *alt_digits)))
1188
					     tim_p->tm_sec, *alt_digits)))
1116
#endif /* _WANT_C99_TIME_FORMATS */
1189
#endif /* _WANT_C99_TIME_FORMATS */
1117
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1190
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1118
			    tim_p->tm_sec);
1191
			    tim_p->tm_sec);
1119
          CHECK_LENGTH ();
1192
          CHECK_LENGTH ();
1120
	  break;
1193
	  break;
1121
	case CQ('t'):
1194
	case CQ('t'):
1122
	  if (count < maxsize - 1)
1195
	  if (count < maxsize - 1)
1123
	    s[count++] = CQ('\t');
1196
	    s[count++] = CQ('\t');
1124
	  else
1197
	  else
1125
  return 0;
1198
	    return 0;
1126
	  break;
1199
	  break;
1127
	case CQ('T'):
1200
	case CQ('T'):
1128
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
1201
          len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
1129
			  tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
1202
			  tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
1130
          CHECK_LENGTH ();
1203
          CHECK_LENGTH ();
1131
          break;
1204
          break;
1132
	case CQ('u'):
1205
	case CQ('u'):
1133
#ifdef _WANT_C99_TIME_FORMATS
1206
#ifdef _WANT_C99_TIME_FORMATS
1134
	  if (alt == CQ('O') && *alt_digits)
1207
	  if (alt == CQ('O') && *alt_digits)
1135
	    {
1208
	    {
1136
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1209
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1137
					tim_p->tm_wday == 0 ? 7
1210
					tim_p->tm_wday == 0 ? 7
1138
							    : tim_p->tm_wday,
1211
							    : tim_p->tm_wday,
1139
					*alt_digits);
1212
					*alt_digits);
1140
	      CHECK_LENGTH ();
1213
	      CHECK_LENGTH ();
1141
	      if (len > 0)
1214
	      if (len > 0)
1142
		break;
1215
		break;
1143
	    }
1216
	    }
1144
#endif /* _WANT_C99_TIME_FORMATS */
1217
#endif /* _WANT_C99_TIME_FORMATS */
1145
          if (count < maxsize - 1)
1218
          if (count < maxsize - 1)
1146
            {
1219
            {
1147
              if (tim_p->tm_wday == 0)
1220
              if (tim_p->tm_wday == 0)
1148
                s[count++] = CQ('7');
1221
                s[count++] = CQ('7');
1149
              else
1222
              else
1150
                s[count++] = CQ('0') + tim_p->tm_wday;
1223
                s[count++] = CQ('0') + tim_p->tm_wday;
1151
            }
1224
            }
1152
          else
1225
          else
1153
            return 0;
1226
            return 0;
1154
          break;
1227
          break;
1155
	case CQ('U'):
1228
	case CQ('U'):
1156
#ifdef _WANT_C99_TIME_FORMATS
1229
#ifdef _WANT_C99_TIME_FORMATS
1157
	  if (alt != CQ('O') || !*alt_digits
1230
	  if (alt != CQ('O') || !*alt_digits
1158
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1231
	      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1159
					     (tim_p->tm_yday + 7 -
1232
					     (tim_p->tm_yday + 7 -
1160
					      tim_p->tm_wday) / 7,
1233
					      tim_p->tm_wday) / 7,
1161
					     *alt_digits)))
1234
					     *alt_digits)))
1162
#endif /* _WANT_C99_TIME_FORMATS */
1235
#endif /* _WANT_C99_TIME_FORMATS */
1163
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1236
	    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1164
			 (tim_p->tm_yday + 7 -
1237
			 (tim_p->tm_yday + 7 -
1165
			  tim_p->tm_wday) / 7);
1238
			  tim_p->tm_wday) / 7);
1166
          CHECK_LENGTH ();
1239
          CHECK_LENGTH ();
1167
	  break;
1240
	  break;
1168
	case CQ('V'):
1241
	case CQ('V'):
1169
	  {
1242
	  {
1170
	    int adjust = iso_year_adjust (tim_p);
1243
	    int adjust = iso_year_adjust (tim_p);
1171
	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1244
	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1172
	    int week = (tim_p->tm_yday + 10 - wday) / 7;
1245
	    int week = (tim_p->tm_yday + 10 - wday) / 7;
1173
	    if (adjust > 0)
1246
	    if (adjust > 0)
1174
		week = 1;
1247
		week = 1;
1175
	    else if (adjust < 0)
1248
	    else if (adjust < 0)
1176
		/* Previous year has 53 weeks if current year starts on
1249
		/* Previous year has 53 weeks if current year starts on
1177
		   Fri, and also if current year starts on Sat and
1250
		   Fri, and also if current year starts on Sat and
1178
		   previous year was leap year.  */
1251
		   previous year was leap year.  */
1179
		week = 52 + (4 >= (wday - tim_p->tm_yday
1252
		week = 52 + (4 >= (wday - tim_p->tm_yday
1180
				   - isleap (tim_p->tm_year
1253
				   - isleap (tim_p->tm_year
1181
					     + (YEAR_BASE - 1
1254
					     + (YEAR_BASE - 1
1182
						- (tim_p->tm_year < 0
1255
						- (tim_p->tm_year < 0
1183
						   ? 0 : 2000)))));
1256
						   ? 0 : 2000)))));
1184
#ifdef _WANT_C99_TIME_FORMATS
1257
#ifdef _WANT_C99_TIME_FORMATS
1185
	    if (alt != CQ('O') || !*alt_digits
1258
	    if (alt != CQ('O') || !*alt_digits
1186
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1259
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1187
					       week, *alt_digits)))
1260
					       week, *alt_digits)))
1188
#endif /* _WANT_C99_TIME_FORMATS */
1261
#endif /* _WANT_C99_TIME_FORMATS */
1189
	      len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
1262
	      len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
1190
            CHECK_LENGTH ();
1263
            CHECK_LENGTH ();
1191
	  }
1264
	  }
1192
          break;
1265
          break;
1193
	case CQ('w'):
1266
	case CQ('w'):
1194
#ifdef _WANT_C99_TIME_FORMATS
1267
#ifdef _WANT_C99_TIME_FORMATS
1195
	  if (alt == CQ('O') && *alt_digits)
1268
	  if (alt == CQ('O') && *alt_digits)
1196
	    {
1269
	    {
1197
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1270
	      len = conv_to_alt_digits (&s[count], maxsize - count,
1198
					tim_p->tm_wday, *alt_digits);
1271
					tim_p->tm_wday, *alt_digits);
1199
	      CHECK_LENGTH ();
1272
	      CHECK_LENGTH ();
1200
	      if (len > 0)
1273
	      if (len > 0)
1201
		break;
1274
		break;
1202
	    }
1275
	    }
1203
#endif /* _WANT_C99_TIME_FORMATS */
1276
#endif /* _WANT_C99_TIME_FORMATS */
1204
	  if (count < maxsize - 1)
1277
	  if (count < maxsize - 1)
1205
            s[count++] = CQ('0') + tim_p->tm_wday;
1278
            s[count++] = CQ('0') + tim_p->tm_wday;
1206
	  else
1279
	  else
1207
	    return 0;
1280
	    return 0;
1208
	  break;
1281
	  break;
1209
	case CQ('W'):
1282
	case CQ('W'):
1210
	  {
1283
	  {
1211
	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1284
	    int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
1212
	    wday = (tim_p->tm_yday + 7 - wday) / 7;
1285
	    wday = (tim_p->tm_yday + 7 - wday) / 7;
1213
#ifdef _WANT_C99_TIME_FORMATS
1286
#ifdef _WANT_C99_TIME_FORMATS
1214
	    if (alt != CQ('O') || !*alt_digits
1287
	    if (alt != CQ('O') || !*alt_digits
1215
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1288
		|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
1216
					       wday, *alt_digits)))
1289
					       wday, *alt_digits)))
1217
#endif /* _WANT_C99_TIME_FORMATS */
1290
#endif /* _WANT_C99_TIME_FORMATS */
1218
	      len = snprintf (&s[count], maxsize - count, CQ("%.2d"), wday);
1291
	      len = snprintf (&s[count], maxsize - count, CQ("%.2d"), wday);
1219
            CHECK_LENGTH ();
1292
            CHECK_LENGTH ();
1220
	  }
1293
	  }
1221
	  break;
1294
	  break;
1222
	case CQ('y'):
1295
	case CQ('y'):
1223
	    {
1296
	    {
1224
#ifdef _WANT_C99_TIME_FORMATS
1297
#ifdef _WANT_C99_TIME_FORMATS
1225
	      if (alt == 'E' && *era_info)
1298
	      if (alt == 'E' && *era_info)
1226
		len = snprintf (&s[count], maxsize - count, CQ("%d"),
1299
		len = snprintf (&s[count], maxsize - count, CQ("%d"),
1227
				(*era_info)->year);
1300
				(*era_info)->year);
1228
	      else
1301
	      else
1229
#endif /* _WANT_C99_TIME_FORMATS */
1302
#endif /* _WANT_C99_TIME_FORMATS */
1230
		{
1303
		{
1231
		  /* Be careful of both overflow and negative years, thanks to
1304
		  /* Be careful of both overflow and negative years, thanks to
1232
		     the asymmetric range of years.  */
1305
		     the asymmetric range of years.  */
1233
		  int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1306
		  int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
1234
			     : abs (tim_p->tm_year + YEAR_BASE) % 100;
1307
			     : abs (tim_p->tm_year + YEAR_BASE) % 100;
1235
#ifdef _WANT_C99_TIME_FORMATS
1308
#ifdef _WANT_C99_TIME_FORMATS
1236
		  if (alt != CQ('O') || !*alt_digits
1309
		  if (alt != CQ('O') || !*alt_digits
1237
		      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1310
		      || !(len = conv_to_alt_digits (&s[count], maxsize - count,
1238
						     year, *alt_digits)))
1311
						     year, *alt_digits)))
1239
#endif /* _WANT_C99_TIME_FORMATS */
1312
#endif /* _WANT_C99_TIME_FORMATS */
1240
		    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1313
		    len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
1241
				    year);
1314
				    year);
1242
		}
1315
		}
1243
              CHECK_LENGTH ();
1316
              CHECK_LENGTH ();
1244
	    }
1317
	    }
1245
	  break;
1318
	  break;
1246
	case CQ('Y'):
1319
	case CQ('Y'):
1247
#ifdef _WANT_C99_TIME_FORMATS
1320
#ifdef _WANT_C99_TIME_FORMATS
1248
	  if (alt == 'E' && *era_info)
1321
	  if (alt == 'E' && *era_info)
1249
	    {
1322
	    {
1250
	      ctloc = (*era_info)->era_Y;
1323
	      ctloc = (*era_info)->era_Y;
1251
	      goto recurse;
1324
	      goto recurse;
1252
	    }
1325
	    }
1253
	  else
1326
	  else
1254
#endif /* _WANT_C99_TIME_FORMATS */
1327
#endif /* _WANT_C99_TIME_FORMATS */
1255
	    {
1328
	    {
1256
	      CHAR fmtbuf[10], *fmt = fmtbuf;
1329
	      CHAR fmtbuf[10], *fmt = fmtbuf;
1257
	      int sign = tim_p->tm_year < -YEAR_BASE;
1330
	      int sign = tim_p->tm_year < -YEAR_BASE;
1258
	      /* int potentially overflows, so use unsigned instead.  */
1331
	      /* int potentially overflows, so use unsigned instead.  */
1259
	      register unsigned year = (unsigned) tim_p->tm_year
1332
	      register unsigned year = (unsigned) tim_p->tm_year
1260
				       + (unsigned) YEAR_BASE;
1333
				       + (unsigned) YEAR_BASE;
1261
	      if (sign)
1334
	      if (sign)
1262
		{
1335
		{
1263
		  *fmt++ = CQ('-');
1336
		  *fmt++ = CQ('-');
1264
		  year = UINT_MAX - year + 1;
1337
		  year = UINT_MAX - year + 1;
1265
		}
1338
		}
1266
	      else if (pad == CQ('+') && year >= 10000)
1339
	      else if (pad == CQ('+') && year >= 10000)
1267
		{
1340
		{
1268
		  *fmt++ = CQ('+');
1341
		  *fmt++ = CQ('+');
1269
		  sign = 1;
1342
		  sign = 1;
1270
		}
1343
		}
1271
	      if (width && sign)
1344
	      if (width && sign)
1272
		--width;
1345
		--width;
1273
	      *fmt++ = CQ('%');
1346
	      *fmt++ = CQ('%');
1274
	      if (pad)
1347
	      if (pad)
1275
		*fmt++ = CQ('0');
1348
		*fmt++ = CQ('0');
1276
	      STRCPY (fmt, CQ(".*u"));
1349
	      STRCPY (fmt, CQ(".*u"));
1277
	      len = snprintf (&s[count], maxsize - count, fmtbuf, width,
1350
	      len = snprintf (&s[count], maxsize - count, fmtbuf, width,
1278
			      year);
1351
			      year);
1279
	      CHECK_LENGTH ();
1352
	      CHECK_LENGTH ();
1280
	    }
1353
	    }
1281
	  break;
1354
	  break;
1282
	case CQ('z'):
1355
	case CQ('z'):
1283
          if (tim_p->tm_isdst >= 0)
1356
          if (tim_p->tm_isdst >= 0)
1284
            {
1357
            {
1285
	      long offset;
1358
	      long offset;
1286
	      __tzinfo_type *tz = __gettzinfo ();
-
 
-
 
1359
 
1287
	      TZ_LOCK;
1360
	      TZ_LOCK;
-
 
1361
	      if (!tzset_called)
-
 
1362
		{
-
 
1363
		  _tzset_unlocked ();
-
 
1364
		  tzset_called = 1;
-
 
1365
		}
-
 
1366
 
-
 
1367
#if defined (__CYGWIN__)
-
 
1368
	      /* Cygwin must check if the application has been built with or
-
 
1369
		 without the extra tm members for backward compatibility, and
-
 
1370
		 then use either that or the old method fetching from tzinfo.
-
 
1371
		 Rather than pulling in the version check infrastructure, we
-
 
1372
		 just call a Cygwin function. */
-
 
1373
	      extern long __cygwin_gettzoffset (const struct tm *tmp);
-
 
1374
	      offset = __cygwin_gettzoffset (tim_p);
-
 
1375
#elif defined (__TM_GMTOFF)
-
 
1376
	      offset = tim_p->__TM_GMTOFF;
-
 
1377
#else
-
 
1378
	      __tzinfo_type *tz = __gettzinfo ();
1288
	      /* The sign of this is exactly opposite the envvar TZ.  We
1379
	      /* The sign of this is exactly opposite the envvar TZ.  We
1289
	         could directly use the global _timezone for tm_isdst==0,
1380
		 could directly use the global _timezone for tm_isdst==0,
1290
	         but have to use __tzrule for daylight savings.  */
1381
		 but have to use __tzrule for daylight savings.  */
1291
	      offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
1382
	      offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
-
 
1383
#endif
1292
	      TZ_UNLOCK;
1384
	      TZ_UNLOCK;
1293
	      len = snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
1385
	      len = snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
1294
			      offset / SECSPERHOUR,
1386
			      offset / SECSPERHOUR,
1295
			      labs (offset / SECSPERMIN) % 60L);
1387
			      labs (offset / SECSPERMIN) % 60L);
1296
              CHECK_LENGTH ();
1388
              CHECK_LENGTH ();
1297
            }
1389
            }
1298
          break;
1390
          break;
1299
	case CQ('Z'):
1391
	case CQ('Z'):
1300
	  if (tim_p->tm_isdst >= 0)
1392
	  if (tim_p->tm_isdst >= 0)
1301
	    {
1393
	    {
1302
	      int size;
1394
	      size_t size;
-
 
1395
	      const char *tznam = NULL;
-
 
1396
 
1303
	      TZ_LOCK;
1397
	      TZ_LOCK;
-
 
1398
	      if (!tzset_called)
-
 
1399
		{
-
 
1400
		  _tzset_unlocked ();
-
 
1401
		  tzset_called = 1;
-
 
1402
		}
-
 
1403
#if defined (__CYGWIN__)
-
 
1404
	      /* See above. */
-
 
1405
	      extern const char *__cygwin_gettzname (const struct tm *tmp);
-
 
1406
	      tznam = __cygwin_gettzname (tim_p);
-
 
1407
#elif defined (__TM_ZONE)
-
 
1408
	      tznam = tim_p->__TM_ZONE;
-
 
1409
#endif
-
 
1410
	      if (!tznam)
1304
	      size = strlen(_tzname[tim_p->tm_isdst > 0]);
1411
		tznam = _tzname[tim_p->tm_isdst > 0];
-
 
1412
	      /* Note that in case of wcsftime this loop only works for
-
 
1413
	         timezone abbreviations using the portable codeset (aka ASCII).
-
 
1414
		 This seems to be the case, but if that ever changes, this
-
 
1415
		 loop needs revisiting. */
-
 
1416
	      size = strlen (tznam);
1305
	      for (i = 0; i < size; i++)
1417
	      for (i = 0; i < size; i++)
1306
		{
1418
		{
1307
		  if (count < maxsize - 1)
1419
		  if (count < maxsize - 1)
1308
		    s[count++] = _tzname[tim_p->tm_isdst > 0][i];
1420
		    s[count++] = tznam[i];
1309
		  else
1421
		  else
1310
		    {
1422
		    {
1311
		      TZ_UNLOCK;
1423
		      TZ_UNLOCK;
1312
		      return 0;
1424
		      return 0;
1313
		    }
1425
		    }
1314
		}
1426
		}
1315
	      TZ_UNLOCK;
1427
	      TZ_UNLOCK;
1316
	    }
1428
	    }
1317
	  break;
1429
	  break;
1318
	case CQ('%'):
1430
	case CQ('%'):
1319
	  if (count < maxsize - 1)
1431
	  if (count < maxsize - 1)
1320
	    s[count++] = CQ('%');
1432
	    s[count++] = CQ('%');
1321
	  else
1433
	  else
1322
	    return 0;
1434
	    return 0;
1323
	  break;
1435
	  break;
1324
	default:
1436
	default:
1325
	  return 0;
1437
	  return 0;
1326
	}
1438
	}
1327
      if (*format)
1439
      if (*format)
1328
	format++;
1440
	format++;
1329
      else
1441
      else
1330
	break;
1442
	break;
1331
    }
1443
    }
1332
  if (maxsize)
1444
  if (maxsize)
1333
    s[count] = CQ('\0');
1445
    s[count] = CQ('\0');
1334
 
1446
 
1335
  return count;
1447
  return count;
1336
}
1448
}
1337
 
1449
 
1338
/* The remainder of this file can serve as a regression test.  Compile
1450
/* The remainder of this file can serve as a regression test.  Compile
1339
 *  with -D_REGRESSION_TEST.  */
1451
 *  with -D_REGRESSION_TEST.  */
1340
#if defined(_REGRESSION_TEST)	/* [Test code:  */
1452
#if defined(_REGRESSION_TEST)	/* [Test code:  */
1341
 
1453
 
1342
/* This test code relies on ANSI C features, in particular on the ability
1454
/* This test code relies on ANSI C features, in particular on the ability
1343
 * of adjacent strings to be pasted together into one string.  */
1455
 * of adjacent strings to be pasted together into one string.  */
1344
 
1456
 
1345
/* Test output buffer size (should be larger than all expected results) */
1457
/* Test output buffer size (should be larger than all expected results) */
1346
#define OUTSIZE	256
1458
#define OUTSIZE	256
1347
 
1459
 
1348
struct test {
1460
struct test {
1349
	CHAR  *fmt;	/* Testing format */
1461
	CHAR  *fmt;	/* Testing format */
1350
	size_t  max;	/* Testing maxsize */
1462
	size_t  max;	/* Testing maxsize */
1351
	size_t	ret;	/* Expected return value */
1463
	size_t	ret;	/* Expected return value */
1352
	CHAR  *out;	/* Expected output string */
1464
	CHAR  *out;	/* Expected output string */
1353
	};
1465
	};
1354
struct list {
1466
struct list {
1355
	const struct tm  *tms;	/* Time used for these vectors */
1467
	const struct tm  *tms;	/* Time used for these vectors */
1356
	const struct test *vec;	/* Test vectors */
1468
	const struct test *vec;	/* Test vectors */
1357
	int  cnt;		/* Number of vectors */
1469
	int  cnt;		/* Number of vectors */
1358
	};
1470
	};
1359
 
1471
 
1360
const char  TZ[]="TZ=EST5EDT";
1472
const char  TZ[]="TZ=EST5EDT";
1361
 
1473
 
1362
/* Define list of test inputs and expected outputs, for the given time zone
1474
/* Define list of test inputs and expected outputs, for the given time zone
1363
 * and time.  */
1475
 * and time.  */
1364
const struct tm  tm0 = {
1476
const struct tm  tm0 = {
1365
	/* Tue Dec 30 10:53:47 EST 2008 (time_t=1230648827) */
1477
	/* Tue Dec 30 10:53:47 EST 2008 (time_t=1230648827) */
1366
	.tm_sec 	= 47,
1478
	.tm_sec 	= 47,
1367
	.tm_min 	= 53,
1479
	.tm_min 	= 53,
1368
	.tm_hour	= 9,
1480
	.tm_hour	= 9,
1369
	.tm_mday	= 30,
1481
	.tm_mday	= 30,
1370
	.tm_mon 	= 11,
1482
	.tm_mon 	= 11,
1371
	.tm_year	= 108,
1483
	.tm_year	= 108,
1372
	.tm_wday	= 2,
1484
	.tm_wday	= 2,
1373
	.tm_yday	= 364,
1485
	.tm_yday	= 364,
1374
	.tm_isdst	= 0
1486
	.tm_isdst	= 0
1375
	};
1487
	};
1376
const struct test  Vec0[] = {
1488
const struct test  Vec0[] = {
1377
	/* Testing fields one at a time, expecting to pass, using exact
1489
	/* Testing fields one at a time, expecting to pass, using exact
1378
	 * allowed length as what is needed.  */
1490
	 * allowed length as what is needed.  */
1379
	/* Using tm0 for time: */
1491
	/* Using tm0 for time: */
1380
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1492
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1381
	{ CQ("%a"), 3+1, EXP(CQ("Tue")) },
1493
	{ CQ("%a"), 3+1, EXP(CQ("Tue")) },
1382
	{ CQ("%A"), 7+1, EXP(CQ("Tuesday")) },
1494
	{ CQ("%A"), 7+1, EXP(CQ("Tuesday")) },
1383
	{ CQ("%b"), 3+1, EXP(CQ("Dec")) },
1495
	{ CQ("%b"), 3+1, EXP(CQ("Dec")) },
1384
	{ CQ("%B"), 8+1, EXP(CQ("December")) },
1496
	{ CQ("%B"), 8+1, EXP(CQ("December")) },
1385
	{ CQ("%c"), 24+1, EXP(CQ("Tue Dec 30 09:53:47 2008")) },
1497
	{ CQ("%c"), 24+1, EXP(CQ("Tue Dec 30 09:53:47 2008")) },
1386
	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1498
	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1387
	{ CQ("%d"), 2+1, EXP(CQ("30")) },
1499
	{ CQ("%d"), 2+1, EXP(CQ("30")) },
1388
	{ CQ("%D"), 8+1, EXP(CQ("12/30/08")) },
1500
	{ CQ("%D"), 8+1, EXP(CQ("12/30/08")) },
1389
	{ CQ("%e"), 2+1, EXP(CQ("30")) },
1501
	{ CQ("%e"), 2+1, EXP(CQ("30")) },
1390
	{ CQ("%F"), 10+1, EXP(CQ("2008-12-30")) },
1502
	{ CQ("%F"), 10+1, EXP(CQ("2008-12-30")) },
1391
	{ CQ("%g"), 2+1, EXP(CQ("09")) },
1503
	{ CQ("%g"), 2+1, EXP(CQ("09")) },
1392
	{ CQ("%G"), 4+1, EXP(CQ("2009")) },
1504
	{ CQ("%G"), 4+1, EXP(CQ("2009")) },
1393
	{ CQ("%h"), 3+1, EXP(CQ("Dec")) },
1505
	{ CQ("%h"), 3+1, EXP(CQ("Dec")) },
1394
	{ CQ("%H"), 2+1, EXP(CQ("09")) },
1506
	{ CQ("%H"), 2+1, EXP(CQ("09")) },
1395
	{ CQ("%I"), 2+1, EXP(CQ("09")) },
1507
	{ CQ("%I"), 2+1, EXP(CQ("09")) },
1396
	{ CQ("%j"), 3+1, EXP(CQ("365")) },
1508
	{ CQ("%j"), 3+1, EXP(CQ("365")) },
1397
	{ CQ("%k"), 2+1, EXP(CQ(" 9")) },
1509
	{ CQ("%k"), 2+1, EXP(CQ(" 9")) },
1398
	{ CQ("%l"), 2+1, EXP(CQ(" 9")) },
1510
	{ CQ("%l"), 2+1, EXP(CQ(" 9")) },
1399
	{ CQ("%m"), 2+1, EXP(CQ("12")) },
1511
	{ CQ("%m"), 2+1, EXP(CQ("12")) },
1400
	{ CQ("%M"), 2+1, EXP(CQ("53")) },
1512
	{ CQ("%M"), 2+1, EXP(CQ("53")) },
1401
	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1513
	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1402
	{ CQ("%p"), 2+1, EXP(CQ("AM")) },
1514
	{ CQ("%p"), 2+1, EXP(CQ("AM")) },
1403
	{ CQ("%r"), 11+1, EXP(CQ("09:53:47 AM")) },
1515
	{ CQ("%r"), 11+1, EXP(CQ("09:53:47 AM")) },
1404
	{ CQ("%R"), 5+1, EXP(CQ("09:53")) },
1516
	{ CQ("%R"), 5+1, EXP(CQ("09:53")) },
-
 
1517
	{ CQ("%s"), 2+1, EXP(CQ("1230648827")) },
1405
	{ CQ("%S"), 2+1, EXP(CQ("47")) },
1518
	{ CQ("%S"), 2+1, EXP(CQ("47")) },
1406
	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1519
	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1407
	{ CQ("%T"), 8+1, EXP(CQ("09:53:47")) },
1520
	{ CQ("%T"), 8+1, EXP(CQ("09:53:47")) },
1408
	{ CQ("%u"), 1+1, EXP(CQ("2")) },
1521
	{ CQ("%u"), 1+1, EXP(CQ("2")) },
1409
	{ CQ("%U"), 2+1, EXP(CQ("52")) },
1522
	{ CQ("%U"), 2+1, EXP(CQ("52")) },
1410
	{ CQ("%V"), 2+1, EXP(CQ("01")) },
1523
	{ CQ("%V"), 2+1, EXP(CQ("01")) },
1411
	{ CQ("%w"), 1+1, EXP(CQ("2")) },
1524
	{ CQ("%w"), 1+1, EXP(CQ("2")) },
1412
	{ CQ("%W"), 2+1, EXP(CQ("52")) },
1525
	{ CQ("%W"), 2+1, EXP(CQ("52")) },
1413
	{ CQ("%x"), 8+1, EXP(CQ("12/30/08")) },
1526
	{ CQ("%x"), 8+1, EXP(CQ("12/30/08")) },
1414
	{ CQ("%X"), 8+1, EXP(CQ("09:53:47")) },
1527
	{ CQ("%X"), 8+1, EXP(CQ("09:53:47")) },
1415
	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1528
	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1416
	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1529
	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1417
	{ CQ("%z"), 5+1, EXP(CQ("-0500")) },
1530
	{ CQ("%z"), 5+1, EXP(CQ("-0500")) },
1418
	{ CQ("%Z"), 3+1, EXP(CQ("EST")) },
1531
	{ CQ("%Z"), 3+1, EXP(CQ("EST")) },
1419
	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1532
	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1420
	#undef EXP
1533
	#undef EXP
1421
	};
1534
	};
1422
/* Define list of test inputs and expected outputs, for the given time zone
1535
/* Define list of test inputs and expected outputs, for the given time zone
1423
 * and time.  */
1536
 * and time.  */
1424
const struct tm  tm1 = {
1537
const struct tm  tm1 = {
1425
	/* Wed Jul  2 23:01:13 EDT 2008 (time_t=1215054073) */
1538
	/* Wed Jul  2 23:01:13 EDT 2008 (time_t=1215054073) */
1426
	.tm_sec 	= 13,
1539
	.tm_sec 	= 13,
1427
	.tm_min 	= 1,
1540
	.tm_min 	= 1,
1428
	.tm_hour	= 23,
1541
	.tm_hour	= 23,
1429
	.tm_mday	= 2,
1542
	.tm_mday	= 2,
1430
	.tm_mon 	= 6,
1543
	.tm_mon 	= 6,
1431
	.tm_year	= 108,
1544
	.tm_year	= 108,
1432
	.tm_wday	= 3,
1545
	.tm_wday	= 3,
1433
	.tm_yday	= 183,
1546
	.tm_yday	= 183,
1434
	.tm_isdst	= 1
1547
	.tm_isdst	= 1
1435
	};
1548
	};
1436
const struct test  Vec1[] = {
1549
const struct test  Vec1[] = {
1437
	/* Testing fields one at a time, expecting to pass, using exact
1550
	/* Testing fields one at a time, expecting to pass, using exact
1438
	 * allowed length as what is needed.  */
1551
	 * allowed length as what is needed.  */
1439
	/* Using tm1 for time: */
1552
	/* Using tm1 for time: */
1440
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1553
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1441
	{ CQ("%a"), 3+1, EXP(CQ("Wed")) },
1554
	{ CQ("%a"), 3+1, EXP(CQ("Wed")) },
1442
	{ CQ("%A"), 9+1, EXP(CQ("Wednesday")) },
1555
	{ CQ("%A"), 9+1, EXP(CQ("Wednesday")) },
1443
	{ CQ("%b"), 3+1, EXP(CQ("Jul")) },
1556
	{ CQ("%b"), 3+1, EXP(CQ("Jul")) },
1444
	{ CQ("%B"), 4+1, EXP(CQ("July")) },
1557
	{ CQ("%B"), 4+1, EXP(CQ("July")) },
1445
	{ CQ("%c"), 24+1, EXP(CQ("Wed Jul  2 23:01:13 2008")) },
1558
	{ CQ("%c"), 24+1, EXP(CQ("Wed Jul  2 23:01:13 2008")) },
1446
	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1559
	{ CQ("%C"), 2+1, EXP(CQ("20")) },
1447
	{ CQ("%d"), 2+1, EXP(CQ("02")) },
1560
	{ CQ("%d"), 2+1, EXP(CQ("02")) },
1448
	{ CQ("%D"), 8+1, EXP(CQ("07/02/08")) },
1561
	{ CQ("%D"), 8+1, EXP(CQ("07/02/08")) },
1449
	{ CQ("%e"), 2+1, EXP(CQ(" 2")) },
1562
	{ CQ("%e"), 2+1, EXP(CQ(" 2")) },
1450
	{ CQ("%F"), 10+1, EXP(CQ("2008-07-02")) },
1563
	{ CQ("%F"), 10+1, EXP(CQ("2008-07-02")) },
1451
	{ CQ("%g"), 2+1, EXP(CQ("08")) },
1564
	{ CQ("%g"), 2+1, EXP(CQ("08")) },
1452
	{ CQ("%G"), 4+1, EXP(CQ("2008")) },
1565
	{ CQ("%G"), 4+1, EXP(CQ("2008")) },
1453
	{ CQ("%h"), 3+1, EXP(CQ("Jul")) },
1566
	{ CQ("%h"), 3+1, EXP(CQ("Jul")) },
1454
	{ CQ("%H"), 2+1, EXP(CQ("23")) },
1567
	{ CQ("%H"), 2+1, EXP(CQ("23")) },
1455
	{ CQ("%I"), 2+1, EXP(CQ("11")) },
1568
	{ CQ("%I"), 2+1, EXP(CQ("11")) },
1456
	{ CQ("%j"), 3+1, EXP(CQ("184")) },
1569
	{ CQ("%j"), 3+1, EXP(CQ("184")) },
1457
	{ CQ("%k"), 2+1, EXP(CQ("23")) },
1570
	{ CQ("%k"), 2+1, EXP(CQ("23")) },
1458
	{ CQ("%l"), 2+1, EXP(CQ("11")) },
1571
	{ CQ("%l"), 2+1, EXP(CQ("11")) },
1459
	{ CQ("%m"), 2+1, EXP(CQ("07")) },
1572
	{ CQ("%m"), 2+1, EXP(CQ("07")) },
1460
	{ CQ("%M"), 2+1, EXP(CQ("01")) },
1573
	{ CQ("%M"), 2+1, EXP(CQ("01")) },
1461
	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1574
	{ CQ("%n"), 1+1, EXP(CQ("\n")) },
1462
	{ CQ("%p"), 2+1, EXP(CQ("PM")) },
1575
	{ CQ("%p"), 2+1, EXP(CQ("PM")) },
1463
	{ CQ("%r"), 11+1, EXP(CQ("11:01:13 PM")) },
1576
	{ CQ("%r"), 11+1, EXP(CQ("11:01:13 PM")) },
1464
	{ CQ("%R"), 5+1, EXP(CQ("23:01")) },
1577
	{ CQ("%R"), 5+1, EXP(CQ("23:01")) },
-
 
1578
	{ CQ("%s"), 2+1, EXP(CQ("1215054073")) },
1465
	{ CQ("%S"), 2+1, EXP(CQ("13")) },
1579
	{ CQ("%S"), 2+1, EXP(CQ("13")) },
1466
	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1580
	{ CQ("%t"), 1+1, EXP(CQ("\t")) },
1467
	{ CQ("%T"), 8+1, EXP(CQ("23:01:13")) },
1581
	{ CQ("%T"), 8+1, EXP(CQ("23:01:13")) },
1468
	{ CQ("%u"), 1+1, EXP(CQ("3")) },
1582
	{ CQ("%u"), 1+1, EXP(CQ("3")) },
1469
	{ CQ("%U"), 2+1, EXP(CQ("26")) },
1583
	{ CQ("%U"), 2+1, EXP(CQ("26")) },
1470
	{ CQ("%V"), 2+1, EXP(CQ("27")) },
1584
	{ CQ("%V"), 2+1, EXP(CQ("27")) },
1471
	{ CQ("%w"), 1+1, EXP(CQ("3")) },
1585
	{ CQ("%w"), 1+1, EXP(CQ("3")) },
1472
	{ CQ("%W"), 2+1, EXP(CQ("26")) },
1586
	{ CQ("%W"), 2+1, EXP(CQ("26")) },
1473
	{ CQ("%x"), 8+1, EXP(CQ("07/02/08")) },
1587
	{ CQ("%x"), 8+1, EXP(CQ("07/02/08")) },
1474
	{ CQ("%X"), 8+1, EXP(CQ("23:01:13")) },
1588
	{ CQ("%X"), 8+1, EXP(CQ("23:01:13")) },
1475
	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1589
	{ CQ("%y"), 2+1, EXP(CQ("08")) },
1476
	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1590
	{ CQ("%Y"), 4+1, EXP(CQ("2008")) },
1477
	{ CQ("%z"), 5+1, EXP(CQ("-0400")) },
1591
	{ CQ("%z"), 5+1, EXP(CQ("-0400")) },
1478
	{ CQ("%Z"), 3+1, EXP(CQ("EDT")) },
1592
	{ CQ("%Z"), 3+1, EXP(CQ("EDT")) },
1479
	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1593
	{ CQ("%%"), 1+1, EXP(CQ("%")) },
1480
	#undef EXP
1594
	#undef EXP
1481
	#define VEC(s)	s, sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1595
	#define VEC(s)	s, sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1482
	#define EXP(s)	sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1596
	#define EXP(s)	sizeof(s)/sizeof(CHAR), sizeof(s)/sizeof(CHAR)-1, s
1483
	{ VEC(CQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) },
1597
	{ VEC(CQ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) },
1484
	{ CQ("0123456789%%%h:`~"), EXP(CQ("0123456789%Jul:`~")) },
1598
	{ CQ("0123456789%%%h:`~"), EXP(CQ("0123456789%Jul:`~")) },
1485
	{ CQ("%R%h:`~ %x %w"), EXP(CQ("23:01Jul:`~ 07/02/08 3")) },
1599
	{ CQ("%R%h:`~ %x %w"), EXP(CQ("23:01Jul:`~ 07/02/08 3")) },
1486
	#undef VEC
1600
	#undef VEC
1487
	#undef EXP
1601
	#undef EXP
1488
	};
1602
	};
1489
 
1603
 
1490
#if YEAR_BASE == 1900  /* ( */
1604
#if YEAR_BASE == 1900  /* ( */
1491
/* Checks for very large years.  YEAR_BASE value relied upon so that the
1605
/* Checks for very large years.  YEAR_BASE value relied upon so that the
1492
 * answer strings can be predetermined.
1606
 * answer strings can be predetermined.
1493
 * Years more than 4 digits are not mentioned in the standard for %C, so the
1607
 * Years more than 4 digits are not mentioned in the standard for %C, so the
1494
 * test for those cases are based on the design intent (which is to print the
1608
 * test for those cases are based on the design intent (which is to print the
1495
 * whole number, being the century).  */
1609
 * whole number, being the century).  */
1496
const struct tm  tmyr0 = {
1610
const struct tm  tmyr0 = {
1497
	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1611
	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1498
	.tm_sec 	= 13,
1612
	.tm_sec 	= 13,
1499
	.tm_min 	= 1,
1613
	.tm_min 	= 1,
1500
	.tm_hour	= 23,
1614
	.tm_hour	= 23,
1501
	.tm_mday	= 2,
1615
	.tm_mday	= 2,
1502
	.tm_mon 	= 6,
1616
	.tm_mon 	= 6,
1503
	.tm_year	= INT_MAX - YEAR_BASE/2,
1617
	.tm_year	= INT_MAX - YEAR_BASE/2,
1504
	.tm_wday	= 3,
1618
	.tm_wday	= 3,
1505
	.tm_yday	= 183,
1619
	.tm_yday	= 183,
1506
	.tm_isdst	= 1
1620
	.tm_isdst	= 1
1507
	};
1621
	};
1508
#if INT_MAX == 32767
1622
#if INT_MAX == 32767
1509
#  define YEAR	CQ("33717")		/* INT_MAX + YEAR_BASE/2 */
1623
#  define YEAR	CQ("33717")		/* INT_MAX + YEAR_BASE/2 */
1510
#  define CENT	CQ("337")
1624
#  define CENT	CQ("337")
1511
#  define Year	   CQ("17")
1625
#  define Year	   CQ("17")
1512
# elif INT_MAX == 2147483647
1626
# elif INT_MAX == 2147483647
1513
#  define YEAR	CQ("2147484597")
1627
#  define YEAR	CQ("2147484597")
1514
#  define CENT	CQ("21474845")
1628
#  define CENT	CQ("21474845")
1515
#  define Year	        CQ("97")
1629
#  define Year	        CQ("97")
1516
# elif INT_MAX == 9223372036854775807
1630
# elif INT_MAX == 9223372036854775807
1517
#  define YEAR	CQ("9223372036854776757")
1631
#  define YEAR	CQ("9223372036854776757")
1518
#  define CENT	CQ("92233720368547777")
1632
#  define CENT	CQ("92233720368547777")
1519
#  define Year	                 CQ("57")
1633
#  define Year	                 CQ("57")
1520
# else
1634
# else
1521
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1635
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1522
#endif
1636
#endif
1523
const struct test  Vecyr0[] = {
1637
const struct test  Vecyr0[] = {
1524
	/* Testing fields one at a time, expecting to pass, using a larger
1638
	/* Testing fields one at a time, expecting to pass, using a larger
1525
	 * allowed length than what is needed.  */
1639
	 * allowed length than what is needed.  */
1526
	/* Using tmyr0 for time: */
1640
	/* Using tmyr0 for time: */
1527
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1641
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1528
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1642
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1529
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1643
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1530
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1644
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1531
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1645
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1532
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1646
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1533
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1647
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1534
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1648
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1535
	#undef EXP
1649
	#undef EXP
1536
	};
1650
	};
1537
#undef YEAR
1651
#undef YEAR
1538
#undef CENT
1652
#undef CENT
1539
#undef Year
1653
#undef Year
1540
/* Checks for very large negative years.  YEAR_BASE value relied upon so that
1654
/* Checks for very large negative years.  YEAR_BASE value relied upon so that
1541
 * the answer strings can be predetermined.  */
1655
 * the answer strings can be predetermined.  */
1542
const struct tm  tmyr1 = {
1656
const struct tm  tmyr1 = {
1543
	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1657
	/* Wed Jul  2 23:01:13 EDT [HUGE#] */
1544
	.tm_sec 	= 13,
1658
	.tm_sec 	= 13,
1545
	.tm_min 	= 1,
1659
	.tm_min 	= 1,
1546
	.tm_hour	= 23,
1660
	.tm_hour	= 23,
1547
	.tm_mday	= 2,
1661
	.tm_mday	= 2,
1548
	.tm_mon 	= 6,
1662
	.tm_mon 	= 6,
1549
	.tm_year	= INT_MIN,
1663
	.tm_year	= INT_MIN,
1550
	.tm_wday	= 3,
1664
	.tm_wday	= 3,
1551
	.tm_yday	= 183,
1665
	.tm_yday	= 183,
1552
	.tm_isdst	= 1
1666
	.tm_isdst	= 1
1553
	};
1667
	};
1554
#if INT_MAX == 32767
1668
#if INT_MAX == 32767
1555
#  define YEAR	CQ("-30868")		/* INT_MIN + YEAR_BASE */
1669
#  define YEAR	CQ("-30868")		/* INT_MIN + YEAR_BASE */
1556
#  define CENT	CQ("-308")
1670
#  define CENT	CQ("-308")
1557
#  define Year	    CQ("68")
1671
#  define Year	    CQ("68")
1558
# elif INT_MAX == 2147483647
1672
# elif INT_MAX == 2147483647
1559
#  define YEAR	CQ("-2147481748")
1673
#  define YEAR	CQ("-2147481748")
1560
#  define CENT	CQ("-21474817")
1674
#  define CENT	CQ("-21474817")
1561
#  define Year	         CQ("48")
1675
#  define Year	         CQ("48")
1562
# elif INT_MAX == 9223372036854775807
1676
# elif INT_MAX == 9223372036854775807
1563
#  define YEAR	CQ("-9223372036854773908")
1677
#  define YEAR	CQ("-9223372036854773908")
1564
#  define CENT	CQ("-92233720368547739")
1678
#  define CENT	CQ("-92233720368547739")
1565
#  define Year	                  CQ("08")
1679
#  define Year	                  CQ("08")
1566
# else
1680
# else
1567
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1681
#  error "Unrecognized INT_MAX value:  enhance me to recognize what you have"
1568
#endif
1682
#endif
1569
const struct test  Vecyr1[] = {
1683
const struct test  Vecyr1[] = {
1570
	/* Testing fields one at a time, expecting to pass, using a larger
1684
	/* Testing fields one at a time, expecting to pass, using a larger
1571
	 * allowed length than what is needed.  */
1685
	 * allowed length than what is needed.  */
1572
	/* Using tmyr1 for time: */
1686
	/* Using tmyr1 for time: */
1573
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1687
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1574
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1688
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1575
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1689
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:13 ")YEAR) },
1576
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1690
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1577
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1691
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1578
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1692
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1579
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1693
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1580
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1694
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1581
	#undef EXP
1695
	#undef EXP
1582
	};
1696
	};
1583
#undef YEAR
1697
#undef YEAR
1584
#undef CENT
1698
#undef CENT
1585
#undef Year
1699
#undef Year
1586
#endif /* YEAR_BASE ) */
1700
#endif /* YEAR_BASE ) */
1587
 
1701
 
1588
/* Checks for years just over zero (also test for s=60).
1702
/* Checks for years just over zero (also test for s=60).
1589
 * Years less than 4 digits are not mentioned for %Y in the standard, so the
1703
 * Years less than 4 digits are not mentioned for %Y in the standard, so the
1590
 * test for that case is based on the design intent.  */
1704
 * test for that case is based on the design intent.  */
1591
const struct tm  tmyrzp = {
1705
const struct tm  tmyrzp = {
1592
	/* Wed Jul  2 23:01:60 EDT 0007 */
1706
	/* Wed Jul  2 23:01:60 EDT 0007 */
1593
	.tm_sec 	= 60,
1707
	.tm_sec 	= 60,
1594
	.tm_min 	= 1,
1708
	.tm_min 	= 1,
1595
	.tm_hour	= 23,
1709
	.tm_hour	= 23,
1596
	.tm_mday	= 2,
1710
	.tm_mday	= 2,
1597
	.tm_mon 	= 6,
1711
	.tm_mon 	= 6,
1598
	.tm_year	= 7-YEAR_BASE,
1712
	.tm_year	= 7-YEAR_BASE,
1599
	.tm_wday	= 3,
1713
	.tm_wday	= 3,
1600
	.tm_yday	= 183,
1714
	.tm_yday	= 183,
1601
	.tm_isdst	= 1
1715
	.tm_isdst	= 1
1602
	};
1716
	};
1603
#define YEAR	CQ("0007")	/* Design intent:  %Y=%C%y */
1717
#define YEAR	CQ("0007")	/* Design intent:  %Y=%C%y */
1604
#define CENT	CQ("00")
1718
#define CENT	CQ("00")
1605
#define Year	  CQ("07")
1719
#define Year	  CQ("07")
1606
const struct test  Vecyrzp[] = {
1720
const struct test  Vecyrzp[] = {
1607
	/* Testing fields one at a time, expecting to pass, using a larger
1721
	/* Testing fields one at a time, expecting to pass, using a larger
1608
	 * allowed length than what is needed.  */
1722
	 * allowed length than what is needed.  */
1609
	/* Using tmyrzp for time: */
1723
	/* Using tmyrzp for time: */
1610
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1724
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1611
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1725
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1612
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:60 ")YEAR) },
1726
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:60 ")YEAR) },
1613
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1727
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1614
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1728
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1615
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1729
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1616
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1730
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1617
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1731
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1618
	#undef EXP
1732
	#undef EXP
1619
	};
1733
	};
1620
#undef YEAR
1734
#undef YEAR
1621
#undef CENT
1735
#undef CENT
1622
#undef Year
1736
#undef Year
1623
/* Checks for years just under zero.
1737
/* Checks for years just under zero.
1624
 * Negative years are not handled by the standard, so the vectors here are
1738
 * Negative years are not handled by the standard, so the vectors here are
1625
 * verifying the chosen implemtation.  */
1739
 * verifying the chosen implemtation.  */
1626
const struct tm  tmyrzn = {
1740
const struct tm  tmyrzn = {
1627
	/* Wed Jul  2 23:01:00 EDT -004 */
1741
	/* Wed Jul  2 23:01:00 EDT -004 */
1628
	.tm_sec 	= 00,
1742
	.tm_sec 	= 00,
1629
	.tm_min 	= 1,
1743
	.tm_min 	= 1,
1630
	.tm_hour	= 23,
1744
	.tm_hour	= 23,
1631
	.tm_mday	= 2,
1745
	.tm_mday	= 2,
1632
	.tm_mon 	= 6,
1746
	.tm_mon 	= 6,
1633
	.tm_year	= -4-YEAR_BASE,
1747
	.tm_year	= -4-YEAR_BASE,
1634
	.tm_wday	= 3,
1748
	.tm_wday	= 3,
1635
	.tm_yday	= 183,
1749
	.tm_yday	= 183,
1636
	.tm_isdst	= 1
1750
	.tm_isdst	= 1
1637
	};
1751
	};
1638
#define YEAR	CQ("-004")
1752
#define YEAR	CQ("-004")
1639
#define CENT	CQ("-0")
1753
#define CENT	CQ("-0")
1640
#define Year	  CQ("04")
1754
#define Year	  CQ("04")
1641
const struct test  Vecyrzn[] = {
1755
const struct test  Vecyrzn[] = {
1642
	/* Testing fields one at a time, expecting to pass, using a larger
1756
	/* Testing fields one at a time, expecting to pass, using a larger
1643
	 * allowed length than what is needed.  */
1757
	 * allowed length than what is needed.  */
1644
	/* Using tmyrzn for time: */
1758
	/* Using tmyrzn for time: */
1645
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1759
	#define EXP(s)	sizeof(s)/sizeof(CHAR)-1, s
1646
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1760
	{ CQ("%C"), OUTSIZE, EXP(CENT) },
1647
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:00 ")YEAR) },
1761
	{ CQ("%c"), OUTSIZE, EXP(CQ("Wed Jul  2 23:01:00 ")YEAR) },
1648
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1762
	{ CQ("%D"), OUTSIZE, EXP(CQ("07/02/")Year) },
1649
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1763
	{ CQ("%F"), OUTSIZE, EXP(YEAR CQ("-07-02")) },
1650
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1764
	{ CQ("%x"), OUTSIZE, EXP(CQ("07/02/")Year) },
1651
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1765
	{ CQ("%y"), OUTSIZE, EXP(Year) },
1652
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1766
	{ CQ("%Y"), OUTSIZE, EXP(YEAR) },
1653
	#undef EXP
1767
	#undef EXP
1654
	};
1768
	};
1655
#undef YEAR
1769
#undef YEAR
1656
#undef CENT
1770
#undef CENT
1657
#undef Year
1771
#undef Year
1658
 
1772
 
1659
const struct list  ListYr[] = {
1773
const struct list  ListYr[] = {
1660
	{ &tmyrzp, Vecyrzp, sizeof(Vecyrzp)/sizeof(Vecyrzp[0]) },
1774
	{ &tmyrzp, Vecyrzp, sizeof(Vecyrzp)/sizeof(Vecyrzp[0]) },
1661
	{ &tmyrzn, Vecyrzn, sizeof(Vecyrzn)/sizeof(Vecyrzn[0]) },
1775
	{ &tmyrzn, Vecyrzn, sizeof(Vecyrzn)/sizeof(Vecyrzn[0]) },
1662
	#if YEAR_BASE == 1900
1776
	#if YEAR_BASE == 1900
1663
	{ &tmyr0, Vecyr0, sizeof(Vecyr0)/sizeof(Vecyr0[0]) },
1777
	{ &tmyr0, Vecyr0, sizeof(Vecyr0)/sizeof(Vecyr0[0]) },
1664
	{ &tmyr1, Vecyr1, sizeof(Vecyr1)/sizeof(Vecyr1[0]) },
1778
	{ &tmyr1, Vecyr1, sizeof(Vecyr1)/sizeof(Vecyr1[0]) },
1665
	#endif
1779
	#endif
1666
	};
1780
	};
1667
 
1781
 
1668
 
1782
 
1669
/* List of tests to be run */
1783
/* List of tests to be run */
1670
const struct list  List[] = {
1784
const struct list  List[] = {
1671
	{ &tm0, Vec0, sizeof(Vec0)/sizeof(Vec0[0]) },
1785
	{ &tm0, Vec0, sizeof(Vec0)/sizeof(Vec0[0]) },
1672
	{ &tm1, Vec1, sizeof(Vec1)/sizeof(Vec1[0]) },
1786
	{ &tm1, Vec1, sizeof(Vec1)/sizeof(Vec1[0]) },
1673
	};
1787
	};
1674
 
1788
 
1675
#if defined(STUB_getenv_r)
1789
#if defined(STUB_getenv_r)
1676
char *
1790
char *
1677
_getenv_r(struct _reent *p, const char *cp) { return getenv(cp); }
1791
_getenv_r(struct _reent *p, const char *cp) { return getenv(cp); }
1678
#endif
1792
#endif
1679
 
1793
 
1680
int
1794
int
1681
main(void)
1795
main(void)
1682
{
1796
{
1683
int  i, l, errr=0, erro=0, tot=0;
1797
int  i, l, errr=0, erro=0, tot=0;
1684
const char  *cp;
1798
const char  *cp;
1685
CHAR  out[OUTSIZE];
1799
CHAR  out[OUTSIZE];
1686
size_t  ret;
1800
size_t  ret;
1687
 
1801
 
1688
/* Set timezone so that %z and %Z tests come out right */
1802
/* Set timezone so that %z and %Z tests come out right */
1689
cp = TZ;
1803
cp = TZ;
1690
if((i=putenv(cp)))  {
1804
if((i=putenv(cp)))  {
1691
    printf( "putenv(%s) FAILED, ret %d\n", cp, i);
1805
    printf( "putenv(%s) FAILED, ret %d\n", cp, i);
1692
    return(-1);
1806
    return(-1);
1693
    }
1807
    }
1694
if(strcmp(getenv("TZ"),strchr(TZ,'=')+1))  {
1808
if(strcmp(getenv("TZ"),strchr(TZ,'=')+1))  {
1695
    printf( "TZ not set properly in environment\n");
1809
    printf( "TZ not set properly in environment\n");
1696
    return(-2);
1810
    return(-2);
1697
    }
1811
    }
1698
tzset();
1812
tzset();
1699
 
1813
 
1700
#if defined(VERBOSE)
1814
#if defined(VERBOSE)
1701
printf("_timezone=%d, _daylight=%d, _tzname[0]=%s, _tzname[1]=%s\n", _timezone, _daylight, _tzname[0], _tzname[1]);
1815
printf("_timezone=%d, _daylight=%d, _tzname[0]=%s, _tzname[1]=%s\n", _timezone, _daylight, _tzname[0], _tzname[1]);
1702
{
1816
{
1703
long offset;
1817
long offset;
1704
__tzinfo_type *tz = __gettzinfo ();
1818
__tzinfo_type *tz = __gettzinfo ();
1705
/* The sign of this is exactly opposite the envvar TZ.  We
1819
/* The sign of this is exactly opposite the envvar TZ.  We
1706
   could directly use the global _timezone for tm_isdst==0,
1820
   could directly use the global _timezone for tm_isdst==0,
1707
   but have to use __tzrule for daylight savings.  */
1821
   but have to use __tzrule for daylight savings.  */
1708
printf("tz->__tzrule[0].offset=%d, tz->__tzrule[1].offset=%d\n", tz->__tzrule[0].offset, tz->__tzrule[1].offset);
1822
printf("tz->__tzrule[0].offset=%d, tz->__tzrule[1].offset=%d\n", tz->__tzrule[0].offset, tz->__tzrule[1].offset);
1709
}
1823
}
1710
#endif
1824
#endif
1711
 
1825
 
1712
/* Run all of the exact-length tests as-given--results should match */
1826
/* Run all of the exact-length tests as-given--results should match */
1713
for(l=0; l
1827
for(l=0; l
1714
    const struct list  *test = &List[l];
1828
    const struct list  *test = &List[l];
1715
    for(i=0; icnt; i++)  {
1829
    for(i=0; icnt; i++)  {
1716
	tot++;	/* Keep track of number of tests */
1830
	tot++;	/* Keep track of number of tests */
1717
	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1831
	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1718
	if(ret != test->vec[i].ret)  {
1832
	if(ret != test->vec[i].ret)  {
1719
	    errr++;
1833
	    errr++;
1720
	    fprintf(stderr,
1834
	    fprintf(stderr,
1721
		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1835
		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1722
						ret, test->vec[i].ret, l, i);
1836
						ret, test->vec[i].ret, l, i);
1723
	    }
1837
	    }
1724
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1838
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1725
	    erro++;
1839
	    erro++;
1726
	    fprintf(stderr,
1840
	    fprintf(stderr,
1727
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1841
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1728
						out, test->vec[i].out, l, i);
1842
						out, test->vec[i].out, l, i);
1729
	    }
1843
	    }
1730
	}
1844
	}
1731
    }
1845
    }
1732
 
1846
 
1733
/* Run all of the exact-length tests with the length made too short--expect to
1847
/* Run all of the exact-length tests with the length made too short--expect to
1734
 * fail.  */
1848
 * fail.  */
1735
for(l=0; l
1849
for(l=0; l
1736
    const struct list  *test = &List[l];
1850
    const struct list  *test = &List[l];
1737
    for(i=0; icnt; i++)  {
1851
    for(i=0; icnt; i++)  {
1738
	tot++;	/* Keep track of number of tests */
1852
	tot++;	/* Keep track of number of tests */
1739
	ret = strftime(out, test->vec[i].max-1, test->vec[i].fmt, test->tms);
1853
	ret = strftime(out, test->vec[i].max-1, test->vec[i].fmt, test->tms);
1740
	if(ret != 0)  {
1854
	if(ret != 0)  {
1741
	    errr++;
1855
	    errr++;
1742
	    fprintf(stderr,
1856
	    fprintf(stderr,
1743
		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1857
		"ERROR:  return %d != %d expected for List[%d].vec[%d]\n",
1744
						ret, 0, l, i);
1858
						ret, 0, l, i);
1745
	    }
1859
	    }
1746
	/* Almost every conversion puts out as many characters as possible, so
1860
	/* Almost every conversion puts out as many characters as possible, so
1747
	 * go ahead and test the output even though have failed.  (The test
1861
	 * go ahead and test the output even though have failed.  (The test
1748
	 * times chosen happen to not hit any of the cases that fail this, so it
1862
	 * times chosen happen to not hit any of the cases that fail this, so it
1749
	 * works.)  */
1863
	 * works.)  */
1750
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1-1))  {
1864
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1-1))  {
1751
	    erro++;
1865
	    erro++;
1752
	    fprintf(stderr,
1866
	    fprintf(stderr,
1753
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1867
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for List[%d].vec[%d]\n",
1754
						out, test->vec[i].out, l, i);
1868
						out, test->vec[i].out, l, i);
1755
	    }
1869
	    }
1756
	}
1870
	}
1757
    }
1871
    }
1758
 
1872
 
1759
/* Run all of the special year test cases */
1873
/* Run all of the special year test cases */
1760
for(l=0; l
1874
for(l=0; l
1761
    const struct list  *test = &ListYr[l];
1875
    const struct list  *test = &ListYr[l];
1762
    for(i=0; icnt; i++)  {
1876
    for(i=0; icnt; i++)  {
1763
	tot++;	/* Keep track of number of tests */
1877
	tot++;	/* Keep track of number of tests */
1764
	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1878
	ret = strftime(out, test->vec[i].max, test->vec[i].fmt, test->tms);
1765
	if(ret != test->vec[i].ret)  {
1879
	if(ret != test->vec[i].ret)  {
1766
	    errr++;
1880
	    errr++;
1767
	    fprintf(stderr,
1881
	    fprintf(stderr,
1768
		"ERROR:  return %d != %d expected for ListYr[%d].vec[%d]\n",
1882
		"ERROR:  return %d != %d expected for ListYr[%d].vec[%d]\n",
1769
						ret, test->vec[i].ret, l, i);
1883
						ret, test->vec[i].ret, l, i);
1770
	    }
1884
	    }
1771
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1885
	if(strncmp(out, test->vec[i].out, test->vec[i].max-1))  {
1772
	    erro++;
1886
	    erro++;
1773
	    fprintf(stderr,
1887
	    fprintf(stderr,
1774
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for ListYr[%d].vec[%d]\n",
1888
		"ERROR:  \"%"SFLG"s\" != \"%"SFLG"s\" expected for ListYr[%d].vec[%d]\n",
1775
						out, test->vec[i].out, l, i);
1889
						out, test->vec[i].out, l, i);
1776
	    }
1890
	    }
1777
	}
1891
	}
1778
    }
1892
    }
1779
 
1893
 
1780
#define STRIZE(f)	#f
1894
#define STRIZE(f)	#f
1781
#define NAME(f)	STRIZE(f)
1895
#define NAME(f)	STRIZE(f)
1782
printf(NAME(strftime) "() test ");
1896
printf(NAME(strftime) "() test ");
1783
if(errr || erro)  printf("FAILED %d/%d of", errr, erro);
1897
if(errr || erro)  printf("FAILED %d/%d of", errr, erro);
1784
  else    printf("passed");
1898
  else    printf("passed");
1785
printf(" %d test cases.\n", tot);
1899
printf(" %d test cases.\n", tot);
1786
 
1900
 
1787
return(errr || erro);
1901
return(errr || erro);
1788
}
1902
}
1789
#endif /* defined(_REGRESSION_TEST) ] */
1903
#endif /* defined(_REGRESSION_TEST) ] */