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 | < |
20 | < |
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 | < |
40 | < |
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 | `< |
61 | `< |
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 | `< |
71 | `< |
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 < |
97 | certain modifiers < |
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 < |
152 | for certain modifiers < |
153 | 153 | ||
154 | o %p |
154 | o %p |
155 | Either `< |
155 | Either `< |
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 < |
252 | ANSI C requires < |
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 | < |
255 | < |
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 < |
258 | This implementation does not support < |
255 | < |
259 | < |
256 | 260 | ||
257 | < |
261 | < |
258 | 262 | ||
259 | BUGS |
263 | BUGS |
260 | < |
264 | < |
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; i |
1829 | for(i=0; 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; i |
1851 | for(i=0; 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; i |
1876 | for(i=0; 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) ] */>>>>>>>>>>1970>>>>>>=>>>>=>>>>>>>>>>>>>>>=>>>>=>>>=>=>><>><>>>>> |