Update.
[glibc.git] / time / strptime.c
blobbbd9e645505ed713509f22e50142d519bba58dae
1 /* Convert a string representation of time to a time value.
2 Copyright (C) 1996-2000, 2001, 2002 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
8 License as published by the Free Software Foundation; either
9 version 2.1 of the 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 Lesser 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; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 /* XXX This version of the implementation is not really complete.
22 Some of the fields cannot add information alone. But if seeing
23 some of them in the same format (such as year, week and weekday)
24 this is enough information for determining the date. */
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <ctype.h>
31 #include <langinfo.h>
32 #include <limits.h>
33 #include <string.h>
34 #include <time.h>
36 #ifdef _LIBC
37 # include "../locale/localeinfo.h"
38 #endif
41 #ifndef __P
42 # if defined __GNUC__ || (defined __STDC__ && __STDC__)
43 # define __P(args) args
44 # else
45 # define __P(args) ()
46 # endif /* GCC. */
47 #endif /* Not __P. */
50 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
51 # ifdef _LIBC
52 # define localtime_r __localtime_r
53 # else
54 /* Approximate localtime_r as best we can in its absence. */
55 # define localtime_r my_localtime_r
56 static struct tm *localtime_r __P ((const time_t *, struct tm *));
57 static struct tm *
58 localtime_r (t, tp)
59 const time_t *t;
60 struct tm *tp;
62 struct tm *l = localtime (t);
63 if (! l)
64 return 0;
65 *tp = *l;
66 return tp;
68 # endif /* ! _LIBC */
69 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
72 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
73 #if defined __GNUC__ && __GNUC__ >= 2
74 # define match_string(cs1, s2) \
75 ({ size_t len = strlen (cs1); \
76 int result = strncasecmp ((cs1), (s2), len) == 0; \
77 if (result) (s2) += len; \
78 result; })
79 #else
80 /* Oh come on. Get a reasonable compiler. */
81 # define match_string(cs1, s2) \
82 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
83 #endif
84 /* We intentionally do not use isdigit() for testing because this will
85 lead to problems with the wide character version. */
86 #define get_number(from, to, n) \
87 do { \
88 int __n = n; \
89 val = 0; \
90 while (*rp == ' ') \
91 ++rp; \
92 if (*rp < '0' || *rp > '9') \
93 return NULL; \
94 do { \
95 val *= 10; \
96 val += *rp++ - '0'; \
97 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
98 if (val < from || val > to) \
99 return NULL; \
100 } while (0)
101 #ifdef _NL_CURRENT
102 # define get_alt_number(from, to, n) \
103 ({ \
104 __label__ do_normal; \
106 if (*decided != raw) \
108 val = _nl_parse_alt_digit (&rp); \
109 if (val == -1 && *decided != loc) \
111 *decided = loc; \
112 goto do_normal; \
114 if (val < from || val > to) \
115 return NULL; \
117 else \
119 do_normal: \
120 get_number (from, to, n); \
122 0; \
124 #else
125 # define get_alt_number(from, to, n) \
126 /* We don't have the alternate representation. */ \
127 get_number(from, to, n)
128 #endif
129 #define recursive(new_fmt) \
130 (*(new_fmt) != '\0' \
131 && (rp = strptime_internal (rp, (new_fmt), tm, \
132 decided, era_cnt LOCALE_ARG)) != NULL)
135 #ifdef _LIBC
136 /* This is defined in locale/C-time.c in the GNU libc. */
137 extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
139 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
140 # define ab_weekday_name \
141 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
142 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
143 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
144 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
145 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
146 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
147 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
148 # define HERE_T_FMT_AMPM \
149 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
150 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
152 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
153 #else
154 static char const weekday_name[][10] =
156 "Sunday", "Monday", "Tuesday", "Wednesday",
157 "Thursday", "Friday", "Saturday"
159 static char const ab_weekday_name[][4] =
161 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
163 static char const month_name[][10] =
165 "January", "February", "March", "April", "May", "June",
166 "July", "August", "September", "October", "November", "December"
168 static char const ab_month_name[][4] =
170 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
171 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
173 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
174 # define HERE_D_FMT "%m/%d/%y"
175 # define HERE_AM_STR "AM"
176 # define HERE_PM_STR "PM"
177 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
178 # define HERE_T_FMT "%H:%M:%S"
180 const unsigned short int __mon_yday[2][13] =
182 /* Normal years. */
183 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
184 /* Leap years. */
185 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
187 #endif
189 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
190 /* We use this code also for the extended locale handling where the
191 function gets as an additional argument the locale which has to be
192 used. To access the values we have to redefine the _NL_CURRENT
193 macro. */
194 # define strptime __strptime_l
195 # undef _NL_CURRENT
196 # define _NL_CURRENT(category, item) \
197 (current->values[_NL_ITEM_INDEX (item)].string)
198 # define LOCALE_PARAM , locale
199 # define LOCALE_ARG , locale
200 # define LOCALE_PARAM_PROTO , __locale_t locale
201 # define LOCALE_PARAM_DECL __locale_t locale;
202 #else
203 # define LOCALE_PARAM
204 # define LOCALE_ARG
205 # define LOCALE_PARAM_DECL
206 # define LOCALE_PARAM_PROTO
207 #endif
210 /* Status of lookup: do we use the locale data or the raw data? */
211 enum locale_status { not, loc, raw };
214 #ifndef __isleap
215 /* Nonzero if YEAR is a leap year (every 4 years,
216 except every 100th isn't, and every 400th is). */
217 # define __isleap(year) \
218 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
219 #endif
221 /* Compute the day of the week. */
222 static void
223 day_of_the_week (struct tm *tm)
225 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
226 the difference between this data in the one on TM and so determine
227 the weekday. */
228 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
229 int wday = (-473
230 + (365 * (tm->tm_year - 70))
231 + (corr_year / 4)
232 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
233 + (((corr_year / 4) / 25) / 4)
234 + __mon_yday[0][tm->tm_mon]
235 + tm->tm_mday - 1);
236 tm->tm_wday = ((wday % 7) + 7) % 7;
239 /* Compute the day of the year. */
240 static void
241 day_of_the_year (struct tm *tm)
243 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
244 + (tm->tm_mday - 1));
248 static char *
249 #ifdef _LIBC
250 internal_function
251 #endif
252 strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
253 enum locale_status *decided, int era_cnt
254 LOCALE_PARAM_PROTO));
256 static char *
257 #ifdef _LIBC
258 internal_function
259 #endif
260 strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
261 const char *rp;
262 const char *fmt;
263 struct tm *tm;
264 enum locale_status *decided;
265 int era_cnt;
266 LOCALE_PARAM_DECL
268 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
269 const struct locale_data *const current = locale->__locales[LC_TIME];
270 #endif
272 const char *rp_backup;
273 int cnt;
274 size_t val;
275 int have_I, is_pm;
276 int century, want_century;
277 int want_era;
278 int have_wday, want_xday;
279 int have_yday;
280 int have_mon, have_mday;
281 int have_uweek, have_wweek;
282 int week_no;
283 size_t num_eras;
284 struct era_entry *era;
286 have_I = is_pm = 0;
287 century = -1;
288 want_century = 0;
289 want_era = 0;
290 era = NULL;
291 week_no = 0;
293 have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
294 have_wweek = 0;
296 while (*fmt != '\0')
298 /* A white space in the format string matches 0 more or white
299 space in the input string. */
300 if (isspace (*fmt))
302 while (isspace (*rp))
303 ++rp;
304 ++fmt;
305 continue;
308 /* Any character but `%' must be matched by the same character
309 in the iput string. */
310 if (*fmt != '%')
312 match_char (*fmt++, *rp++);
313 continue;
316 ++fmt;
317 #ifndef _NL_CURRENT
318 /* We need this for handling the `E' modifier. */
319 start_over:
320 #endif
322 /* Make back up of current processing pointer. */
323 rp_backup = rp;
325 switch (*fmt++)
327 case '%':
328 /* Match the `%' character itself. */
329 match_char ('%', *rp++);
330 break;
331 case 'a':
332 case 'A':
333 /* Match day of week. */
334 for (cnt = 0; cnt < 7; ++cnt)
336 #ifdef _NL_CURRENT
337 if (*decided !=raw)
339 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
341 if (*decided == not
342 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
343 weekday_name[cnt]))
344 *decided = loc;
345 break;
347 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
349 if (*decided == not
350 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
351 ab_weekday_name[cnt]))
352 *decided = loc;
353 break;
356 #endif
357 if (*decided != loc
358 && (match_string (weekday_name[cnt], rp)
359 || match_string (ab_weekday_name[cnt], rp)))
361 *decided = raw;
362 break;
365 if (cnt == 7)
366 /* Does not match a weekday name. */
367 return NULL;
368 tm->tm_wday = cnt;
369 have_wday = 1;
370 break;
371 case 'b':
372 case 'B':
373 case 'h':
374 /* Match month name. */
375 for (cnt = 0; cnt < 12; ++cnt)
377 #ifdef _NL_CURRENT
378 if (*decided !=raw)
380 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
382 if (*decided == not
383 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
384 month_name[cnt]))
385 *decided = loc;
386 break;
388 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
390 if (*decided == not
391 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
392 ab_month_name[cnt]))
393 *decided = loc;
394 break;
397 #endif
398 if (match_string (month_name[cnt], rp)
399 || match_string (ab_month_name[cnt], rp))
401 *decided = raw;
402 break;
405 if (cnt == 12)
406 /* Does not match a month name. */
407 return NULL;
408 tm->tm_mon = cnt;
409 want_xday = 1;
410 break;
411 case 'c':
412 /* Match locale's date and time format. */
413 #ifdef _NL_CURRENT
414 if (*decided != raw)
416 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
418 if (*decided == loc)
419 return NULL;
420 else
421 rp = rp_backup;
423 else
425 if (*decided == not &&
426 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
427 *decided = loc;
428 want_xday = 1;
429 break;
431 *decided = raw;
433 #endif
434 if (!recursive (HERE_D_T_FMT))
435 return NULL;
436 want_xday = 1;
437 break;
438 case 'C':
439 /* Match century number. */
440 match_century:
441 get_number (0, 99, 2);
442 century = val;
443 want_xday = 1;
444 break;
445 case 'd':
446 case 'e':
447 /* Match day of month. */
448 get_number (1, 31, 2);
449 tm->tm_mday = val;
450 have_mday = 1;
451 want_xday = 1;
452 break;
453 case 'F':
454 if (!recursive ("%Y-%m-%d"))
455 return NULL;
456 want_xday = 1;
457 break;
458 case 'x':
459 #ifdef _NL_CURRENT
460 if (*decided != raw)
462 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
464 if (*decided == loc)
465 return NULL;
466 else
467 rp = rp_backup;
469 else
471 if (*decided == not
472 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
473 *decided = loc;
474 want_xday = 1;
475 break;
477 *decided = raw;
479 #endif
480 /* Fall through. */
481 case 'D':
482 /* Match standard day format. */
483 if (!recursive (HERE_D_FMT))
484 return NULL;
485 want_xday = 1;
486 break;
487 case 'k':
488 case 'H':
489 /* Match hour in 24-hour clock. */
490 get_number (0, 23, 2);
491 tm->tm_hour = val;
492 have_I = 0;
493 break;
494 case 'l':
495 /* Match hour in 12-hour clock. GNU extension. */
496 case 'I':
497 /* Match hour in 12-hour clock. */
498 get_number (1, 12, 2);
499 tm->tm_hour = val % 12;
500 have_I = 1;
501 break;
502 case 'j':
503 /* Match day number of year. */
504 get_number (1, 366, 3);
505 tm->tm_yday = val - 1;
506 have_yday = 1;
507 break;
508 case 'm':
509 /* Match number of month. */
510 get_number (1, 12, 2);
511 tm->tm_mon = val - 1;
512 have_mon = 1;
513 want_xday = 1;
514 break;
515 case 'M':
516 /* Match minute. */
517 get_number (0, 59, 2);
518 tm->tm_min = val;
519 break;
520 case 'n':
521 case 't':
522 /* Match any white space. */
523 while (isspace (*rp))
524 ++rp;
525 break;
526 case 'p':
527 /* Match locale's equivalent of AM/PM. */
528 #ifdef _NL_CURRENT
529 if (*decided != raw)
531 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
533 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
534 *decided = loc;
535 break;
537 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
539 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
540 *decided = loc;
541 is_pm = 1;
542 break;
544 *decided = raw;
546 #endif
547 if (!match_string (HERE_AM_STR, rp))
548 if (match_string (HERE_PM_STR, rp))
549 is_pm = 1;
550 else
551 return NULL;
552 break;
553 case 'r':
554 #ifdef _NL_CURRENT
555 if (*decided != raw)
557 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
559 if (*decided == loc)
560 return NULL;
561 else
562 rp = rp_backup;
564 else
566 if (*decided == not &&
567 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
568 HERE_T_FMT_AMPM))
569 *decided = loc;
570 break;
572 *decided = raw;
574 #endif
575 if (!recursive (HERE_T_FMT_AMPM))
576 return NULL;
577 break;
578 case 'R':
579 if (!recursive ("%H:%M"))
580 return NULL;
581 break;
582 case 's':
584 /* The number of seconds may be very high so we cannot use
585 the `get_number' macro. Instead read the number
586 character for character and construct the result while
587 doing this. */
588 time_t secs = 0;
589 if (*rp < '0' || *rp > '9')
590 /* We need at least one digit. */
591 return NULL;
595 secs *= 10;
596 secs += *rp++ - '0';
598 while (*rp >= '0' && *rp <= '9');
600 if (localtime_r (&secs, tm) == NULL)
601 /* Error in function. */
602 return NULL;
604 break;
605 case 'S':
606 get_number (0, 61, 2);
607 tm->tm_sec = val;
608 break;
609 case 'X':
610 #ifdef _NL_CURRENT
611 if (*decided != raw)
613 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
615 if (*decided == loc)
616 return NULL;
617 else
618 rp = rp_backup;
620 else
622 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
623 *decided = loc;
624 break;
626 *decided = raw;
628 #endif
629 /* Fall through. */
630 case 'T':
631 if (!recursive (HERE_T_FMT))
632 return NULL;
633 break;
634 case 'u':
635 get_number (1, 7, 1);
636 tm->tm_wday = val % 7;
637 have_wday = 1;
638 break;
639 case 'g':
640 get_number (0, 99, 2);
641 /* XXX This cannot determine any field in TM. */
642 break;
643 case 'G':
644 if (*rp < '0' || *rp > '9')
645 return NULL;
646 /* XXX Ignore the number since we would need some more
647 information to compute a real date. */
649 ++rp;
650 while (*rp >= '0' && *rp <= '9');
651 break;
652 case 'U':
653 get_number (0, 53, 2);
654 week_no = val;
655 have_uweek = 1;
656 break;
657 case 'W':
658 get_number (0, 53, 2);
659 week_no = val;
660 have_wweek = 1;
661 break;
662 case 'V':
663 get_number (0, 53, 2);
664 /* XXX This cannot determine any field in TM without some
665 information. */
666 break;
667 case 'w':
668 /* Match number of weekday. */
669 get_number (0, 6, 1);
670 tm->tm_wday = val;
671 have_wday = 1;
672 break;
673 case 'y':
674 match_year_in_century:
675 /* Match year within century. */
676 get_number (0, 99, 2);
677 /* The "Year 2000: The Millennium Rollover" paper suggests that
678 values in the range 69-99 refer to the twentieth century. */
679 tm->tm_year = val >= 69 ? val : val + 100;
680 /* Indicate that we want to use the century, if specified. */
681 want_century = 1;
682 want_xday = 1;
683 break;
684 case 'Y':
685 /* Match year including century number. */
686 get_number (0, 9999, 4);
687 tm->tm_year = val - 1900;
688 want_century = 0;
689 want_xday = 1;
690 break;
691 case 'Z':
692 /* XXX How to handle this? */
693 break;
694 case 'E':
695 #ifdef _NL_CURRENT
696 switch (*fmt++)
698 case 'c':
699 /* Match locale's alternate date and time format. */
700 if (*decided != raw)
702 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
704 if (*fmt == '\0')
705 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
707 if (!recursive (fmt))
709 if (*decided == loc)
710 return NULL;
711 else
712 rp = rp_backup;
714 else
716 if (strcmp (fmt, HERE_D_T_FMT))
717 *decided = loc;
718 want_xday = 1;
719 break;
721 *decided = raw;
723 /* The C locale has no era information, so use the
724 normal representation. */
725 if (!recursive (HERE_D_T_FMT))
726 return NULL;
727 want_xday = 1;
728 break;
729 case 'C':
730 if (*decided != raw)
732 if (era_cnt >= 0)
734 era = _nl_select_era_entry (era_cnt);
735 if (match_string (era->era_name, rp))
737 *decided = loc;
738 break;
740 else
741 return NULL;
743 else
745 num_eras = _NL_CURRENT_WORD (LC_TIME,
746 _NL_TIME_ERA_NUM_ENTRIES);
747 for (era_cnt = 0; era_cnt < (int) num_eras;
748 ++era_cnt, rp = rp_backup)
750 era = _nl_select_era_entry (era_cnt);
751 if (match_string (era->era_name, rp))
753 *decided = loc;
754 break;
757 if (era_cnt == (int) num_eras)
759 era_cnt = -1;
760 if (*decided == loc)
761 return NULL;
763 else
764 break;
767 *decided = raw;
769 /* The C locale has no era information, so use the
770 normal representation. */
771 goto match_century;
772 case 'y':
773 if (*decided == raw)
774 goto match_year_in_century;
776 get_number(0, 9999, 4);
777 tm->tm_year = val;
778 want_era = 1;
779 want_xday = 1;
780 want_century = 1;
781 break;
782 case 'Y':
783 if (*decided != raw)
785 num_eras = _NL_CURRENT_WORD (LC_TIME,
786 _NL_TIME_ERA_NUM_ENTRIES);
787 for (era_cnt = 0; era_cnt < (int) num_eras;
788 ++era_cnt, rp = rp_backup)
790 era = _nl_select_era_entry (era_cnt);
791 if (recursive (era->era_format))
792 break;
794 if (era_cnt == (int) num_eras)
796 era_cnt = -1;
797 if (*decided == loc)
798 return NULL;
799 else
800 rp = rp_backup;
802 else
804 *decided = loc;
805 era_cnt = -1;
806 break;
809 *decided = raw;
811 get_number (0, 9999, 4);
812 tm->tm_year = val - 1900;
813 want_century = 0;
814 want_xday = 1;
815 break;
816 case 'x':
817 if (*decided != raw)
819 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
821 if (*fmt == '\0')
822 fmt = _NL_CURRENT (LC_TIME, D_FMT);
824 if (!recursive (fmt))
826 if (*decided == loc)
827 return NULL;
828 else
829 rp = rp_backup;
831 else
833 if (strcmp (fmt, HERE_D_FMT))
834 *decided = loc;
835 break;
837 *decided = raw;
839 if (!recursive (HERE_D_FMT))
840 return NULL;
841 break;
842 case 'X':
843 if (*decided != raw)
845 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
847 if (*fmt == '\0')
848 fmt = _NL_CURRENT (LC_TIME, T_FMT);
850 if (!recursive (fmt))
852 if (*decided == loc)
853 return NULL;
854 else
855 rp = rp_backup;
857 else
859 if (strcmp (fmt, HERE_T_FMT))
860 *decided = loc;
861 break;
863 *decided = raw;
865 if (!recursive (HERE_T_FMT))
866 return NULL;
867 break;
868 default:
869 return NULL;
871 break;
872 #else
873 /* We have no information about the era format. Just use
874 the normal format. */
875 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
876 && *fmt != 'x' && *fmt != 'X')
877 /* This is an illegal format. */
878 return NULL;
880 goto start_over;
881 #endif
882 case 'O':
883 switch (*fmt++)
885 case 'd':
886 case 'e':
887 /* Match day of month using alternate numeric symbols. */
888 get_alt_number (1, 31, 2);
889 tm->tm_mday = val;
890 have_mday = 1;
891 want_xday = 1;
892 break;
893 case 'H':
894 /* Match hour in 24-hour clock using alternate numeric
895 symbols. */
896 get_alt_number (0, 23, 2);
897 tm->tm_hour = val;
898 have_I = 0;
899 break;
900 case 'I':
901 /* Match hour in 12-hour clock using alternate numeric
902 symbols. */
903 get_alt_number (1, 12, 2);
904 tm->tm_hour = val % 12;
905 have_I = 1;
906 break;
907 case 'm':
908 /* Match month using alternate numeric symbols. */
909 get_alt_number (1, 12, 2);
910 tm->tm_mon = val - 1;
911 have_mon = 1;
912 want_xday = 1;
913 break;
914 case 'M':
915 /* Match minutes using alternate numeric symbols. */
916 get_alt_number (0, 59, 2);
917 tm->tm_min = val;
918 break;
919 case 'S':
920 /* Match seconds using alternate numeric symbols. */
921 get_alt_number (0, 61, 2);
922 tm->tm_sec = val;
923 break;
924 case 'U':
925 get_alt_number (0, 53, 2);
926 week_no = val;
927 have_uweek = 1;
928 break;
929 case 'W':
930 get_alt_number (0, 53, 2);
931 week_no = val;
932 have_wweek = 1;
933 break;
934 case 'V':
935 get_alt_number (0, 53, 2);
936 /* XXX This cannot determine any field in TM without
937 further information. */
938 break;
939 case 'w':
940 /* Match number of weekday using alternate numeric symbols. */
941 get_alt_number (0, 6, 1);
942 tm->tm_wday = val;
943 have_wday = 1;
944 break;
945 case 'y':
946 /* Match year within century using alternate numeric symbols. */
947 get_alt_number (0, 99, 2);
948 tm->tm_year = val >= 69 ? val : val + 100;
949 want_xday = 1;
950 break;
951 default:
952 return NULL;
954 break;
955 default:
956 return NULL;
960 if (have_I && is_pm)
961 tm->tm_hour += 12;
963 if (century != -1)
965 if (want_century)
966 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
967 else
968 /* Only the century, but not the year. Strange, but so be it. */
969 tm->tm_year = (century - 19) * 100;
972 if (era_cnt != -1)
974 era = _nl_select_era_entry (era_cnt);
975 if (want_era)
976 tm->tm_year = (era->start_date[0]
977 + ((tm->tm_year - era->offset)
978 * era->absolute_direction));
979 else
980 /* Era start year assumed. */
981 tm->tm_year = era->start_date[0];
983 else
984 if (want_era)
986 /* No era found but we have seen an E modifier. Rectify some
987 values. */
988 if (want_century && century == -1 && tm->tm_year < 69)
989 tm->tm_year += 100;
992 if (want_xday && !have_wday)
994 if ( !(have_mon && have_mday) && have_yday)
996 /* We don't have tm_mon and/or tm_mday, compute them. */
997 int t_mon = 0;
998 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
999 t_mon++;
1000 if (!have_mon)
1001 tm->tm_mon = t_mon - 1;
1002 if (!have_mday)
1003 tm->tm_mday =
1004 (tm->tm_yday
1005 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1007 day_of_the_week (tm);
1010 if (want_xday && !have_yday)
1011 day_of_the_year (tm);
1013 if ((have_uweek || have_wweek) && have_wday)
1015 int save_wday = tm->tm_wday;
1016 int save_mday = tm->tm_mday;
1017 int save_mon = tm->tm_mon;
1018 int w_offset = have_uweek ? 0 : 1;
1020 tm->tm_mday = 1;
1021 tm->tm_mon = 0;
1022 day_of_the_week (tm);
1023 if (have_mday)
1024 tm->tm_mday = save_mday;
1025 if (have_mon)
1026 tm->tm_mon = save_mon;
1028 if (!have_yday)
1029 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1030 + (week_no - 1) *7
1031 + save_wday - w_offset);
1033 if (!have_mday || !have_mon)
1035 int t_mon = 0;
1036 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1037 <= tm->tm_yday)
1038 t_mon++;
1039 if (!have_mon)
1040 tm->tm_mon = t_mon - 1;
1041 if (!have_mday)
1042 tm->tm_mday =
1043 (tm->tm_yday
1044 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1047 tm->tm_wday = save_wday;
1050 return (char *) rp;
1054 char *
1055 strptime (buf, format, tm LOCALE_PARAM)
1056 const char *buf;
1057 const char *format;
1058 struct tm *tm;
1059 LOCALE_PARAM_DECL
1061 enum locale_status decided;
1063 #ifdef _NL_CURRENT
1064 decided = not;
1065 #else
1066 decided = raw;
1067 #endif
1068 return strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
1070 #if defined _LIBC && !defined USE_IN_EXTENDED_LOCALE_MODEL
1071 libc_hidden_def (strptime)
1072 #endif