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