This source file includes following definitions.
- day_of_the_week
- day_of_the_year
- __strptime_internal
- strptime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #ifndef _LIBC
19 # include <config.h>
20 #endif
21
22 #include <time.h>
23
24 #include <assert.h>
25 #include <ctype.h>
26 #ifdef _LIBC
27 # include <langinfo.h>
28 #endif
29 #include <limits.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <stdbool.h>
33
34 #ifdef _LIBC
35 # include "../locale/localeinfo.h"
36 #endif
37
38 #ifndef _LIBC
39 enum ptime_locale_status { not, loc, raw };
40 #endif
41
42
43
44 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
45 #if defined _LIBC && defined __GNUC__ && __GNUC__ >= 2
46 # define match_string(cs1, s2) \
47 ({ size_t len = strlen (cs1); \
48 int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0; \
49 if (result) (s2) += len; \
50 result; })
51 #else
52
53 # define match_string(cs1, s2) \
54 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
55 #endif
56
57
58 #define get_number(from, to, n) \
59 do { \
60 int __n = n; \
61 val = 0; \
62 while (*rp == ' ') \
63 ++rp; \
64 if (*rp < '0' || *rp > '9') \
65 return NULL; \
66 do { \
67 val *= 10; \
68 val += *rp++ - '0'; \
69 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
70 if (val < from || val > to) \
71 return NULL; \
72 } while (0)
73 #ifdef _NL_CURRENT
74 # define get_alt_number(from, to, n) \
75 ({ \
76 __label__ do_normal; \
77 \
78 if (*decided != raw) \
79 { \
80 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG); \
81 if (val == -1 && *decided != loc) \
82 { \
83 *decided = loc; \
84 goto do_normal; \
85 } \
86 if (val < from || val > to) \
87 return NULL; \
88 } \
89 else \
90 { \
91 do_normal: \
92 get_number (from, to, n); \
93 } \
94 0; \
95 })
96 #else
97 # define get_alt_number(from, to, n) \
98 \
99 get_number(from, to, n)
100 #endif
101 #define recursive(new_fmt) \
102 (*(new_fmt) != '\0' \
103 && (rp = __strptime_internal (rp, (new_fmt), tm, \
104 decided, era_cnt LOCALE_ARG)) != NULL)
105
106
107 #ifdef _LIBC
108
109 extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
110
111 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
112 # define ab_weekday_name \
113 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
114 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
115 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
116 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
117 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
118 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
119 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
120 # define HERE_T_FMT_AMPM \
121 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
122 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
123
124 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
125 #else
126 static char const weekday_name[][10] =
127 {
128 "Sunday", "Monday", "Tuesday", "Wednesday",
129 "Thursday", "Friday", "Saturday"
130 };
131 static char const ab_weekday_name[][4] =
132 {
133 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
134 };
135 static char const month_name[][10] =
136 {
137 "January", "February", "March", "April", "May", "June",
138 "July", "August", "September", "October", "November", "December"
139 };
140 static char const ab_month_name[][4] =
141 {
142 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
144 };
145 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
146 # define HERE_D_FMT "%m/%d/%y"
147 # define HERE_AM_STR "AM"
148 # define HERE_PM_STR "PM"
149 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
150 # define HERE_T_FMT "%H:%M:%S"
151
152 static const unsigned short int __mon_yday[2][13] =
153 {
154
155 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
156
157 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
158 };
159 #endif
160
161 #if defined _LIBC
162
163
164
165
166 # define strptime __strptime_l
167 # undef _NL_CURRENT
168 # define _NL_CURRENT(category, item) \
169 (current->values[_NL_ITEM_INDEX (item)].string)
170 # undef _NL_CURRENT_WORD
171 # define _NL_CURRENT_WORD(category, item) \
172 (current->values[_NL_ITEM_INDEX (item)].word)
173 # define LOCALE_PARAM , locale
174 # define LOCALE_ARG , locale
175 # define LOCALE_PARAM_PROTO , __locale_t locale
176 # define LOCALE_PARAM_DECL __locale_t locale;
177 # define HELPER_LOCALE_ARG , current
178 # define ISSPACE(Ch) __isspace_l (Ch, locale)
179 #else
180 # define LOCALE_PARAM
181 # define LOCALE_ARG
182 # define LOCALE_PARAM_DECL
183 # define LOCALE_PARAM_PROTO
184 # define HELPER_LOCALE_ARG
185 # define ISSPACE(Ch) isspace (Ch)
186 #endif
187
188
189
190
191 #ifndef __isleap
192
193
194 # define __isleap(year) \
195 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
196 #endif
197
198
199 static void
200 day_of_the_week (struct tm *tm)
201 {
202
203
204
205 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
206 int corr_quad = corr_year / 4;
207 int wday = (-473
208 + (365 * (tm->tm_year - 70))
209 + corr_quad
210 - ((corr_quad + (corr_quad < 0)) / 25 - (corr_quad < 0))
211 + ((corr_quad / 25) / 4)
212 + __mon_yday[0][tm->tm_mon]
213 + tm->tm_mday - 1);
214 tm->tm_wday = ((wday % 7) + 7) % 7;
215 }
216
217
218 static void
219 day_of_the_year (struct tm *tm)
220 {
221 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
222 + (tm->tm_mday - 1));
223 }
224
225
226 #ifdef _LIBC
227 char *
228 internal_function
229 #else
230 static char *
231 #endif
232 __strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
233 const char *rp;
234 const char *fmt;
235 struct tm *tm;
236 enum ptime_locale_status *decided;
237 int era_cnt;
238 LOCALE_PARAM_DECL
239 {
240 #ifdef _LIBC
241 struct locale_data *const current = locale->__locales[LC_TIME];
242 #endif
243
244 int cnt;
245 size_t val;
246 int have_I, is_pm;
247 int century, want_century;
248 int want_era;
249 int have_wday, want_xday;
250 int have_yday;
251 int have_mon, have_mday;
252 int have_uweek, have_wweek;
253 int week_no;
254 #ifdef _NL_CURRENT
255 size_t num_eras;
256 struct era_entry *era = NULL;
257 const char *rp_backup;
258 #endif
259
260 have_I = is_pm = 0;
261 century = -1;
262 want_century = 0;
263 want_era = 0;
264 week_no = 0;
265
266 have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
267 have_wweek = 0;
268
269 while (*fmt != '\0')
270 {
271
272
273 if (ISSPACE (*fmt))
274 {
275 while (ISSPACE (*rp))
276 ++rp;
277 ++fmt;
278 continue;
279 }
280
281
282
283 if (*fmt != '%')
284 {
285 match_char (*fmt++, *rp++);
286 continue;
287 }
288
289 ++fmt;
290 #ifndef _NL_CURRENT
291
292 start_over:
293 #else
294
295 rp_backup = rp;
296 #endif
297
298 switch (*fmt++)
299 {
300 case '%':
301
302 match_char ('%', *rp++);
303 break;
304 case 'a':
305 case 'A':
306
307 for (cnt = 0; cnt < 7; ++cnt)
308 {
309 #ifdef _NL_CURRENT
310 if (*decided !=raw)
311 {
312 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
313 {
314 if (*decided == not
315 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
316 weekday_name[cnt]))
317 *decided = loc;
318 break;
319 }
320 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
321 {
322 if (*decided == not
323 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
324 ab_weekday_name[cnt]))
325 *decided = loc;
326 break;
327 }
328 }
329 #endif
330 if (*decided != loc
331 && (match_string (weekday_name[cnt], rp)
332 || match_string (ab_weekday_name[cnt], rp)))
333 {
334 *decided = raw;
335 break;
336 }
337 }
338 if (cnt == 7)
339
340 return NULL;
341 tm->tm_wday = cnt;
342 have_wday = 1;
343 break;
344 case 'b':
345 case 'B':
346 case 'h':
347
348 for (cnt = 0; cnt < 12; ++cnt)
349 {
350 #ifdef _NL_CURRENT
351 if (*decided !=raw)
352 {
353 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
354 {
355 if (*decided == not
356 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
357 month_name[cnt]))
358 *decided = loc;
359 break;
360 }
361 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
362 {
363 if (*decided == not
364 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
365 ab_month_name[cnt]))
366 *decided = loc;
367 break;
368 }
369 }
370 #endif
371 if (match_string (month_name[cnt], rp)
372 || match_string (ab_month_name[cnt], rp))
373 {
374 *decided = raw;
375 break;
376 }
377 }
378 if (cnt == 12)
379
380 return NULL;
381 tm->tm_mon = cnt;
382 want_xday = 1;
383 break;
384 case 'c':
385
386 #ifdef _NL_CURRENT
387 if (*decided != raw)
388 {
389 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
390 {
391 if (*decided == loc)
392 return NULL;
393 else
394 rp = rp_backup;
395 }
396 else
397 {
398 if (*decided == not &&
399 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
400 *decided = loc;
401 want_xday = 1;
402 break;
403 }
404 *decided = raw;
405 }
406 #endif
407 if (!recursive (HERE_D_T_FMT))
408 return NULL;
409 want_xday = 1;
410 break;
411 case 'C':
412
413 #ifdef _NL_CURRENT
414 match_century:
415 #endif
416 get_number (0, 99, 2);
417 century = val;
418 want_xday = 1;
419 break;
420 case 'd':
421 case 'e':
422
423 get_number (1, 31, 2);
424 tm->tm_mday = val;
425 have_mday = 1;
426 want_xday = 1;
427 break;
428 case 'F':
429 if (!recursive ("%Y-%m-%d"))
430 return NULL;
431 want_xday = 1;
432 break;
433 case 'x':
434 #ifdef _NL_CURRENT
435 if (*decided != raw)
436 {
437 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
438 {
439 if (*decided == loc)
440 return NULL;
441 else
442 rp = rp_backup;
443 }
444 else
445 {
446 if (*decided == not
447 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
448 *decided = loc;
449 want_xday = 1;
450 break;
451 }
452 *decided = raw;
453 }
454 #endif
455
456 case 'D':
457
458 if (!recursive (HERE_D_FMT))
459 return NULL;
460 want_xday = 1;
461 break;
462 case 'k':
463 case 'H':
464
465 get_number (0, 23, 2);
466 tm->tm_hour = val;
467 have_I = 0;
468 break;
469 case 'l':
470
471 case 'I':
472
473 get_number (1, 12, 2);
474 tm->tm_hour = val % 12;
475 have_I = 1;
476 break;
477 case 'j':
478
479 get_number (1, 366, 3);
480 tm->tm_yday = val - 1;
481 have_yday = 1;
482 break;
483 case 'm':
484
485 get_number (1, 12, 2);
486 tm->tm_mon = val - 1;
487 have_mon = 1;
488 want_xday = 1;
489 break;
490 case 'M':
491
492 get_number (0, 59, 2);
493 tm->tm_min = val;
494 break;
495 case 'n':
496 case 't':
497
498 while (ISSPACE (*rp))
499 ++rp;
500 break;
501 case 'p':
502
503 #ifdef _NL_CURRENT
504 if (*decided != raw)
505 {
506 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
507 {
508 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
509 *decided = loc;
510 break;
511 }
512 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
513 {
514 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
515 *decided = loc;
516 is_pm = 1;
517 break;
518 }
519 *decided = raw;
520 }
521 #endif
522 if (!match_string (HERE_AM_STR, rp))
523 {
524 if (match_string (HERE_PM_STR, rp))
525 is_pm = 1;
526 else
527 return NULL;
528 }
529 break;
530 case 'q':
531
532 get_number (1, 4, 1);
533 tm->tm_mon = (val - 1) * 3;
534 tm->tm_mday = 1;
535 have_mon = 1;
536 have_mday = 1;
537 want_xday = 1;
538 break;
539 case 'r':
540 #ifdef _NL_CURRENT
541 if (*decided != raw)
542 {
543 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
544 {
545 if (*decided == loc)
546 return NULL;
547 else
548 rp = rp_backup;
549 }
550 else
551 {
552 if (*decided == not &&
553 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
554 HERE_T_FMT_AMPM))
555 *decided = loc;
556 break;
557 }
558 *decided = raw;
559 }
560 #endif
561 if (!recursive (HERE_T_FMT_AMPM))
562 return NULL;
563 break;
564 case 'R':
565 if (!recursive ("%H:%M"))
566 return NULL;
567 break;
568 case 's':
569 {
570
571
572
573
574 time_t secs = 0;
575 if (*rp < '0' || *rp > '9')
576
577 return NULL;
578
579 do
580 {
581 secs *= 10;
582 secs += *rp++ - '0';
583 }
584 while (*rp >= '0' && *rp <= '9');
585
586 if (localtime_r (&secs, tm) == NULL)
587
588 return NULL;
589 }
590 break;
591 case 'S':
592 get_number (0, 61, 2);
593 tm->tm_sec = val;
594 break;
595 case 'X':
596 #ifdef _NL_CURRENT
597 if (*decided != raw)
598 {
599 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
600 {
601 if (*decided == loc)
602 return NULL;
603 else
604 rp = rp_backup;
605 }
606 else
607 {
608 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
609 *decided = loc;
610 break;
611 }
612 *decided = raw;
613 }
614 #endif
615
616 case 'T':
617 if (!recursive (HERE_T_FMT))
618 return NULL;
619 break;
620 case 'u':
621 get_number (1, 7, 1);
622 tm->tm_wday = val % 7;
623 have_wday = 1;
624 break;
625 case 'g':
626 get_number (0, 99, 2);
627
628 break;
629 case 'G':
630 if (*rp < '0' || *rp > '9')
631 return NULL;
632
633
634 do
635 ++rp;
636 while (*rp >= '0' && *rp <= '9');
637 break;
638 case 'U':
639 get_number (0, 53, 2);
640 week_no = val;
641 have_uweek = 1;
642 break;
643 case 'W':
644 get_number (0, 53, 2);
645 week_no = val;
646 have_wweek = 1;
647 break;
648 case 'V':
649 get_number (0, 53, 2);
650
651
652 break;
653 case 'w':
654
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
664 get_number (0, 99, 2);
665
666
667 tm->tm_year = val >= 69 ? val : val + 100;
668
669 want_century = 1;
670 want_xday = 1;
671 break;
672 case 'Y':
673
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
681 break;
682 case 'z':
683
684
685
686 {
687 _GL_UNUSED bool neg;
688 int n;
689
690 val = 0;
691 while (*rp == ' ')
692 ++rp;
693 if (*rp != '+' && *rp != '-')
694 return NULL;
695 neg = *rp++ == '-';
696 n = 0;
697 while (n < 4 && *rp >= '0' && *rp <= '9')
698 {
699 val = val * 10 + *rp++ - '0';
700 ++n;
701 }
702 if (n == 2)
703 val *= 100;
704 else if (n != 4)
705
706 return NULL;
707 else
708 {
709
710 if (val % 100 >= 60)
711 return NULL;
712 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
713 }
714 if (val > 1200)
715 return NULL;
716 #if defined _LIBC || HAVE_TM_GMTOFF
717 tm->tm_gmtoff = (val * 3600) / 100;
718 if (neg)
719 tm->tm_gmtoff = -tm->tm_gmtoff;
720 #endif
721 }
722 break;
723 case 'E':
724 #ifdef _NL_CURRENT
725 switch (*fmt++)
726 {
727 case 'c':
728
729 if (*decided != raw)
730 {
731 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
732
733 if (*fmt == '\0')
734 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
735
736 if (!recursive (fmt))
737 {
738 if (*decided == loc)
739 return NULL;
740 else
741 rp = rp_backup;
742 }
743 else
744 {
745 if (strcmp (fmt, HERE_D_T_FMT))
746 *decided = loc;
747 want_xday = 1;
748 break;
749 }
750 *decided = raw;
751 }
752
753
754 if (!recursive (HERE_D_T_FMT))
755 return NULL;
756 want_xday = 1;
757 break;
758 case 'C':
759 if (*decided != raw)
760 {
761 if (era_cnt >= 0)
762 {
763 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
764 if (era != NULL && match_string (era->era_name, rp))
765 {
766 *decided = loc;
767 break;
768 }
769 else
770 return NULL;
771 }
772
773 num_eras = _NL_CURRENT_WORD (LC_TIME,
774 _NL_TIME_ERA_NUM_ENTRIES);
775 for (era_cnt = 0; era_cnt < (int) num_eras;
776 ++era_cnt, rp = rp_backup)
777 {
778 era = _nl_select_era_entry (era_cnt
779 HELPER_LOCALE_ARG);
780 if (era != NULL && match_string (era->era_name, rp))
781 {
782 *decided = loc;
783 break;
784 }
785 }
786 if (era_cnt != (int) num_eras)
787 break;
788
789 era_cnt = -1;
790 if (*decided == loc)
791 return NULL;
792
793 *decided = raw;
794 }
795
796
797 goto match_century;
798 case 'y':
799 if (*decided != raw)
800 {
801 get_number(0, 9999, 4);
802 tm->tm_year = val;
803 want_era = 1;
804 want_xday = 1;
805 want_century = 1;
806
807 if (era_cnt >= 0)
808 {
809 assert (*decided == loc);
810
811 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
812 bool match = false;
813 if (era != NULL)
814 {
815 int delta = ((tm->tm_year - era->offset)
816 * era->absolute_direction);
817 match = (delta >= 0
818 && delta < (((int64_t) era->stop_date[0]
819 - (int64_t) era->start_date[0])
820 * era->absolute_direction));
821 }
822 if (! match)
823 return NULL;
824
825 break;
826 }
827
828 num_eras = _NL_CURRENT_WORD (LC_TIME,
829 _NL_TIME_ERA_NUM_ENTRIES);
830 for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt)
831 {
832 era = _nl_select_era_entry (era_cnt
833 HELPER_LOCALE_ARG);
834 if (era != NULL)
835 {
836 int delta = ((tm->tm_year - era->offset)
837 * era->absolute_direction);
838 if (delta >= 0
839 && delta < (((int64_t) era->stop_date[0]
840 - (int64_t) era->start_date[0])
841 * era->absolute_direction))
842 {
843 *decided = loc;
844 break;
845 }
846 }
847 }
848 if (era_cnt != (int) num_eras)
849 break;
850
851 era_cnt = -1;
852 if (*decided == loc)
853 return NULL;
854
855 *decided = raw;
856 }
857
858 goto match_year_in_century;
859 case 'Y':
860 if (*decided != raw)
861 {
862 num_eras = _NL_CURRENT_WORD (LC_TIME,
863 _NL_TIME_ERA_NUM_ENTRIES);
864 for (era_cnt = 0; era_cnt < (int) num_eras;
865 ++era_cnt, rp = rp_backup)
866 {
867 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
868 if (era != NULL && recursive (era->era_format))
869 break;
870 }
871 if (era_cnt == (int) num_eras)
872 {
873 era_cnt = -1;
874 if (*decided == loc)
875 return NULL;
876 else
877 rp = rp_backup;
878 }
879 else
880 {
881 *decided = loc;
882 era_cnt = -1;
883 break;
884 }
885
886 *decided = raw;
887 }
888 get_number (0, 9999, 4);
889 tm->tm_year = val - 1900;
890 want_century = 0;
891 want_xday = 1;
892 break;
893 case 'x':
894 if (*decided != raw)
895 {
896 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
897
898 if (*fmt == '\0')
899 fmt = _NL_CURRENT (LC_TIME, D_FMT);
900
901 if (!recursive (fmt))
902 {
903 if (*decided == loc)
904 return NULL;
905 else
906 rp = rp_backup;
907 }
908 else
909 {
910 if (strcmp (fmt, HERE_D_FMT))
911 *decided = loc;
912 break;
913 }
914 *decided = raw;
915 }
916 if (!recursive (HERE_D_FMT))
917 return NULL;
918 break;
919 case 'X':
920 if (*decided != raw)
921 {
922 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
923
924 if (*fmt == '\0')
925 fmt = _NL_CURRENT (LC_TIME, T_FMT);
926
927 if (!recursive (fmt))
928 {
929 if (*decided == loc)
930 return NULL;
931 else
932 rp = rp_backup;
933 }
934 else
935 {
936 if (strcmp (fmt, HERE_T_FMT))
937 *decided = loc;
938 break;
939 }
940 *decided = raw;
941 }
942 if (!recursive (HERE_T_FMT))
943 return NULL;
944 break;
945 default:
946 return NULL;
947 }
948 break;
949 #else
950
951
952 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
953 && *fmt != 'x' && *fmt != 'X')
954
955 return NULL;
956
957 goto start_over;
958 #endif
959 case 'O':
960 switch (*fmt++)
961 {
962 case 'd':
963 case 'e':
964
965 get_alt_number (1, 31, 2);
966 tm->tm_mday = val;
967 have_mday = 1;
968 want_xday = 1;
969 break;
970 case 'H':
971
972
973 get_alt_number (0, 23, 2);
974 tm->tm_hour = val;
975 have_I = 0;
976 break;
977 case 'I':
978
979
980 get_alt_number (1, 12, 2);
981 tm->tm_hour = val % 12;
982 have_I = 1;
983 break;
984 case 'm':
985
986 get_alt_number (1, 12, 2);
987 tm->tm_mon = val - 1;
988 have_mon = 1;
989 want_xday = 1;
990 break;
991 case 'M':
992
993 get_alt_number (0, 59, 2);
994 tm->tm_min = val;
995 break;
996 case 'q':
997
998 get_alt_number (1, 4, 1);
999 tm->tm_mon = (val - 1) * 3;
1000 tm->tm_mday = 1;
1001 have_mon = 1;
1002 have_mday = 1;
1003 want_xday = 1;
1004 break;
1005 case 'S':
1006
1007 get_alt_number (0, 61, 2);
1008 tm->tm_sec = val;
1009 break;
1010 case 'U':
1011 get_alt_number (0, 53, 2);
1012 week_no = val;
1013 have_uweek = 1;
1014 break;
1015 case 'W':
1016 get_alt_number (0, 53, 2);
1017 week_no = val;
1018 have_wweek = 1;
1019 break;
1020 case 'V':
1021 get_alt_number (0, 53, 2);
1022
1023
1024 break;
1025 case 'w':
1026
1027 get_alt_number (0, 6, 1);
1028 tm->tm_wday = val;
1029 have_wday = 1;
1030 break;
1031 case 'y':
1032
1033 get_alt_number (0, 99, 2);
1034 tm->tm_year = val >= 69 ? val : val + 100;
1035 want_xday = 1;
1036 break;
1037 default:
1038 return NULL;
1039 }
1040 break;
1041 default:
1042 return NULL;
1043 }
1044 }
1045
1046 if (have_I && is_pm)
1047 tm->tm_hour += 12;
1048
1049 if (century != -1)
1050 {
1051 if (want_century)
1052 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
1053 else
1054
1055 tm->tm_year = (century - 19) * 100;
1056 }
1057
1058 if (era_cnt != -1)
1059 {
1060 #ifdef _NL_CURRENT
1061 era = _nl_select_era_entry (era_cnt HELPER_LOCALE_ARG);
1062 if (era == NULL)
1063 return NULL;
1064 if (want_era)
1065 tm->tm_year = (era->start_date[0]
1066 + ((tm->tm_year - era->offset)
1067 * era->absolute_direction));
1068 else
1069
1070 tm->tm_year = era->start_date[0];
1071 #endif
1072 }
1073 else
1074 if (want_era)
1075 {
1076
1077
1078 if (want_century && century == -1 && tm->tm_year < 69)
1079 tm->tm_year += 100;
1080 }
1081
1082 if (want_xday && !have_wday)
1083 {
1084 if ( !(have_mon && have_mday) && have_yday)
1085 {
1086
1087 int t_mon = 0;
1088 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1089 t_mon++;
1090 if (!have_mon)
1091 tm->tm_mon = t_mon - 1;
1092 if (!have_mday)
1093 tm->tm_mday =
1094 (tm->tm_yday
1095 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1096 }
1097 day_of_the_week (tm);
1098 }
1099
1100 if (want_xday && !have_yday)
1101 day_of_the_year (tm);
1102
1103 if ((have_uweek || have_wweek) && have_wday)
1104 {
1105 int save_wday = tm->tm_wday;
1106 int save_mday = tm->tm_mday;
1107 int save_mon = tm->tm_mon;
1108 int w_offset = have_uweek ? 0 : 1;
1109
1110 tm->tm_mday = 1;
1111 tm->tm_mon = 0;
1112 day_of_the_week (tm);
1113 if (have_mday)
1114 tm->tm_mday = save_mday;
1115 if (have_mon)
1116 tm->tm_mon = save_mon;
1117
1118 if (!have_yday)
1119 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1120 + (week_no - 1) *7
1121 + save_wday - w_offset);
1122
1123 if (!have_mday || !have_mon)
1124 {
1125 int t_mon = 0;
1126 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1127 <= tm->tm_yday)
1128 t_mon++;
1129 if (!have_mon)
1130 tm->tm_mon = t_mon - 1;
1131 if (!have_mday)
1132 tm->tm_mday =
1133 (tm->tm_yday
1134 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1135 }
1136
1137 tm->tm_wday = save_wday;
1138 }
1139
1140 return (char *) rp;
1141 }
1142
1143
1144 char *
1145 strptime (buf, format, tm LOCALE_PARAM)
1146 const char *restrict buf;
1147 const char *restrict format;
1148 struct tm *restrict tm;
1149 LOCALE_PARAM_DECL
1150 {
1151 enum ptime_locale_status decided;
1152
1153 #ifdef _NL_CURRENT
1154 decided = not;
1155 #else
1156 decided = raw;
1157 #endif
1158 return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
1159 }
1160
1161 #ifdef _LIBC
1162 weak_alias (__strptime_l, strptime_l)
1163 #endif