MSWSP: parse_CColumnGroupArray() etc.
[wireshark-wip.git] / wsutil / strptime.c
blob2af685dbf02344d6ecdf9a6db9f2d1c8a832bf45
1 /*
2 $Id$
4 Convert a string representation of time to a time value.
5 Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
6 This file is part of the GNU C Library.
7 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
9 The GNU C Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
14 The GNU C Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with the GNU C Library; see the file COPYING.LIB. If not,
21 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301 USA. */
24 /* XXX This version of the implementation is not really complete.
25 Some of the fields cannot add information alone. But if seeing
26 some of them in the same format (such as year, week and weekday)
27 this is enough information for determining the date. */
29 #include "config.h"
31 #include <ctype.h>
32 #include <limits.h>
33 #include <string.h>
34 #include <time.h>
36 #ifdef _LIBC
37 # include "../locale/localeinfo.h"
38 #endif
40 #include "strptime.h"
42 #ifndef __P
43 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
44 # define __P(args) args
45 # else
46 # define __P(args) ()
47 # endif /* GCC. */
48 #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; \
105 if (*decided != raw) \
107 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
108 int __n = n; \
109 int any = 0; \
110 while (*rp == ' ') \
111 ++rp; \
112 val = 0; \
113 do { \
114 val *= 10; \
115 while (*alts != '\0') \
117 size_t len = strlen (alts); \
118 if (strncasecmp (alts, rp, len) == 0) \
119 break; \
120 alts += len + 1; \
121 ++val; \
123 if (*alts == '\0') \
125 if (*decided == not && ! any) \
126 goto do_normal; \
127 /* If we haven't read anything it's an error. */ \
128 if (! any) \
129 return NULL; \
130 /* Correct the premature multiplication. */ \
131 val /= 10; \
132 break; \
134 else \
135 *decided = loc; \
136 } while (--__n > 0 && val * 10 <= to); \
137 if (val < from || val > to) \
138 return NULL; \
140 else \
142 do_normal: \
143 get_number (from, to, n); \
145 0; \
147 #else
148 # define get_alt_number(from, to, n) \
149 /* We don't have the alternate representation. */ \
150 get_number(from, to, n)
151 #endif
152 #define recursive(new_fmt) \
153 (*(new_fmt) != '\0' \
154 && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
157 #ifdef _LIBC
158 /* This is defined in locale/C-time.c in the GNU libc. */
159 extern const struct locale_data _nl_C_LC_TIME;
160 extern const unsigned short int __mon_yday[2][13];
162 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
163 # define ab_weekday_name \
164 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
165 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
166 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
167 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
168 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
169 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
170 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
171 # define HERE_T_FMT_AMPM \
172 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
173 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
175 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
176 #else
177 static char const weekday_name[][10] =
179 "Sunday", "Monday", "Tuesday", "Wednesday",
180 "Thursday", "Friday", "Saturday"
182 static char const ab_weekday_name[][4] =
184 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
186 static char const month_name[][10] =
188 "January", "February", "March", "April", "May", "June",
189 "July", "August", "September", "October", "November", "December"
191 static char const ab_month_name[][4] =
193 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
194 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
196 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
197 # define HERE_D_FMT "%m/%d/%y"
198 # define HERE_AM_STR "AM"
199 # define HERE_PM_STR "PM"
200 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
201 # define HERE_T_FMT "%H:%M:%S"
203 const unsigned short int __mon_yday[2][13] =
205 /* Normal years. */
206 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
207 /* Leap years. */
208 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
210 #endif
212 /* Status of lookup: do we use the locale data or the raw data? */
213 enum locale_status { not, loc, raw };
216 #ifndef __isleap
217 /* Nonzero if YEAR is a leap year (every 4 years,
218 except every 100th isn't, and every 400th is). */
219 # define __isleap(year) \
220 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
221 #endif
223 /* Compute the day of the week. */
224 static void
225 day_of_the_week (struct tm *tm)
227 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
228 the difference between this data in the one on TM and so determine
229 the weekday. */
230 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
231 int wday = (-473
232 + (365 * (tm->tm_year - 70))
233 + (corr_year / 4)
234 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
235 + (((corr_year / 4) / 25) / 4)
236 + __mon_yday[0][tm->tm_mon]
237 + tm->tm_mday - 1);
238 tm->tm_wday = ((wday % 7) + 7) % 7;
241 /* Compute the day of the year. */
242 static void
243 day_of_the_year (struct tm *tm)
245 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
246 + (tm->tm_mday - 1));
249 static char *
250 #ifdef _LIBC
251 internal_function
252 #endif
253 strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
254 enum locale_status *decided, int era_cnt));
256 static char *
257 #ifdef _LIBC
258 internal_function
259 #endif
260 strptime_internal (rp, fmt, tm, decided, era_cnt)
261 const char *rp;
262 const char *fmt;
263 struct tm *tm;
264 enum locale_status *decided;
265 int era_cnt;
267 const char *rp_backup;
268 int cnt;
269 int val;
270 int have_I, is_pm;
271 int century, want_century;
272 int want_era;
273 int have_wday, want_xday;
274 int have_yday;
275 int have_mon, have_mday;
276 #ifdef _NL_CURRENT
277 size_t num_eras;
278 #endif
279 struct era_entry *era;
281 have_I = is_pm = 0;
282 century = -1;
283 want_century = 0;
284 want_era = 0;
285 era = NULL;
287 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
289 while (*fmt != '\0')
291 /* A white space in the format string matches 0 more or white
292 space in the input string. */
293 if (isspace (*fmt))
295 while (isspace (*rp))
296 ++rp;
297 ++fmt;
298 continue;
301 /* Any character but `%' must be matched by the same character
302 in the iput string. */
303 if (*fmt != '%')
305 match_char (*fmt++, *rp++);
306 continue;
309 ++fmt;
310 #ifndef _NL_CURRENT
311 /* We need this for handling the `E' modifier. */
312 start_over:
313 #endif
315 /* Make back up of current processing pointer. */
316 rp_backup = rp;
318 switch (*fmt++)
320 case '%':
321 /* Match the `%' character itself. */
322 match_char ('%', *rp++);
323 break;
324 case 'a':
325 case 'A':
326 /* Match day of week. */
327 for (cnt = 0; cnt < 7; ++cnt)
329 #ifdef _NL_CURRENT
330 if (*decided !=raw)
332 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
334 if (*decided == not
335 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
336 weekday_name[cnt]))
337 *decided = loc;
338 break;
340 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
342 if (*decided == not
343 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
344 ab_weekday_name[cnt]))
345 *decided = loc;
346 break;
349 #endif
350 if (*decided != loc
351 && (match_string (weekday_name[cnt], rp)
352 || match_string (ab_weekday_name[cnt], rp)))
354 *decided = raw;
355 break;
358 if (cnt == 7)
359 /* Does not match a weekday name. */
360 return NULL;
361 tm->tm_wday = cnt;
362 have_wday = 1;
363 break;
364 case 'b':
365 case 'B':
366 case 'h':
367 /* Match month name. */
368 for (cnt = 0; cnt < 12; ++cnt)
370 #ifdef _NL_CURRENT
371 if (*decided !=raw)
373 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
375 if (*decided == not
376 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
377 month_name[cnt]))
378 *decided = loc;
379 break;
381 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
383 if (*decided == not
384 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
385 ab_month_name[cnt]))
386 *decided = loc;
387 break;
390 #endif
391 if (match_string (month_name[cnt], rp)
392 || match_string (ab_month_name[cnt], rp))
394 *decided = raw;
395 break;
398 if (cnt == 12)
399 /* Does not match a month name. */
400 return NULL;
401 tm->tm_mon = cnt;
402 want_xday = 1;
403 break;
404 case 'c':
405 /* Match locale's date and time format. */
406 #ifdef _NL_CURRENT
407 if (*decided != raw)
409 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
411 if (*decided == loc)
412 return NULL;
413 else
414 rp = rp_backup;
416 else
418 if (*decided == not &&
419 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
420 *decided = loc;
421 want_xday = 1;
422 break;
424 *decided = raw;
426 #endif
427 if (!recursive (HERE_D_T_FMT))
428 return NULL;
429 want_xday = 1;
430 break;
431 case 'C':
432 /* Match century number. */
433 #ifdef _NL_CURRENT
434 match_century:
435 #endif
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 'I':
490 /* Match hour in 12-hour clock. */
491 get_number (1, 12, 2);
492 tm->tm_hour = val % 12;
493 have_I = 1;
494 break;
495 case 'j':
496 /* Match day number of year. */
497 get_number (1, 366, 3);
498 tm->tm_yday = val - 1;
499 have_yday = 1;
500 break;
501 case 'm':
502 /* Match number of month. */
503 get_number (1, 12, 2);
504 tm->tm_mon = val - 1;
505 have_mon = 1;
506 want_xday = 1;
507 break;
508 case 'M':
509 /* Match minute. */
510 get_number (0, 59, 2);
511 tm->tm_min = val;
512 break;
513 case 'n':
514 case 't':
515 /* Match any white space. */
516 while (isspace (*rp))
517 ++rp;
518 break;
519 case 'p':
520 /* Match locale's equivalent of AM/PM. */
521 #ifdef _NL_CURRENT
522 if (*decided != raw)
524 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
526 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
527 *decided = loc;
528 break;
530 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
532 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
533 *decided = loc;
534 is_pm = 1;
535 break;
537 *decided = raw;
539 #endif
540 if (!match_string (HERE_AM_STR, rp)) {
541 if (match_string (HERE_PM_STR, rp))
542 is_pm = 1;
543 else
544 return NULL;
546 break;
547 case 'r':
548 #ifdef _NL_CURRENT
549 if (*decided != raw)
551 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
553 if (*decided == loc)
554 return NULL;
555 else
556 rp = rp_backup;
558 else
560 if (*decided == not &&
561 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
562 HERE_T_FMT_AMPM))
563 *decided = loc;
564 break;
566 *decided = raw;
568 #endif
569 if (!recursive (HERE_T_FMT_AMPM))
570 return NULL;
571 break;
572 case 'R':
573 if (!recursive ("%H:%M"))
574 return NULL;
575 break;
576 case 's':
578 /* The number of seconds may be very high so we cannot use
579 the `get_number' macro. Instead read the number
580 character for character and construct the result while
581 doing this. */
582 time_t secs = 0;
583 if (*rp < '0' || *rp > '9')
584 /* We need at least one digit. */
585 return NULL;
589 secs *= 10;
590 secs += *rp++ - '0';
592 while (*rp >= '0' && *rp <= '9');
594 if (localtime_r (&secs, tm) == NULL)
595 /* Error in function. */
596 return NULL;
598 break;
599 case 'S':
600 get_number (0, 61, 2);
601 tm->tm_sec = val;
602 break;
603 case 'X':
604 #ifdef _NL_CURRENT
605 if (*decided != raw)
607 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
609 if (*decided == loc)
610 return NULL;
611 else
612 rp = rp_backup;
614 else
616 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
617 *decided = loc;
618 break;
620 *decided = raw;
622 #endif
623 /* Fall through. */
624 case 'T':
625 if (!recursive (HERE_T_FMT))
626 return NULL;
627 break;
628 case 'u':
629 get_number (1, 7, 1);
630 tm->tm_wday = val % 7;
631 have_wday = 1;
632 break;
633 case 'g':
634 get_number (0, 99, 2);
635 /* XXX This cannot determine any field in TM. */
636 break;
637 case 'G':
638 if (*rp < '0' || *rp > '9')
639 return NULL;
640 /* XXX Ignore the number since we would need some more
641 information to compute a real date. */
643 ++rp;
644 while (*rp >= '0' && *rp <= '9');
645 break;
646 case 'U':
647 case 'V':
648 case 'W':
649 get_number (0, 53, 2);
650 /* XXX This cannot determine any field in TM without some
651 information. */
652 break;
653 case 'w':
654 /* Match number of weekday. */
655 get_number (0, 6, 1);
656 tm->tm_wday = val;
657 have_wday = 1;
658 break;
659 case 'y':
660 #ifdef _NL_CURRENT
661 match_year_in_century:
662 #endif
663 /* Match year within century. */
664 get_number (0, 99, 2);
665 /* The "Year 2000: The Millennium Rollover" paper suggests that
666 values in the range 69-99 refer to the twentieth century. */
667 tm->tm_year = val >= 69 ? val : val + 100;
668 /* Indicate that we want to use the century, if specified. */
669 want_century = 1;
670 want_xday = 1;
671 break;
672 case 'Y':
673 /* Match year including century number. */
674 get_number (0, 9999, 4);
675 tm->tm_year = val - 1900;
676 want_century = 0;
677 want_xday = 1;
678 break;
679 case 'Z':
680 /* XXX How to handle this? */
681 break;
682 case 'E':
683 #ifdef _NL_CURRENT
684 switch (*fmt++)
686 case 'c':
687 /* Match locale's alternate date and time format. */
688 if (*decided != raw)
690 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
692 if (*fmt == '\0')
693 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
695 if (!recursive (fmt))
697 if (*decided == loc)
698 return NULL;
699 else
700 rp = rp_backup;
702 else
704 if (strcmp (fmt, HERE_D_T_FMT))
705 *decided = loc;
706 want_xday = 1;
707 break;
709 *decided = raw;
711 /* The C locale has no era information, so use the
712 normal representation. */
713 if (!recursive (HERE_D_T_FMT))
714 return NULL;
715 want_xday = 1;
716 break;
717 case 'C':
718 if (*decided != raw)
720 if (era_cnt >= 0)
722 era = _nl_select_era_entry (era_cnt);
723 if (match_string (era->era_name, rp))
725 *decided = loc;
726 break;
728 else
729 return NULL;
731 else
733 num_eras = _NL_CURRENT_WORD (LC_TIME,
734 _NL_TIME_ERA_NUM_ENTRIES);
735 for (era_cnt = 0; era_cnt < (int) num_eras;
736 ++era_cnt, rp = rp_backup)
738 era = _nl_select_era_entry (era_cnt);
739 if (match_string (era->era_name, rp))
741 *decided = loc;
742 break;
745 if (era_cnt == (int) num_eras)
747 era_cnt = -1;
748 if (*decided == loc)
749 return NULL;
751 else
752 break;
755 *decided = raw;
757 /* The C locale has no era information, so use the
758 normal representation. */
759 goto match_century;
760 case 'y':
761 if (*decided == raw)
762 goto match_year_in_century;
764 get_number(0, 9999, 4);
765 tm->tm_year = val;
766 want_era = 1;
767 want_xday = 1;
768 break;
769 case 'Y':
770 if (*decided != raw)
772 num_eras = _NL_CURRENT_WORD (LC_TIME,
773 _NL_TIME_ERA_NUM_ENTRIES);
774 for (era_cnt = 0; era_cnt < (int) num_eras;
775 ++era_cnt, rp = rp_backup)
777 era = _nl_select_era_entry (era_cnt);
778 if (recursive (era->era_format))
779 break;
781 if (era_cnt == (int) num_eras)
783 era_cnt = -1;
784 if (*decided == loc)
785 return NULL;
786 else
787 rp = rp_backup;
789 else
791 *decided = loc;
792 era_cnt = -1;
793 break;
796 *decided = raw;
798 get_number (0, 9999, 4);
799 tm->tm_year = val - 1900;
800 want_century = 0;
801 want_xday = 1;
802 break;
803 case 'x':
804 if (*decided != raw)
806 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
808 if (*fmt == '\0')
809 fmt = _NL_CURRENT (LC_TIME, D_FMT);
811 if (!recursive (fmt))
813 if (*decided == loc)
814 return NULL;
815 else
816 rp = rp_backup;
818 else
820 if (strcmp (fmt, HERE_D_FMT))
821 *decided = loc;
822 break;
824 *decided = raw;
826 if (!recursive (HERE_D_FMT))
827 return NULL;
828 break;
829 case 'X':
830 if (*decided != raw)
832 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
834 if (*fmt == '\0')
835 fmt = _NL_CURRENT (LC_TIME, T_FMT);
837 if (!recursive (fmt))
839 if (*decided == loc)
840 return NULL;
841 else
842 rp = rp_backup;
844 else
846 if (strcmp (fmt, HERE_T_FMT))
847 *decided = loc;
848 break;
850 *decided = raw;
852 if (!recursive (HERE_T_FMT))
853 return NULL;
854 break;
855 default:
856 return NULL;
858 break;
859 #else
860 /* We have no information about the era format. Just use
861 the normal format. */
862 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
863 && *fmt != 'x' && *fmt != 'X')
864 /* This is an illegal format. */
865 return NULL;
867 goto start_over;
868 #endif
869 case 'O':
870 switch (*fmt++)
872 case 'd':
873 case 'e':
874 /* Match day of month using alternate numeric symbols. */
875 get_alt_number (1, 31, 2);
876 tm->tm_mday = val;
877 have_mday = 1;
878 want_xday = 1;
879 break;
880 case 'H':
881 /* Match hour in 24-hour clock using alternate numeric
882 symbols. */
883 get_alt_number (0, 23, 2);
884 tm->tm_hour = val;
885 have_I = 0;
886 break;
887 case 'I':
888 /* Match hour in 12-hour clock using alternate numeric
889 symbols. */
890 get_alt_number (1, 12, 2);
891 tm->tm_hour = val - 1;
892 have_I = 1;
893 break;
894 case 'm':
895 /* Match month using alternate numeric symbols. */
896 get_alt_number (1, 12, 2);
897 tm->tm_mon = val - 1;
898 have_mon = 1;
899 want_xday = 1;
900 break;
901 case 'M':
902 /* Match minutes using alternate numeric symbols. */
903 get_alt_number (0, 59, 2);
904 tm->tm_min = val;
905 break;
906 case 'S':
907 /* Match seconds using alternate numeric symbols. */
908 get_alt_number (0, 61, 2);
909 tm->tm_sec = val;
910 break;
911 case 'U':
912 case 'V':
913 case 'W':
914 get_alt_number (0, 53, 2);
915 /* XXX This cannot determine any field in TM without
916 further information. */
917 break;
918 case 'w':
919 /* Match number of weekday using alternate numeric symbols. */
920 get_alt_number (0, 6, 1);
921 tm->tm_wday = val;
922 have_wday = 1;
923 break;
924 case 'y':
925 /* Match year within century using alternate numeric symbols. */
926 get_alt_number (0, 99, 2);
927 tm->tm_year = val >= 69 ? val : val + 100;
928 want_xday = 1;
929 break;
930 default:
931 return NULL;
933 break;
934 default:
935 return NULL;
939 if (have_I && is_pm)
940 tm->tm_hour += 12;
942 if (century != -1)
944 if (want_century)
945 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
946 else
947 /* Only the century, but not the year. Strange, but so be it. */
948 tm->tm_year = (century - 19) * 100;
951 #ifdef _NL_CURRENT
952 if (era_cnt != -1)
954 era = _nl_select_era_entry(era_cnt);
955 if (want_era)
956 tm->tm_year = (era->start_date[0]
957 + ((tm->tm_year - era->offset)
958 * era->absolute_direction));
959 else
960 /* Era start year assumed. */
961 tm->tm_year = era->start_date[0];
963 else
964 #endif
965 if (want_era)
966 return NULL;
968 if (want_xday && !have_wday)
970 if ( !(have_mon && have_mday) && have_yday)
972 /* We don't have tm_mon and/or tm_mday, compute them. */
973 int t_mon = 0;
974 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
975 t_mon++;
976 if (!have_mon)
977 tm->tm_mon = t_mon - 1;
978 if (!have_mday)
979 tm->tm_mday =
980 (tm->tm_yday
981 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
983 day_of_the_week (tm);
985 if (want_xday && !have_yday)
986 day_of_the_year (tm);
988 return (char *) rp;
992 char *
993 strptime (buf, format, tm)
994 const char *buf;
995 const char *format;
996 struct tm *tm;
998 enum locale_status decided;
1000 #ifdef _NL_CURRENT
1001 decided = not;
1002 #else
1003 decided = raw;
1004 #endif
1005 return strptime_internal (buf, format, tm, &decided, -1);