1 /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
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.
8 
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.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <assert.h>
23 #include <ctype.h>
24 #include <langinfo.h>
25 #include <limits.h>
26 #include <string.h>
27 #include <time.h>
28 #include <stdbool.h>
29 
30 #ifdef _LIBC
31 # define HAVE_LOCALTIME_R 0
32 # include "../locale/localeinfo.h"
33 #endif
34 
35 
36 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
37 # ifdef _LIBC
38 #  define localtime_r __localtime_r
39 # else
40 /* Approximate localtime_r as best we can in its absence.  */
41 #  define localtime_r my_localtime_r
42 static struct tm *localtime_r (const time_t *, struct tm *);
43 static struct tm *
localtime_r(const time_t * t,struct tm * tp)44 localtime_r (const time_t *t, struct tm *tp)
45 {
46   struct tm *l = localtime (t);
47   if (! l)
48     return 0;
49   *tp = *l;
50   return tp;
51 }
52 # endif /* ! _LIBC */
53 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
54 
55 
56 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
57 #if defined __GNUC__ && __GNUC__ >= 2
58 # define match_string(cs1, s2) \
59   ({ size_t len = strlen (cs1);						      \
60      int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0;	      \
61      if (result) (s2) += len;						      \
62      result; })
63 #else
64 /* Oh come on.  Get a reasonable compiler.  */
65 # define match_string(cs1, s2) \
66   (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
67 #endif
68 /* We intentionally do not use isdigit() for testing because this will
69    lead to problems with the wide character version.  */
70 #define get_number(from, to, n) \
71   do {									      \
72     int __n = n;							      \
73     val = 0;								      \
74     while (ISSPACE (*rp))						      \
75       ++rp;								      \
76     if (*rp < '0' || *rp > '9')						      \
77       return NULL;							      \
78     do {								      \
79       val *= 10;							      \
80       val += *rp++ - '0';						      \
81     } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9');	      \
82     if (val < from || val > to)						      \
83       return NULL;							      \
84   } while (0)
85 #ifdef _NL_CURRENT
86 # define get_alt_number(from, to, n) \
87   ({									      \
88      __label__ do_normal;						      \
89 									      \
90      if (s.decided != raw)						      \
91        {								      \
92 	 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG);		      \
93 	 if (val == -1 && s.decided != loc)				      \
94 	   {								      \
95 	     s.decided = loc;						      \
96 	     goto do_normal;						      \
97 	   }								      \
98 	if (val < from || val > to)					      \
99 	  return NULL;							      \
100        }								      \
101      else								      \
102        {								      \
103        do_normal:							      \
104 	 get_number (from, to, n);					      \
105        }								      \
106     0;									      \
107   })
108 #else
109 # define get_alt_number(from, to, n) \
110   /* We don't have the alternate representation.  */			      \
111   get_number(from, to, n)
112 #endif
113 #define recursive(new_fmt) \
114   (*(new_fmt) != '\0'							      \
115    && (rp = __strptime_internal (rp, (new_fmt), tm, &s LOCALE_ARG)) != NULL)
116 
117 
118 #ifdef _LIBC
119 /* This is defined in locale/C-time.c in the GNU libc.  */
120 extern const struct __locale_data _nl_C_LC_TIME attribute_hidden;
121 
122 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
123 # define ab_weekday_name \
124   (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
125 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
126 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
127 # define alt_month_name \
128   (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ALTMON_1)].string)
129 # define ab_alt_month_name \
130   (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (_NL_ABALTMON_1)].string)
131 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
132 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
133 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
134 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
135 # define HERE_T_FMT_AMPM \
136   (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
137 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
138 
139 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
140 #else
141 static char const weekday_name[][10] =
142   {
143     "Sunday", "Monday", "Tuesday", "Wednesday",
144     "Thursday", "Friday", "Saturday"
145   };
146 static char const ab_weekday_name[][4] =
147   {
148     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
149   };
150 static char const month_name[][10] =
151   {
152     "January", "February", "March", "April", "May", "June",
153     "July", "August", "September", "October", "November", "December"
154   };
155 static char const ab_month_name[][4] =
156   {
157     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
158     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
159   };
160 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
161 # define HERE_D_FMT "%m/%d/%y"
162 # define HERE_AM_STR "AM"
163 # define HERE_PM_STR "PM"
164 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
165 # define HERE_T_FMT "%H:%M:%S"
166 
167 static const unsigned short int __mon_yday[2][13] =
168   {
169     /* Normal years.  */
170     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
171     /* Leap years.  */
172     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
173   };
174 #endif
175 
176 #if defined _LIBC
177 /* We use this code also for the extended locale handling where the
178    function gets as an additional argument the locale which has to be
179    used.  To access the values we have to redefine the _NL_CURRENT
180    macro.  */
181 # define strptime		__strptime_l
182 # undef _NL_CURRENT
183 # define _NL_CURRENT(category, item) \
184   (current->values[_NL_ITEM_INDEX (item)].string)
185 # undef _NL_CURRENT_WORD
186 # define _NL_CURRENT_WORD(category, item) \
187   (current->values[_NL_ITEM_INDEX (item)].word)
188 # define LOCALE_PARAM , locale_t locale
189 # define LOCALE_ARG , locale
190 # define HELPER_LOCALE_ARG , current
191 # define ISSPACE(Ch) __isspace_l (Ch, locale)
192 #else
193 # define LOCALE_PARAM
194 # define LOCALE_ARG
195 # define HELPER_LOCALE_ARG
196 # define ISSPACE(Ch) isspace (Ch)
197 #endif
198 
199 
200 
201 
202 #ifndef __isleap
203 /* Nonzero if YEAR is a leap year (every 4 years,
204    except every 100th isn't, and every 400th is).  */
205 # define __isleap(year)	\
206   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
207 #endif
208 
209 /* Compute the day of the week.  */
210 static void
day_of_the_week(struct tm * tm)211 day_of_the_week (struct tm *tm)
212 {
213   /* We know that January 1st 1970 was a Thursday (= 4).  Compute the
214      difference between this data in the one on TM and so determine
215      the weekday.  */
216   int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
217   int wday = (-473
218 	      + (365 * (tm->tm_year - 70))
219 	      + (corr_year / 4)
220 	      - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
221 	      + (((corr_year / 4) / 25) / 4)
222 	      + __mon_yday[0][tm->tm_mon]
223 	      + tm->tm_mday - 1);
224   tm->tm_wday = ((wday % 7) + 7) % 7;
225 }
226 
227 /* Compute the day of the year.  */
228 static void
day_of_the_year(struct tm * tm)229 day_of_the_year (struct tm *tm)
230 {
231   tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
232 		 + (tm->tm_mday - 1));
233 }
234 
235 
236 #ifdef _LIBC
237 char *
238 #else
239 static char *
240 #endif
__strptime_internal(const char * rp,const char * fmt,struct tm * tmp,void * statep LOCALE_PARAM)241 __strptime_internal (const char *rp, const char *fmt, struct tm *tmp,
242 		     void *statep LOCALE_PARAM)
243 {
244 #ifdef _LIBC
245   struct __locale_data *const current = locale->__locales[LC_TIME];
246 #endif
247 
248   const char *rp_backup;
249   const char *rp_longest;
250   int cnt;
251   int cnt_longest;
252   size_t val;
253   size_t num_eras;
254   struct era_entry *era = NULL;
255   enum ptime_locale_status { not, loc, raw } decided_longest;
256   struct __strptime_state
257   {
258     unsigned int have_I : 1;
259     unsigned int have_wday : 1;
260     unsigned int have_yday : 1;
261     unsigned int have_mon : 1;
262     unsigned int have_mday : 1;
263     unsigned int have_uweek : 1;
264     unsigned int have_wweek : 1;
265     unsigned int is_pm : 1;
266     unsigned int want_century : 1;
267     unsigned int want_era : 1;
268     unsigned int want_xday : 1;
269     enum ptime_locale_status decided : 2;
270     signed char week_no;
271     signed char century;
272     int era_cnt;
273   } s;
274   struct tm tmb;
275   struct tm *tm;
276 
277   if (statep == NULL)
278     {
279       memset (&s, 0, sizeof (s));
280       s.century = -1;
281       s.era_cnt = -1;
282 #ifdef _NL_CURRENT
283       s.decided = not;
284 #else
285       s.decided = raw;
286 #endif
287       tm = tmp;
288     }
289   else
290     {
291       s = *(struct __strptime_state *) statep;
292       tmb = *tmp;
293       tm = &tmb;
294     }
295 
296   while (*fmt != '\0')
297     {
298       /* A white space in the format string matches 0 more or white
299 	 space in the input string.  */
300       if (ISSPACE (*fmt))
301 	{
302 	  while (ISSPACE (*rp))
303 	    ++rp;
304 	  ++fmt;
305 	  continue;
306 	}
307 
308       /* Any character but `%' must be matched by the same character
309 	 in the input string.  */
310       if (*fmt != '%')
311 	{
312 	  match_char (*fmt++, *rp++);
313 	  continue;
314 	}
315 
316       ++fmt;
317       /* We discard strftime modifiers.  */
318       while (*fmt == '-' || *fmt == '_' || *fmt == '0'
319 	     || *fmt == '^' || *fmt == '#')
320 	++fmt;
321 
322       /* And field width.  */
323       while (*fmt >= '0' && *fmt <= '9')
324 	++fmt;
325 
326       /* In some cases, modifiers are handled by adjusting state and
327          then restarting the switch statement below.  */
328     start_over:
329 
330       /* Make back up of current processing pointer.  */
331       rp_backup = rp;
332 
333       switch (*fmt++)
334 	{
335 	case '%':
336 	  /* Match the `%' character itself.  */
337 	  match_char ('%', *rp++);
338 	  break;
339 	case 'a':
340 	case 'A':
341 	  /* Match day of week.  */
342 	  rp_longest = NULL;
343 	  decided_longest = s.decided;
344 	  cnt_longest = -1;
345 	  for (cnt = 0; cnt < 7; ++cnt)
346 	    {
347 	      const char *trp;
348 #ifdef _NL_CURRENT
349 	      if (s.decided !=raw)
350 		{
351 		  trp = rp;
352 		  if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), trp)
353 		      && trp > rp_longest)
354 		    {
355 		      rp_longest = trp;
356 		      cnt_longest = cnt;
357 		      if (s.decided == not
358 			  && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
359 				     weekday_name[cnt]))
360 			decided_longest = loc;
361 		    }
362 		  trp = rp;
363 		  if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), trp)
364 		      && trp > rp_longest)
365 		    {
366 		      rp_longest = trp;
367 		      cnt_longest = cnt;
368 		      if (s.decided == not
369 			  && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
370 				     ab_weekday_name[cnt]))
371 			decided_longest = loc;
372 		    }
373 		}
374 #endif
375 	      if (s.decided != loc
376 		  && (((trp = rp, match_string (weekday_name[cnt], trp))
377 		       && trp > rp_longest)
378 		      || ((trp = rp, match_string (ab_weekday_name[cnt], rp))
379 			  && trp > rp_longest)))
380 		{
381 		  rp_longest = trp;
382 		  cnt_longest = cnt;
383 		  decided_longest = raw;
384 		}
385 	    }
386 	  if (rp_longest == NULL)
387 	    /* Does not match a weekday name.  */
388 	    return NULL;
389 	  rp = rp_longest;
390 	  s.decided = decided_longest;
391 	  tm->tm_wday = cnt_longest;
392 	  s.have_wday = 1;
393 	  break;
394 	case 'b':
395 	case 'B':
396 	case 'h':
397 	  /* Match month name.  */
398 	  rp_longest = NULL;
399 	  decided_longest = s.decided;
400 	  cnt_longest = -1;
401 	  for (cnt = 0; cnt < 12; ++cnt)
402 	    {
403 	      const char *trp;
404 #ifdef _NL_CURRENT
405 	      if (s.decided !=raw)
406 		{
407 		  trp = rp;
408 		  if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), trp)
409 		      && trp > rp_longest)
410 		    {
411 		      rp_longest = trp;
412 		      cnt_longest = cnt;
413 		      if (s.decided == not
414 			  && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
415 				     month_name[cnt]))
416 			decided_longest = loc;
417 		    }
418 		  trp = rp;
419 		  if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), trp)
420 		      && trp > rp_longest)
421 		    {
422 		      rp_longest = trp;
423 		      cnt_longest = cnt;
424 		      if (s.decided == not
425 			  && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
426 				     ab_month_name[cnt]))
427 			decided_longest = loc;
428 		    }
429 #ifdef _LIBC
430 		  /* Now check the alt month.  */
431 		  trp = rp;
432 		  if (match_string (_NL_CURRENT (LC_TIME, ALTMON_1 + cnt), trp)
433 		      && trp > rp_longest)
434 		    {
435 		      rp_longest = trp;
436 		      cnt_longest = cnt;
437 		      if (s.decided == not
438 			  && strcmp (_NL_CURRENT (LC_TIME, ALTMON_1 + cnt),
439 				     alt_month_name[cnt]))
440 			decided_longest = loc;
441 		    }
442 		  trp = rp;
443 		  if (match_string (_NL_CURRENT (LC_TIME, _NL_ABALTMON_1 + cnt),
444 				    trp)
445 		      && trp > rp_longest)
446 		    {
447 		      rp_longest = trp;
448 		      cnt_longest = cnt;
449 		      if (s.decided == not
450 			  && strcmp (_NL_CURRENT (LC_TIME, _NL_ABALTMON_1 + cnt),
451 				     alt_month_name[cnt]))
452 			decided_longest = loc;
453 		    }
454 #endif
455 		}
456 #endif
457 	      if (s.decided != loc
458 		  && (((trp = rp, match_string (month_name[cnt], trp))
459 		       && trp > rp_longest)
460 		      || ((trp = rp, match_string (ab_month_name[cnt], trp))
461 			  && trp > rp_longest)
462 #ifdef _LIBC
463 		      || ((trp = rp, match_string (alt_month_name[cnt], trp))
464 			  && trp > rp_longest)
465 		      || ((trp = rp, match_string (ab_alt_month_name[cnt], trp))
466 			  && trp > rp_longest)
467 #endif
468 	      ))
469 		{
470 		  rp_longest = trp;
471 		  cnt_longest = cnt;
472 		  decided_longest = raw;
473 		}
474 	    }
475 	  if (rp_longest == NULL)
476 	    /* Does not match a month name.  */
477 	    return NULL;
478 	  rp = rp_longest;
479 	  s.decided = decided_longest;
480 	  tm->tm_mon = cnt_longest;
481 	  s.have_mon = 1;
482 	  s.want_xday = 1;
483 	  break;
484 	case 'c':
485 	  /* Match locale's date and time format.  */
486 #ifdef _NL_CURRENT
487 	  if (s.decided != raw)
488 	    {
489 	      if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
490 		{
491 		  if (s.decided == loc)
492 		    return NULL;
493 		  else
494 		    rp = rp_backup;
495 		}
496 	      else
497 		{
498 		  if (s.decided == not
499 		      && strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
500 		    s.decided = loc;
501 		  s.want_xday = 1;
502 		  break;
503 		}
504 	      s.decided = raw;
505 	    }
506 #endif
507 	  if (!recursive (HERE_D_T_FMT))
508 	    return NULL;
509 	  s.want_xday = 1;
510 	  break;
511 	case 'C':
512 	  /* Match century number.  */
513 	match_century:
514 	  get_number (0, 99, 2);
515 	  s.century = val;
516 	  s.want_xday = 1;
517 	  break;
518 	case 'd':
519 	case 'e':
520 	  /* Match day of month.  */
521 	  get_number (1, 31, 2);
522 	  tm->tm_mday = val;
523 	  s.have_mday = 1;
524 	  s.want_xday = 1;
525 	  break;
526 	case 'F':
527 	  if (!recursive ("%Y-%m-%d"))
528 	    return NULL;
529 	  s.want_xday = 1;
530 	  break;
531 	case 'x':
532 #ifdef _NL_CURRENT
533 	  if (s.decided != raw)
534 	    {
535 	      if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
536 		{
537 		  if (s.decided == loc)
538 		    return NULL;
539 		  else
540 		    rp = rp_backup;
541 		}
542 	      else
543 		{
544 		  if (s.decided == not
545 		      && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
546 		    s.decided = loc;
547 		  s.want_xday = 1;
548 		  break;
549 		}
550 	      s.decided = raw;
551 	    }
552 #endif
553 	  /* Fall through.  */
554 	case 'D':
555 	  /* Match standard day format.  */
556 	  if (!recursive (HERE_D_FMT))
557 	    return NULL;
558 	  s.want_xday = 1;
559 	  break;
560 	case 'k':
561 	case 'H':
562 	  /* Match hour in 24-hour clock.  */
563 	  get_number (0, 23, 2);
564 	  tm->tm_hour = val;
565 	  s.have_I = 0;
566 	  break;
567 	case 'l':
568 	  /* Match hour in 12-hour clock.  GNU extension.  */
569 	case 'I':
570 	  /* Match hour in 12-hour clock.  */
571 	  get_number (1, 12, 2);
572 	  tm->tm_hour = val % 12;
573 	  s.have_I = 1;
574 	  break;
575 	case 'j':
576 	  /* Match day number of year.  */
577 	  get_number (1, 366, 3);
578 	  tm->tm_yday = val - 1;
579 	  s.have_yday = 1;
580 	  break;
581 	case 'm':
582 	  /* Match number of month.  */
583 	  get_number (1, 12, 2);
584 	  tm->tm_mon = val - 1;
585 	  s.have_mon = 1;
586 	  s.want_xday = 1;
587 	  break;
588 	case 'M':
589 	  /* Match minute.  */
590 	  get_number (0, 59, 2);
591 	  tm->tm_min = val;
592 	  break;
593 	case 'n':
594 	case 't':
595 	  /* Match any white space.  */
596 	  while (ISSPACE (*rp))
597 	    ++rp;
598 	  break;
599 	case 'p':
600 	  /* Match locale's equivalent of AM/PM.  */
601 #ifdef _NL_CURRENT
602 	  if (s.decided != raw)
603 	    {
604 	      if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
605 		{
606 		  if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
607 		    s.decided = loc;
608 		  s.is_pm = 0;
609 		  break;
610 		}
611 	      if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
612 		{
613 		  if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
614 		    s.decided = loc;
615 		  s.is_pm = 1;
616 		  break;
617 		}
618 	      s.decided = raw;
619 	    }
620 #endif
621 	  if (!match_string (HERE_AM_STR, rp))
622 	    {
623 	      if (match_string (HERE_PM_STR, rp))
624 		s.is_pm = 1;
625 	      else
626 		return NULL;
627 	    }
628 	  else
629 	    s.is_pm = 0;
630 	  break;
631 	case 'r':
632 #ifdef _NL_CURRENT
633 	  if (s.decided != raw)
634 	    {
635 	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
636 		{
637 		  if (s.decided == loc)
638 		    return NULL;
639 		  else
640 		    rp = rp_backup;
641 		}
642 	      else
643 		{
644 		  if (s.decided == not
645 		      && strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
646 				 HERE_T_FMT_AMPM))
647 		    s.decided = loc;
648 		  break;
649 		}
650 	      s.decided = raw;
651 	    }
652 #endif
653 	  if (!recursive (HERE_T_FMT_AMPM))
654 	    return NULL;
655 	  break;
656 	case 'R':
657 	  if (!recursive ("%H:%M"))
658 	    return NULL;
659 	  break;
660 	case 's':
661 	  {
662 	    /* The number of seconds may be very high so we cannot use
663 	       the `get_number' macro.  Instead read the number
664 	       character for character and construct the result while
665 	       doing this.  */
666 	    time_t secs = 0;
667 	    if (*rp < '0' || *rp > '9')
668 	      /* We need at least one digit.  */
669 	      return NULL;
670 
671 	    do
672 	      {
673 		secs *= 10;
674 		secs += *rp++ - '0';
675 	      }
676 	    while (*rp >= '0' && *rp <= '9');
677 
678 	    if (localtime_r (&secs, tm) == NULL)
679 	      /* Error in function.  */
680 	      return NULL;
681 	  }
682 	  break;
683 	case 'S':
684 	  get_number (0, 61, 2);
685 	  tm->tm_sec = val;
686 	  break;
687 	case 'X':
688 #ifdef _NL_CURRENT
689 	  if (s.decided != raw)
690 	    {
691 	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
692 		{
693 		  if (s.decided == loc)
694 		    return NULL;
695 		  else
696 		    rp = rp_backup;
697 		}
698 	      else
699 		{
700 		  if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
701 		    s.decided = loc;
702 		  break;
703 		}
704 	      s.decided = raw;
705 	    }
706 #endif
707 	  /* Fall through.  */
708 	case 'T':
709 	  if (!recursive (HERE_T_FMT))
710 	    return NULL;
711 	  break;
712 	case 'u':
713 	  get_number (1, 7, 1);
714 	  tm->tm_wday = val % 7;
715 	  s.have_wday = 1;
716 	  break;
717 	case 'g':
718 	  get_number (0, 99, 2);
719 	  /* XXX This cannot determine any field in TM.  */
720 	  break;
721 	case 'G':
722 	  if (*rp < '0' || *rp > '9')
723 	    return NULL;
724 	  /* XXX Ignore the number since we would need some more
725 	     information to compute a real date.  */
726 	  do
727 	    ++rp;
728 	  while (*rp >= '0' && *rp <= '9');
729 	  break;
730 	case 'U':
731 	  get_number (0, 53, 2);
732 	  s.week_no = val;
733 	  s.have_uweek = 1;
734 	  break;
735 	case 'W':
736 	  get_number (0, 53, 2);
737 	  s.week_no = val;
738 	  s.have_wweek = 1;
739 	  break;
740 	case 'V':
741 	  get_number (0, 53, 2);
742 	  /* XXX This cannot determine any field in TM without some
743 	     information.  */
744 	  break;
745 	case 'w':
746 	  /* Match number of weekday.  */
747 	  get_number (0, 6, 1);
748 	  tm->tm_wday = val;
749 	  s.have_wday = 1;
750 	  break;
751 	case 'y':
752 	match_year_in_century:
753 	  /* Match year within century.  */
754 	  get_number (0, 99, 2);
755 	  /* The "Year 2000: The Millennium Rollover" paper suggests that
756 	     values in the range 69-99 refer to the twentieth century.  */
757 	  tm->tm_year = val >= 69 ? val : val + 100;
758 	  /* Indicate that we want to use the century, if specified.  */
759 	  s.want_century = 1;
760 	  s.want_xday = 1;
761 	  break;
762 	case 'Y':
763 	  /* Match year including century number.  */
764 	  get_number (0, 9999, 4);
765 	  tm->tm_year = val - 1900;
766 	  s.want_century = 0;
767 	  s.want_xday = 1;
768 	  break;
769 	case 'Z':
770 	  /* Read timezone but perform no conversion.  */
771 	  while (ISSPACE (*rp))
772 	    rp++;
773 	  while (!ISSPACE (*rp) && *rp != '\0')
774 	    rp++;
775 	  break;
776 	case 'z':
777 	  /* We recognize four formats:
778 	     1. Two digits specify hours.
779 	     2. Four digits specify hours and minutes.
780 	     3. Two digits, ':', and two digits specify hours and minutes.
781 	     4. 'Z' is equivalent to +0000.  */
782 	  {
783 	    val = 0;
784 	    while (ISSPACE (*rp))
785 	      ++rp;
786 	    if (*rp == 'Z')
787 	      {
788 		++rp;
789 		tm->tm_gmtoff = 0;
790 		break;
791 	      }
792 	    if (*rp != '+' && *rp != '-')
793 	      return NULL;
794 	    bool neg = *rp++ == '-';
795 	    int n = 0;
796 	    while (n < 4 && *rp >= '0' && *rp <= '9')
797 	      {
798 		val = val * 10 + *rp++ - '0';
799 		++n;
800 		if (*rp == ':' && n == 2 && isdigit (*(rp + 1)))
801 		  ++rp;
802 	      }
803 	    if (n == 2)
804 	      val *= 100;
805 	    else if (n != 4)
806 	      /* Only two or four digits recognized.  */
807 	      return NULL;
808 	    else if (val % 100 >= 60)
809 	      /* Minutes valid range is 0 through 59.  */
810 	      return NULL;
811 	    tm->tm_gmtoff = (val / 100) * 3600 + (val % 100) * 60;
812 	    if (neg)
813 	      tm->tm_gmtoff = -tm->tm_gmtoff;
814 	  }
815 	  break;
816 	case 'E':
817 #ifdef _NL_CURRENT
818 	  switch (*fmt++)
819 	    {
820 	    case 'c':
821 	      /* Match locale's alternate date and time format.  */
822 	      if (s.decided != raw)
823 		{
824 		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
825 
826 		  if (*fmt == '\0')
827 		    fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
828 
829 		  if (!recursive (fmt))
830 		    {
831 		      if (s.decided == loc)
832 			return NULL;
833 		      else
834 			rp = rp_backup;
835 		    }
836 		  else
837 		    {
838 		      if (strcmp (fmt, HERE_D_T_FMT))
839 			s.decided = loc;
840 		      s.want_xday = 1;
841 		      break;
842 		    }
843 		  s.decided = raw;
844 		}
845 	      /* The C locale has no era information, so use the
846 		 normal representation.  */
847 	      if (!recursive (HERE_D_T_FMT))
848 		return NULL;
849 	      s.want_xday = 1;
850 	      break;
851 	    case 'C':
852 	      if (s.decided != raw)
853 		{
854 		  if (s.era_cnt >= 0)
855 		    {
856 		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
857 		      if (era != NULL && match_string (era->era_name, rp))
858 			{
859 			  s.decided = loc;
860 			  break;
861 			}
862 		      else
863 			return NULL;
864 		    }
865 
866 		  num_eras = _NL_CURRENT_WORD (LC_TIME,
867 					       _NL_TIME_ERA_NUM_ENTRIES);
868 		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras;
869 		       ++s.era_cnt, rp = rp_backup)
870 		    {
871 		      era = _nl_select_era_entry (s.era_cnt
872 						  HELPER_LOCALE_ARG);
873 		      if (era != NULL && match_string (era->era_name, rp))
874 			{
875 			  s.decided = loc;
876 			  break;
877 			}
878 		    }
879 		  if (s.era_cnt != (int) num_eras)
880 		    break;
881 
882 		  s.era_cnt = -1;
883 		  if (s.decided == loc)
884 		    return NULL;
885 
886 		  s.decided = raw;
887 		}
888 	      /* The C locale has no era information, so use the
889 		 normal representation.  */
890 	      goto match_century;
891  	    case 'y':
892 	      if (s.decided != raw)
893 		{
894 		  get_number(0, 9999, 4);
895 		  tm->tm_year = val;
896 		  s.want_era = 1;
897 		  s.want_xday = 1;
898 		  s.want_century = 1;
899 
900 		  if (s.era_cnt >= 0)
901 		    {
902 		      assert (s.decided == loc);
903 
904 		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
905 		      bool match = false;
906 		      if (era != NULL)
907 			{
908 			  int delta = ((tm->tm_year - era->offset)
909 				       * era->absolute_direction);
910 			  /* The difference between two sets of years
911 			     does not include the final year itself,
912 			     therefore add 1 to the difference to
913 			     account for that final year.  */
914 			  match = (delta >= 0
915 				   && delta < (((int64_t) era->stop_date[0]
916 						- (int64_t) era->start_date[0])
917 					       * era->absolute_direction
918 					       + 1));
919 			}
920 		      if (! match)
921 			return NULL;
922 
923 		      break;
924 		    }
925 
926 		  num_eras = _NL_CURRENT_WORD (LC_TIME,
927 					       _NL_TIME_ERA_NUM_ENTRIES);
928 		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras; ++s.era_cnt)
929 		    {
930 		      era = _nl_select_era_entry (s.era_cnt
931 						  HELPER_LOCALE_ARG);
932 		      if (era != NULL)
933 			{
934 			  int delta = ((tm->tm_year - era->offset)
935 				       * era->absolute_direction);
936 			  /* See comment above about year difference + 1.  */
937 			  if (delta >= 0
938 			      && delta < (((int64_t) era->stop_date[0]
939 					   - (int64_t) era->start_date[0])
940 					  * era->absolute_direction
941 					  + 1))
942 			    {
943 			      s.decided = loc;
944 			      break;
945 			    }
946 			}
947 		    }
948 		  if (s.era_cnt != (int) num_eras)
949 		    break;
950 
951 		  s.era_cnt = -1;
952 		  if (s.decided == loc)
953 		    return NULL;
954 
955 		  s.decided = raw;
956 		}
957 
958 	      goto match_year_in_century;
959 	    case 'Y':
960 	      if (s.decided != raw)
961 		{
962 		  num_eras = _NL_CURRENT_WORD (LC_TIME,
963 					       _NL_TIME_ERA_NUM_ENTRIES);
964 		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras;
965 		       ++s.era_cnt, rp = rp_backup)
966 		    {
967 		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
968 		      if (era != NULL && recursive (era->era_format))
969 			break;
970 		    }
971 		  if (s.era_cnt == (int) num_eras)
972 		    {
973 		      s.era_cnt = -1;
974 		      if (s.decided == loc)
975 			return NULL;
976 		      else
977 			rp = rp_backup;
978 		    }
979 		  else
980 		    {
981 		      s.decided = loc;
982 		      break;
983 		    }
984 
985 		  s.decided = raw;
986 		}
987 	      get_number (0, 9999, 4);
988 	      tm->tm_year = val - 1900;
989 	      s.want_century = 0;
990 	      s.want_xday = 1;
991 	      break;
992 	    case 'x':
993 	      if (s.decided != raw)
994 		{
995 		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
996 
997 		  if (*fmt == '\0')
998 		    fmt = _NL_CURRENT (LC_TIME, D_FMT);
999 
1000 		  if (!recursive (fmt))
1001 		    {
1002 		      if (s.decided == loc)
1003 			return NULL;
1004 		      else
1005 			rp = rp_backup;
1006 		    }
1007 		  else
1008 		    {
1009 		      if (strcmp (fmt, HERE_D_FMT))
1010 			s.decided = loc;
1011 		      break;
1012 		    }
1013 		  s.decided = raw;
1014 		}
1015 	      if (!recursive (HERE_D_FMT))
1016 		return NULL;
1017 	      break;
1018 	    case 'X':
1019 	      if (s.decided != raw)
1020 		{
1021 		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
1022 
1023 		  if (*fmt == '\0')
1024 		    fmt = _NL_CURRENT (LC_TIME, T_FMT);
1025 
1026 		  if (!recursive (fmt))
1027 		    {
1028 		      if (s.decided == loc)
1029 			return NULL;
1030 		      else
1031 			rp = rp_backup;
1032 		    }
1033 		  else
1034 		    {
1035 		      if (strcmp (fmt, HERE_T_FMT))
1036 			s.decided = loc;
1037 		      break;
1038 		    }
1039 		  s.decided = raw;
1040 		}
1041 	      if (!recursive (HERE_T_FMT))
1042 		return NULL;
1043 	      break;
1044 	    default:
1045 	      return NULL;
1046 	    }
1047 	  break;
1048 #else
1049 	  /* We have no information about the era format.  Just use
1050 	     the normal format.  */
1051 	  if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
1052 	      && *fmt != 'x' && *fmt != 'X')
1053 	    /* This is an illegal format.  */
1054 	    return NULL;
1055 
1056 	  goto start_over;
1057 #endif
1058 	case 'O':
1059 	  switch (*fmt++)
1060 	    {
1061 	    case 'b':
1062 	    case 'B':
1063 	    case 'h':
1064 	      /* Match month name.  Reprocess as plain 'B'.  */
1065 	      fmt--;
1066 	      goto start_over;
1067 	    case 'd':
1068 	    case 'e':
1069 	      /* Match day of month using alternate numeric symbols.  */
1070 	      get_alt_number (1, 31, 2);
1071 	      tm->tm_mday = val;
1072 	      s.have_mday = 1;
1073 	      s.want_xday = 1;
1074 	      break;
1075 	    case 'H':
1076 	      /* Match hour in 24-hour clock using alternate numeric
1077 		 symbols.  */
1078 	      get_alt_number (0, 23, 2);
1079 	      tm->tm_hour = val;
1080 	      s.have_I = 0;
1081 	      break;
1082 	    case 'I':
1083 	      /* Match hour in 12-hour clock using alternate numeric
1084 		 symbols.  */
1085 	      get_alt_number (1, 12, 2);
1086 	      tm->tm_hour = val % 12;
1087 	      s.have_I = 1;
1088 	      break;
1089 	    case 'm':
1090 	      /* Match month using alternate numeric symbols.  */
1091 	      get_alt_number (1, 12, 2);
1092 	      tm->tm_mon = val - 1;
1093 	      s.have_mon = 1;
1094 	      s.want_xday = 1;
1095 	      break;
1096 	    case 'M':
1097 	      /* Match minutes using alternate numeric symbols.  */
1098 	      get_alt_number (0, 59, 2);
1099 	      tm->tm_min = val;
1100 	      break;
1101 	    case 'S':
1102 	      /* Match seconds using alternate numeric symbols.  */
1103 	      get_alt_number (0, 61, 2);
1104 	      tm->tm_sec = val;
1105 	      break;
1106 	    case 'U':
1107 	      get_alt_number (0, 53, 2);
1108 	      s.week_no = val;
1109 	      s.have_uweek = 1;
1110 	      break;
1111 	    case 'W':
1112 	      get_alt_number (0, 53, 2);
1113 	      s.week_no = val;
1114 	      s.have_wweek = 1;
1115 	      break;
1116 	    case 'V':
1117 	      get_alt_number (0, 53, 2);
1118 	      /* XXX This cannot determine any field in TM without
1119 		 further information.  */
1120 	      break;
1121 	    case 'w':
1122 	      /* Match number of weekday using alternate numeric symbols.  */
1123 	      get_alt_number (0, 6, 1);
1124 	      tm->tm_wday = val;
1125 	      s.have_wday = 1;
1126 	      break;
1127 	    case 'y':
1128 	      /* Match year within century using alternate numeric symbols.  */
1129 	      get_alt_number (0, 99, 2);
1130 	      tm->tm_year = val >= 69 ? val : val + 100;
1131 	      s.want_xday = 1;
1132 	      break;
1133 	    default:
1134 	      return NULL;
1135 	    }
1136 	  break;
1137 	default:
1138 	  return NULL;
1139 	}
1140     }
1141 
1142   if (statep != NULL)
1143     {
1144       /* Recursive invocation, returning success, so
1145 	 update parent's struct tm and state.  */
1146       *(struct __strptime_state *) statep = s;
1147       *tmp = tmb;
1148       return (char *) rp;
1149     }
1150 
1151   if (s.have_I && s.is_pm)
1152     tm->tm_hour += 12;
1153 
1154   if (s.century != -1)
1155     {
1156       if (s.want_century)
1157 	tm->tm_year = tm->tm_year % 100 + (s.century - 19) * 100;
1158       else
1159 	/* Only the century, but not the year.  Strange, but so be it.  */
1160 	tm->tm_year = (s.century - 19) * 100;
1161     }
1162 
1163   if (s.era_cnt != -1)
1164     {
1165       era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
1166       if (era == NULL)
1167 	return NULL;
1168       if (s.want_era)
1169 	tm->tm_year = (era->start_date[0]
1170 		       + ((tm->tm_year - era->offset)
1171 			  * era->absolute_direction));
1172       else
1173 	/* Era start year assumed.  */
1174 	tm->tm_year = era->start_date[0];
1175     }
1176   else
1177     if (s.want_era)
1178       {
1179 	/* No era found but we have seen an E modifier.  Rectify some
1180 	   values.  */
1181 	if (s.want_century && s.century == -1 && tm->tm_year < 69)
1182 	  tm->tm_year += 100;
1183       }
1184 
1185   if (s.want_xday && !s.have_wday)
1186     {
1187       if ( !(s.have_mon && s.have_mday) && s.have_yday)
1188 	{
1189 	  /* We don't have tm_mon and/or tm_mday, compute them.  */
1190 	  int t_mon = 0;
1191 	  while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1192 	      t_mon++;
1193 	  if (!s.have_mon)
1194 	      tm->tm_mon = t_mon - 1;
1195 	  if (!s.have_mday)
1196 	      tm->tm_mday =
1197 		(tm->tm_yday
1198 		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1199 	  s.have_mon = 1;
1200 	  s.have_mday = 1;
1201 	}
1202       /* Don't crash in day_of_the_week if tm_mon is uninitialized.  */
1203       if (s.have_mon || (unsigned) tm->tm_mon <= 11)
1204 	day_of_the_week (tm);
1205     }
1206 
1207   if (s.want_xday && !s.have_yday && (s.have_mon || (unsigned) tm->tm_mon <= 11))
1208     day_of_the_year (tm);
1209 
1210   if ((s.have_uweek || s.have_wweek) && s.have_wday)
1211     {
1212       int save_wday = tm->tm_wday;
1213       int save_mday = tm->tm_mday;
1214       int save_mon = tm->tm_mon;
1215       int w_offset = s.have_uweek ? 0 : 1;
1216 
1217       tm->tm_mday = 1;
1218       tm->tm_mon = 0;
1219       day_of_the_week (tm);
1220       if (s.have_mday)
1221 	tm->tm_mday = save_mday;
1222       if (s.have_mon)
1223 	tm->tm_mon = save_mon;
1224 
1225       if (!s.have_yday)
1226 	tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
1227 		       + (s.week_no - 1) * 7
1228 		       + (save_wday - w_offset + 7) % 7);
1229 
1230       if (!s.have_mday || !s.have_mon)
1231 	{
1232 	  int t_mon = 0;
1233 	  while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
1234 		 <= tm->tm_yday)
1235 	    t_mon++;
1236 	  if (!s.have_mon)
1237 	    tm->tm_mon = t_mon - 1;
1238 	  if (!s.have_mday)
1239 	      tm->tm_mday =
1240 		(tm->tm_yday
1241 		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1242 	}
1243 
1244       tm->tm_wday = save_wday;
1245     }
1246 
1247   return (char *) rp;
1248 }
1249 
1250 
1251 char *
strptime(const char * buf,const char * format,struct tm * tm LOCALE_PARAM)1252 strptime (const char *buf, const char *format, struct tm *tm LOCALE_PARAM)
1253 {
1254   return __strptime_internal (buf, format, tm, NULL LOCALE_ARG);
1255 }
1256 
1257 #ifdef _LIBC
1258 weak_alias (__strptime_l, strptime_l)
1259 #endif
1260