diff options
author | Ron Yorston <rmy@pobox.com> | 2014-01-20 22:07:54 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2014-01-20 22:07:54 +0000 |
commit | 61a0fc571381226c48728b262495c1c5eafc4fed (patch) | |
tree | 42989d08f6926b73d6ed03ef92f8f1ee4b5062f9 | |
parent | 19148b1e7ebb279bfbc1ea8be329f795fa2c1eb0 (diff) | |
download | busybox-w32-61a0fc571381226c48728b262495c1c5eafc4fed.tar.gz busybox-w32-61a0fc571381226c48728b262495c1c5eafc4fed.tar.bz2 busybox-w32-61a0fc571381226c48728b262495c1c5eafc4fed.zip |
win32: use strptime from gnulib
-rw-r--r-- | win32/Kbuild | 1 | ||||
-rw-r--r-- | win32/mingw.c | 5 | ||||
-rw-r--r-- | win32/strptime.c | 648 |
3 files changed, 649 insertions, 5 deletions
diff --git a/win32/Kbuild b/win32/Kbuild index 564498c78..c1005bd11 100644 --- a/win32/Kbuild +++ b/win32/Kbuild | |||
@@ -15,6 +15,7 @@ lib-$(CONFIG_PLATFORM_MINGW32) += poll.o | |||
15 | lib-$(CONFIG_PLATFORM_MINGW32) += popen.o | 15 | lib-$(CONFIG_PLATFORM_MINGW32) += popen.o |
16 | lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o | 16 | lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o |
17 | lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o | 17 | lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o |
18 | lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o | ||
18 | lib-$(CONFIG_PLATFORM_MINGW32) += system.o | 19 | lib-$(CONFIG_PLATFORM_MINGW32) += system.o |
19 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o | 20 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o |
20 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o | 21 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o |
diff --git a/win32/mingw.c b/win32/mingw.c index b5b3576eb..810cce604 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -799,11 +799,6 @@ int mingw_unlink(const char *pathname) | |||
799 | return unlink(pathname); | 799 | return unlink(pathname); |
800 | } | 800 | } |
801 | 801 | ||
802 | char *strptime(const char *s UNUSED_PARAM, const char *format UNUSED_PARAM, struct tm *tm UNUSED_PARAM) | ||
803 | { | ||
804 | return NULL; | ||
805 | } | ||
806 | |||
807 | #undef strftime | 802 | #undef strftime |
808 | size_t mingw_strftime(const char *buf, size_t max, const char *format, const struct tm *tm) | 803 | size_t mingw_strftime(const char *buf, size_t max, const char *format, const struct tm *tm) |
809 | { | 804 | { |
diff --git a/win32/strptime.c b/win32/strptime.c new file mode 100644 index 000000000..64fd37779 --- /dev/null +++ b/win32/strptime.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* Copyright (C) 2002, 2004-2005, 2007, 2009-2014 Free Software Foundation, | ||
2 | Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License along | ||
16 | with this program; if not, see <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | /* | ||
19 | * File from gnulib (http://www.gnu.org/software/gnulib/), processed with | ||
20 | * coan source -U_LIBC -U_NL_CURRENT -UHAVE_TM_GMTOFF strptime.c | ||
21 | * and lightly edited. | ||
22 | */ | ||
23 | |||
24 | #include <time.h> | ||
25 | |||
26 | #include <assert.h> | ||
27 | #include <ctype.h> | ||
28 | #include <limits.h> | ||
29 | #include <string.h> | ||
30 | #include <stdbool.h> | ||
31 | |||
32 | |||
33 | enum ptime_locale_status { not, loc, raw }; | ||
34 | |||
35 | |||
36 | |||
37 | #define match_char(ch1, ch2) if (ch1 != ch2) return NULL | ||
38 | /* Oh come on. Get a reasonable compiler. */ | ||
39 | # define match_string(cs1, s2) \ | ||
40 | (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) | ||
41 | /* We intentionally do not use isdigit() for testing because this will | ||
42 | lead to problems with the wide character version. */ | ||
43 | #define get_number(from, to, n) \ | ||
44 | do { \ | ||
45 | int __n = n; \ | ||
46 | val = 0; \ | ||
47 | while (*rp == ' ') \ | ||
48 | ++rp; \ | ||
49 | if (*rp < '0' || *rp > '9') \ | ||
50 | return NULL; \ | ||
51 | do { \ | ||
52 | val *= 10; \ | ||
53 | val += *rp++ - '0'; \ | ||
54 | } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \ | ||
55 | if (val < from || val > to) \ | ||
56 | return NULL; \ | ||
57 | } while (0) | ||
58 | # define get_alt_number(from, to, n) \ | ||
59 | /* We don't have the alternate representation. */ \ | ||
60 | get_number(from, to, n) | ||
61 | #define recursive(new_fmt) \ | ||
62 | (*(new_fmt) != '\0' \ | ||
63 | && (rp = __strptime_internal (rp, (new_fmt), tm, \ | ||
64 | decided, era_cnt LOCALE_ARG)) != NULL) | ||
65 | |||
66 | |||
67 | static char const weekday_name[][10] = | ||
68 | { | ||
69 | "Sunday", "Monday", "Tuesday", "Wednesday", | ||
70 | "Thursday", "Friday", "Saturday" | ||
71 | }; | ||
72 | static char const ab_weekday_name[][4] = | ||
73 | { | ||
74 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | ||
75 | }; | ||
76 | static char const month_name[][10] = | ||
77 | { | ||
78 | "January", "February", "March", "April", "May", "June", | ||
79 | "July", "August", "September", "October", "November", "December" | ||
80 | }; | ||
81 | static char const ab_month_name[][4] = | ||
82 | { | ||
83 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", | ||
84 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | ||
85 | }; | ||
86 | # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" | ||
87 | # define HERE_D_FMT "%m/%d/%y" | ||
88 | # define HERE_AM_STR "AM" | ||
89 | # define HERE_PM_STR "PM" | ||
90 | # define HERE_T_FMT_AMPM "%I:%M:%S %p" | ||
91 | # define HERE_T_FMT "%H:%M:%S" | ||
92 | |||
93 | static const unsigned short int __mon_yday[2][13] = | ||
94 | { | ||
95 | /* Normal years. */ | ||
96 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | ||
97 | /* Leap years. */ | ||
98 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
99 | }; | ||
100 | |||
101 | # define LOCALE_PARAM | ||
102 | # define LOCALE_ARG | ||
103 | # define LOCALE_PARAM_DECL | ||
104 | # define LOCALE_PARAM_PROTO | ||
105 | # define HELPER_LOCALE_ARG | ||
106 | # define ISSPACE(Ch) isspace (Ch) | ||
107 | |||
108 | |||
109 | |||
110 | |||
111 | #ifndef __isleap | ||
112 | /* Nonzero if YEAR is a leap year (every 4 years, | ||
113 | except every 100th isn't, and every 400th is). */ | ||
114 | # define __isleap(year) \ | ||
115 | ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) | ||
116 | #endif | ||
117 | |||
118 | /* Compute the day of the week. */ | ||
119 | static void | ||
120 | day_of_the_week (struct tm *tm) | ||
121 | { | ||
122 | /* We know that January 1st 1970 was a Thursday (= 4). Compute the | ||
123 | difference between this data in the one on TM and so determine | ||
124 | the weekday. */ | ||
125 | int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); | ||
126 | int wday = (-473 | ||
127 | + (365 * (tm->tm_year - 70)) | ||
128 | + (corr_year / 4) | ||
129 | - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) | ||
130 | + (((corr_year / 4) / 25) / 4) | ||
131 | + __mon_yday[0][tm->tm_mon] | ||
132 | + tm->tm_mday - 1); | ||
133 | tm->tm_wday = ((wday % 7) + 7) % 7; | ||
134 | } | ||
135 | |||
136 | /* Compute the day of the year. */ | ||
137 | static void | ||
138 | day_of_the_year (struct tm *tm) | ||
139 | { | ||
140 | tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] | ||
141 | + (tm->tm_mday - 1)); | ||
142 | } | ||
143 | |||
144 | |||
145 | static char * | ||
146 | __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM) | ||
147 | const char *rp; | ||
148 | const char *fmt; | ||
149 | struct tm *tm; | ||
150 | enum ptime_locale_status *decided; | ||
151 | int era_cnt; | ||
152 | LOCALE_PARAM_DECL | ||
153 | { | ||
154 | |||
155 | int cnt; | ||
156 | size_t val; | ||
157 | int have_I, is_pm; | ||
158 | int century, want_century; | ||
159 | int want_era; | ||
160 | int have_wday, want_xday; | ||
161 | int have_yday; | ||
162 | int have_mon, have_mday; | ||
163 | int have_uweek, have_wweek; | ||
164 | int week_no; | ||
165 | |||
166 | have_I = is_pm = 0; | ||
167 | century = -1; | ||
168 | want_century = 0; | ||
169 | want_era = 0; | ||
170 | week_no = 0; | ||
171 | |||
172 | have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0; | ||
173 | have_wweek = 0; | ||
174 | |||
175 | while (*fmt != '\0') | ||
176 | { | ||
177 | /* A white space in the format string matches 0 more or white | ||
178 | space in the input string. */ | ||
179 | if (ISSPACE (*fmt)) | ||
180 | { | ||
181 | while (ISSPACE (*rp)) | ||
182 | ++rp; | ||
183 | ++fmt; | ||
184 | continue; | ||
185 | } | ||
186 | |||
187 | /* Any character but '%' must be matched by the same character | ||
188 | in the iput string. */ | ||
189 | if (*fmt != '%') | ||
190 | { | ||
191 | match_char (*fmt++, *rp++); | ||
192 | continue; | ||
193 | } | ||
194 | |||
195 | ++fmt; | ||
196 | /* We need this for handling the 'E' modifier. */ | ||
197 | start_over: | ||
198 | |||
199 | switch (*fmt++) | ||
200 | { | ||
201 | case '%': | ||
202 | /* Match the '%' character itself. */ | ||
203 | match_char ('%', *rp++); | ||
204 | break; | ||
205 | case 'a': | ||
206 | case 'A': | ||
207 | /* Match day of week. */ | ||
208 | for (cnt = 0; cnt < 7; ++cnt) | ||
209 | { | ||
210 | if (*decided != loc | ||
211 | && (match_string (weekday_name[cnt], rp) | ||
212 | || match_string (ab_weekday_name[cnt], rp))) | ||
213 | { | ||
214 | *decided = raw; | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | if (cnt == 7) | ||
219 | /* Does not match a weekday name. */ | ||
220 | return NULL; | ||
221 | tm->tm_wday = cnt; | ||
222 | have_wday = 1; | ||
223 | break; | ||
224 | case 'b': | ||
225 | case 'B': | ||
226 | case 'h': | ||
227 | /* Match month name. */ | ||
228 | for (cnt = 0; cnt < 12; ++cnt) | ||
229 | { | ||
230 | if (match_string (month_name[cnt], rp) | ||
231 | || match_string (ab_month_name[cnt], rp)) | ||
232 | { | ||
233 | *decided = raw; | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | if (cnt == 12) | ||
238 | /* Does not match a month name. */ | ||
239 | return NULL; | ||
240 | tm->tm_mon = cnt; | ||
241 | want_xday = 1; | ||
242 | break; | ||
243 | case 'c': | ||
244 | /* Match locale's date and time format. */ | ||
245 | if (!recursive (HERE_D_T_FMT)) | ||
246 | return NULL; | ||
247 | want_xday = 1; | ||
248 | break; | ||
249 | case 'C': | ||
250 | /* Match century number. */ | ||
251 | get_number (0, 99, 2); | ||
252 | century = val; | ||
253 | want_xday = 1; | ||
254 | break; | ||
255 | case 'd': | ||
256 | case 'e': | ||
257 | /* Match day of month. */ | ||
258 | get_number (1, 31, 2); | ||
259 | tm->tm_mday = val; | ||
260 | have_mday = 1; | ||
261 | want_xday = 1; | ||
262 | break; | ||
263 | case 'F': | ||
264 | if (!recursive ("%Y-%m-%d")) | ||
265 | return NULL; | ||
266 | want_xday = 1; | ||
267 | break; | ||
268 | case 'x': | ||
269 | /* Fall through. */ | ||
270 | case 'D': | ||
271 | /* Match standard day format. */ | ||
272 | if (!recursive (HERE_D_FMT)) | ||
273 | return NULL; | ||
274 | want_xday = 1; | ||
275 | break; | ||
276 | case 'k': | ||
277 | case 'H': | ||
278 | /* Match hour in 24-hour clock. */ | ||
279 | get_number (0, 23, 2); | ||
280 | tm->tm_hour = val; | ||
281 | have_I = 0; | ||
282 | break; | ||
283 | case 'l': | ||
284 | /* Match hour in 12-hour clock. GNU extension. */ | ||
285 | case 'I': | ||
286 | /* Match hour in 12-hour clock. */ | ||
287 | get_number (1, 12, 2); | ||
288 | tm->tm_hour = val % 12; | ||
289 | have_I = 1; | ||
290 | break; | ||
291 | case 'j': | ||
292 | /* Match day number of year. */ | ||
293 | get_number (1, 366, 3); | ||
294 | tm->tm_yday = val - 1; | ||
295 | have_yday = 1; | ||
296 | break; | ||
297 | case 'm': | ||
298 | /* Match number of month. */ | ||
299 | get_number (1, 12, 2); | ||
300 | tm->tm_mon = val - 1; | ||
301 | have_mon = 1; | ||
302 | want_xday = 1; | ||
303 | break; | ||
304 | case 'M': | ||
305 | /* Match minute. */ | ||
306 | get_number (0, 59, 2); | ||
307 | tm->tm_min = val; | ||
308 | break; | ||
309 | case 'n': | ||
310 | case 't': | ||
311 | /* Match any white space. */ | ||
312 | while (ISSPACE (*rp)) | ||
313 | ++rp; | ||
314 | break; | ||
315 | case 'p': | ||
316 | /* Match locale's equivalent of AM/PM. */ | ||
317 | if (!match_string (HERE_AM_STR, rp)) | ||
318 | { | ||
319 | if (match_string (HERE_PM_STR, rp)) | ||
320 | is_pm = 1; | ||
321 | else | ||
322 | return NULL; | ||
323 | } | ||
324 | break; | ||
325 | case 'r': | ||
326 | if (!recursive (HERE_T_FMT_AMPM)) | ||
327 | return NULL; | ||
328 | break; | ||
329 | case 'R': | ||
330 | if (!recursive ("%H:%M")) | ||
331 | return NULL; | ||
332 | break; | ||
333 | case 's': | ||
334 | { | ||
335 | /* The number of seconds may be very high so we cannot use | ||
336 | the 'get_number' macro. Instead read the number | ||
337 | character for character and construct the result while | ||
338 | doing this. */ | ||
339 | time_t secs = 0; | ||
340 | struct tm *mytm; | ||
341 | if (*rp < '0' || *rp > '9') | ||
342 | /* We need at least one digit. */ | ||
343 | return NULL; | ||
344 | |||
345 | do | ||
346 | { | ||
347 | secs *= 10; | ||
348 | secs += *rp++ - '0'; | ||
349 | } | ||
350 | while (*rp >= '0' && *rp <= '9'); | ||
351 | |||
352 | if ((mytm=localtime(&secs)) == NULL) | ||
353 | /* Error in function. */ | ||
354 | return NULL; | ||
355 | *tm = *mytm; | ||
356 | } | ||
357 | break; | ||
358 | case 'S': | ||
359 | get_number (0, 61, 2); | ||
360 | tm->tm_sec = val; | ||
361 | break; | ||
362 | case 'X': | ||
363 | /* Fall through. */ | ||
364 | case 'T': | ||
365 | if (!recursive (HERE_T_FMT)) | ||
366 | return NULL; | ||
367 | break; | ||
368 | case 'u': | ||
369 | get_number (1, 7, 1); | ||
370 | tm->tm_wday = val % 7; | ||
371 | have_wday = 1; | ||
372 | break; | ||
373 | case 'g': | ||
374 | get_number (0, 99, 2); | ||
375 | /* XXX This cannot determine any field in TM. */ | ||
376 | break; | ||
377 | case 'G': | ||
378 | if (*rp < '0' || *rp > '9') | ||
379 | return NULL; | ||
380 | /* XXX Ignore the number since we would need some more | ||
381 | information to compute a real date. */ | ||
382 | do | ||
383 | ++rp; | ||
384 | while (*rp >= '0' && *rp <= '9'); | ||
385 | break; | ||
386 | case 'U': | ||
387 | get_number (0, 53, 2); | ||
388 | week_no = val; | ||
389 | have_uweek = 1; | ||
390 | break; | ||
391 | case 'W': | ||
392 | get_number (0, 53, 2); | ||
393 | week_no = val; | ||
394 | have_wweek = 1; | ||
395 | break; | ||
396 | case 'V': | ||
397 | get_number (0, 53, 2); | ||
398 | /* XXX This cannot determine any field in TM without some | ||
399 | information. */ | ||
400 | break; | ||
401 | case 'w': | ||
402 | /* Match number of weekday. */ | ||
403 | get_number (0, 6, 1); | ||
404 | tm->tm_wday = val; | ||
405 | have_wday = 1; | ||
406 | break; | ||
407 | case 'y': | ||
408 | /* Match year within century. */ | ||
409 | get_number (0, 99, 2); | ||
410 | /* The "Year 2000: The Millennium Rollover" paper suggests that | ||
411 | values in the range 69-99 refer to the twentieth century. */ | ||
412 | tm->tm_year = val >= 69 ? val : val + 100; | ||
413 | /* Indicate that we want to use the century, if specified. */ | ||
414 | want_century = 1; | ||
415 | want_xday = 1; | ||
416 | break; | ||
417 | case 'Y': | ||
418 | /* Match year including century number. */ | ||
419 | get_number (0, 9999, 4); | ||
420 | tm->tm_year = val - 1900; | ||
421 | want_century = 0; | ||
422 | want_xday = 1; | ||
423 | break; | ||
424 | case 'Z': | ||
425 | /* XXX How to handle this? */ | ||
426 | break; | ||
427 | case 'z': | ||
428 | /* We recognize two formats: if two digits are given, these | ||
429 | specify hours. If fours digits are used, minutes are | ||
430 | also specified. */ | ||
431 | { | ||
432 | bool neg; | ||
433 | int n; | ||
434 | |||
435 | val = 0; | ||
436 | while (*rp == ' ') | ||
437 | ++rp; | ||
438 | if (*rp != '+' && *rp != '-') | ||
439 | return NULL; | ||
440 | neg = *rp++ == '-'; | ||
441 | n = 0; | ||
442 | while (n < 4 && *rp >= '0' && *rp <= '9') | ||
443 | { | ||
444 | val = val * 10 + *rp++ - '0'; | ||
445 | ++n; | ||
446 | } | ||
447 | if (n == 2) | ||
448 | val *= 100; | ||
449 | else if (n != 4) | ||
450 | /* Only two or four digits recognized. */ | ||
451 | return NULL; | ||
452 | else | ||
453 | { | ||
454 | /* We have to convert the minutes into decimal. */ | ||
455 | if (val % 100 >= 60) | ||
456 | return NULL; | ||
457 | val = (val / 100) * 100 + ((val % 100) * 50) / 30; | ||
458 | } | ||
459 | if (val > 1200) | ||
460 | return NULL; | ||
461 | } | ||
462 | break; | ||
463 | case 'E': | ||
464 | /* We have no information about the era format. Just use | ||
465 | the normal format. */ | ||
466 | if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' | ||
467 | && *fmt != 'x' && *fmt != 'X') | ||
468 | /* This is an illegal format. */ | ||
469 | return NULL; | ||
470 | |||
471 | goto start_over; | ||
472 | case 'O': | ||
473 | switch (*fmt++) | ||
474 | { | ||
475 | case 'd': | ||
476 | case 'e': | ||
477 | /* Match day of month using alternate numeric symbols. */ | ||
478 | get_alt_number (1, 31, 2); | ||
479 | tm->tm_mday = val; | ||
480 | have_mday = 1; | ||
481 | want_xday = 1; | ||
482 | break; | ||
483 | case 'H': | ||
484 | /* Match hour in 24-hour clock using alternate numeric | ||
485 | symbols. */ | ||
486 | get_alt_number (0, 23, 2); | ||
487 | tm->tm_hour = val; | ||
488 | have_I = 0; | ||
489 | break; | ||
490 | case 'I': | ||
491 | /* Match hour in 12-hour clock using alternate numeric | ||
492 | symbols. */ | ||
493 | get_alt_number (1, 12, 2); | ||
494 | tm->tm_hour = val % 12; | ||
495 | have_I = 1; | ||
496 | break; | ||
497 | case 'm': | ||
498 | /* Match month using alternate numeric symbols. */ | ||
499 | get_alt_number (1, 12, 2); | ||
500 | tm->tm_mon = val - 1; | ||
501 | have_mon = 1; | ||
502 | want_xday = 1; | ||
503 | break; | ||
504 | case 'M': | ||
505 | /* Match minutes using alternate numeric symbols. */ | ||
506 | get_alt_number (0, 59, 2); | ||
507 | tm->tm_min = val; | ||
508 | break; | ||
509 | case 'S': | ||
510 | /* Match seconds using alternate numeric symbols. */ | ||
511 | get_alt_number (0, 61, 2); | ||
512 | tm->tm_sec = val; | ||
513 | break; | ||
514 | case 'U': | ||
515 | get_alt_number (0, 53, 2); | ||
516 | week_no = val; | ||
517 | have_uweek = 1; | ||
518 | break; | ||
519 | case 'W': | ||
520 | get_alt_number (0, 53, 2); | ||
521 | week_no = val; | ||
522 | have_wweek = 1; | ||
523 | break; | ||
524 | case 'V': | ||
525 | get_alt_number (0, 53, 2); | ||
526 | /* XXX This cannot determine any field in TM without | ||
527 | further information. */ | ||
528 | break; | ||
529 | case 'w': | ||
530 | /* Match number of weekday using alternate numeric symbols. */ | ||
531 | get_alt_number (0, 6, 1); | ||
532 | tm->tm_wday = val; | ||
533 | have_wday = 1; | ||
534 | break; | ||
535 | case 'y': | ||
536 | /* Match year within century using alternate numeric symbols. */ | ||
537 | get_alt_number (0, 99, 2); | ||
538 | tm->tm_year = val >= 69 ? val : val + 100; | ||
539 | want_xday = 1; | ||
540 | break; | ||
541 | default: | ||
542 | return NULL; | ||
543 | } | ||
544 | break; | ||
545 | default: | ||
546 | return NULL; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | if (have_I && is_pm) | ||
551 | tm->tm_hour += 12; | ||
552 | |||
553 | if (century != -1) | ||
554 | { | ||
555 | if (want_century) | ||
556 | tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; | ||
557 | else | ||
558 | /* Only the century, but not the year. Strange, but so be it. */ | ||
559 | tm->tm_year = (century - 19) * 100; | ||
560 | } | ||
561 | |||
562 | if (era_cnt != -1) | ||
563 | { | ||
564 | } | ||
565 | else | ||
566 | if (want_era) | ||
567 | { | ||
568 | /* No era found but we have seen an E modifier. Rectify some | ||
569 | values. */ | ||
570 | if (want_century && century == -1 && tm->tm_year < 69) | ||
571 | tm->tm_year += 100; | ||
572 | } | ||
573 | |||
574 | if (want_xday && !have_wday) | ||
575 | { | ||
576 | if ( !(have_mon && have_mday) && have_yday) | ||
577 | { | ||
578 | /* We don't have tm_mon and/or tm_mday, compute them. */ | ||
579 | int t_mon = 0; | ||
580 | while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) | ||
581 | t_mon++; | ||
582 | if (!have_mon) | ||
583 | tm->tm_mon = t_mon - 1; | ||
584 | if (!have_mday) | ||
585 | tm->tm_mday = | ||
586 | (tm->tm_yday | ||
587 | - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); | ||
588 | } | ||
589 | day_of_the_week (tm); | ||
590 | } | ||
591 | |||
592 | if (want_xday && !have_yday) | ||
593 | day_of_the_year (tm); | ||
594 | |||
595 | if ((have_uweek || have_wweek) && have_wday) | ||
596 | { | ||
597 | int save_wday = tm->tm_wday; | ||
598 | int save_mday = tm->tm_mday; | ||
599 | int save_mon = tm->tm_mon; | ||
600 | int w_offset = have_uweek ? 0 : 1; | ||
601 | |||
602 | tm->tm_mday = 1; | ||
603 | tm->tm_mon = 0; | ||
604 | day_of_the_week (tm); | ||
605 | if (have_mday) | ||
606 | tm->tm_mday = save_mday; | ||
607 | if (have_mon) | ||
608 | tm->tm_mon = save_mon; | ||
609 | |||
610 | if (!have_yday) | ||
611 | tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7 | ||
612 | + (week_no - 1) *7 | ||
613 | + save_wday - w_offset); | ||
614 | |||
615 | if (!have_mday || !have_mon) | ||
616 | { | ||
617 | int t_mon = 0; | ||
618 | while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] | ||
619 | <= tm->tm_yday) | ||
620 | t_mon++; | ||
621 | if (!have_mon) | ||
622 | tm->tm_mon = t_mon - 1; | ||
623 | if (!have_mday) | ||
624 | tm->tm_mday = | ||
625 | (tm->tm_yday | ||
626 | - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); | ||
627 | } | ||
628 | |||
629 | tm->tm_wday = save_wday; | ||
630 | } | ||
631 | |||
632 | return (char *) rp; | ||
633 | } | ||
634 | |||
635 | |||
636 | char * | ||
637 | strptime (buf, format, tm LOCALE_PARAM) | ||
638 | const char *buf; | ||
639 | const char *format; | ||
640 | struct tm *tm; | ||
641 | LOCALE_PARAM_DECL | ||
642 | { | ||
643 | enum ptime_locale_status decided; | ||
644 | |||
645 | decided = raw; | ||
646 | return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG); | ||
647 | } | ||
648 | |||