WHATSNEW: Add major enhancements.
[Samba.git] / lib / replace / strptime.c
blob20e5d8c39b6a2acc0189ad8fcb5ddf11285b0f52
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 int cnt;
255 size_t val;
256 int have_I, is_pm;
257 int century, want_century;
258 int want_era;
259 int have_wday, want_xday;
260 int have_yday;
261 int have_mon, have_mday;
262 #ifdef _NL_CURRENT
263 const char *rp_backup;
264 size_t num_eras;
265 struct era_entry *era;
267 era = NULL;
268 #endif
270 have_I = is_pm = 0;
271 century = -1;
272 want_century = 0;
273 want_era = 0;
275 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
277 while (*fmt != '\0')
279 /* A white space in the format string matches 0 more or white
280 space in the input string. */
281 if (isspace (*fmt))
283 while (isspace (*rp))
284 ++rp;
285 ++fmt;
286 continue;
289 /* Any character but `%' must be matched by the same character
290 in the iput string. */
291 if (*fmt != '%')
293 match_char (*fmt++, *rp++);
294 continue;
297 ++fmt;
298 #ifndef _NL_CURRENT
299 /* We need this for handling the `E' modifier. */
300 start_over:
301 #endif
303 #ifdef _NL_CURRENT
304 /* Make back up of current processing pointer. */
305 rp_backup = rp;
306 #endif
308 switch (*fmt++)
310 case '%':
311 /* Match the `%' character itself. */
312 match_char ('%', *rp++);
313 break;
314 case 'a':
315 case 'A':
316 /* Match day of week. */
317 for (cnt = 0; cnt < 7; ++cnt)
319 #ifdef _NL_CURRENT
320 if (*decided !=raw)
322 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
324 if (*decided == not
325 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
326 weekday_name[cnt]))
327 *decided = loc;
328 break;
330 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
332 if (*decided == not
333 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
334 ab_weekday_name[cnt]))
335 *decided = loc;
336 break;
339 #endif
340 if (*decided != loc
341 && (match_string (weekday_name[cnt], rp)
342 || match_string (ab_weekday_name[cnt], rp)))
344 *decided = raw;
345 break;
348 if (cnt == 7)
349 /* Does not match a weekday name. */
350 return NULL;
351 tm->tm_wday = cnt;
352 have_wday = 1;
353 break;
354 case 'b':
355 case 'B':
356 case 'h':
357 /* Match month name. */
358 for (cnt = 0; cnt < 12; ++cnt)
360 #ifdef _NL_CURRENT
361 if (*decided !=raw)
363 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
365 if (*decided == not
366 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
367 month_name[cnt]))
368 *decided = loc;
369 break;
371 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
373 if (*decided == not
374 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
375 ab_month_name[cnt]))
376 *decided = loc;
377 break;
380 #endif
381 if (match_string (month_name[cnt], rp)
382 || match_string (ab_month_name[cnt], rp))
384 *decided = raw;
385 break;
388 if (cnt == 12)
389 /* Does not match a month name. */
390 return NULL;
391 tm->tm_mon = cnt;
392 want_xday = 1;
393 break;
394 case 'c':
395 /* Match locale's date and time format. */
396 #ifdef _NL_CURRENT
397 if (*decided != raw)
399 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
401 if (*decided == loc)
402 return NULL;
403 else
404 rp = rp_backup;
406 else
408 if (*decided == not &&
409 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
410 *decided = loc;
411 want_xday = 1;
412 break;
414 *decided = raw;
416 #endif
417 if (!recursive (HERE_D_T_FMT))
418 return NULL;
419 want_xday = 1;
420 break;
421 case 'C':
422 /* Match century number. */
423 #ifdef _NL_CURRENT
424 match_century:
425 #endif
426 get_number (0, 99, 2);
427 century = val;
428 want_xday = 1;
429 break;
430 case 'd':
431 case 'e':
432 /* Match day of month. */
433 get_number (1, 31, 2);
434 tm->tm_mday = val;
435 have_mday = 1;
436 want_xday = 1;
437 break;
438 case 'F':
439 if (!recursive ("%Y-%m-%d"))
440 return NULL;
441 want_xday = 1;
442 break;
443 case 'x':
444 #ifdef _NL_CURRENT
445 if (*decided != raw)
447 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
449 if (*decided == loc)
450 return NULL;
451 else
452 rp = rp_backup;
454 else
456 if (*decided == not
457 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
458 *decided = loc;
459 want_xday = 1;
460 break;
462 *decided = raw;
464 #endif
465 /* Fall through. */
466 case 'D':
467 /* Match standard day format. */
468 if (!recursive (HERE_D_FMT))
469 return NULL;
470 want_xday = 1;
471 break;
472 case 'k':
473 case 'H':
474 /* Match hour in 24-hour clock. */
475 get_number (0, 23, 2);
476 tm->tm_hour = val;
477 have_I = 0;
478 break;
479 case 'I':
480 /* Match hour in 12-hour clock. */
481 get_number (1, 12, 2);
482 tm->tm_hour = val % 12;
483 have_I = 1;
484 break;
485 case 'j':
486 /* Match day number of year. */
487 get_number (1, 366, 3);
488 tm->tm_yday = val - 1;
489 have_yday = 1;
490 break;
491 case 'm':
492 /* Match number of month. */
493 get_number (1, 12, 2);
494 tm->tm_mon = val - 1;
495 have_mon = 1;
496 want_xday = 1;
497 break;
498 case 'M':
499 /* Match minute. */
500 get_number (0, 59, 2);
501 tm->tm_min = val;
502 break;
503 case 'n':
504 case 't':
505 /* Match any white space. */
506 while (isspace (*rp))
507 ++rp;
508 break;
509 case 'p':
510 /* Match locale's equivalent of AM/PM. */
511 #ifdef _NL_CURRENT
512 if (*decided != raw)
514 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
516 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
517 *decided = loc;
518 break;
520 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
522 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
523 *decided = loc;
524 is_pm = 1;
525 break;
527 *decided = raw;
529 #endif
530 if (!match_string (HERE_AM_STR, rp)) {
531 if (match_string (HERE_PM_STR, rp)) {
532 is_pm = 1;
533 } else {
534 return NULL;
537 break;
538 case 'r':
539 #ifdef _NL_CURRENT
540 if (*decided != raw)
542 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
544 if (*decided == loc)
545 return NULL;
546 else
547 rp = rp_backup;
549 else
551 if (*decided == not &&
552 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
553 HERE_T_FMT_AMPM))
554 *decided = loc;
555 break;
557 *decided = raw;
559 #endif
560 if (!recursive (HERE_T_FMT_AMPM))
561 return NULL;
562 break;
563 case 'R':
564 if (!recursive ("%H:%M"))
565 return NULL;
566 break;
567 case 's':
569 /* The number of seconds may be very high so we cannot use
570 the `get_number' macro. Instead read the number
571 character for character and construct the result while
572 doing this. */
573 time_t secs = 0;
574 if (*rp < '0' || *rp > '9')
575 /* We need at least one digit. */
576 return NULL;
580 secs *= 10;
581 secs += *rp++ - '0';
583 while (*rp >= '0' && *rp <= '9');
585 if (localtime_r (&secs, tm) == NULL)
586 /* Error in function. */
587 return NULL;
589 break;
590 case 'S':
591 get_number (0, 61, 2);
592 tm->tm_sec = val;
593 break;
594 case 'X':
595 #ifdef _NL_CURRENT
596 if (*decided != raw)
598 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
600 if (*decided == loc)
601 return NULL;
602 else
603 rp = rp_backup;
605 else
607 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
608 *decided = loc;
609 break;
611 *decided = raw;
613 #endif
614 /* Fall through. */
615 case 'T':
616 if (!recursive (HERE_T_FMT))
617 return NULL;
618 break;
619 case 'u':
620 get_number (1, 7, 1);
621 tm->tm_wday = val % 7;
622 have_wday = 1;
623 break;
624 case 'g':
625 get_number (0, 99, 2);
626 /* XXX This cannot determine any field in TM. */
627 break;
628 case 'G':
629 if (*rp < '0' || *rp > '9')
630 return NULL;
631 /* XXX Ignore the number since we would need some more
632 information to compute a real date. */
634 ++rp;
635 while (*rp >= '0' && *rp <= '9');
636 break;
637 case 'U':
638 case 'V':
639 case 'W':
640 get_number (0, 53, 2);
641 /* XXX This cannot determine any field in TM without some
642 information. */
643 break;
644 case 'w':
645 /* Match number of weekday. */
646 get_number (0, 6, 1);
647 tm->tm_wday = val;
648 have_wday = 1;
649 break;
650 case 'y':
651 #ifdef _NL_CURRENT
652 match_year_in_century:
653 #endif
654 /* Match year within century. */
655 get_number (0, 99, 2);
656 /* The "Year 2000: The Millennium Rollover" paper suggests that
657 values in the range 69-99 refer to the twentieth century. */
658 tm->tm_year = val >= 69 ? val : val + 100;
659 /* Indicate that we want to use the century, if specified. */
660 want_century = 1;
661 want_xday = 1;
662 break;
663 case 'Y':
664 /* Match year including century number. */
665 get_number (0, 9999, 4);
666 tm->tm_year = val - 1900;
667 want_century = 0;
668 want_xday = 1;
669 break;
670 case 'Z':
671 /* XXX How to handle this? */
672 break;
673 case 'E':
674 #ifdef _NL_CURRENT
675 switch (*fmt++)
677 case 'c':
678 /* Match locale's alternate date and time format. */
679 if (*decided != raw)
681 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
683 if (*fmt == '\0')
684 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
686 if (!recursive (fmt))
688 if (*decided == loc)
689 return NULL;
690 else
691 rp = rp_backup;
693 else
695 if (strcmp (fmt, HERE_D_T_FMT))
696 *decided = loc;
697 want_xday = 1;
698 break;
700 *decided = raw;
702 /* The C locale has no era information, so use the
703 normal representation. */
704 if (!recursive (HERE_D_T_FMT))
705 return NULL;
706 want_xday = 1;
707 break;
708 case 'C':
709 if (*decided != raw)
711 if (era_cnt >= 0)
713 era = _nl_select_era_entry (era_cnt);
714 if (match_string (era->era_name, rp))
716 *decided = loc;
717 break;
719 else
720 return NULL;
722 else
724 num_eras = _NL_CURRENT_WORD (LC_TIME,
725 _NL_TIME_ERA_NUM_ENTRIES);
726 for (era_cnt = 0; era_cnt < (int) num_eras;
727 ++era_cnt, rp = rp_backup)
729 era = _nl_select_era_entry (era_cnt);
730 if (match_string (era->era_name, rp))
732 *decided = loc;
733 break;
736 if (era_cnt == (int) num_eras)
738 era_cnt = -1;
739 if (*decided == loc)
740 return NULL;
742 else
743 break;
746 *decided = raw;
748 /* The C locale has no era information, so use the
749 normal representation. */
750 goto match_century;
751 case 'y':
752 if (*decided == raw)
753 goto match_year_in_century;
755 get_number(0, 9999, 4);
756 tm->tm_year = val;
757 want_era = 1;
758 want_xday = 1;
759 break;
760 case 'Y':
761 if (*decided != raw)
763 num_eras = _NL_CURRENT_WORD (LC_TIME,
764 _NL_TIME_ERA_NUM_ENTRIES);
765 for (era_cnt = 0; era_cnt < (int) num_eras;
766 ++era_cnt, rp = rp_backup)
768 era = _nl_select_era_entry (era_cnt);
769 if (recursive (era->era_format))
770 break;
772 if (era_cnt == (int) num_eras)
774 era_cnt = -1;
775 if (*decided == loc)
776 return NULL;
777 else
778 rp = rp_backup;
780 else
782 *decided = loc;
783 era_cnt = -1;
784 break;
787 *decided = raw;
789 get_number (0, 9999, 4);
790 tm->tm_year = val - 1900;
791 want_century = 0;
792 want_xday = 1;
793 break;
794 case 'x':
795 if (*decided != raw)
797 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
799 if (*fmt == '\0')
800 fmt = _NL_CURRENT (LC_TIME, D_FMT);
802 if (!recursive (fmt))
804 if (*decided == loc)
805 return NULL;
806 else
807 rp = rp_backup;
809 else
811 if (strcmp (fmt, HERE_D_FMT))
812 *decided = loc;
813 break;
815 *decided = raw;
817 if (!recursive (HERE_D_FMT))
818 return NULL;
819 break;
820 case 'X':
821 if (*decided != raw)
823 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
825 if (*fmt == '\0')
826 fmt = _NL_CURRENT (LC_TIME, T_FMT);
828 if (!recursive (fmt))
830 if (*decided == loc)
831 return NULL;
832 else
833 rp = rp_backup;
835 else
837 if (strcmp (fmt, HERE_T_FMT))
838 *decided = loc;
839 break;
841 *decided = raw;
843 if (!recursive (HERE_T_FMT))
844 return NULL;
845 break;
846 default:
847 return NULL;
849 break;
850 #else
851 /* We have no information about the era format. Just use
852 the normal format. */
853 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
854 && *fmt != 'x' && *fmt != 'X')
855 /* This is an illegal format. */
856 return NULL;
858 goto start_over;
859 #endif
860 case 'O':
861 switch (*fmt++)
863 case 'd':
864 case 'e':
865 /* Match day of month using alternate numeric symbols. */
866 get_alt_number (1, 31, 2);
867 tm->tm_mday = val;
868 have_mday = 1;
869 want_xday = 1;
870 break;
871 case 'H':
872 /* Match hour in 24-hour clock using alternate numeric
873 symbols. */
874 get_alt_number (0, 23, 2);
875 tm->tm_hour = val;
876 have_I = 0;
877 break;
878 case 'I':
879 /* Match hour in 12-hour clock using alternate numeric
880 symbols. */
881 get_alt_number (1, 12, 2);
882 tm->tm_hour = val - 1;
883 have_I = 1;
884 break;
885 case 'm':
886 /* Match month using alternate numeric symbols. */
887 get_alt_number (1, 12, 2);
888 tm->tm_mon = val - 1;
889 have_mon = 1;
890 want_xday = 1;
891 break;
892 case 'M':
893 /* Match minutes using alternate numeric symbols. */
894 get_alt_number (0, 59, 2);
895 tm->tm_min = val;
896 break;
897 case 'S':
898 /* Match seconds using alternate numeric symbols. */
899 get_alt_number (0, 61, 2);
900 tm->tm_sec = val;
901 break;
902 case 'U':
903 case 'V':
904 case 'W':
905 get_alt_number (0, 53, 2);
906 /* XXX This cannot determine any field in TM without
907 further information. */
908 break;
909 case 'w':
910 /* Match number of weekday using alternate numeric symbols. */
911 get_alt_number (0, 6, 1);
912 tm->tm_wday = val;
913 have_wday = 1;
914 break;
915 case 'y':
916 /* Match year within century using alternate numeric symbols. */
917 get_alt_number (0, 99, 2);
918 tm->tm_year = val >= 69 ? val : val + 100;
919 want_xday = 1;
920 break;
921 default:
922 return NULL;
924 break;
925 default:
926 return NULL;
930 if (have_I && is_pm)
931 tm->tm_hour += 12;
933 if (century != -1)
935 if (want_century)
936 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
937 else
938 /* Only the century, but not the year. Strange, but so be it. */
939 tm->tm_year = (century - 19) * 100;
942 #ifdef _NL_CURRENT
943 if (era_cnt != -1)
945 era = _nl_select_era_entry(era_cnt);
946 if (want_era)
947 tm->tm_year = (era->start_date[0]
948 + ((tm->tm_year - era->offset)
949 * era->absolute_direction));
950 else
951 /* Era start year assumed. */
952 tm->tm_year = era->start_date[0];
954 else
955 #endif
956 if (want_era)
957 return NULL;
959 if (want_xday && !have_wday)
961 if ( !(have_mon && have_mday) && have_yday)
963 /* We don't have tm_mon and/or tm_mday, compute them. */
964 int t_mon = 0;
965 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
966 t_mon++;
967 if (!have_mon)
968 tm->tm_mon = t_mon - 1;
969 if (!have_mday)
970 tm->tm_mday =
971 (tm->tm_yday
972 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
974 day_of_the_week (tm);
976 if (want_xday && !have_yday)
977 day_of_the_year (tm);
979 return discard_const_p(char, rp);
983 char *rep_strptime(const char *buf, const char *format, struct tm *tm)
985 enum locale_status decided;
987 #ifdef _NL_CURRENT
988 decided = not;
989 #else
990 decided = raw;
991 #endif
992 return strptime_internal (buf, format, tm, &decided, -1);