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