]> sjero.net Git - wget/blob - src/cmpt.c
4b4d68cb4b34e9bc3b76689f9f3ec258b2e113fa
[wget] / src / cmpt.c
1 /* Replacements for routines missing on some systems.
2    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #ifdef HAVE_STRING_H
25 # include <string.h>
26 #else
27 # include <strings.h>
28 #endif /* HAVE_STRING_H */
29
30 #include <sys/types.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <limits.h>
35
36 #include "wget.h"
37
38 #ifndef HAVE_STRERROR
39 /* A strerror() clone, for systems that don't have it.  */
40 char *
41 strerror (int err)
42 {
43   /* This loses on a system without `sys_errlist'.  */
44   extern char *sys_errlist[];
45   return sys_errlist[err];
46 }
47 #endif /* not HAVE_STRERROR */
48
49 /* Some systems don't have some str* functions in libc.  Here we
50    define them.  The same goes for strptime.  */
51
52 #ifndef HAVE_STRCASECMP
53 /* From GNU libc.  */
54 /* Compare S1 and S2, ignoring case, returning less than, equal to or
55    greater than zero if S1 is lexiographically less than,
56    equal to or greater than S2.  */
57 int
58 strcasecmp (const char *s1, const char *s2)
59 {
60   register const unsigned char *p1 = (const unsigned char *) s1;
61   register const unsigned char *p2 = (const unsigned char *) s2;
62   unsigned char c1, c2;
63
64   if (p1 == p2)
65     return 0;
66
67   do
68     {
69       c1 = TOLOWER (*p1++);
70       c2 = TOLOWER (*p2++);
71       if (c1 == '\0')
72         break;
73     }
74   while (c1 == c2);
75
76   return c1 - c2;
77 }
78 #endif /* not HAVE_STRCASECMP */
79
80 #ifndef HAVE_STRNCASECMP
81 /* From GNU libc.  */
82 /* Compare no more than N characters of S1 and S2,
83    ignoring case, returning less than, equal to or
84    greater than zero if S1 is lexicographically less
85    than, equal to or greater than S2.  */
86 int
87 strncasecmp (const char *s1, const char *s2, size_t n)
88 {
89   register const unsigned char *p1 = (const unsigned char *) s1;
90   register const unsigned char *p2 = (const unsigned char *) s2;
91   unsigned char c1, c2;
92
93   if (p1 == p2 || n == 0)
94     return 0;
95
96   do
97     {
98       c1 = TOLOWER (*p1++);
99       c2 = TOLOWER (*p2++);
100       if (c1 == '\0' || c1 != c2)
101         return c1 - c2;
102     } while (--n > 0);
103
104   return c1 - c2;
105 }
106 #endif /* not HAVE_STRNCASECMP */
107
108 #ifndef HAVE_STRSTR
109 /* From GNU libc 2.0.6.  */
110 /* Return the first ocurrence of NEEDLE in HAYSTACK.  */
111 /*
112  * My personal strstr() implementation that beats most other algorithms.
113  * Until someone tells me otherwise, I assume that this is the
114  * fastest implementation of strstr() in C.
115  * I deliberately chose not to comment it.  You should have at least
116  * as much fun trying to understand it, as I had to write it :-).
117  *
118  * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
119 typedef unsigned chartype;
120
121 char *
122 strstr (phaystack, pneedle)
123      const char *phaystack;
124      const char *pneedle;
125 {
126   register const unsigned char *haystack, *needle;
127   register chartype b, c;
128
129   haystack = (const unsigned char *) phaystack;
130   needle = (const unsigned char *) pneedle;
131
132   b = *needle;
133   if (b != '\0')
134     {
135       haystack--;                               /* possible ANSI violation */
136       do
137         {
138           c = *++haystack;
139           if (c == '\0')
140             goto ret0;
141         }
142       while (c != b);
143
144       c = *++needle;
145       if (c == '\0')
146         goto foundneedle;
147       ++needle;
148       goto jin;
149
150       for (;;)
151         {
152           register chartype a;
153           register const unsigned char *rhaystack, *rneedle;
154
155           do
156             {
157               a = *++haystack;
158               if (a == '\0')
159                 goto ret0;
160               if (a == b)
161                 break;
162               a = *++haystack;
163               if (a == '\0')
164                 goto ret0;
165 shloop:     }
166           while (a != b);
167
168 jin:      a = *++haystack;
169           if (a == '\0')
170             goto ret0;
171
172           if (a != c)
173             goto shloop;
174
175           rhaystack = haystack-- + 1;
176           rneedle = needle;
177           a = *rneedle;
178
179           if (*rhaystack == a)
180             do
181               {
182                 if (a == '\0')
183                   goto foundneedle;
184                 ++rhaystack;
185                 a = *++needle;
186                 if (*rhaystack != a)
187                   break;
188                 if (a == '\0')
189                   goto foundneedle;
190                 ++rhaystack;
191                 a = *++needle;
192               }
193             while (*rhaystack == a);
194
195           needle = rneedle;             /* took the register-poor approach */
196
197           if (a == '\0')
198             break;
199         }
200     }
201 foundneedle:
202   return (char*) haystack;
203 ret0:
204   return 0;
205 }
206 #endif /* not HAVE_STRSTR */
207
208 #ifndef HAVE_MKTIME
209 /* From GNU libc 2.0.  */
210
211 /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
212    This file is part of the GNU C Library.
213    Contributed by Paul Eggert (eggert@twinsun.com).  */
214
215 #ifdef _LIBC
216 # define HAVE_LIMITS_H 1
217 # define HAVE_LOCALTIME_R 1
218 # define STDC_HEADERS 1
219 #endif
220
221 /* Assume that leap seconds are possible, unless told otherwise.
222    If the host has a `zic' command with a `-L leapsecondfilename' option,
223    then it supports leap seconds; otherwise it probably doesn't.  */
224 #ifndef LEAP_SECONDS_POSSIBLE
225 # define LEAP_SECONDS_POSSIBLE 1
226 #endif
227
228 #ifndef __P
229 # define __P(args) PARAMS (args)
230 #endif  /* Not __P.  */
231
232 #ifndef CHAR_BIT
233 # define CHAR_BIT 8
234 #endif
235
236 #ifndef INT_MIN
237 # define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
238 #endif
239 #ifndef INT_MAX
240 # define INT_MAX (~0 - INT_MIN)
241 #endif
242
243 #ifndef TIME_T_MIN
244 /* The outer cast to time_t works around a bug in Cray C 5.0.3.0.  */
245 # define TIME_T_MIN ((time_t) \
246                     (0 < (time_t) -1 ? (time_t) 0 \
247                      : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)))
248 #endif
249 #ifndef TIME_T_MAX
250 # define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
251 #endif
252
253 #define TM_YEAR_BASE 1900
254 #define EPOCH_YEAR 1970
255
256 #ifndef __isleap
257 /* Nonzero if YEAR is a leap year (every 4 years,
258    except every 100th isn't, and every 400th is).  */
259 # define __isleap(year) \
260   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
261 #endif
262
263 /* How many days come before each month (0-12).  */
264 const unsigned short int __mon_yday[2][13] =
265   {
266     /* Normal years.  */
267     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
268     /* Leap years.  */
269     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
270   };
271
272 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
273 time_t __mktime_internal __P ((struct tm *,
274                                struct tm *(*) (const time_t *, struct tm *),
275                                time_t *));
276
277
278 #ifdef _LIBC
279 # define localtime_r __localtime_r
280 #else
281 # if ! HAVE_LOCALTIME_R && ! defined localtime_r
282 /* Approximate localtime_r as best we can in its absence.  */
283 #  define localtime_r my_mktime_localtime_r
284 static struct tm *localtime_r __P ((const time_t *, struct tm *));
285 static struct tm *
286 localtime_r (t, tp)
287      const time_t *t;
288      struct tm *tp;
289 {
290   struct tm *l = localtime (t);
291   if (! l)
292     return 0;
293   *tp = *l;
294   return tp;
295 }
296 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
297 #endif /* ! _LIBC */
298
299
300 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
301    measured in seconds, ignoring leap seconds.
302    YEAR uses the same numbering as TM->tm_year.
303    All values are in range, except possibly YEAR.
304    If overflow occurs, yield the low order bits of the correct answer.  */
305 static time_t
306 ydhms_tm_diff (year, yday, hour, min, sec, tp)
307      int year, yday, hour, min, sec;
308      const struct tm *tp;
309 {
310   /* Compute intervening leap days correctly even if year is negative.
311      Take care to avoid int overflow.  time_t overflow is OK, since
312      only the low order bits of the correct time_t answer are needed.
313      Don't convert to time_t until after all divisions are done, since
314      time_t might be unsigned.  */
315   int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
316   int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
317   int a100 = a4 / 25 - (a4 % 25 < 0);
318   int b100 = b4 / 25 - (b4 % 25 < 0);
319   int a400 = a100 >> 2;
320   int b400 = b100 >> 2;
321   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
322   time_t years = year - (time_t) tp->tm_year;
323   time_t days = (365 * years + intervening_leap_days
324                  + (yday - tp->tm_yday));
325   return (60 * (60 * (24 * days + (hour - tp->tm_hour))
326                 + (min - tp->tm_min))
327           + (sec - tp->tm_sec));
328 }
329
330
331 static time_t localtime_offset;
332
333 /* Convert *TP to a time_t value.  */
334 time_t
335 mktime (tp)
336      struct tm *tp;
337 {
338 #ifdef _LIBC
339   /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
340      time zone names contained in the external variable `tzname' shall
341      be set as if the tzset() function had been called.  */
342   __tzset ();
343 #endif
344
345   return __mktime_internal (tp, localtime_r, &localtime_offset);
346 }
347
348 /* Convert *TP to a time_t value, inverting
349    the monotonic and mostly-unit-linear conversion function CONVERT.
350    Use *OFFSET to keep track of a guess at the offset of the result,
351    compared to what the result would be for UTC without leap seconds.
352    If *OFFSET's guess is correct, only one CONVERT call is needed.  */
353 time_t
354 __mktime_internal (tp, convert, offset)
355      struct tm *tp;
356      struct tm *(*convert) __P ((const time_t *, struct tm *));
357      time_t *offset;
358 {
359   time_t t, dt, t0;
360   struct tm tm;
361
362   /* The maximum number of probes (calls to CONVERT) should be enough
363      to handle any combinations of time zone rule changes, solar time,
364      and leap seconds.  Posix.1 prohibits leap seconds, but some hosts
365      have them anyway.  */
366   int remaining_probes = 4;
367
368   /* Time requested.  Copy it in case CONVERT modifies *TP; this can
369      occur if TP is localtime's returned value and CONVERT is localtime.  */
370   int sec = tp->tm_sec;
371   int min = tp->tm_min;
372   int hour = tp->tm_hour;
373   int mday = tp->tm_mday;
374   int mon = tp->tm_mon;
375   int year_requested = tp->tm_year;
376   int isdst = tp->tm_isdst;
377
378   /* Ensure that mon is in range, and set year accordingly.  */
379   int mon_remainder = mon % 12;
380   int negative_mon_remainder = mon_remainder < 0;
381   int mon_years = mon / 12 - negative_mon_remainder;
382   int year = year_requested + mon_years;
383
384   /* The other values need not be in range:
385      the remaining code handles minor overflows correctly,
386      assuming int and time_t arithmetic wraps around.
387      Major overflows are caught at the end.  */
388
389   /* Calculate day of year from year, month, and day of month.
390      The result need not be in range.  */
391   int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
392                [mon_remainder + 12 * negative_mon_remainder])
393               + mday - 1);
394
395   int sec_requested = sec;
396 #if LEAP_SECONDS_POSSIBLE
397   /* Handle out-of-range seconds specially,
398      since ydhms_tm_diff assumes every minute has 60 seconds.  */
399   if (sec < 0)
400     sec = 0;
401   if (59 < sec)
402     sec = 59;
403 #endif
404
405   /* Invert CONVERT by probing.  First assume the same offset as last time.
406      Then repeatedly use the error to improve the guess.  */
407
408   tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
409   tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
410   t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
411
412   for (t = t0 + *offset;
413        (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
414        t += dt)
415     if (--remaining_probes == 0)
416       return -1;
417
418   /* Check whether tm.tm_isdst has the requested value, if any.  */
419   if (0 <= isdst && 0 <= tm.tm_isdst)
420     {
421       int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
422       if (dst_diff)
423         {
424           /* Move two hours in the direction indicated by the disagreement,
425              probe some more, and switch to a new time if found.
426              The largest known fallback due to daylight savings is two hours:
427              once, in Newfoundland, 1988-10-30 02:00 -> 00:00.  */
428           time_t ot = t - 2 * 60 * 60 * dst_diff;
429           while (--remaining_probes != 0)
430             {
431               struct tm otm;
432               if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
433                                          (*convert) (&ot, &otm))))
434                 {
435                   t = ot;
436                   tm = otm;
437                   break;
438                 }
439               if ((ot += dt) == t)
440                 break;  /* Avoid a redundant probe.  */
441             }
442         }
443     }
444
445   *offset = t - t0;
446
447 #if LEAP_SECONDS_POSSIBLE
448   if (sec_requested != tm.tm_sec)
449     {
450       /* Adjust time to reflect the tm_sec requested, not the normalized value.
451          Also, repair any damage from a false match due to a leap second.  */
452       t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
453       (*convert) (&t, &tm);
454     }
455 #endif
456
457   if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
458     {
459       /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
460          so check for major overflows.  A gross check suffices,
461          since if t has overflowed, it is off by a multiple of
462          TIME_T_MAX - TIME_T_MIN + 1.  So ignore any component of
463          the difference that is bounded by a small value.  */
464
465       double dyear = (double) year_requested + mon_years - tm.tm_year;
466       double dday = 366 * dyear + mday;
467       double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
468
469       if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
470         return -1;
471     }
472
473   *tp = tm;
474   return t;
475 }
476
477 #ifdef weak_alias
478 weak_alias (mktime, timelocal)
479 #endif
480 #endif /* not HAVE_MKTIME */
481
482
483 #ifndef HAVE_STRPTIME
484 /* From GNU libc 2.0.6.  */
485 /* Ulrich, thanks for helping me out with this!  --hniksic  */
486
487 /* strptime - Convert a string representation of time to a time value.
488    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
489    This file is part of the GNU C Library.
490    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.  */
491
492 /* XXX This version of the implementation is not really complete.
493    Some of the fields cannot add information alone.  But if seeing
494    some of them in the same format (such as year, week and weekday)
495    this is enough information for determining the date.  */
496
497 #ifndef __P
498 # define __P(args) PARAMS (args)
499 #endif /* not __P */
500
501 #if ! HAVE_LOCALTIME_R && ! defined (localtime_r)
502 #ifdef _LIBC
503 #define localtime_r __localtime_r
504 #else
505 /* Approximate localtime_r as best we can in its absence.  */
506 #define localtime_r my_localtime_r
507 static struct tm *localtime_r __P ((const time_t *, struct tm *));
508 static struct tm *
509 localtime_r (t, tp)
510      const time_t *t;
511      struct tm *tp;
512 {
513   struct tm *l = localtime (t);
514   if (! l)
515     return 0;
516   *tp = *l;
517   return tp;
518 }
519 #endif /* ! _LIBC */
520 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
521
522
523 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
524 #if defined __GNUC__ && __GNUC__ >= 2
525 # define match_string(cs1, s2) \
526   ({ size_t len = strlen (cs1);                                               \
527      int result = strncasecmp ((cs1), (s2), len) == 0;                        \
528      if (result) (s2) += len;                                                 \
529      result; })
530 #else
531 /* Oh come on.  Get a reasonable compiler.  */
532 # define match_string(cs1, s2) \
533   (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
534 #endif
535 /* We intentionally do not use isdigit() for testing because this will
536    lead to problems with the wide character version.  */
537 #define get_number(from, to) \
538   do {                                                                        \
539     val = 0;                                                                  \
540     if (*rp < '0' || *rp > '9')                                               \
541       return NULL;                                                            \
542     do {                                                                      \
543       val *= 10;                                                              \
544       val += *rp++ - '0';                                                     \
545     } while (val * 10 <= to && *rp >= '0' && *rp <= '9');                     \
546     if (val < from || val > to)                                               \
547       return NULL;                                                            \
548   } while (0)
549 #ifdef _NL_CURRENT
550 # define get_alt_number(from, to) \
551   do {                                                                        \
552     if (*decided != raw)                                                      \
553       {                                                                       \
554         const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS);                 \
555         val = 0;                                                              \
556         while (*alts != '\0')                                                 \
557           {                                                                   \
558             size_t len = strlen (alts);                                       \
559             if (strncasecmp (alts, rp, len) == 0)                             \
560               break;                                                          \
561             alts = strchr (alts, '\0') + 1;                                   \
562             ++val;                                                            \
563           }                                                                   \
564         if (*alts == '\0')                                                    \
565           {                                                                   \
566             if (*decided == loc && val != 0)                                  \
567               return NULL;                                                    \
568           }                                                                   \
569         else                                                                  \
570           {                                                                   \
571             *decided = loc;                                                   \
572             break;                                                            \
573           }                                                                   \
574       }                                                                       \
575     get_number (from, to);                                                    \
576   } while (0)
577 #else
578 # define get_alt_number(from, to) \
579   /* We don't have the alternate representation.  */                          \
580   get_number(from, to)
581 #endif
582 #define recursive(new_fmt) \
583   (*(new_fmt) != '\0'                                                         \
584    && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)
585
586
587 #ifdef _LIBC
588 /* This is defined in locale/C-time.c in the GNU libc.  */
589 extern const struct locale_data _nl_C_LC_TIME;
590
591 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
592 # define ab_weekday_name \
593   (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
594 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
595 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
596 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
597 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
598 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
599 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
600 # define HERE_T_FMT_AMPM \
601   (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
602 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
603 #else
604 static char const weekday_name[][10] =
605   {
606     "Sunday", "Monday", "Tuesday", "Wednesday",
607     "Thursday", "Friday", "Saturday"
608   };
609 static char const ab_weekday_name[][4] =
610   {
611     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
612   };
613 static char const month_name[][10] =
614   {
615     "January", "February", "March", "April", "May", "June",
616     "July", "August", "September", "October", "November", "December"
617   };
618 static char const ab_month_name[][4] =
619   {
620     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
621     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
622   };
623 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
624 # define HERE_D_FMT "%m/%d/%y"
625 # define HERE_AM_STR "AM"
626 # define HERE_PM_STR "PM"
627 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
628 # define HERE_T_FMT "%H:%M:%S"
629 #endif
630
631 /* Status of lookup: do we use the locale data or the raw data?  */
632 enum locale_status { not, loc, raw };
633
634 static char *
635 strptime_internal __P ((const char *buf, const char *format, struct tm *tm,
636                         enum locale_status *decided));
637
638 static char *
639 strptime_internal (buf, format, tm, decided)
640      const char *buf;
641      const char *format;
642      struct tm *tm;
643      enum locale_status *decided;
644 {
645   const char *rp;
646   const char *fmt;
647   int cnt;
648   size_t val;
649   int have_I, is_pm;
650
651   rp = buf;
652   fmt = format;
653   have_I = is_pm = 0;
654
655   while (*fmt != '\0')
656     {
657       /* A white space in the format string matches 0 more or white
658          space in the input string.  */
659       if (ISSPACE (*fmt))
660         {
661           while (ISSPACE (*rp))
662             ++rp;
663           ++fmt;
664           continue;
665         }
666
667       /* Any character but `%' must be matched by the same character
668          in the iput string.  */
669       if (*fmt != '%')
670         {
671           match_char (*fmt++, *rp++);
672           continue;
673         }
674
675       ++fmt;
676 #ifndef _NL_CURRENT
677       /* We need this for handling the `E' modifier.  */
678     start_over:
679 #endif
680       switch (*fmt++)
681         {
682         case '%':
683           /* Match the `%' character itself.  */
684           match_char ('%', *rp++);
685           break;
686         case 'a':
687         case 'A':
688           /* Match day of week.  */
689           for (cnt = 0; cnt < 7; ++cnt)
690             {
691 #ifdef _NL_CURRENT
692               if (*decided !=raw)
693                 {
694                   if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
695                     {
696                       if (*decided == not
697                           && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
698                                      weekday_name[cnt]))
699                         *decided = loc;
700                       break;
701                     }
702                   if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
703                     {
704                       if (*decided == not
705                           && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
706                                      ab_weekday_name[cnt]))
707                         *decided = loc;
708                       break;
709                     }
710                 }
711 #endif
712               if (*decided != loc
713                   && (match_string (weekday_name[cnt], rp)
714                       || match_string (ab_weekday_name[cnt], rp)))
715                 {
716                   *decided = raw;
717                   break;
718                 }
719             }
720           if (cnt == 7)
721             /* Does not match a weekday name.  */
722             return NULL;
723           tm->tm_wday = cnt;
724           break;
725         case 'b':
726         case 'B':
727         case 'h':
728           /* Match month name.  */
729           for (cnt = 0; cnt < 12; ++cnt)
730             {
731 #ifdef _NL_CURRENT
732               if (*decided !=raw)
733                 {
734                   if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
735                     {
736                       if (*decided == not
737                           && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
738                                      month_name[cnt]))
739                         *decided = loc;
740                       break;
741                     }
742                   if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
743                     {
744                       if (*decided == not
745                           && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
746                                      ab_month_name[cnt]))
747                         *decided = loc;
748                       break;
749                     }
750                 }
751 #endif
752               if (match_string (month_name[cnt], rp)
753                   || match_string (ab_month_name[cnt], rp))
754                 {
755                   *decided = raw;
756                   break;
757                 }
758             }
759           if (cnt == 12)
760             /* Does not match a month name.  */
761             return NULL;
762           tm->tm_mon = cnt;
763           break;
764         case 'c':
765           /* Match locale's date and time format.  */
766 #ifdef _NL_CURRENT
767           if (*decided != raw)
768             {
769               if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
770                 {
771                   if (*decided == loc)
772                     return NULL;
773                 }
774               else
775                 {
776                   if (*decided == not &&
777                       strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
778                     *decided = loc;
779                   break;
780                 }
781               *decided = raw;
782             }
783 #endif
784           if (!recursive (HERE_D_T_FMT))
785             return NULL;
786           break;
787         case 'C':
788           /* Match century number.  */
789           get_number (0, 99);
790           /* We don't need the number.  */
791           break;
792         case 'd':
793         case 'e':
794           /* Match day of month.  */
795           get_number (1, 31);
796           tm->tm_mday = val;
797           break;
798         case 'x':
799 #ifdef _NL_CURRENT
800           if (*decided != raw)
801             {
802               if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
803                 {
804                   if (*decided == loc)
805                     return NULL;
806                 }
807               else
808                 {
809                   if (decided == not
810                       && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
811                     *decided = loc;
812                   break;
813                 }
814               *decided = raw;
815             }
816 #endif
817           /* Fall through.  */
818         case 'D':
819           /* Match standard day format.  */
820           if (!recursive (HERE_D_FMT))
821             return NULL;
822           break;
823         case 'H':
824           /* Match hour in 24-hour clock.  */
825           get_number (0, 23);
826           tm->tm_hour = val;
827           have_I = 0;
828           break;
829         case 'I':
830           /* Match hour in 12-hour clock.  */
831           get_number (1, 12);
832           tm->tm_hour = val % 12;
833           have_I = 1;
834           break;
835         case 'j':
836           /* Match day number of year.  */
837           get_number (1, 366);
838           tm->tm_yday = val - 1;
839           break;
840         case 'm':
841           /* Match number of month.  */
842           get_number (1, 12);
843           tm->tm_mon = val - 1;
844           break;
845         case 'M':
846           /* Match minute.  */
847           get_number (0, 59);
848           tm->tm_min = val;
849           break;
850         case 'n':
851         case 't':
852           /* Match any white space.  */
853           while (ISSPACE (*rp))
854             ++rp;
855           break;
856         case 'p':
857           /* Match locale's equivalent of AM/PM.  */
858 #ifdef _NL_CURRENT
859           if (*decided != raw)
860             {
861               if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
862                 {
863                   if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
864                     *decided = loc;
865                   break;
866                 }
867               if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
868                 {
869                   if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
870                     *decided = loc;
871                   is_pm = 1;
872                   break;
873                 }
874               *decided = raw;
875             }
876 #endif
877           if (!match_string (HERE_AM_STR, rp))
878             if (match_string (HERE_PM_STR, rp))
879               is_pm = 1;
880             else
881               return NULL;
882           break;
883         case 'r':
884 #ifdef _NL_CURRENT
885           if (*decided != raw)
886             {
887               if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
888                 {
889                   if (*decided == loc)
890                     return NULL;
891                 }
892               else
893                 {
894                   if (*decided == not &&
895                       strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
896                               HERE_T_FMT_AMPM))
897                     *decided = loc;
898                   break;
899                 }
900               *decided = raw;
901             }
902 #endif
903           if (!recursive (HERE_T_FMT_AMPM))
904             return NULL;
905           break;
906         case 'R':
907           if (!recursive ("%H:%M"))
908             return NULL;
909           break;
910         case 's':
911           {
912             /* The number of seconds may be very high so we cannot use
913                the `get_number' macro.  Instead read the number
914                character for character and construct the result while
915                doing this.  */
916             time_t secs;
917             if (*rp < '0' || *rp > '9')
918               /* We need at least one digit.  */
919               return NULL;
920
921             do
922               {
923                 secs *= 10;
924                 secs += *rp++ - '0';
925               }
926             while (*rp >= '0' && *rp <= '9');
927
928             if (localtime_r (&secs, tm) == NULL)
929               /* Error in function.  */
930               return NULL;
931           }
932           break;
933         case 'S':
934           get_number (0, 61);
935           tm->tm_sec = val;
936           break;
937         case 'X':
938 #ifdef _NL_CURRENT
939           if (*decided != raw)
940             {
941               if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
942                 {
943                   if (*decided == loc)
944                     return NULL;
945                 }
946               else
947                 {
948                   if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
949                     *decided = loc;
950                   break;
951                 }
952               *decided = raw;
953             }
954 #endif
955           /* Fall through.  */
956         case 'T':
957           if (!recursive (HERE_T_FMT))
958             return NULL;
959           break;
960         case 'u':
961           get_number (1, 7);
962           tm->tm_wday = val % 7;
963           break;
964         case 'g':
965           get_number (0, 99);
966           /* XXX This cannot determine any field in TM.  */
967           break;
968         case 'G':
969           if (*rp < '0' || *rp > '9')
970             return NULL;
971           /* XXX Ignore the number since we would need some more
972              information to compute a real date.  */
973           do
974             ++rp;
975           while (*rp >= '0' && *rp <= '9');
976           break;
977         case 'U':
978         case 'V':
979         case 'W':
980           get_number (0, 53);
981           /* XXX This cannot determine any field in TM without some
982              information.  */
983           break;
984         case 'w':
985           /* Match number of weekday.  */
986           get_number (0, 6);
987           tm->tm_wday = val;
988           break;
989         case 'y':
990           /* Match year within century.  */
991           get_number (0, 99);
992           tm->tm_year = val >= 50 ? val : val + 100;
993           break;
994         case 'Y':
995           /* Match year including century number.  */
996           if (sizeof (time_t) > 4)
997             get_number (0, 9999);
998           else
999             get_number (0, 2036);
1000           tm->tm_year = val - 1900;
1001           break;
1002         case 'Z':
1003           /* XXX How to handle this?  */
1004           break;
1005         case 'E':
1006 #ifdef _NL_CURRENT
1007           switch (*fmt++)
1008             {
1009             case 'c':
1010               /* Match locale's alternate date and time format.  */
1011               if (*decided != raw)
1012                 {
1013                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
1014
1015                   if (*fmt == '\0')
1016                     fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
1017
1018                   if (!recursive (fmt))
1019                     {
1020                       if (*decided == loc)
1021                         return NULL;
1022                     }
1023                   else
1024                     {
1025                       if (strcmp (fmt, HERE_D_T_FMT))
1026                         *decided = loc;
1027                       break;
1028                     }
1029                   *decided = raw;
1030                 }
1031               /* The C locale has no era information, so use the
1032                  normal representation.  */
1033               if (!recursive (HERE_D_T_FMT))
1034                 return NULL;
1035               break;
1036             case 'C':
1037             case 'y':
1038             case 'Y':
1039               /* Match name of base year in locale's alternate
1040                  representation.  */
1041               /* XXX This is currently not implemented.  It should
1042                  use the value _NL_CURRENT (LC_TIME, ERA).  */
1043               break;
1044             case 'x':
1045               if (*decided != raw)
1046                 {
1047                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
1048
1049                   if (*fmt == '\0')
1050                     fmt = _NL_CURRENT (LC_TIME, D_FMT);
1051
1052                   if (!recursive (fmt))
1053                     {
1054                       if (*decided == loc)
1055                         return NULL;
1056                     }
1057                   else
1058                     {
1059                       if (strcmp (fmt, HERE_D_FMT))
1060                         *decided = loc;
1061                       break;
1062                     }
1063                   *decided = raw;
1064                 }
1065               if (!recursive (HERE_D_FMT))
1066                 return NULL;
1067               break;
1068             case 'X':
1069               if (*decided != raw)
1070                 {
1071                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
1072
1073                   if (*fmt == '\0')
1074                     fmt = _NL_CURRENT (LC_TIME, T_FMT);
1075
1076                   if (!recursive (fmt))
1077                     {
1078                       if (*decided == loc)
1079                         return NULL;
1080                     }
1081                   else
1082                     {
1083                       if (strcmp (fmt, HERE_T_FMT))
1084                         *decided = loc;
1085                       break;
1086                     }
1087                   *decided = raw;
1088                 }
1089               if (!recursive (HERE_T_FMT))
1090                 return NULL;
1091               break;
1092             default:
1093               return NULL;
1094             }
1095           break;
1096 #else
1097           /* We have no information about the era format.  Just use
1098              the normal format.  */
1099           if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
1100               && *fmt != 'x' && *fmt != 'X')
1101             /* This is an illegal format.  */
1102             return NULL;
1103
1104           goto start_over;
1105 #endif
1106         case 'O':
1107           switch (*fmt++)
1108             {
1109             case 'd':
1110             case 'e':
1111               /* Match day of month using alternate numeric symbols.  */
1112               get_alt_number (1, 31);
1113               tm->tm_mday = val;
1114               break;
1115             case 'H':
1116               /* Match hour in 24-hour clock using alternate numeric
1117                  symbols.  */
1118               get_alt_number (0, 23);
1119               tm->tm_hour = val;
1120               have_I = 0;
1121               break;
1122             case 'I':
1123               /* Match hour in 12-hour clock using alternate numeric
1124                  symbols.  */
1125               get_alt_number (1, 12);
1126               tm->tm_hour = val - 1;
1127               have_I = 1;
1128               break;
1129             case 'm':
1130               /* Match month using alternate numeric symbols.  */
1131               get_alt_number (1, 12);
1132               tm->tm_mon = val - 1;
1133               break;
1134             case 'M':
1135               /* Match minutes using alternate numeric symbols.  */
1136               get_alt_number (0, 59);
1137               tm->tm_min = val;
1138               break;
1139             case 'S':
1140               /* Match seconds using alternate numeric symbols.  */
1141               get_alt_number (0, 61);
1142               tm->tm_sec = val;
1143               break;
1144             case 'U':
1145             case 'V':
1146             case 'W':
1147               get_alt_number (0, 53);
1148               /* XXX This cannot determine any field in TM without
1149                  further information.  */
1150               break;
1151             case 'w':
1152               /* Match number of weekday using alternate numeric symbols.  */
1153               get_alt_number (0, 6);
1154               tm->tm_wday = val;
1155               break;
1156             case 'y':
1157               /* Match year within century using alternate numeric symbols.  */
1158               get_alt_number (0, 99);
1159               break;
1160             default:
1161               return NULL;
1162             }
1163           break;
1164         default:
1165           return NULL;
1166         }
1167     }
1168
1169   if (have_I && is_pm)
1170     tm->tm_hour += 12;
1171
1172   return (char *) rp;
1173 }
1174
1175
1176 char *
1177 strptime (buf, format, tm)
1178      const char *buf;
1179      const char *format;
1180      struct tm *tm;
1181 {
1182   enum locale_status decided;
1183 #ifdef _NL_CURRENT
1184   decided = not;
1185 #else
1186   decided = raw;
1187 #endif
1188   return strptime_internal (buf, format, tm, &decided);
1189 }
1190 #endif /* not HAVE_STRPTIME */