comparison strptime.c @ 0:05318cf2e886 libavformat

renamed libav to libavformat
author bellard
date Mon, 25 Nov 2002 19:07:40 +0000
parents
children 89a78842f6c2
comparison
equal deleted inserted replaced
-1:000000000000 0:05318cf2e886
1 /* Convert a string representation of time to a time value.
2 Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
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. */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <ctype.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <time.h>
34
35 #ifdef _LIBC
36 # include "../locale/localeinfo.h"
37 #endif
38
39 #include "strptime.h"
40
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. */
48
49 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
50 # ifdef _LIBC
51 # define localtime_r __localtime_r
52 # else
53 /* Approximate localtime_r as best we can in its absence. */
54 # define localtime_r my_localtime_r
55 static struct tm *localtime_r __P ((const time_t *, struct tm *));
56 static struct tm *
57 localtime_r (t, tp)
58 const time_t *t;
59 struct tm *tp;
60 {
61 struct tm *l = localtime (t);
62 if (! l)
63 return 0;
64 *tp = *l;
65 return tp;
66 }
67 # endif /* ! _LIBC */
68 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
69
70
71 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
72 #if defined __GNUC__ && __GNUC__ >= 2
73 # define match_string(cs1, s2) \
74 ({ size_t len = strlen (cs1); \
75 int result = strncasecmp ((cs1), (s2), len) == 0; \
76 if (result) (s2) += len; \
77 result; })
78 #else
79 /* Oh come on. Get a reasonable compiler. */
80 # define match_string(cs1, s2) \
81 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
82 #endif
83 /* We intentionally do not use isdigit() for testing because this will
84 lead to problems with the wide character version. */
85 #define get_number(from, to, n) \
86 do { \
87 int __n = n; \
88 val = 0; \
89 while (*rp == ' ') \
90 ++rp; \
91 if (*rp < '0' || *rp > '9') \
92 return NULL; \
93 do { \
94 val *= 10; \
95 val += *rp++ - '0'; \
96 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
97 if (val < from || val > to) \
98 return NULL; \
99 } while (0)
100 #ifdef _NL_CURRENT
101 # define get_alt_number(from, to, n) \
102 ({ \
103 __label__ do_normal; \
104 if (*decided != raw) \
105 { \
106 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
107 int __n = n; \
108 int any = 0; \
109 while (*rp == ' ') \
110 ++rp; \
111 val = 0; \
112 do { \
113 val *= 10; \
114 while (*alts != '\0') \
115 { \
116 size_t len = strlen (alts); \
117 if (strncasecmp (alts, rp, len) == 0) \
118 break; \
119 alts += len + 1; \
120 ++val; \
121 } \
122 if (*alts == '\0') \
123 { \
124 if (*decided == not && ! any) \
125 goto do_normal; \
126 /* If we haven't read anything it's an error. */ \
127 if (! any) \
128 return NULL; \
129 /* Correct the premature multiplication. */ \
130 val /= 10; \
131 break; \
132 } \
133 else \
134 *decided = loc; \
135 } while (--__n > 0 && val * 10 <= to); \
136 if (val < from || val > to) \
137 return NULL; \
138 } \
139 else \
140 { \
141 do_normal: \
142 get_number (from, to, n); \
143 } \
144 0; \
145 })
146 #else
147 # define get_alt_number(from, to, n) \
148 /* We don't have the alternate representation. */ \
149 get_number(from, to, n)
150 #endif
151 #define recursive(new_fmt) \
152 (*(new_fmt) != '\0' \
153 && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
154
155
156 #ifdef _LIBC
157 /* This is defined in locale/C-time.c in the GNU libc. */
158 extern const struct locale_data _nl_C_LC_TIME;
159 extern const unsigned short int __mon_yday[2][13];
160
161 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
162 # define ab_weekday_name \
163 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
164 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
165 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
166 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
167 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
168 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
169 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
170 # define HERE_T_FMT_AMPM \
171 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
172 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
173
174 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
175 #else
176 static char const weekday_name[][10] =
177 {
178 "Sunday", "Monday", "Tuesday", "Wednesday",
179 "Thursday", "Friday", "Saturday"
180 };
181 static char const ab_weekday_name[][4] =
182 {
183 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
184 };
185 static char const month_name[][10] =
186 {
187 "January", "February", "March", "April", "May", "June",
188 "July", "August", "September", "October", "November", "December"
189 };
190 static char const ab_month_name[][4] =
191 {
192 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
193 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
194 };
195 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
196 # define HERE_D_FMT "%m/%d/%y"
197 # define HERE_AM_STR "AM"
198 # define HERE_PM_STR "PM"
199 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
200 # define HERE_T_FMT "%H:%M:%S"
201
202 const unsigned short int __mon_yday[2][13] =
203 {
204 /* Normal years. */
205 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
206 /* Leap years. */
207 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
208 };
209 #endif
210
211 /* Status of lookup: do we use the locale data or the raw data? */
212 enum locale_status { not, loc, raw };
213
214
215 #ifndef __isleap
216 /* Nonzero if YEAR is a leap year (every 4 years,
217 except every 100th isn't, and every 400th is). */
218 # define __isleap(year) \
219 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
220 #endif
221
222 /* Compute the day of the week. */
223 static void
224 day_of_the_week (struct tm *tm)
225 {
226 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
227 the difference between this data in the one on TM and so determine
228 the weekday. */
229 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
230 int wday = (-473
231 + (365 * (tm->tm_year - 70))
232 + (corr_year / 4)
233 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
234 + (((corr_year / 4) / 25) / 4)
235 + __mon_yday[0][tm->tm_mon]
236 + tm->tm_mday - 1);
237 tm->tm_wday = ((wday % 7) + 7) % 7;
238 }
239
240 /* Compute the day of the year. */
241 static void
242 day_of_the_year (struct tm *tm)
243 {
244 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
245 + (tm->tm_mday - 1));
246 }
247
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
255 static char *
256 #ifdef _LIBC
257 internal_function
258 #endif
259 strptime_internal (rp, fmt, tm, decided, era_cnt)
260 const char *rp;
261 const char *fmt;
262 struct tm *tm;
263 enum locale_status *decided;
264 int era_cnt;
265 {
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 #ifdef _NL_CURRENT
276 size_t num_eras;
277 #endif
278 struct era_entry *era;
279
280 have_I = is_pm = 0;
281 century = -1;
282 want_century = 0;
283 want_era = 0;
284 era = NULL;
285
286 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
287
288 while (*fmt != '\0')
289 {
290 /* A white space in the format string matches 0 more or white
291 space in the input string. */
292 if (isspace (*fmt))
293 {
294 while (isspace (*rp))
295 ++rp;
296 ++fmt;
297 continue;
298 }
299
300 /* Any character but `%' must be matched by the same character
301 in the iput string. */
302 if (*fmt != '%')
303 {
304 match_char (*fmt++, *rp++);
305 continue;
306 }
307
308 ++fmt;
309 #ifndef _NL_CURRENT
310 /* We need this for handling the `E' modifier. */
311 start_over:
312 #endif
313
314 /* Make back up of current processing pointer. */
315 rp_backup = rp;
316
317 switch (*fmt++)
318 {
319 case '%':
320 /* Match the `%' character itself. */
321 match_char ('%', *rp++);
322 break;
323 case 'a':
324 case 'A':
325 /* Match day of week. */
326 for (cnt = 0; cnt < 7; ++cnt)
327 {
328 #ifdef _NL_CURRENT
329 if (*decided !=raw)
330 {
331 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
332 {
333 if (*decided == not
334 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
335 weekday_name[cnt]))
336 *decided = loc;
337 break;
338 }
339 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
340 {
341 if (*decided == not
342 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
343 ab_weekday_name[cnt]))
344 *decided = loc;
345 break;
346 }
347 }
348 #endif
349 if (*decided != loc
350 && (match_string (weekday_name[cnt], rp)
351 || match_string (ab_weekday_name[cnt], rp)))
352 {
353 *decided = raw;
354 break;
355 }
356 }
357 if (cnt == 7)
358 /* Does not match a weekday name. */
359 return NULL;
360 tm->tm_wday = cnt;
361 have_wday = 1;
362 break;
363 case 'b':
364 case 'B':
365 case 'h':
366 /* Match month name. */
367 for (cnt = 0; cnt < 12; ++cnt)
368 {
369 #ifdef _NL_CURRENT
370 if (*decided !=raw)
371 {
372 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
373 {
374 if (*decided == not
375 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
376 month_name[cnt]))
377 *decided = loc;
378 break;
379 }
380 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
381 {
382 if (*decided == not
383 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
384 ab_month_name[cnt]))
385 *decided = loc;
386 break;
387 }
388 }
389 #endif
390 if (match_string (month_name[cnt], rp)
391 || match_string (ab_month_name[cnt], rp))
392 {
393 *decided = raw;
394 break;
395 }
396 }
397 if (cnt == 12)
398 /* Does not match a month name. */
399 return NULL;
400 tm->tm_mon = cnt;
401 want_xday = 1;
402 break;
403 case 'c':
404 /* Match locale's date and time format. */
405 #ifdef _NL_CURRENT
406 if (*decided != raw)
407 {
408 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
409 {
410 if (*decided == loc)
411 return NULL;
412 else
413 rp = rp_backup;
414 }
415 else
416 {
417 if (*decided == not &&
418 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
419 *decided = loc;
420 want_xday = 1;
421 break;
422 }
423 *decided = raw;
424 }
425 #endif
426 if (!recursive (HERE_D_T_FMT))
427 return NULL;
428 want_xday = 1;
429 break;
430 case 'C':
431 /* Match century number. */
432 #ifdef _NL_CURRENT
433 match_century:
434 #endif
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)
455 {
456 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
457 {
458 if (*decided == loc)
459 return NULL;
460 else
461 rp = rp_backup;
462 }
463 else
464 {
465 if (*decided == not
466 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
467 *decided = loc;
468 want_xday = 1;
469 break;
470 }
471 *decided = raw;
472 }
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 'I':
489 /* Match hour in 12-hour clock. */
490 get_number (1, 12, 2);
491 tm->tm_hour = val % 12;
492 have_I = 1;
493 break;
494 case 'j':
495 /* Match day number of year. */
496 get_number (1, 366, 3);
497 tm->tm_yday = val - 1;
498 have_yday = 1;
499 break;
500 case 'm':
501 /* Match number of month. */
502 get_number (1, 12, 2);
503 tm->tm_mon = val - 1;
504 have_mon = 1;
505 want_xday = 1;
506 break;
507 case 'M':
508 /* Match minute. */
509 get_number (0, 59, 2);
510 tm->tm_min = val;
511 break;
512 case 'n':
513 case 't':
514 /* Match any white space. */
515 while (isspace (*rp))
516 ++rp;
517 break;
518 case 'p':
519 /* Match locale's equivalent of AM/PM. */
520 #ifdef _NL_CURRENT
521 if (*decided != raw)
522 {
523 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
524 {
525 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
526 *decided = loc;
527 break;
528 }
529 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
530 {
531 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
532 *decided = loc;
533 is_pm = 1;
534 break;
535 }
536 *decided = raw;
537 }
538 #endif
539 if (!match_string (HERE_AM_STR, rp))
540 if (match_string (HERE_PM_STR, rp))
541 is_pm = 1;
542 else
543 return NULL;
544 break;
545 case 'r':
546 #ifdef _NL_CURRENT
547 if (*decided != raw)
548 {
549 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
550 {
551 if (*decided == loc)
552 return NULL;
553 else
554 rp = rp_backup;
555 }
556 else
557 {
558 if (*decided == not &&
559 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
560 HERE_T_FMT_AMPM))
561 *decided = loc;
562 break;
563 }
564 *decided = raw;
565 }
566 #endif
567 if (!recursive (HERE_T_FMT_AMPM))
568 return NULL;
569 break;
570 case 'R':
571 if (!recursive ("%H:%M"))
572 return NULL;
573 break;
574 case 's':
575 {
576 /* The number of seconds may be very high so we cannot use
577 the `get_number' macro. Instead read the number
578 character for character and construct the result while
579 doing this. */
580 time_t secs = 0;
581 if (*rp < '0' || *rp > '9')
582 /* We need at least one digit. */
583 return NULL;
584
585 do
586 {
587 secs *= 10;
588 secs += *rp++ - '0';
589 }
590 while (*rp >= '0' && *rp <= '9');
591
592 if (localtime_r (&secs, tm) == NULL)
593 /* Error in function. */
594 return NULL;
595 }
596 break;
597 case 'S':
598 get_number (0, 61, 2);
599 tm->tm_sec = val;
600 break;
601 case 'X':
602 #ifdef _NL_CURRENT
603 if (*decided != raw)
604 {
605 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
606 {
607 if (*decided == loc)
608 return NULL;
609 else
610 rp = rp_backup;
611 }
612 else
613 {
614 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
615 *decided = loc;
616 break;
617 }
618 *decided = raw;
619 }
620 #endif
621 /* Fall through. */
622 case 'T':
623 if (!recursive (HERE_T_FMT))
624 return NULL;
625 break;
626 case 'u':
627 get_number (1, 7, 1);
628 tm->tm_wday = val % 7;
629 have_wday = 1;
630 break;
631 case 'g':
632 get_number (0, 99, 2);
633 /* XXX This cannot determine any field in TM. */
634 break;
635 case 'G':
636 if (*rp < '0' || *rp > '9')
637 return NULL;
638 /* XXX Ignore the number since we would need some more
639 information to compute a real date. */
640 do
641 ++rp;
642 while (*rp >= '0' && *rp <= '9');
643 break;
644 case 'U':
645 case 'V':
646 case 'W':
647 get_number (0, 53, 2);
648 /* XXX This cannot determine any field in TM without some
649 information. */
650 break;
651 case 'w':
652 /* Match number of weekday. */
653 get_number (0, 6, 1);
654 tm->tm_wday = val;
655 have_wday = 1;
656 break;
657 case 'y':
658 #ifdef _NL_CURRENT
659 match_year_in_century:
660 #endif
661 /* Match year within century. */
662 get_number (0, 99, 2);
663 /* The "Year 2000: The Millennium Rollover" paper suggests that
664 values in the range 69-99 refer to the twentieth century. */
665 tm->tm_year = val >= 69 ? val : val + 100;
666 /* Indicate that we want to use the century, if specified. */
667 want_century = 1;
668 want_xday = 1;
669 break;
670 case 'Y':
671 /* Match year including century number. */
672 get_number (0, 9999, 4);
673 tm->tm_year = val - 1900;
674 want_century = 0;
675 want_xday = 1;
676 break;
677 case 'Z':
678 /* XXX How to handle this? */
679 break;
680 case 'E':
681 #ifdef _NL_CURRENT
682 switch (*fmt++)
683 {
684 case 'c':
685 /* Match locale's alternate date and time format. */
686 if (*decided != raw)
687 {
688 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
689
690 if (*fmt == '\0')
691 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
692
693 if (!recursive (fmt))
694 {
695 if (*decided == loc)
696 return NULL;
697 else
698 rp = rp_backup;
699 }
700 else
701 {
702 if (strcmp (fmt, HERE_D_T_FMT))
703 *decided = loc;
704 want_xday = 1;
705 break;
706 }
707 *decided = raw;
708 }
709 /* The C locale has no era information, so use the
710 normal representation. */
711 if (!recursive (HERE_D_T_FMT))
712 return NULL;
713 want_xday = 1;
714 break;
715 case 'C':
716 if (*decided != raw)
717 {
718 if (era_cnt >= 0)
719 {
720 era = _nl_select_era_entry (era_cnt);
721 if (match_string (era->era_name, rp))
722 {
723 *decided = loc;
724 break;
725 }
726 else
727 return NULL;
728 }
729 else
730 {
731 num_eras = _NL_CURRENT_WORD (LC_TIME,
732 _NL_TIME_ERA_NUM_ENTRIES);
733 for (era_cnt = 0; era_cnt < (int) num_eras;
734 ++era_cnt, rp = rp_backup)
735 {
736 era = _nl_select_era_entry (era_cnt);
737 if (match_string (era->era_name, rp))
738 {
739 *decided = loc;
740 break;
741 }
742 }
743 if (era_cnt == (int) num_eras)
744 {
745 era_cnt = -1;
746 if (*decided == loc)
747 return NULL;
748 }
749 else
750 break;
751 }
752
753 *decided = raw;
754 }
755 /* The C locale has no era information, so use the
756 normal representation. */
757 goto match_century;
758 case 'y':
759 if (*decided == raw)
760 goto match_year_in_century;
761
762 get_number(0, 9999, 4);
763 tm->tm_year = val;
764 want_era = 1;
765 want_xday = 1;
766 break;
767 case 'Y':
768 if (*decided != raw)
769 {
770 num_eras = _NL_CURRENT_WORD (LC_TIME,
771 _NL_TIME_ERA_NUM_ENTRIES);
772 for (era_cnt = 0; era_cnt < (int) num_eras;
773 ++era_cnt, rp = rp_backup)
774 {
775 era = _nl_select_era_entry (era_cnt);
776 if (recursive (era->era_format))
777 break;
778 }
779 if (era_cnt == (int) num_eras)
780 {
781 era_cnt = -1;
782 if (*decided == loc)
783 return NULL;
784 else
785 rp = rp_backup;
786 }
787 else
788 {
789 *decided = loc;
790 era_cnt = -1;
791 break;
792 }
793
794 *decided = raw;
795 }
796 get_number (0, 9999, 4);
797 tm->tm_year = val - 1900;
798 want_century = 0;
799 want_xday = 1;
800 break;
801 case 'x':
802 if (*decided != raw)
803 {
804 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
805
806 if (*fmt == '\0')
807 fmt = _NL_CURRENT (LC_TIME, D_FMT);
808
809 if (!recursive (fmt))
810 {
811 if (*decided == loc)
812 return NULL;
813 else
814 rp = rp_backup;
815 }
816 else
817 {
818 if (strcmp (fmt, HERE_D_FMT))
819 *decided = loc;
820 break;
821 }
822 *decided = raw;
823 }
824 if (!recursive (HERE_D_FMT))
825 return NULL;
826 break;
827 case 'X':
828 if (*decided != raw)
829 {
830 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
831
832 if (*fmt == '\0')
833 fmt = _NL_CURRENT (LC_TIME, T_FMT);
834
835 if (!recursive (fmt))
836 {
837 if (*decided == loc)
838 return NULL;
839 else
840 rp = rp_backup;
841 }
842 else
843 {
844 if (strcmp (fmt, HERE_T_FMT))
845 *decided = loc;
846 break;
847 }
848 *decided = raw;
849 }
850 if (!recursive (HERE_T_FMT))
851 return NULL;
852 break;
853 default:
854 return NULL;
855 }
856 break;
857 #else
858 /* We have no information about the era format. Just use
859 the normal format. */
860 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
861 && *fmt != 'x' && *fmt != 'X')
862 /* This is an illegal format. */
863 return NULL;
864
865 goto start_over;
866 #endif
867 case 'O':
868 switch (*fmt++)
869 {
870 case 'd':
871 case 'e':
872 /* Match day of month using alternate numeric symbols. */
873 get_alt_number (1, 31, 2);
874 tm->tm_mday = val;
875 have_mday = 1;
876 want_xday = 1;
877 break;
878 case 'H':
879 /* Match hour in 24-hour clock using alternate numeric
880 symbols. */
881 get_alt_number (0, 23, 2);
882 tm->tm_hour = val;
883 have_I = 0;
884 break;
885 case 'I':
886 /* Match hour in 12-hour clock using alternate numeric
887 symbols. */
888 get_alt_number (1, 12, 2);
889 tm->tm_hour = val - 1;
890 have_I = 1;
891 break;
892 case 'm':
893 /* Match month using alternate numeric symbols. */
894 get_alt_number (1, 12, 2);
895 tm->tm_mon = val - 1;
896 have_mon = 1;
897 want_xday = 1;
898 break;
899 case 'M':
900 /* Match minutes using alternate numeric symbols. */
901 get_alt_number (0, 59, 2);
902 tm->tm_min = val;
903 break;
904 case 'S':
905 /* Match seconds using alternate numeric symbols. */
906 get_alt_number (0, 61, 2);
907 tm->tm_sec = val;
908 break;
909 case 'U':
910 case 'V':
911 case 'W':
912 get_alt_number (0, 53, 2);
913 /* XXX This cannot determine any field in TM without
914 further information. */
915 break;
916 case 'w':
917 /* Match number of weekday using alternate numeric symbols. */
918 get_alt_number (0, 6, 1);
919 tm->tm_wday = val;
920 have_wday = 1;
921 break;
922 case 'y':
923 /* Match year within century using alternate numeric symbols. */
924 get_alt_number (0, 99, 2);
925 tm->tm_year = val >= 69 ? val : val + 100;
926 want_xday = 1;
927 break;
928 default:
929 return NULL;
930 }
931 break;
932 default:
933 return NULL;
934 }
935 }
936
937 if (have_I && is_pm)
938 tm->tm_hour += 12;
939
940 if (century != -1)
941 {
942 if (want_century)
943 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
944 else
945 /* Only the century, but not the year. Strange, but so be it. */
946 tm->tm_year = (century - 19) * 100;
947 }
948
949 #ifdef _NL_CURRENT
950 if (era_cnt != -1)
951 {
952 era = _nl_select_era_entry(era_cnt);
953 if (want_era)
954 tm->tm_year = (era->start_date[0]
955 + ((tm->tm_year - era->offset)
956 * era->absolute_direction));
957 else
958 /* Era start year assumed. */
959 tm->tm_year = era->start_date[0];
960 }
961 else
962 #endif
963 if (want_era)
964 return NULL;
965
966 if (want_xday && !have_wday)
967 {
968 if ( !(have_mon && have_mday) && have_yday)
969 {
970 /* We don't have tm_mon and/or tm_mday, compute them. */
971 int t_mon = 0;
972 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
973 t_mon++;
974 if (!have_mon)
975 tm->tm_mon = t_mon - 1;
976 if (!have_mday)
977 tm->tm_mday =
978 (tm->tm_yday
979 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
980 }
981 day_of_the_week (tm);
982 }
983 if (want_xday && !have_yday)
984 day_of_the_year (tm);
985
986 return (char *) rp;
987 }
988
989
990 char *
991 strptime (buf, format, tm)
992 const char *buf;
993 const char *format;
994 struct tm *tm;
995 {
996 enum locale_status decided;
997
998 #ifdef _NL_CURRENT
999 decided = not;
1000 #else
1001 decided = raw;
1002 #endif
1003 return strptime_internal (buf, format, tm, &decided, -1);
1004 }