.
[glibc.git] / time / strptime_l.c
blob443a6fa88e387547d8c157f411cd034a3da1aa21
1 /* Copyright (C) 2002, 2004, 2005, 2007 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 have_mon = 1;
404 want_xday = 1;
405 break;
406 case 'c':
407 /* Match locale's date and time format. */
408 #ifdef _NL_CURRENT
409 if (*decided != raw)
411 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
413 if (*decided == loc)
414 return NULL;
415 else
416 rp = rp_backup;
418 else
420 if (*decided == not &&
421 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
422 *decided = loc;
423 want_xday = 1;
424 break;
426 *decided = raw;
428 #endif
429 if (!recursive (HERE_D_T_FMT))
430 return NULL;
431 want_xday = 1;
432 break;
433 case 'C':
434 /* Match century number. */
435 match_century:
436 get_number (0, 99, 2);
437 century = val;
438 want_xday = 1;
439 break;
440 case 'd':
441 case 'e':
442 /* Match day of month. */
443 get_number (1, 31, 2);
444 tm->tm_mday = val;
445 have_mday = 1;
446 want_xday = 1;
447 break;
448 case 'F':
449 if (!recursive ("%Y-%m-%d"))
450 return NULL;
451 want_xday = 1;
452 break;
453 case 'x':
454 #ifdef _NL_CURRENT
455 if (*decided != raw)
457 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
459 if (*decided == loc)
460 return NULL;
461 else
462 rp = rp_backup;
464 else
466 if (*decided == not
467 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
468 *decided = loc;
469 want_xday = 1;
470 break;
472 *decided = raw;
474 #endif
475 /* Fall through. */
476 case 'D':
477 /* Match standard day format. */
478 if (!recursive (HERE_D_FMT))
479 return NULL;
480 want_xday = 1;
481 break;
482 case 'k':
483 case 'H':
484 /* Match hour in 24-hour clock. */
485 get_number (0, 23, 2);
486 tm->tm_hour = val;
487 have_I = 0;
488 break;
489 case 'l':
490 /* Match hour in 12-hour clock. GNU extension. */
491 case 'I':
492 /* Match hour in 12-hour clock. */
493 get_number (1, 12, 2);
494 tm->tm_hour = val % 12;
495 have_I = 1;
496 break;
497 case 'j':
498 /* Match day number of year. */
499 get_number (1, 366, 3);
500 tm->tm_yday = val - 1;
501 have_yday = 1;
502 break;
503 case 'm':
504 /* Match number of month. */
505 get_number (1, 12, 2);
506 tm->tm_mon = val - 1;
507 have_mon = 1;
508 want_xday = 1;
509 break;
510 case 'M':
511 /* Match minute. */
512 get_number (0, 59, 2);
513 tm->tm_min = val;
514 break;
515 case 'n':
516 case 't':
517 /* Match any white space. */
518 while (ISSPACE (*rp))
519 ++rp;
520 break;
521 case 'p':
522 /* Match locale's equivalent of AM/PM. */
523 #ifdef _NL_CURRENT
524 if (*decided != raw)
526 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
528 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
529 *decided = loc;
530 break;
532 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
534 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
535 *decided = loc;
536 is_pm = 1;
537 break;
539 *decided = raw;
541 #endif
542 if (!match_string (HERE_AM_STR, rp))
544 if (match_string (HERE_PM_STR, rp))
545 is_pm = 1;
546 else
547 return NULL;
549 break;
550 case 'r':
551 #ifdef _NL_CURRENT
552 if (*decided != raw)
554 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
556 if (*decided == loc)
557 return NULL;
558 else
559 rp = rp_backup;
561 else
563 if (*decided == not &&
564 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
565 HERE_T_FMT_AMPM))
566 *decided = loc;
567 break;
569 *decided = raw;
571 #endif
572 if (!recursive (HERE_T_FMT_AMPM))
573 return NULL;
574 break;
575 case 'R':
576 if (!recursive ("%H:%M"))
577 return NULL;
578 break;
579 case 's':
581 /* The number of seconds may be very high so we cannot use
582 the `get_number' macro. Instead read the number
583 character for character and construct the result while
584 doing this. */
585 time_t secs = 0;
586 if (*rp < '0' || *rp > '9')
587 /* We need at least one digit. */
588 return NULL;
592 secs *= 10;
593 secs += *rp++ - '0';
595 while (*rp >= '0' && *rp <= '9');
597 if (localtime_r (&secs, tm) == NULL)
598 /* Error in function. */
599 return NULL;
601 break;
602 case 'S':
603 get_number (0, 61, 2);
604 tm->tm_sec = val;
605 break;
606 case 'X':
607 #ifdef _NL_CURRENT
608 if (*decided != raw)
610 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
612 if (*decided == loc)
613 return NULL;
614 else
615 rp = rp_backup;
617 else
619 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
620 *decided = loc;
621 break;
623 *decided = raw;
625 #endif
626 /* Fall through. */
627 case 'T':
628 if (!recursive (HERE_T_FMT))
629 return NULL;
630 break;
631 case 'u':
632 get_number (1, 7, 1);
633 tm->tm_wday = val % 7;
634 have_wday = 1;
635 break;
636 case 'g':
637 get_number (0, 99, 2);
638 /* XXX This cannot determine any field in TM. */
639 break;
640 case 'G':
641 if (*rp < '0' || *rp > '9')
642 return NULL;
643 /* XXX Ignore the number since we would need some more
644 information to compute a real date. */
646 ++rp;
647 while (*rp >= '0' && *rp <= '9');
648 break;
649 case 'U':
650 get_number (0, 53, 2);
651 week_no = val;
652 have_uweek = 1;
653 break;
654 case 'W':
655 get_number (0, 53, 2);
656 week_no = val;
657 have_wweek = 1;
658 break;
659 case 'V':
660 get_number (0, 53, 2);
661 /* XXX This cannot determine any field in TM without some
662 information. */
663 break;
664 case 'w':
665 /* Match number of weekday. */
666 get_number (0, 6, 1);
667 tm->tm_wday = val;
668 have_wday = 1;
669 break;
670 case 'y':
671 match_year_in_century:
672 /* Match year within century. */
673 get_number (0, 99, 2);
674 /* The "Year 2000: The Millennium Rollover" paper suggests that
675 values in the range 69-99 refer to the twentieth century. */
676 tm->tm_year = val >= 69 ? val : val + 100;
677 /* Indicate that we want to use the century, if specified. */
678 want_century = 1;
679 want_xday = 1;
680 break;
681 case 'Y':
682 /* Match year including century number. */
683 get_number (0, 9999, 4);
684 tm->tm_year = val - 1900;
685 want_century = 0;
686 want_xday = 1;
687 break;
688 case 'Z':
689 /* XXX How to handle this? */
690 break;
691 case 'z':
692 /* We recognize two formats: if two digits are given, these
693 specify hours. If fours digits are used, minutes are
694 also specified. */
696 val = 0;
697 while (*rp == ' ')
698 ++rp;
699 if (*rp != '+' && *rp != '-')
700 return NULL;
701 bool neg = *rp++ == '-';
702 int n = 0;
703 while (n < 4 && *rp >= '0' && *rp <= '9')
705 val = val * 10 + *rp++ - '0';
706 ++n;
708 if (n == 2)
709 val *= 100;
710 else if (n != 4)
711 /* Only two or four digits recognized. */
712 return NULL;
713 else
715 /* We have to convert the minutes into decimal. */
716 if (val % 100 >= 60)
717 return NULL;
718 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
720 if (val > 1200)
721 return NULL;
722 tm->tm_gmtoff = (val * 3600) / 100;
723 if (neg)
724 tm->tm_gmtoff = -tm->tm_gmtoff;
726 break;
727 case 'E':
728 #ifdef _NL_CURRENT
729 switch (*fmt++)
731 case 'c':
732 /* Match locale's alternate date and time format. */
733 if (*decided != raw)
735 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
737 if (*fmt == '\0')
738 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
740 if (!recursive (fmt))
742 if (*decided == loc)
743 return NULL;
744 else
745 rp = rp_backup;
747 else
749 if (strcmp (fmt, HERE_D_T_FMT))
750 *decided = loc;
751 want_xday = 1;
752 break;
754 *decided = raw;
756 /* The C locale has no era information, so use the
757 normal representation. */
758 if (!recursive (HERE_D_T_FMT))
759 return NULL;
760 want_xday = 1;
761 break;
762 case 'C':
763 if (*decided != raw)
765 if (era_cnt >= 0)
767 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
768 if (era != NULL && match_string (era->era_name, rp))
770 *decided = loc;
771 break;
773 else
774 return NULL;
777 num_eras = _NL_CURRENT_WORD (LC_TIME,
778 _NL_TIME_ERA_NUM_ENTRIES);
779 for (era_cnt = 0; era_cnt < (int) num_eras;
780 ++era_cnt, rp = rp_backup)
782 era = _nl_select_era_entry (era_cnt
783 HELPER_LOCALE_ARG);
784 if (era != NULL && match_string (era->era_name, rp))
786 *decided = loc;
787 break;
790 if (era_cnt != (int) num_eras)
791 break;
793 era_cnt = -1;
794 if (*decided == loc)
795 return NULL;
797 *decided = raw;
799 /* The C locale has no era information, so use the
800 normal representation. */
801 goto match_century;
802 case 'y':
803 if (*decided != raw)
805 get_number(0, 9999, 4);
806 tm->tm_year = val;
807 want_era = 1;
808 want_xday = 1;
809 want_century = 1;
811 if (era_cnt >= 0)
813 assert (*decided == loc);
815 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
816 bool match = false;
817 if (era != NULL)
819 int delta = ((tm->tm_year - era->offset)
820 * era->absolute_direction);
821 match = (delta >= 0
822 && delta < (((int64_t) era->stop_date[0]
823 - (int64_t) era->start_date[0])
824 * era->absolute_direction));
826 if (! match)
827 return NULL;
829 break;
832 num_eras = _NL_CURRENT_WORD (LC_TIME,
833 _NL_TIME_ERA_NUM_ENTRIES);
834 for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt)
836 era = _nl_select_era_entry (era_cnt
837 HELPER_LOCALE_ARG);
838 if (era != NULL)
840 int delta = ((tm->tm_year - era->offset)
841 * era->absolute_direction);
842 if (delta >= 0
843 && delta < (((int64_t) era->stop_date[0]
844 - (int64_t) era->start_date[0])
845 * era->absolute_direction))
847 *decided = loc;
848 break;
852 if (era_cnt != (int) num_eras)
853 break;
855 era_cnt = -1;
856 if (*decided == loc)
857 return NULL;
859 *decided = raw;
862 goto match_year_in_century;
863 case 'Y':
864 if (*decided != raw)
866 num_eras = _NL_CURRENT_WORD (LC_TIME,
867 _NL_TIME_ERA_NUM_ENTRIES);
868 for (era_cnt = 0; era_cnt < (int) num_eras;
869 ++era_cnt, rp = rp_backup)
871 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
872 if (era != NULL && recursive (era->era_format))
873 break;
875 if (era_cnt == (int) num_eras)
877 era_cnt = -1;
878 if (*decided == loc)
879 return NULL;
880 else
881 rp = rp_backup;
883 else
885 *decided = loc;
886 era_cnt = -1;
887 break;
890 *decided = raw;
892 get_number (0, 9999, 4);
893 tm->tm_year = val - 1900;
894 want_century = 0;
895 want_xday = 1;
896 break;
897 case 'x':
898 if (*decided != raw)
900 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
902 if (*fmt == '\0')
903 fmt = _NL_CURRENT (LC_TIME, D_FMT);
905 if (!recursive (fmt))
907 if (*decided == loc)
908 return NULL;
909 else
910 rp = rp_backup;
912 else
914 if (strcmp (fmt, HERE_D_FMT))
915 *decided = loc;
916 break;
918 *decided = raw;
920 if (!recursive (HERE_D_FMT))
921 return NULL;
922 break;
923 case 'X':
924 if (*decided != raw)
926 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
928 if (*fmt == '\0')
929 fmt = _NL_CURRENT (LC_TIME, T_FMT);
931 if (!recursive (fmt))
933 if (*decided == loc)
934 return NULL;
935 else
936 rp = rp_backup;
938 else
940 if (strcmp (fmt, HERE_T_FMT))
941 *decided = loc;
942 break;
944 *decided = raw;
946 if (!recursive (HERE_T_FMT))
947 return NULL;
948 break;
949 default:
950 return NULL;
952 break;
953 #else
954 /* We have no information about the era format. Just use
955 the normal format. */
956 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
957 && *fmt != 'x' && *fmt != 'X')
958 /* This is an illegal format. */
959 return NULL;
961 goto start_over;
962 #endif
963 case 'O':
964 switch (*fmt++)
966 case 'd':
967 case 'e':
968 /* Match day of month using alternate numeric symbols. */
969 get_alt_number (1, 31, 2);
970 tm->tm_mday = val;
971 have_mday = 1;
972 want_xday = 1;
973 break;
974 case 'H':
975 /* Match hour in 24-hour clock using alternate numeric
976 symbols. */
977 get_alt_number (0, 23, 2);
978 tm->tm_hour = val;
979 have_I = 0;
980 break;
981 case 'I':
982 /* Match hour in 12-hour clock using alternate numeric
983 symbols. */
984 get_alt_number (1, 12, 2);
985 tm->tm_hour = val % 12;
986 have_I = 1;
987 break;
988 case 'm':
989 /* Match month using alternate numeric symbols. */
990 get_alt_number (1, 12, 2);
991 tm->tm_mon = val - 1;
992 have_mon = 1;
993 want_xday = 1;
994 break;
995 case 'M':
996 /* Match minutes using alternate numeric symbols. */
997 get_alt_number (0, 59, 2);
998 tm->tm_min = val;
999 break;
1000 case 'S':
1001 /* Match seconds using alternate numeric symbols. */
1002 get_alt_number (0, 61, 2);
1003 tm->tm_sec = val;
1004 break;
1005 case 'U':
1006 get_alt_number (0, 53, 2);
1007 week_no = val;
1008 have_uweek = 1;
1009 break;
1010 case 'W':
1011 get_alt_number (0, 53, 2);
1012 week_no = val;
1013 have_wweek = 1;
1014 break;
1015 case 'V':
1016 get_alt_number (0, 53, 2);
1017 /* XXX This cannot determine any field in TM without
1018 further information. */
1019 break;
1020 case 'w':
1021 /* Match number of weekday using alternate numeric symbols. */
1022 get_alt_number (0, 6, 1);
1023 tm->tm_wday = val;
1024 have_wday = 1;
1025 break;
1026 case 'y':
1027 /* Match year within century using alternate numeric symbols. */
1028 get_alt_number (0, 99, 2);
1029 tm->tm_year = val >= 69 ? val : val + 100;
1030 want_xday = 1;
1031 break;
1032 default:
1033 return NULL;
1035 break;
1036 default:
1037 return NULL;
1041 if (have_I && is_pm)
1042 tm->tm_hour += 12;
1044 if (century != -1)
1046 if (want_century)
1047 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
1048 else
1049 /* Only the century, but not the year. Strange, but so be it. */
1050 tm->tm_year = (century - 19) * 100;
1053 if (era_cnt != -1)
1055 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
1056 if (era == NULL)
1057 return NULL;
1058 if (want_era)
1059 tm->tm_year = (era->start_date[0]
1060 + ((tm->tm_year - era->offset)
1061 * era->absolute_direction));
1062 else
1063 /* Era start year assumed. */
1064 tm->tm_year = era->start_date[0];
1066 else
1067 if (want_era)
1069 /* No era found but we have seen an E modifier. Rectify some
1070 values. */
1071 if (want_century && century == -1 && tm->tm_year < 69)
1072 tm->tm_year += 100;
1075 if (want_xday && !have_wday)
1077 if ( !(have_mon && have_mday) && have_yday)
1079 /* We don't have tm_mon and/or tm_mday, compute them. */
1080 int t_mon = 0;
1081 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1082 t_mon++;
1083 if (!have_mon)
1084 tm->tm_mon = t_mon - 1;
1085 if (!have_mday)
1086 tm->tm_mday =
1087 (tm->tm_yday
1088 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1089 have_mon = 1;
1090 have_mday = 1;
1092 /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
1093 if (have_mon || (unsigned) tm->tm_mon <= 11)
1094 day_of_the_week (tm);
1097 if (want_xday && !have_yday && (have_mon || (unsigned) tm->tm_mon <= 11))
1098 day_of_the_year (tm);
1100 if ((have_uweek || have_wweek) && have_wday)
1102 int save_wday = tm->tm_wday;
1103 int save_mday = tm->tm_mday;
1104 int save_mon = tm->tm_mon;
1105 int w_offset = have_uweek ? 0 : 1;
1107 tm->tm_mday = 1;
1108 tm->tm_mon = 0;
1109 day_of_the_week (tm);
1110 if (have_mday)
1111 tm->tm_mday = save_mday;
1112 if (have_mon)
1113 tm->tm_mon = save_mon;
1115 if (!have_yday)
1116 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1117 + (week_no - 1) *7
1118 + save_wday - w_offset);
1120 if (!have_mday || !have_mon)
1122 int t_mon = 0;
1123 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1124 <= tm->tm_yday)
1125 t_mon++;
1126 if (!have_mon)
1127 tm->tm_mon = t_mon - 1;
1128 if (!have_mday)
1129 tm->tm_mday =
1130 (tm->tm_yday
1131 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1134 tm->tm_wday = save_wday;
1137 return (char *) rp;
1141 char *
1142 strptime (buf, format, tm LOCALE_PARAM)
1143 const char *buf;
1144 const char *format;
1145 struct tm *tm;
1146 LOCALE_PARAM_DECL
1148 enum ptime_locale_status decided;
1150 #ifdef _NL_CURRENT
1151 decided = not;
1152 #else
1153 decided = raw;
1154 #endif
1155 return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
1158 #ifdef _LIBC
1159 weak_alias (__strptime_l, strptime_l)
1160 #endif