Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / talloc / libreplace / strptime.c
blob0e40f7561acd72e1e2b3cfb11393331a44f67d1a
1 /* Convert a string representation of time to a time value.
2 Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 3 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 see <http://www.gnu.org/licenses/>. */
20 /* XXX This version of the implementation is not really complete.
21 Some of the fields cannot add information alone. But if seeing
22 some of them in the same format (such as year, week and weekday)
23 this is enough information for determining the date. */
25 #include "replace.h"
26 #include "system/locale.h"
27 #include "system/time.h"
29 #ifndef __P
30 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
31 # define __P(args) args
32 # else
33 # define __P(args) ()
34 # endif /* GCC. */
35 #endif /* Not __P. */
37 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
38 # ifdef _LIBC
39 # define localtime_r __localtime_r
40 # else
41 /* Approximate localtime_r as best we can in its absence. */
42 # define localtime_r my_localtime_r
43 static struct tm *localtime_r __P ((const time_t *, struct tm *));
44 static struct tm *
45 localtime_r (t, tp)
46 const time_t *t;
47 struct tm *tp;
49 struct tm *l = localtime (t);
50 if (! l)
51 return 0;
52 *tp = *l;
53 return tp;
55 # endif /* ! _LIBC */
56 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
59 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
60 #if defined __GNUC__ && __GNUC__ >= 2
61 # define match_string(cs1, s2) \
62 ({ size_t len = strlen (cs1); \
63 int result = strncasecmp ((cs1), (s2), len) == 0; \
64 if (result) (s2) += len; \
65 result; })
66 #else
67 /* Oh come on. Get a reasonable compiler. */
68 # define match_string(cs1, s2) \
69 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
70 #endif
71 /* We intentionally do not use isdigit() for testing because this will
72 lead to problems with the wide character version. */
73 #define get_number(from, to, n) \
74 do { \
75 int __n = n; \
76 val = 0; \
77 while (*rp == ' ') \
78 ++rp; \
79 if (*rp < '0' || *rp > '9') \
80 return NULL; \
81 do { \
82 val *= 10; \
83 val += *rp++ - '0'; \
84 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
85 if (val < from || val > to) \
86 return NULL; \
87 } while (0)
88 #ifdef _NL_CURRENT
89 # define get_alt_number(from, to, n) \
90 ({ \
91 __label__ do_normal; \
92 if (*decided != raw) \
93 { \
94 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
95 int __n = n; \
96 int any = 0; \
97 while (*rp == ' ') \
98 ++rp; \
99 val = 0; \
100 do { \
101 val *= 10; \
102 while (*alts != '\0') \
104 size_t len = strlen (alts); \
105 if (strncasecmp (alts, rp, len) == 0) \
106 break; \
107 alts += len + 1; \
108 ++val; \
110 if (*alts == '\0') \
112 if (*decided == not && ! any) \
113 goto do_normal; \
114 /* If we haven't read anything it's an error. */ \
115 if (! any) \
116 return NULL; \
117 /* Correct the premature multiplication. */ \
118 val /= 10; \
119 break; \
121 else \
122 *decided = loc; \
123 } while (--__n > 0 && val * 10 <= to); \
124 if (val < from || val > to) \
125 return NULL; \
127 else \
129 do_normal: \
130 get_number (from, to, n); \
132 0; \
134 #else
135 # define get_alt_number(from, to, n) \
136 /* We don't have the alternate representation. */ \
137 get_number(from, to, n)
138 #endif
139 #define recursive(new_fmt) \
140 (*(new_fmt) != '\0' \
141 && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
144 #ifdef _LIBC
145 /* This is defined in locale/C-time.c in the GNU libc. */
146 extern const struct locale_data _nl_C_LC_TIME;
147 extern const unsigned short int __mon_yday[2][13];
149 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
150 # define ab_weekday_name \
151 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
152 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
153 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
154 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
155 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
156 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
157 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
158 # define HERE_T_FMT_AMPM \
159 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
160 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
162 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
163 #else
164 static char const weekday_name[][10] =
166 "Sunday", "Monday", "Tuesday", "Wednesday",
167 "Thursday", "Friday", "Saturday"
169 static char const ab_weekday_name[][4] =
171 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
173 static char const month_name[][10] =
175 "January", "February", "March", "April", "May", "June",
176 "July", "August", "September", "October", "November", "December"
178 static char const ab_month_name[][4] =
180 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
181 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
183 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
184 # define HERE_D_FMT "%m/%d/%y"
185 # define HERE_AM_STR "AM"
186 # define HERE_PM_STR "PM"
187 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
188 # define HERE_T_FMT "%H:%M:%S"
190 static const unsigned short int __mon_yday[2][13] =
192 /* Normal years. */
193 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
194 /* Leap years. */
195 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
197 #endif
199 /* Status of lookup: do we use the locale data or the raw data? */
200 enum locale_status { not, loc, raw };
203 #ifndef __isleap
204 /* Nonzero if YEAR is a leap year (every 4 years,
205 except every 100th isn't, and every 400th is). */
206 # define __isleap(year) \
207 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
208 #endif
210 /* Compute the day of the week. */
211 static void
212 day_of_the_week (struct tm *tm)
214 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
215 the difference between this data in the one on TM and so determine
216 the weekday. */
217 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
218 int wday = (-473
219 + (365 * (tm->tm_year - 70))
220 + (corr_year / 4)
221 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
222 + (((corr_year / 4) / 25) / 4)
223 + __mon_yday[0][tm->tm_mon]
224 + tm->tm_mday - 1);
225 tm->tm_wday = ((wday % 7) + 7) % 7;
228 /* Compute the day of the year. */
229 static void
230 day_of_the_year (struct tm *tm)
232 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
233 + (tm->tm_mday - 1));
236 static char *
237 #ifdef _LIBC
238 internal_function
239 #endif
240 strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
241 enum locale_status *decided, int era_cnt));
243 static char *
244 #ifdef _LIBC
245 internal_function
246 #endif
247 strptime_internal (rp, fmt, tm, decided, era_cnt)
248 const char *rp;
249 const char *fmt;
250 struct tm *tm;
251 enum locale_status *decided;
252 int era_cnt;
254 const char *rp_backup;
255 int cnt;
256 size_t val;
257 int have_I, is_pm;
258 int century, want_century;
259 int want_era;
260 int have_wday, want_xday;
261 int have_yday;
262 int have_mon, have_mday;
263 #ifdef _NL_CURRENT
264 size_t num_eras;
265 #endif
266 struct era_entry *era;
268 have_I = is_pm = 0;
269 century = -1;
270 want_century = 0;
271 want_era = 0;
272 era = NULL;
274 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
276 while (*fmt != '\0')
278 /* A white space in the format string matches 0 more or white
279 space in the input string. */
280 if (isspace (*fmt))
282 while (isspace (*rp))
283 ++rp;
284 ++fmt;
285 continue;
288 /* Any character but `%' must be matched by the same character
289 in the iput string. */
290 if (*fmt != '%')
292 match_char (*fmt++, *rp++);
293 continue;
296 ++fmt;
297 #ifndef _NL_CURRENT
298 /* We need this for handling the `E' modifier. */
299 start_over:
300 #endif
302 /* Make back up of current processing pointer. */
303 rp_backup = rp;
305 switch (*fmt++)
307 case '%':
308 /* Match the `%' character itself. */
309 match_char ('%', *rp++);
310 break;
311 case 'a':
312 case 'A':
313 /* Match day of week. */
314 for (cnt = 0; cnt < 7; ++cnt)
316 #ifdef _NL_CURRENT
317 if (*decided !=raw)
319 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
321 if (*decided == not
322 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
323 weekday_name[cnt]))
324 *decided = loc;
325 break;
327 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
329 if (*decided == not
330 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
331 ab_weekday_name[cnt]))
332 *decided = loc;
333 break;
336 #endif
337 if (*decided != loc
338 && (match_string (weekday_name[cnt], rp)
339 || match_string (ab_weekday_name[cnt], rp)))
341 *decided = raw;
342 break;
345 if (cnt == 7)
346 /* Does not match a weekday name. */
347 return NULL;
348 tm->tm_wday = cnt;
349 have_wday = 1;
350 break;
351 case 'b':
352 case 'B':
353 case 'h':
354 /* Match month name. */
355 for (cnt = 0; cnt < 12; ++cnt)
357 #ifdef _NL_CURRENT
358 if (*decided !=raw)
360 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
362 if (*decided == not
363 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
364 month_name[cnt]))
365 *decided = loc;
366 break;
368 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
370 if (*decided == not
371 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
372 ab_month_name[cnt]))
373 *decided = loc;
374 break;
377 #endif
378 if (match_string (month_name[cnt], rp)
379 || match_string (ab_month_name[cnt], rp))
381 *decided = raw;
382 break;
385 if (cnt == 12)
386 /* Does not match a month name. */
387 return NULL;
388 tm->tm_mon = cnt;
389 want_xday = 1;
390 break;
391 case 'c':
392 /* Match locale's date and time format. */
393 #ifdef _NL_CURRENT
394 if (*decided != raw)
396 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
398 if (*decided == loc)
399 return NULL;
400 else
401 rp = rp_backup;
403 else
405 if (*decided == not &&
406 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
407 *decided = loc;
408 want_xday = 1;
409 break;
411 *decided = raw;
413 #endif
414 if (!recursive (HERE_D_T_FMT))
415 return NULL;
416 want_xday = 1;
417 break;
418 case 'C':
419 /* Match century number. */
420 #ifdef _NL_CURRENT
421 match_century:
422 #endif
423 get_number (0, 99, 2);
424 century = val;
425 want_xday = 1;
426 break;
427 case 'd':
428 case 'e':
429 /* Match day of month. */
430 get_number (1, 31, 2);
431 tm->tm_mday = val;
432 have_mday = 1;
433 want_xday = 1;
434 break;
435 case 'F':
436 if (!recursive ("%Y-%m-%d"))
437 return NULL;
438 want_xday = 1;
439 break;
440 case 'x':
441 #ifdef _NL_CURRENT
442 if (*decided != raw)
444 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
446 if (*decided == loc)
447 return NULL;
448 else
449 rp = rp_backup;
451 else
453 if (*decided == not
454 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
455 *decided = loc;
456 want_xday = 1;
457 break;
459 *decided = raw;
461 #endif
462 /* Fall through. */
463 case 'D':
464 /* Match standard day format. */
465 if (!recursive (HERE_D_FMT))
466 return NULL;
467 want_xday = 1;
468 break;
469 case 'k':
470 case 'H':
471 /* Match hour in 24-hour clock. */
472 get_number (0, 23, 2);
473 tm->tm_hour = val;
474 have_I = 0;
475 break;
476 case 'I':
477 /* Match hour in 12-hour clock. */
478 get_number (1, 12, 2);
479 tm->tm_hour = val % 12;
480 have_I = 1;
481 break;
482 case 'j':
483 /* Match day number of year. */
484 get_number (1, 366, 3);
485 tm->tm_yday = val - 1;
486 have_yday = 1;
487 break;
488 case 'm':
489 /* Match number of month. */
490 get_number (1, 12, 2);
491 tm->tm_mon = val - 1;
492 have_mon = 1;
493 want_xday = 1;
494 break;
495 case 'M':
496 /* Match minute. */
497 get_number (0, 59, 2);
498 tm->tm_min = val;
499 break;
500 case 'n':
501 case 't':
502 /* Match any white space. */
503 while (isspace (*rp))
504 ++rp;
505 break;
506 case 'p':
507 /* Match locale's equivalent of AM/PM. */
508 #ifdef _NL_CURRENT
509 if (*decided != raw)
511 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
513 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
514 *decided = loc;
515 break;
517 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
519 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
520 *decided = loc;
521 is_pm = 1;
522 break;
524 *decided = raw;
526 #endif
527 if (!match_string (HERE_AM_STR, rp)) {
528 if (match_string (HERE_PM_STR, rp)) {
529 is_pm = 1;
530 } else {
531 return NULL;
534 break;
535 case 'r':
536 #ifdef _NL_CURRENT
537 if (*decided != raw)
539 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
541 if (*decided == loc)
542 return NULL;
543 else
544 rp = rp_backup;
546 else
548 if (*decided == not &&
549 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
550 HERE_T_FMT_AMPM))
551 *decided = loc;
552 break;
554 *decided = raw;
556 #endif
557 if (!recursive (HERE_T_FMT_AMPM))
558 return NULL;
559 break;
560 case 'R':
561 if (!recursive ("%H:%M"))
562 return NULL;
563 break;
564 case 's':
566 /* The number of seconds may be very high so we cannot use
567 the `get_number' macro. Instead read the number
568 character for character and construct the result while
569 doing this. */
570 time_t secs = 0;
571 if (*rp < '0' || *rp > '9')
572 /* We need at least one digit. */
573 return NULL;
577 secs *= 10;
578 secs += *rp++ - '0';
580 while (*rp >= '0' && *rp <= '9');
582 if (localtime_r (&secs, tm) == NULL)
583 /* Error in function. */
584 return NULL;
586 break;
587 case 'S':
588 get_number (0, 61, 2);
589 tm->tm_sec = val;
590 break;
591 case 'X':
592 #ifdef _NL_CURRENT
593 if (*decided != raw)
595 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
597 if (*decided == loc)
598 return NULL;
599 else
600 rp = rp_backup;
602 else
604 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
605 *decided = loc;
606 break;
608 *decided = raw;
610 #endif
611 /* Fall through. */
612 case 'T':
613 if (!recursive (HERE_T_FMT))
614 return NULL;
615 break;
616 case 'u':
617 get_number (1, 7, 1);
618 tm->tm_wday = val % 7;
619 have_wday = 1;
620 break;
621 case 'g':
622 get_number (0, 99, 2);
623 /* XXX This cannot determine any field in TM. */
624 break;
625 case 'G':
626 if (*rp < '0' || *rp > '9')
627 return NULL;
628 /* XXX Ignore the number since we would need some more
629 information to compute a real date. */
631 ++rp;
632 while (*rp >= '0' && *rp <= '9');
633 break;
634 case 'U':
635 case 'V':
636 case 'W':
637 get_number (0, 53, 2);
638 /* XXX This cannot determine any field in TM without some
639 information. */
640 break;
641 case 'w':
642 /* Match number of weekday. */
643 get_number (0, 6, 1);
644 tm->tm_wday = val;
645 have_wday = 1;
646 break;
647 case 'y':
648 #ifdef _NL_CURRENT
649 match_year_in_century:
650 #endif
651 /* Match year within century. */
652 get_number (0, 99, 2);
653 /* The "Year 2000: The Millennium Rollover" paper suggests that
654 values in the range 69-99 refer to the twentieth century. */
655 tm->tm_year = val >= 69 ? val : val + 100;
656 /* Indicate that we want to use the century, if specified. */
657 want_century = 1;
658 want_xday = 1;
659 break;
660 case 'Y':
661 /* Match year including century number. */
662 get_number (0, 9999, 4);
663 tm->tm_year = val - 1900;
664 want_century = 0;
665 want_xday = 1;
666 break;
667 case 'Z':
668 /* XXX How to handle this? */
669 break;
670 case 'E':
671 #ifdef _NL_CURRENT
672 switch (*fmt++)
674 case 'c':
675 /* Match locale's alternate date and time format. */
676 if (*decided != raw)
678 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
680 if (*fmt == '\0')
681 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
683 if (!recursive (fmt))
685 if (*decided == loc)
686 return NULL;
687 else
688 rp = rp_backup;
690 else
692 if (strcmp (fmt, HERE_D_T_FMT))
693 *decided = loc;
694 want_xday = 1;
695 break;
697 *decided = raw;
699 /* The C locale has no era information, so use the
700 normal representation. */
701 if (!recursive (HERE_D_T_FMT))
702 return NULL;
703 want_xday = 1;
704 break;
705 case 'C':
706 if (*decided != raw)
708 if (era_cnt >= 0)
710 era = _nl_select_era_entry (era_cnt);
711 if (match_string (era->era_name, rp))
713 *decided = loc;
714 break;
716 else
717 return NULL;
719 else
721 num_eras = _NL_CURRENT_WORD (LC_TIME,
722 _NL_TIME_ERA_NUM_ENTRIES);
723 for (era_cnt = 0; era_cnt < (int) num_eras;
724 ++era_cnt, rp = rp_backup)
726 era = _nl_select_era_entry (era_cnt);
727 if (match_string (era->era_name, rp))
729 *decided = loc;
730 break;
733 if (era_cnt == (int) num_eras)
735 era_cnt = -1;
736 if (*decided == loc)
737 return NULL;
739 else
740 break;
743 *decided = raw;
745 /* The C locale has no era information, so use the
746 normal representation. */
747 goto match_century;
748 case 'y':
749 if (*decided == raw)
750 goto match_year_in_century;
752 get_number(0, 9999, 4);
753 tm->tm_year = val;
754 want_era = 1;
755 want_xday = 1;
756 break;
757 case 'Y':
758 if (*decided != raw)
760 num_eras = _NL_CURRENT_WORD (LC_TIME,
761 _NL_TIME_ERA_NUM_ENTRIES);
762 for (era_cnt = 0; era_cnt < (int) num_eras;
763 ++era_cnt, rp = rp_backup)
765 era = _nl_select_era_entry (era_cnt);
766 if (recursive (era->era_format))
767 break;
769 if (era_cnt == (int) num_eras)
771 era_cnt = -1;
772 if (*decided == loc)
773 return NULL;
774 else
775 rp = rp_backup;
777 else
779 *decided = loc;
780 era_cnt = -1;
781 break;
784 *decided = raw;
786 get_number (0, 9999, 4);
787 tm->tm_year = val - 1900;
788 want_century = 0;
789 want_xday = 1;
790 break;
791 case 'x':
792 if (*decided != raw)
794 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
796 if (*fmt == '\0')
797 fmt = _NL_CURRENT (LC_TIME, D_FMT);
799 if (!recursive (fmt))
801 if (*decided == loc)
802 return NULL;
803 else
804 rp = rp_backup;
806 else
808 if (strcmp (fmt, HERE_D_FMT))
809 *decided = loc;
810 break;
812 *decided = raw;
814 if (!recursive (HERE_D_FMT))
815 return NULL;
816 break;
817 case 'X':
818 if (*decided != raw)
820 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
822 if (*fmt == '\0')
823 fmt = _NL_CURRENT (LC_TIME, T_FMT);
825 if (!recursive (fmt))
827 if (*decided == loc)
828 return NULL;
829 else
830 rp = rp_backup;
832 else
834 if (strcmp (fmt, HERE_T_FMT))
835 *decided = loc;
836 break;
838 *decided = raw;
840 if (!recursive (HERE_T_FMT))
841 return NULL;
842 break;
843 default:
844 return NULL;
846 break;
847 #else
848 /* We have no information about the era format. Just use
849 the normal format. */
850 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
851 && *fmt != 'x' && *fmt != 'X')
852 /* This is an illegal format. */
853 return NULL;
855 goto start_over;
856 #endif
857 case 'O':
858 switch (*fmt++)
860 case 'd':
861 case 'e':
862 /* Match day of month using alternate numeric symbols. */
863 get_alt_number (1, 31, 2);
864 tm->tm_mday = val;
865 have_mday = 1;
866 want_xday = 1;
867 break;
868 case 'H':
869 /* Match hour in 24-hour clock using alternate numeric
870 symbols. */
871 get_alt_number (0, 23, 2);
872 tm->tm_hour = val;
873 have_I = 0;
874 break;
875 case 'I':
876 /* Match hour in 12-hour clock using alternate numeric
877 symbols. */
878 get_alt_number (1, 12, 2);
879 tm->tm_hour = val - 1;
880 have_I = 1;
881 break;
882 case 'm':
883 /* Match month using alternate numeric symbols. */
884 get_alt_number (1, 12, 2);
885 tm->tm_mon = val - 1;
886 have_mon = 1;
887 want_xday = 1;
888 break;
889 case 'M':
890 /* Match minutes using alternate numeric symbols. */
891 get_alt_number (0, 59, 2);
892 tm->tm_min = val;
893 break;
894 case 'S':
895 /* Match seconds using alternate numeric symbols. */
896 get_alt_number (0, 61, 2);
897 tm->tm_sec = val;
898 break;
899 case 'U':
900 case 'V':
901 case 'W':
902 get_alt_number (0, 53, 2);
903 /* XXX This cannot determine any field in TM without
904 further information. */
905 break;
906 case 'w':
907 /* Match number of weekday using alternate numeric symbols. */
908 get_alt_number (0, 6, 1);
909 tm->tm_wday = val;
910 have_wday = 1;
911 break;
912 case 'y':
913 /* Match year within century using alternate numeric symbols. */
914 get_alt_number (0, 99, 2);
915 tm->tm_year = val >= 69 ? val : val + 100;
916 want_xday = 1;
917 break;
918 default:
919 return NULL;
921 break;
922 default:
923 return NULL;
927 if (have_I && is_pm)
928 tm->tm_hour += 12;
930 if (century != -1)
932 if (want_century)
933 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
934 else
935 /* Only the century, but not the year. Strange, but so be it. */
936 tm->tm_year = (century - 19) * 100;
939 #ifdef _NL_CURRENT
940 if (era_cnt != -1)
942 era = _nl_select_era_entry(era_cnt);
943 if (want_era)
944 tm->tm_year = (era->start_date[0]
945 + ((tm->tm_year - era->offset)
946 * era->absolute_direction));
947 else
948 /* Era start year assumed. */
949 tm->tm_year = era->start_date[0];
951 else
952 #endif
953 if (want_era)
954 return NULL;
956 if (want_xday && !have_wday)
958 if ( !(have_mon && have_mday) && have_yday)
960 /* We don't have tm_mon and/or tm_mday, compute them. */
961 int t_mon = 0;
962 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
963 t_mon++;
964 if (!have_mon)
965 tm->tm_mon = t_mon - 1;
966 if (!have_mday)
967 tm->tm_mday =
968 (tm->tm_yday
969 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
971 day_of_the_week (tm);
973 if (want_xday && !have_yday)
974 day_of_the_year (tm);
976 return discard_const_p(char, rp);
980 char *rep_strptime(const char *buf, const char *format, struct tm *tm)
982 enum locale_status decided;
984 #ifdef _NL_CURRENT
985 decided = not;
986 #else
987 decided = raw;
988 #endif
989 return strptime_internal (buf, format, tm, &decided, -1);