.
[glibc/history.git] / time / strptime_l.c
blobcf0ab7153d99c025c9f12c5299926fa309bafb33
1 /* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <assert.h>
24 #include <ctype.h>
25 #include <langinfo.h>
26 #include <limits.h>
27 #include <string.h>
28 #include <time.h>
29 #include <stdbool.h>
31 #ifdef _LIBC
32 # include "../locale/localeinfo.h"
33 #endif
36 #ifndef __P
37 # if defined __GNUC__ || (defined __STDC__ && __STDC__)
38 # define __P(args) args
39 # else
40 # define __P(args) ()
41 # endif /* GCC. */
42 #endif /* Not __P. */
45 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
46 # ifdef _LIBC
47 # define localtime_r __localtime_r
48 # else
49 /* Approximate localtime_r as best we can in its absence. */
50 # define localtime_r my_localtime_r
51 static struct tm *localtime_r __P ((const time_t *, struct tm *));
52 static struct tm *
53 localtime_r (t, tp)
54 const time_t *t;
55 struct tm *tp;
57 struct tm *l = localtime (t);
58 if (! l)
59 return 0;
60 *tp = *l;
61 return tp;
63 # endif /* ! _LIBC */
64 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
67 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
68 #if defined __GNUC__ && __GNUC__ >= 2
69 # define match_string(cs1, s2) \
70 ({ size_t len = strlen (cs1); \
71 int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
72 if (result) (s2) += len; \
73 result; })
74 #else
75 /* Oh come on. Get a reasonable compiler. */
76 # define match_string(cs1, s2) \
77 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
78 #endif
79 /* We intentionally do not use isdigit() for testing because this will
80 lead to problems with the wide character version. */
81 #define get_number(from, to, n) \
82 do { \
83 int __n = n; \
84 val = 0; \
85 while (*rp == ' ') \
86 ++rp; \
87 if (*rp < '0' || *rp > '9') \
88 return NULL; \
89 do { \
90 val *= 10; \
91 val += *rp++ - '0'; \
92 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
93 if (val < from || val > to) \
94 return NULL; \
95 } while (0)
96 #ifdef _NL_CURRENT
97 # define get_alt_number(from, to, n) \
98 ({ \
99 __label__ do_normal; \
101 if (*decided != raw) \
103 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
104 if (val == -1 && *decided != loc) \
106 *decided = loc; \
107 goto do_normal; \
109 if (val < from || val > to) \
110 return NULL; \
112 else \
114 do_normal: \
115 get_number (from, to, n); \
117 0; \
119 #else
120 # define get_alt_number(from, to, n) \
121 /* We don't have the alternate representation. */ \
122 get_number(from, to, n)
123 #endif
124 #define recursive(new_fmt) \
125 (*(new_fmt) != '\0' \
126 && (rp = __strptime_internal (rp, (new_fmt), tm, \
127 decided, era_cnt LOCALE_ARG)) != NULL)
130 #ifdef _LIBC
131 /* This is defined in locale/C-time.c in the GNU libc. */
132 extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
134 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
135 # define ab_weekday_name \
136 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
137 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
138 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
139 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
140 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
141 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
142 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
143 # define HERE_T_FMT_AMPM \
144 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
145 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
147 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
148 #else
149 static char const weekday_name[][10] =
151 "Sunday", "Monday", "Tuesday", "Wednesday",
152 "Thursday", "Friday", "Saturday"
154 static char const ab_weekday_name[][4] =
156 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
158 static char const month_name[][10] =
160 "January", "February", "March", "April", "May", "June",
161 "July", "August", "September", "October", "November", "December"
163 static char const ab_month_name[][4] =
165 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
166 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
168 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
169 # define HERE_D_FMT "%m/%d/%y"
170 # define HERE_AM_STR "AM"
171 # define HERE_PM_STR "PM"
172 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
173 # define HERE_T_FMT "%H:%M:%S"
175 static const unsigned short int __mon_yday[2][13] =
177 /* Normal years. */
178 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
179 /* Leap years. */
180 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
182 #endif
184 #if defined _LIBC
185 /* We use this code also for the extended locale handling where the
186 function gets as an additional argument the locale which has to be
187 used. To access the values we have to redefine the _NL_CURRENT
188 macro. */
189 # define strptime __strptime_l
190 # undef _NL_CURRENT
191 # define _NL_CURRENT(category, item) \
192 (current->values[_NL_ITEM_INDEX (item)].string)
193 # undef _NL_CURRENT_WORD
194 # define _NL_CURRENT_WORD(category, item) \
195 (current->values[_NL_ITEM_INDEX (item)].word)
196 # define LOCALE_PARAM , locale
197 # define LOCALE_ARG , locale
198 # define LOCALE_PARAM_PROTO , __locale_t locale
199 # define LOCALE_PARAM_DECL __locale_t locale;
200 # define HELPER_LOCALE_ARG , current
201 # define ISSPACE(Ch) __isspace_l (Ch, locale)
202 #else
203 # define LOCALE_PARAM
204 # define LOCALE_ARG
205 # define LOCALE_PARAM_DECL
206 # define LOCALE_PARAM_PROTO
207 # define HELPER_LOCALE_ARG
208 # define ISSPACE(Ch) isspace (Ch)
209 #endif
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 #ifdef _LIBC
249 char *
250 internal_function
251 #else
252 static char *
253 #endif
254 __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
255 const char *rp;
256 const char *fmt;
257 struct tm *tm;
258 enum ptime_locale_status *decided;
259 int era_cnt;
260 LOCALE_PARAM_DECL
262 #ifdef _LIBC
263 struct locale_data *const current = locale->__locales[LC_TIME];
264 #endif
266 const char *rp_backup;
267 int cnt;
268 size_t val;
269 int have_I, is_pm;
270 int century, want_century;
271 int want_era;
272 int have_wday, want_xday;
273 int have_yday;
274 int have_mon, have_mday;
275 int have_uweek, have_wweek;
276 int week_no;
277 size_t num_eras;
278 struct era_entry *era;
280 have_I = is_pm = 0;
281 century = -1;
282 want_century = 0;
283 want_era = 0;
284 era = NULL;
285 week_no = 0;
287 have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
288 have_wweek = 0;
290 while (*fmt != '\0')
292 /* A white space in the format string matches 0 more or white
293 space in the input string. */
294 if (ISSPACE (*fmt))
296 while (ISSPACE (*rp))
297 ++rp;
298 ++fmt;
299 continue;
302 /* Any character but `%' must be matched by the same character
303 in the iput string. */
304 if (*fmt != '%')
306 match_char (*fmt++, *rp++);
307 continue;
310 ++fmt;
311 #ifndef _NL_CURRENT
312 /* We need this for handling the `E' modifier. */
313 start_over:
314 #endif
316 /* Make back up of current processing pointer. */
317 rp_backup = rp;
319 switch (*fmt++)
321 case '%':
322 /* Match the `%' character itself. */
323 match_char ('%', *rp++);
324 break;
325 case 'a':
326 case 'A':
327 /* Match day of week. */
328 for (cnt = 0; cnt < 7; ++cnt)
330 #ifdef _NL_CURRENT
331 if (*decided !=raw)
333 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
335 if (*decided == not
336 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
337 weekday_name[cnt]))
338 *decided = loc;
339 break;
341 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
343 if (*decided == not
344 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
345 ab_weekday_name[cnt]))
346 *decided = loc;
347 break;
350 #endif
351 if (*decided != loc
352 && (match_string (weekday_name[cnt], rp)
353 || match_string (ab_weekday_name[cnt], rp)))
355 *decided = raw;
356 break;
359 if (cnt == 7)
360 /* Does not match a weekday name. */
361 return NULL;
362 tm->tm_wday = cnt;
363 have_wday = 1;
364 break;
365 case 'b':
366 case 'B':
367 case 'h':
368 /* Match month name. */
369 for (cnt = 0; cnt < 12; ++cnt)
371 #ifdef _NL_CURRENT
372 if (*decided !=raw)
374 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
376 if (*decided == not
377 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
378 month_name[cnt]))
379 *decided = loc;
380 break;
382 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
384 if (*decided == not
385 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
386 ab_month_name[cnt]))
387 *decided = loc;
388 break;
391 #endif
392 if (match_string (month_name[cnt], rp)
393 || match_string (ab_month_name[cnt], rp))
395 *decided = raw;
396 break;
399 if (cnt == 12)
400 /* Does not match a month name. */
401 return NULL;
402 tm->tm_mon = cnt;
403 want_xday = 1;
404 break;
405 case 'c':
406 /* Match locale's date and time format. */
407 #ifdef _NL_CURRENT
408 if (*decided != raw)
410 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
412 if (*decided == loc)
413 return NULL;
414 else
415 rp = rp_backup;
417 else
419 if (*decided == not &&
420 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
421 *decided = loc;
422 want_xday = 1;
423 break;
425 *decided = raw;
427 #endif
428 if (!recursive (HERE_D_T_FMT))
429 return NULL;
430 want_xday = 1;
431 break;
432 case 'C':
433 /* Match century number. */
434 match_century:
435 get_number (0, 99, 2);
436 century = val;
437 want_xday = 1;
438 break;
439 case 'd':
440 case 'e':
441 /* Match day of month. */
442 get_number (1, 31, 2);
443 tm->tm_mday = val;
444 have_mday = 1;
445 want_xday = 1;
446 break;
447 case 'F':
448 if (!recursive ("%Y-%m-%d"))
449 return NULL;
450 want_xday = 1;
451 break;
452 case 'x':
453 #ifdef _NL_CURRENT
454 if (*decided != raw)
456 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
458 if (*decided == loc)
459 return NULL;
460 else
461 rp = rp_backup;
463 else
465 if (*decided == not
466 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
467 *decided = loc;
468 want_xday = 1;
469 break;
471 *decided = raw;
473 #endif
474 /* Fall through. */
475 case 'D':
476 /* Match standard day format. */
477 if (!recursive (HERE_D_FMT))
478 return NULL;
479 want_xday = 1;
480 break;
481 case 'k':
482 case 'H':
483 /* Match hour in 24-hour clock. */
484 get_number (0, 23, 2);
485 tm->tm_hour = val;
486 have_I = 0;
487 break;
488 case 'l':
489 /* Match hour in 12-hour clock. GNU extension. */
490 case 'I':
491 /* Match hour in 12-hour clock. */
492 get_number (1, 12, 2);
493 tm->tm_hour = val % 12;
494 have_I = 1;
495 break;
496 case 'j':
497 /* Match day number of year. */
498 get_number (1, 366, 3);
499 tm->tm_yday = val - 1;
500 have_yday = 1;
501 break;
502 case 'm':
503 /* Match number of month. */
504 get_number (1, 12, 2);
505 tm->tm_mon = val - 1;
506 have_mon = 1;
507 want_xday = 1;
508 break;
509 case 'M':
510 /* Match minute. */
511 get_number (0, 59, 2);
512 tm->tm_min = val;
513 break;
514 case 'n':
515 case 't':
516 /* Match any white space. */
517 while (ISSPACE (*rp))
518 ++rp;
519 break;
520 case 'p':
521 /* Match locale's equivalent of AM/PM. */
522 #ifdef _NL_CURRENT
523 if (*decided != raw)
525 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
527 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
528 *decided = loc;
529 break;
531 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
533 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
534 *decided = loc;
535 is_pm = 1;
536 break;
538 *decided = raw;
540 #endif
541 if (!match_string (HERE_AM_STR, rp))
543 if (match_string (HERE_PM_STR, rp))
544 is_pm = 1;
545 else
546 return NULL;
548 break;
549 case 'r':
550 #ifdef _NL_CURRENT
551 if (*decided != raw)
553 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
555 if (*decided == loc)
556 return NULL;
557 else
558 rp = rp_backup;
560 else
562 if (*decided == not &&
563 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
564 HERE_T_FMT_AMPM))
565 *decided = loc;
566 break;
568 *decided = raw;
570 #endif
571 if (!recursive (HERE_T_FMT_AMPM))
572 return NULL;
573 break;
574 case 'R':
575 if (!recursive ("%H:%M"))
576 return NULL;
577 break;
578 case 's':
580 /* The number of seconds may be very high so we cannot use
581 the `get_number' macro. Instead read the number
582 character for character and construct the result while
583 doing this. */
584 time_t secs = 0;
585 if (*rp < '0' || *rp > '9')
586 /* We need at least one digit. */
587 return NULL;
591 secs *= 10;
592 secs += *rp++ - '0';
594 while (*rp >= '0' && *rp <= '9');
596 if (localtime_r (&secs, tm) == NULL)
597 /* Error in function. */
598 return NULL;
600 break;
601 case 'S':
602 get_number (0, 61, 2);
603 tm->tm_sec = val;
604 break;
605 case 'X':
606 #ifdef _NL_CURRENT
607 if (*decided != raw)
609 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
611 if (*decided == loc)
612 return NULL;
613 else
614 rp = rp_backup;
616 else
618 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
619 *decided = loc;
620 break;
622 *decided = raw;
624 #endif
625 /* Fall through. */
626 case 'T':
627 if (!recursive (HERE_T_FMT))
628 return NULL;
629 break;
630 case 'u':
631 get_number (1, 7, 1);
632 tm->tm_wday = val % 7;
633 have_wday = 1;
634 break;
635 case 'g':
636 get_number (0, 99, 2);
637 /* XXX This cannot determine any field in TM. */
638 break;
639 case 'G':
640 if (*rp < '0' || *rp > '9')
641 return NULL;
642 /* XXX Ignore the number since we would need some more
643 information to compute a real date. */
645 ++rp;
646 while (*rp >= '0' && *rp <= '9');
647 break;
648 case 'U':
649 get_number (0, 53, 2);
650 week_no = val;
651 have_uweek = 1;
652 break;
653 case 'W':
654 get_number (0, 53, 2);
655 week_no = val;
656 have_wweek = 1;
657 break;
658 case 'V':
659 get_number (0, 53, 2);
660 /* XXX This cannot determine any field in TM without some
661 information. */
662 break;
663 case 'w':
664 /* Match number of weekday. */
665 get_number (0, 6, 1);
666 tm->tm_wday = val;
667 have_wday = 1;
668 break;
669 case 'y':
670 match_year_in_century:
671 /* Match year within century. */
672 get_number (0, 99, 2);
673 /* The "Year 2000: The Millennium Rollover" paper suggests that
674 values in the range 69-99 refer to the twentieth century. */
675 tm->tm_year = val >= 69 ? val : val + 100;
676 /* Indicate that we want to use the century, if specified. */
677 want_century = 1;
678 want_xday = 1;
679 break;
680 case 'Y':
681 /* Match year including century number. */
682 get_number (0, 9999, 4);
683 tm->tm_year = val - 1900;
684 want_century = 0;
685 want_xday = 1;
686 break;
687 case 'Z':
688 /* XXX How to handle this? */
689 break;
690 case 'E':
691 #ifdef _NL_CURRENT
692 switch (*fmt++)
694 case 'c':
695 /* Match locale's alternate date and time format. */
696 if (*decided != raw)
698 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
700 if (*fmt == '\0')
701 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
703 if (!recursive (fmt))
705 if (*decided == loc)
706 return NULL;
707 else
708 rp = rp_backup;
710 else
712 if (strcmp (fmt, HERE_D_T_FMT))
713 *decided = loc;
714 want_xday = 1;
715 break;
717 *decided = raw;
719 /* The C locale has no era information, so use the
720 normal representation. */
721 if (!recursive (HERE_D_T_FMT))
722 return NULL;
723 want_xday = 1;
724 break;
725 case 'C':
726 if (*decided != raw)
728 if (era_cnt >= 0)
730 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
731 if (era != NULL && match_string (era->era_name, rp))
733 *decided = loc;
734 break;
736 else
737 return NULL;
740 num_eras = _NL_CURRENT_WORD (LC_TIME,
741 _NL_TIME_ERA_NUM_ENTRIES);
742 for (era_cnt = 0; era_cnt < (int) num_eras;
743 ++era_cnt, rp = rp_backup)
745 era = _nl_select_era_entry (era_cnt
746 HELPER_LOCALE_ARG);
747 if (era != NULL && match_string (era->era_name, rp))
749 *decided = loc;
750 break;
753 if (era_cnt != (int) num_eras)
754 break;
756 era_cnt = -1;
757 if (*decided == loc)
758 return NULL;
760 *decided = raw;
762 /* The C locale has no era information, so use the
763 normal representation. */
764 goto match_century;
765 case 'y':
766 if (*decided != raw)
768 get_number(0, 9999, 4);
769 tm->tm_year = val;
770 want_era = 1;
771 want_xday = 1;
772 want_century = 1;
774 if (era_cnt >= 0)
776 assert (*decided == loc);
778 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
779 bool match = false;
780 if (era != NULL)
782 int delta = ((tm->tm_year - era->offset)
783 * era->absolute_direction);
784 match = (delta >= 0
785 && delta < (((int64_t) era->stop_date[0]
786 - (int64_t) era->start_date[0])
787 * era->absolute_direction));
789 if (! match)
790 return NULL;
792 break;
795 num_eras = _NL_CURRENT_WORD (LC_TIME,
796 _NL_TIME_ERA_NUM_ENTRIES);
797 for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt)
799 era = _nl_select_era_entry (era_cnt
800 HELPER_LOCALE_ARG);
801 if (era != NULL)
803 int delta = ((tm->tm_year - era->offset)
804 * era->absolute_direction);
805 if (delta >= 0
806 && delta < (((int64_t) era->stop_date[0]
807 - (int64_t) era->start_date[0])
808 * era->absolute_direction))
810 *decided = loc;
811 break;
815 if (era_cnt != (int) num_eras)
816 break;
818 era_cnt = -1;
819 if (*decided == loc)
820 return NULL;
822 *decided = raw;
825 goto match_year_in_century;
826 case 'Y':
827 if (*decided != raw)
829 num_eras = _NL_CURRENT_WORD (LC_TIME,
830 _NL_TIME_ERA_NUM_ENTRIES);
831 for (era_cnt = 0; era_cnt < (int) num_eras;
832 ++era_cnt, rp = rp_backup)
834 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
835 if (era != NULL && recursive (era->era_format))
836 break;
838 if (era_cnt == (int) num_eras)
840 era_cnt = -1;
841 if (*decided == loc)
842 return NULL;
843 else
844 rp = rp_backup;
846 else
848 *decided = loc;
849 era_cnt = -1;
850 break;
853 *decided = raw;
855 get_number (0, 9999, 4);
856 tm->tm_year = val - 1900;
857 want_century = 0;
858 want_xday = 1;
859 break;
860 case 'x':
861 if (*decided != raw)
863 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
865 if (*fmt == '\0')
866 fmt = _NL_CURRENT (LC_TIME, D_FMT);
868 if (!recursive (fmt))
870 if (*decided == loc)
871 return NULL;
872 else
873 rp = rp_backup;
875 else
877 if (strcmp (fmt, HERE_D_FMT))
878 *decided = loc;
879 break;
881 *decided = raw;
883 if (!recursive (HERE_D_FMT))
884 return NULL;
885 break;
886 case 'X':
887 if (*decided != raw)
889 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
891 if (*fmt == '\0')
892 fmt = _NL_CURRENT (LC_TIME, T_FMT);
894 if (!recursive (fmt))
896 if (*decided == loc)
897 return NULL;
898 else
899 rp = rp_backup;
901 else
903 if (strcmp (fmt, HERE_T_FMT))
904 *decided = loc;
905 break;
907 *decided = raw;
909 if (!recursive (HERE_T_FMT))
910 return NULL;
911 break;
912 default:
913 return NULL;
915 break;
916 #else
917 /* We have no information about the era format. Just use
918 the normal format. */
919 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
920 && *fmt != 'x' && *fmt != 'X')
921 /* This is an illegal format. */
922 return NULL;
924 goto start_over;
925 #endif
926 case 'O':
927 switch (*fmt++)
929 case 'd':
930 case 'e':
931 /* Match day of month using alternate numeric symbols. */
932 get_alt_number (1, 31, 2);
933 tm->tm_mday = val;
934 have_mday = 1;
935 want_xday = 1;
936 break;
937 case 'H':
938 /* Match hour in 24-hour clock using alternate numeric
939 symbols. */
940 get_alt_number (0, 23, 2);
941 tm->tm_hour = val;
942 have_I = 0;
943 break;
944 case 'I':
945 /* Match hour in 12-hour clock using alternate numeric
946 symbols. */
947 get_alt_number (1, 12, 2);
948 tm->tm_hour = val % 12;
949 have_I = 1;
950 break;
951 case 'm':
952 /* Match month using alternate numeric symbols. */
953 get_alt_number (1, 12, 2);
954 tm->tm_mon = val - 1;
955 have_mon = 1;
956 want_xday = 1;
957 break;
958 case 'M':
959 /* Match minutes using alternate numeric symbols. */
960 get_alt_number (0, 59, 2);
961 tm->tm_min = val;
962 break;
963 case 'S':
964 /* Match seconds using alternate numeric symbols. */
965 get_alt_number (0, 61, 2);
966 tm->tm_sec = val;
967 break;
968 case 'U':
969 get_alt_number (0, 53, 2);
970 week_no = val;
971 have_uweek = 1;
972 break;
973 case 'W':
974 get_alt_number (0, 53, 2);
975 week_no = val;
976 have_wweek = 1;
977 break;
978 case 'V':
979 get_alt_number (0, 53, 2);
980 /* XXX This cannot determine any field in TM without
981 further information. */
982 break;
983 case 'w':
984 /* Match number of weekday using alternate numeric symbols. */
985 get_alt_number (0, 6, 1);
986 tm->tm_wday = val;
987 have_wday = 1;
988 break;
989 case 'y':
990 /* Match year within century using alternate numeric symbols. */
991 get_alt_number (0, 99, 2);
992 tm->tm_year = val >= 69 ? val : val + 100;
993 want_xday = 1;
994 break;
995 default:
996 return NULL;
998 break;
999 default:
1000 return NULL;
1004 if (have_I && is_pm)
1005 tm->tm_hour += 12;
1007 if (century != -1)
1009 if (want_century)
1010 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
1011 else
1012 /* Only the century, but not the year. Strange, but so be it. */
1013 tm->tm_year = (century - 19) * 100;
1016 if (era_cnt != -1)
1018 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
1019 if (era == NULL)
1020 return NULL;
1021 if (want_era)
1022 tm->tm_year = (era->start_date[0]
1023 + ((tm->tm_year - era->offset)
1024 * era->absolute_direction));
1025 else
1026 /* Era start year assumed. */
1027 tm->tm_year = era->start_date[0];
1029 else
1030 if (want_era)
1032 /* No era found but we have seen an E modifier. Rectify some
1033 values. */
1034 if (want_century && century == -1 && tm->tm_year < 69)
1035 tm->tm_year += 100;
1038 if (want_xday && !have_wday)
1040 if ( !(have_mon && have_mday) && have_yday)
1042 /* We don't have tm_mon and/or tm_mday, compute them. */
1043 int t_mon = 0;
1044 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1045 t_mon++;
1046 if (!have_mon)
1047 tm->tm_mon = t_mon - 1;
1048 if (!have_mday)
1049 tm->tm_mday =
1050 (tm->tm_yday
1051 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1053 day_of_the_week (tm);
1056 if (want_xday && !have_yday)
1057 day_of_the_year (tm);
1059 if ((have_uweek || have_wweek) && have_wday)
1061 int save_wday = tm->tm_wday;
1062 int save_mday = tm->tm_mday;
1063 int save_mon = tm->tm_mon;
1064 int w_offset = have_uweek ? 0 : 1;
1066 tm->tm_mday = 1;
1067 tm->tm_mon = 0;
1068 day_of_the_week (tm);
1069 if (have_mday)
1070 tm->tm_mday = save_mday;
1071 if (have_mon)
1072 tm->tm_mon = save_mon;
1074 if (!have_yday)
1075 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1076 + (week_no - 1) *7
1077 + save_wday - w_offset);
1079 if (!have_mday || !have_mon)
1081 int t_mon = 0;
1082 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1083 <= tm->tm_yday)
1084 t_mon++;
1085 if (!have_mon)
1086 tm->tm_mon = t_mon - 1;
1087 if (!have_mday)
1088 tm->tm_mday =
1089 (tm->tm_yday
1090 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1093 tm->tm_wday = save_wday;
1096 return (char *) rp;
1100 char *
1101 strptime (buf, format, tm LOCALE_PARAM)
1102 const char *buf;
1103 const char *format;
1104 struct tm *tm;
1105 LOCALE_PARAM_DECL
1107 enum ptime_locale_status decided;
1109 #ifdef _NL_CURRENT
1110 decided = not;
1111 #else
1112 decided = raw;
1113 #endif
1114 return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
1117 #ifdef _LIBC
1118 weak_alias (__strptime_l, strptime_l)
1119 #endif