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