Subversion Repositories Kolibri OS

Rev

Rev 4874 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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