]> sjero.net Git - wget/blob - src/cmpt.c
[svn] Doc fix.
[wget] / src / cmpt.c
1 /* Replacements for routines missing on some systems.
2    Copyright (C) 1996-2005 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 Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40
41 #include <errno.h>
42
43 #include "wget.h"
44
45 /* Some systems lack certain functions normally taken for granted.
46    For example, Windows doesn't have strptime, and some systems don't
47    have a usable fnmatch.  This file should contain fallback
48    implementations of such missing functions.  It should *not* define
49    new Wget-specific interfaces -- those should be placed in utils.c
50    or elsewhere.  */
51 \f
52 /* strcasecmp and strncasecmp apparently originated with BSD 4.4.
53    SUSv3 seems to be the only standard out there (that I can find)
54    that requires their existence, so in theory there might be systems
55    still in use that lack them.  Note that these don't get defined
56    under Windows because mswindows.h defines them to the equivalent
57    Windows functions stricmp and strnicmp.  */
58
59 #ifndef HAVE_STRCASECMP
60 /* From GNU libc.  */
61 /* Compare S1 and S2, ignoring case, returning less than, equal to or
62    greater than zero if S1 is lexiographically less than,
63    equal to or greater than S2.  */
64 int
65 strcasecmp (const char *s1, const char *s2)
66 {
67   register const unsigned char *p1 = (const unsigned char *) s1;
68   register const unsigned char *p2 = (const unsigned char *) s2;
69   unsigned char c1, c2;
70
71   if (p1 == p2)
72     return 0;
73
74   do
75     {
76       c1 = TOLOWER (*p1++);
77       c2 = TOLOWER (*p2++);
78       if (c1 == '\0')
79         break;
80     }
81   while (c1 == c2);
82
83   return c1 - c2;
84 }
85 #endif /* not HAVE_STRCASECMP */
86
87 #ifndef HAVE_STRNCASECMP
88 /* From GNU libc.  */
89 /* Compare no more than N characters of S1 and S2,
90    ignoring case, returning less than, equal to or
91    greater than zero if S1 is lexicographically less
92    than, equal to or greater than S2.  */
93 int
94 strncasecmp (const char *s1, const char *s2, size_t n)
95 {
96   register const unsigned char *p1 = (const unsigned char *) s1;
97   register const unsigned char *p2 = (const unsigned char *) s2;
98   unsigned char c1, c2;
99
100   if (p1 == p2 || n == 0)
101     return 0;
102
103   do
104     {
105       c1 = TOLOWER (*p1++);
106       c2 = TOLOWER (*p2++);
107       if (c1 == '\0' || c1 != c2)
108         return c1 - c2;
109     } while (--n > 0);
110
111   return c1 - c2;
112 }
113 #endif /* not HAVE_STRNCASECMP */
114 \f
115 /* strptime is required by POSIX, but it is missing from Windows,
116    which means we must keep a fallback implementation.  It is
117    reportedly missing or broken on many older systems as well.  */
118
119 #ifndef HAVE_STRPTIME
120 /* From GNU libc 2.1.3.  */
121 /* Ulrich, thanks for helping me out with this!  --hniksic  */
122
123 /* strptime - Convert a string representation of time to a time value.
124    Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
125    This file is part of the GNU C Library.
126    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.  */
127
128 /* XXX This version of the implementation is not really complete.
129    Some of the fields cannot add information alone.  But if seeing
130    some of them in the same format (such as year, week and weekday)
131    this is enough information for determining the date.  */
132
133 #ifndef __P
134 # define __P(args) args
135 #endif /* not __P */
136
137 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
138 # ifdef _LIBC
139 #  define localtime_r __localtime_r
140 # else
141 /* Approximate localtime_r as best we can in its absence.  */
142 #  define localtime_r my_localtime_r
143 static struct tm *localtime_r __P ((const time_t *, struct tm *));
144 static struct tm *
145 localtime_r (t, tp)
146      const time_t *t;
147      struct tm *tp;
148 {
149   struct tm *l = localtime (t);
150   if (! l)
151     return 0;
152   *tp = *l;
153   return tp;
154 }
155 # endif /* ! _LIBC */
156 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
157
158
159 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
160 #if defined __GNUC__ && __GNUC__ >= 2
161 # define match_string(cs1, s2) \
162   ({ size_t len = strlen (cs1);                                               \
163      int result = strncasecmp ((cs1), (s2), len) == 0;                        \
164      if (result) (s2) += len;                                                 \
165      result; })
166 #else
167 /* Oh come on.  Get a reasonable compiler.  */
168 # define match_string(cs1, s2) \
169   (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
170 #endif
171 /* We intentionally do not use isdigit() for testing because this will
172    lead to problems with the wide character version.  */
173 #define get_number(from, to, n) \
174   do {                                                                        \
175     int __n = n;                                                              \
176     val = 0;                                                                  \
177     while (*rp == ' ')                                                        \
178       ++rp;                                                                   \
179     if (*rp < '0' || *rp > '9')                                               \
180       return NULL;                                                            \
181     do {                                                                      \
182       val *= 10;                                                              \
183       val += *rp++ - '0';                                                     \
184     } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9');        \
185     if (val < from || val > to)                                               \
186       return NULL;                                                            \
187   } while (0)
188 #ifdef _NL_CURRENT
189 /* Added check for __GNUC__ extensions here for Wget. --abbotti */
190 # if defined __GNUC__ && __GNUC__ >= 2
191 #  define get_alt_number(from, to, n) \
192   ({                                                                          \
193     __label__ do_normal;                                                      \
194     if (*decided != raw)                                                      \
195       {                                                                       \
196         const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS);                 \
197         int __n = n;                                                          \
198         int any = 0;                                                          \
199         while (*rp == ' ')                                                    \
200           ++rp;                                                               \
201         val = 0;                                                              \
202         do {                                                                  \
203           val *= 10;                                                          \
204           while (*alts != '\0')                                               \
205             {                                                                 \
206               size_t len = strlen (alts);                                     \
207               if (strncasecmp (alts, rp, len) == 0)                           \
208                 break;                                                        \
209               alts += len + 1;                                                \
210               ++val;                                                          \
211             }                                                                 \
212           if (*alts == '\0')                                                  \
213             {                                                                 \
214               if (*decided == not && ! any)                                   \
215                 goto do_normal;                                               \
216               /* If we haven't read anything it's an error.  */               \
217               if (! any)                                                      \
218                 return NULL;                                                  \
219               /* Correct the premature multiplication.  */                    \
220               val /= 10;                                                      \
221               break;                                                          \
222             }                                                                 \
223           else                                                                \
224             *decided = loc;                                                   \
225         } while (--__n > 0 && val * 10 <= to);                                \
226         if (val < from || val > to)                                           \
227           return NULL;                                                        \
228       }                                                                       \
229     else                                                                      \
230       {                                                                       \
231        do_normal:                                                             \
232         get_number (from, to, n);                                             \
233       }                                                                       \
234     0;                                                                        \
235   })
236 # else
237 #  define get_alt_number(from, to, n) \
238   do {
239     if (*decided != raw)                                                      \
240       {                                                                       \
241         const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS);                 \
242         int __n = n;                                                          \
243         int any = 0;                                                          \
244         while (*rp == ' ')                                                    \
245           ++rp;                                                               \
246         val = 0;                                                              \
247         do {                                                                  \
248           val *= 10;                                                          \
249           while (*alts != '\0')                                               \
250             {                                                                 \
251               size_t len = strlen (alts);                                     \
252               if (strncasecmp (alts, rp, len) == 0)                           \
253                 break;                                                        \
254               alts += len + 1;                                                \
255               ++val;                                                          \
256             }                                                                 \
257           if (*alts == '\0')                                                  \
258             {                                                                 \
259               if (*decided == not && ! any)                                   \
260                 goto do_normal;                                               \
261               /* If we haven't read anything it's an error.  */               \
262               if (! any)                                                      \
263                 return NULL;                                                  \
264               /* Correct the premature multiplication.  */                    \
265               val /= 10;                                                      \
266               break;                                                          \
267             }                                                                 \
268           else                                                                \
269             *decided = loc;                                                   \
270         } while (--__n > 0 && val * 10 <= to);                                \
271         if (val < from || val > to)                                           \
272           return NULL;                                                        \
273       }                                                                       \
274     else                                                                      \
275       {                                                                       \
276        do_normal:                                                             \
277         get_number (from, to, n);                                             \
278       }                                                                       \
279   } while (0)
280 # endif /* defined __GNUC__ && __GNUC__ >= 2 */
281 #else
282 # define get_alt_number(from, to, n) \
283   /* We don't have the alternate representation.  */                          \
284   get_number(from, to, n)
285 #endif
286 #define recursive(new_fmt) \
287   (*(new_fmt) != '\0'                                                         \
288    && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)
289
290
291 #ifdef _LIBC
292 /* This is defined in locale/C-time.c in the GNU libc.  */
293 extern const struct locale_data _nl_C_LC_TIME;
294 extern const unsigned short int __mon_yday[2][13];
295
296 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
297 # define ab_weekday_name \
298   (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
299 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
300 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
301 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
302 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
303 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
304 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
305 # define HERE_T_FMT_AMPM \
306   (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
307 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
308
309 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
310 #else
311 static char const weekday_name[][10] =
312   {
313     "Sunday", "Monday", "Tuesday", "Wednesday",
314     "Thursday", "Friday", "Saturday"
315   };
316 static char const ab_weekday_name[][4] =
317   {
318     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
319   };
320 static char const month_name[][10] =
321   {
322     "January", "February", "March", "April", "May", "June",
323     "July", "August", "September", "October", "November", "December"
324   };
325 static char const ab_month_name[][4] =
326   {
327     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
328     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
329   };
330 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
331 # define HERE_D_FMT "%m/%d/%y"
332 # define HERE_AM_STR "AM"
333 # define HERE_PM_STR "PM"
334 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
335 # define HERE_T_FMT "%H:%M:%S"
336
337 const unsigned short int __mon_yday[2][13];
338 # ifndef NEED_MON_YDAY
339 #  define NEED_MON_YDAY
340 # endif
341 #endif
342
343 /* Status of lookup: do we use the locale data or the raw data?  */
344 enum locale_status { not, loc, raw };
345
346
347 #ifndef __isleap
348 /* Nonzero if YEAR is a leap year (every 4 years,
349    except every 100th isn't, and every 400th is).  */
350 # define __isleap(year) \
351   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
352 #endif
353
354 /* Compute the day of the week.  */
355 static void
356 day_of_the_week (struct tm *tm)
357 {
358   /* We know that January 1st 1970 was a Thursday (= 4).  Compute the
359      the difference between this data in the one on TM and so determine
360      the weekday.  */
361   int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
362   int wday = (-473
363               + (365 * (tm->tm_year - 70))
364               + (corr_year / 4)
365               - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
366               + (((corr_year / 4) / 25) / 4)
367               + __mon_yday[0][tm->tm_mon]
368               + tm->tm_mday - 1);
369   tm->tm_wday = ((wday % 7) + 7) % 7;
370 }
371
372 /* Compute the day of the year.  */
373 static void
374 day_of_the_year (struct tm *tm)
375 {
376   tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
377                  + (tm->tm_mday - 1));
378 }
379
380 static char *
381 #ifdef _LIBC
382 internal_function
383 #endif
384 strptime_internal __P ((const char *buf, const char *format, struct tm *tm,
385                         enum locale_status *decided));
386
387 static char *
388 #ifdef _LIBC
389 internal_function
390 #endif
391 strptime_internal (rp, fmt, tm, decided)
392      const char *rp;
393      const char *fmt;
394      struct tm *tm;
395      enum locale_status *decided;
396 {
397 #ifdef _NL_CURRENT
398   const char *rp_backup;
399 #endif
400   int cnt;
401   size_t val;
402   int have_I, is_pm;
403   int century, want_century;
404   int have_wday, want_xday;
405   int have_yday;
406   int have_mon, have_mday;
407
408   have_I = is_pm = 0;
409   century = -1;
410   want_century = 0;
411   have_wday = want_xday = have_yday = have_mon = have_mday = 0;
412
413   while (*fmt != '\0')
414     {
415       /* A white space in the format string matches 0 more or white
416          space in the input string.  */
417       if (ISSPACE (*fmt))
418         {
419           while (ISSPACE (*rp))
420             ++rp;
421           ++fmt;
422           continue;
423         }
424
425       /* Any character but `%' must be matched by the same character
426          in the iput string.  */
427       if (*fmt != '%')
428         {
429           match_char (*fmt++, *rp++);
430           continue;
431         }
432
433       ++fmt;
434 #ifndef _NL_CURRENT
435       /* We need this for handling the `E' modifier.  */
436     start_over:
437 #endif
438
439 #ifdef _NL_CURRENT
440       /* Make back up of current processing pointer.  */
441       rp_backup = rp;
442 #endif
443
444       switch (*fmt++)
445         {
446         case '%':
447           /* Match the `%' character itself.  */
448           match_char ('%', *rp++);
449           break;
450         case 'a':
451         case 'A':
452           /* Match day of week.  */
453           for (cnt = 0; cnt < 7; ++cnt)
454             {
455 #ifdef _NL_CURRENT
456               if (*decided !=raw)
457                 {
458                   if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
459                     {
460                       if (*decided == not
461                           && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
462                                      weekday_name[cnt]))
463                         *decided = loc;
464                       break;
465                     }
466                   if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
467                     {
468                       if (*decided == not
469                           && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
470                                      ab_weekday_name[cnt]))
471                         *decided = loc;
472                       break;
473                     }
474                 }
475 #endif
476               if (*decided != loc
477                   && (match_string (weekday_name[cnt], rp)
478                       || match_string (ab_weekday_name[cnt], rp)))
479                 {
480                   *decided = raw;
481                   break;
482                 }
483             }
484           if (cnt == 7)
485             /* Does not match a weekday name.  */
486             return NULL;
487           tm->tm_wday = cnt;
488           have_wday = 1;
489           break;
490         case 'b':
491         case 'B':
492         case 'h':
493           /* Match month name.  */
494           for (cnt = 0; cnt < 12; ++cnt)
495             {
496 #ifdef _NL_CURRENT
497               if (*decided !=raw)
498                 {
499                   if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
500                     {
501                       if (*decided == not
502                           && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
503                                      month_name[cnt]))
504                         *decided = loc;
505                       break;
506                     }
507                   if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
508                     {
509                       if (*decided == not
510                           && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
511                                      ab_month_name[cnt]))
512                         *decided = loc;
513                       break;
514                     }
515                 }
516 #endif
517               if (match_string (month_name[cnt], rp)
518                   || match_string (ab_month_name[cnt], rp))
519                 {
520                   *decided = raw;
521                   break;
522                 }
523             }
524           if (cnt == 12)
525             /* Does not match a month name.  */
526             return NULL;
527           tm->tm_mon = cnt;
528           want_xday = 1;
529           break;
530         case 'c':
531           /* Match locale's date and time format.  */
532 #ifdef _NL_CURRENT
533           if (*decided != raw)
534             {
535               if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
536                 {
537                   if (*decided == loc)
538                     return NULL;
539                   else
540                     rp = rp_backup;
541                 }
542               else
543                 {
544                   if (*decided == not &&
545                       strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
546                     *decided = loc;
547                   want_xday = 1;
548                   break;
549                 }
550               *decided = raw;
551             }
552 #endif
553           if (!recursive (HERE_D_T_FMT))
554             return NULL;
555           want_xday = 1;
556           break;
557         case 'C':
558           /* Match century number.  */
559           get_number (0, 99, 2);
560           century = val;
561           want_xday = 1;
562           break;
563         case 'd':
564         case 'e':
565           /* Match day of month.  */
566           get_number (1, 31, 2);
567           tm->tm_mday = val;
568           have_mday = 1;
569           want_xday = 1;
570           break;
571         case 'F':
572           if (!recursive ("%Y-%m-%d"))
573             return NULL;
574           want_xday = 1;
575           break;
576         case 'x':
577 #ifdef _NL_CURRENT
578           if (*decided != raw)
579             {
580               if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
581                 {
582                   if (*decided == loc)
583                     return NULL;
584                   else
585                     rp = rp_backup;
586                 }
587               else
588                 {
589                   if (*decided == not
590                       && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
591                     *decided = loc;
592                   want_xday = 1;
593                   break;
594                 }
595               *decided = raw;
596             }
597 #endif
598           /* Fall through.  */
599         case 'D':
600           /* Match standard day format.  */
601           if (!recursive (HERE_D_FMT))
602             return NULL;
603           want_xday = 1;
604           break;
605         case 'k':
606         case 'H':
607           /* Match hour in 24-hour clock.  */
608           get_number (0, 23, 2);
609           tm->tm_hour = val;
610           have_I = 0;
611           break;
612         case 'I':
613           /* Match hour in 12-hour clock.  */
614           get_number (1, 12, 2);
615           tm->tm_hour = val % 12;
616           have_I = 1;
617           break;
618         case 'j':
619           /* Match day number of year.  */
620           get_number (1, 366, 3);
621           tm->tm_yday = val - 1;
622           have_yday = 1;
623           break;
624         case 'm':
625           /* Match number of month.  */
626           get_number (1, 12, 2);
627           tm->tm_mon = val - 1;
628           have_mon = 1;
629           want_xday = 1;
630           break;
631         case 'M':
632           /* Match minute.  */
633           get_number (0, 59, 2);
634           tm->tm_min = val;
635           break;
636         case 'n':
637         case 't':
638           /* Match any white space.  */
639           while (ISSPACE (*rp))
640             ++rp;
641           break;
642         case 'p':
643           /* Match locale's equivalent of AM/PM.  */
644 #ifdef _NL_CURRENT
645           if (*decided != raw)
646             {
647               if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
648                 {
649                   if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
650                     *decided = loc;
651                   break;
652                 }
653               if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
654                 {
655                   if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
656                     *decided = loc;
657                   is_pm = 1;
658                   break;
659                 }
660               *decided = raw;
661             }
662 #endif
663           if (!match_string (HERE_AM_STR, rp))
664             {
665               if (match_string (HERE_PM_STR, rp))
666                 is_pm = 1;
667               else
668                 return NULL;
669             }
670           break;
671         case 'r':
672 #ifdef _NL_CURRENT
673           if (*decided != raw)
674             {
675               if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
676                 {
677                   if (*decided == loc)
678                     return NULL;
679                   else
680                     rp = rp_backup;
681                 }
682               else
683                 {
684                   if (*decided == not &&
685                       strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
686                               HERE_T_FMT_AMPM))
687                     *decided = loc;
688                   break;
689                 }
690               *decided = raw;
691             }
692 #endif
693           if (!recursive (HERE_T_FMT_AMPM))
694             return NULL;
695           break;
696         case 'R':
697           if (!recursive ("%H:%M"))
698             return NULL;
699           break;
700         case 's':
701           {
702             /* The number of seconds may be very high so we cannot use
703                the `get_number' macro.  Instead read the number
704                character for character and construct the result while
705                doing this.  */
706             time_t secs = 0;
707             if (*rp < '0' || *rp > '9')
708               /* We need at least one digit.  */
709               return NULL;
710
711             do
712               {
713                 secs *= 10;
714                 secs += *rp++ - '0';
715               }
716             while (*rp >= '0' && *rp <= '9');
717
718             if (localtime_r (&secs, tm) == NULL)
719               /* Error in function.  */
720               return NULL;
721           }
722           break;
723         case 'S':
724           get_number (0, 61, 2);
725           tm->tm_sec = val;
726           break;
727         case 'X':
728 #ifdef _NL_CURRENT
729           if (*decided != raw)
730             {
731               if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
732                 {
733                   if (*decided == loc)
734                     return NULL;
735                   else
736                     rp = rp_backup;
737                 }
738               else
739                 {
740                   if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
741                     *decided = loc;
742                   break;
743                 }
744               *decided = raw;
745             }
746 #endif
747           /* Fall through.  */
748         case 'T':
749           if (!recursive (HERE_T_FMT))
750             return NULL;
751           break;
752         case 'u':
753           get_number (1, 7, 1);
754           tm->tm_wday = val % 7;
755           have_wday = 1;
756           break;
757         case 'g':
758           get_number (0, 99, 2);
759           /* XXX This cannot determine any field in TM.  */
760           break;
761         case 'G':
762           if (*rp < '0' || *rp > '9')
763             return NULL;
764           /* XXX Ignore the number since we would need some more
765              information to compute a real date.  */
766           do
767             ++rp;
768           while (*rp >= '0' && *rp <= '9');
769           break;
770         case 'U':
771         case 'V':
772         case 'W':
773           get_number (0, 53, 2);
774           /* XXX This cannot determine any field in TM without some
775              information.  */
776           break;
777         case 'w':
778           /* Match number of weekday.  */
779           get_number (0, 6, 1);
780           tm->tm_wday = val;
781           have_wday = 1;
782           break;
783         case 'y':
784           /* Match year within century.  */
785           get_number (0, 99, 2);
786           /* The "Year 2000: The Millennium Rollover" paper suggests that
787              values in the range 69-99 refer to the twentieth century.  */
788           tm->tm_year = val >= 69 ? val : val + 100;
789           /* Indicate that we want to use the century, if specified.  */
790           want_century = 1;
791           want_xday = 1;
792           break;
793         case 'Y':
794           /* Match year including century number.  */
795           get_number (0, 9999, 4);
796           tm->tm_year = val - 1900;
797           want_century = 0;
798           want_xday = 1;
799           break;
800         case 'Z':
801           /* XXX How to handle this?  */
802           break;
803         case 'E':
804 #ifdef _NL_CURRENT
805           switch (*fmt++)
806             {
807             case 'c':
808               /* Match locale's alternate date and time format.  */
809               if (*decided != raw)
810                 {
811                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
812
813                   if (*fmt == '\0')
814                     fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
815
816                   if (!recursive (fmt))
817                     {
818                       if (*decided == loc)
819                         return NULL;
820                       else
821                         rp = rp_backup;
822                     }
823                   else
824                     {
825                       if (strcmp (fmt, HERE_D_T_FMT))
826                         *decided = loc;
827                       want_xday = 1;
828                       break;
829                     }
830                   *decided = raw;
831                 }
832               /* The C locale has no era information, so use the
833                  normal representation.  */
834               if (!recursive (HERE_D_T_FMT))
835                 return NULL;
836               want_xday = 1;
837               break;
838             case 'C':
839             case 'y':
840             case 'Y':
841               /* Match name of base year in locale's alternate
842                  representation.  */
843               /* XXX This is currently not implemented.  It should
844                  use the value _NL_CURRENT (LC_TIME, ERA).  */
845               break;
846             case 'x':
847               if (*decided != raw)
848                 {
849                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
850
851                   if (*fmt == '\0')
852                     fmt = _NL_CURRENT (LC_TIME, D_FMT);
853
854                   if (!recursive (fmt))
855                     {
856                       if (*decided == loc)
857                         return NULL;
858                       else
859                         rp = rp_backup;
860                     }
861                   else
862                     {
863                       if (strcmp (fmt, HERE_D_FMT))
864                         *decided = loc;
865                       break;
866                     }
867                   *decided = raw;
868                 }
869               if (!recursive (HERE_D_FMT))
870                 return NULL;
871               break;
872             case 'X':
873               if (*decided != raw)
874                 {
875                   const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
876
877                   if (*fmt == '\0')
878                     fmt = _NL_CURRENT (LC_TIME, T_FMT);
879
880                   if (!recursive (fmt))
881                     {
882                       if (*decided == loc)
883                         return NULL;
884                       else
885                         rp = rp_backup;
886                     }
887                   else
888                     {
889                       if (strcmp (fmt, HERE_T_FMT))
890                         *decided = loc;
891                       break;
892                     }
893                   *decided = raw;
894                 }
895               if (!recursive (HERE_T_FMT))
896                 return NULL;
897               break;
898             default:
899               return NULL;
900             }
901           break;
902 #else
903           /* We have no information about the era format.  Just use
904              the normal format.  */
905           if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
906               && *fmt != 'x' && *fmt != 'X')
907             /* This is an illegal format.  */
908             return NULL;
909
910           goto start_over;
911 #endif
912         case 'O':
913           switch (*fmt++)
914             {
915             case 'd':
916             case 'e':
917               /* Match day of month using alternate numeric symbols.  */
918               get_alt_number (1, 31, 2);
919               tm->tm_mday = val;
920               have_mday = 1;
921               want_xday = 1;
922               break;
923             case 'H':
924               /* Match hour in 24-hour clock using alternate numeric
925                  symbols.  */
926               get_alt_number (0, 23, 2);
927               tm->tm_hour = val;
928               have_I = 0;
929               break;
930             case 'I':
931               /* Match hour in 12-hour clock using alternate numeric
932                  symbols.  */
933               get_alt_number (1, 12, 2);
934               tm->tm_hour = val - 1;
935               have_I = 1;
936               break;
937             case 'm':
938               /* Match month using alternate numeric symbols.  */
939               get_alt_number (1, 12, 2);
940               tm->tm_mon = val - 1;
941               have_mon = 1;
942               want_xday = 1;
943               break;
944             case 'M':
945               /* Match minutes using alternate numeric symbols.  */
946               get_alt_number (0, 59, 2);
947               tm->tm_min = val;
948               break;
949             case 'S':
950               /* Match seconds using alternate numeric symbols.  */
951               get_alt_number (0, 61, 2);
952               tm->tm_sec = val;
953               break;
954             case 'U':
955             case 'V':
956             case 'W':
957               get_alt_number (0, 53, 2);
958               /* XXX This cannot determine any field in TM without
959                  further information.  */
960               break;
961             case 'w':
962               /* Match number of weekday using alternate numeric symbols.  */
963               get_alt_number (0, 6, 1);
964               tm->tm_wday = val;
965               have_wday = 1;
966               break;
967             case 'y':
968               /* Match year within century using alternate numeric symbols.  */
969               get_alt_number (0, 99, 2);
970               tm->tm_year = val >= 69 ? val : val + 100;
971               want_xday = 1;
972               break;
973             default:
974               return NULL;
975             }
976           break;
977         default:
978           return NULL;
979         }
980     }
981
982   if (have_I && is_pm)
983     tm->tm_hour += 12;
984
985   if (century != -1)
986     {
987       if (want_century)
988         tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
989       else
990         /* Only the century, but not the year.  Strange, but so be it.  */
991         tm->tm_year = (century - 19) * 100;
992     }
993
994   if (want_xday && !have_wday) {
995       if ( !(have_mon && have_mday) && have_yday)  {
996           /* we don't have tm_mon and/or tm_mday, compute them */
997           int t_mon = 0;
998           while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
999               t_mon++;
1000           if (!have_mon)
1001               tm->tm_mon = t_mon - 1;
1002           if (!have_mday)
1003               tm->tm_mday = tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1;
1004       }
1005       day_of_the_week (tm);
1006   }
1007   if (want_xday && !have_yday)
1008     day_of_the_year (tm);
1009
1010   return (char *) rp;
1011 }
1012
1013
1014 char *
1015 strptime (buf, format, tm)
1016      const char *buf;
1017      const char *format;
1018      struct tm *tm;
1019 {
1020   enum locale_status decided;
1021 #ifdef _NL_CURRENT
1022   decided = not;
1023 #else
1024   decided = raw;
1025 #endif
1026   return strptime_internal (buf, format, tm, &decided);
1027 }
1028 #endif /* not HAVE_STRPTIME */
1029
1030 #ifdef NEED_MON_YDAY
1031 const unsigned short int __mon_yday[2][13] =
1032   {
1033     /* Normal years.  */
1034     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
1035     /* Leap years.  */
1036     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
1037   };
1038 #endif
1039 \f
1040 /* fnmatch is required by POSIX, but we include an implementation for
1041    the sake of systems that don't have it, most notably Windows.  Some
1042    systems do have fnmatch, but Apache's installation process installs
1043    its own fnmatch.h (incompatible with the system one!) in a system
1044    include directory, effectively rendering fnmatch unusable.  This
1045    has been fixed with Apache 2, where fnmatch has been moved to apr
1046    and given a prefix, but many systems out there are still (as of
1047    this writing in 2005) broken and we must cater to them.
1048
1049    Additionally, according to some conventional, many historical
1050    implementations of fnmatch are buggy and unreliable.  If yours is
1051    such, undefine SYSTEM_FNMATCH in sysdep.h and tell us about it.  */
1052
1053 #ifndef SYSTEM_FNMATCH
1054
1055 #define __FNM_FLAGS     (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD)
1056
1057 /* Match STRING against the filename pattern PATTERN, returning zero
1058    if it matches, FNM_NOMATCH if not.  This implementation comes from
1059    an earlier version of GNU Bash.  (It doesn't make sense to update
1060    it with a newer version because those versions add a lot of
1061    features Wget doesn't use or care about.)  */
1062
1063 int
1064 fnmatch (const char *pattern, const char *string, int flags)
1065 {
1066   register const char *p = pattern, *n = string;
1067   register char c;
1068
1069   if ((flags & ~__FNM_FLAGS) != 0)
1070     {
1071       errno = EINVAL;
1072       return (-1);
1073     }
1074
1075   while ((c = *p++) != '\0')
1076     {
1077       switch (c)
1078         {
1079         case '?':
1080           if (*n == '\0')
1081             return (FNM_NOMATCH);
1082           else if ((flags & FNM_PATHNAME) && *n == '/')
1083             return (FNM_NOMATCH);
1084           else if ((flags & FNM_PERIOD) && *n == '.' &&
1085                    (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
1086             return (FNM_NOMATCH);
1087           break;
1088
1089         case '\\':
1090           if (!(flags & FNM_NOESCAPE))
1091             c = *p++;
1092           if (*n != c)
1093             return (FNM_NOMATCH);
1094           break;
1095
1096         case '*':
1097           if ((flags & FNM_PERIOD) && *n == '.' &&
1098               (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
1099             return (FNM_NOMATCH);
1100
1101           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
1102             if (((flags & FNM_PATHNAME) && *n == '/') ||
1103                 (c == '?' && *n == '\0'))
1104               return (FNM_NOMATCH);
1105
1106           if (c == '\0')
1107             return (0);
1108
1109           {
1110             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
1111             for (--p; *n != '\0'; ++n)
1112               if ((c == '[' || *n == c1) &&
1113                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
1114                 return (0);
1115             return (FNM_NOMATCH);
1116           }
1117
1118         case '[':
1119           {
1120             /* Nonzero if the sense of the character class is
1121                inverted.  */
1122             register int not;
1123
1124             if (*n == '\0')
1125               return (FNM_NOMATCH);
1126
1127             if ((flags & FNM_PERIOD) && *n == '.' &&
1128                 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
1129               return (FNM_NOMATCH);
1130
1131             /* Make sure there is a closing `]'.  If there isn't,
1132                the `[' is just a character to be matched.  */
1133             {
1134               register const char *np;
1135
1136               for (np = p; np && *np && *np != ']'; np++);
1137
1138               if (np && !*np)
1139                 {
1140                   if (*n != '[')
1141                     return (FNM_NOMATCH);
1142                   goto next_char;
1143                 }
1144             }
1145
1146             not = (*p == '!' || *p == '^');
1147             if (not)
1148               ++p;
1149
1150             c = *p++;
1151             while (1)
1152               {
1153                 register char cstart = c, cend = c;
1154
1155                 if (!(flags & FNM_NOESCAPE) && c == '\\')
1156                   cstart = cend = *p++;
1157
1158                 if (c == '\0')
1159                   /* [ (unterminated) loses.  */
1160                   return (FNM_NOMATCH);
1161
1162                 c = *p++;
1163
1164                 if ((flags & FNM_PATHNAME) && c == '/')
1165                   /* [/] can never match.  */
1166                   return (FNM_NOMATCH);
1167
1168                 if (c == '-' && *p != ']')
1169                   {
1170                     cend = *p++;
1171                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
1172                       cend = *p++;
1173                     if (cend == '\0')
1174                       return (FNM_NOMATCH);
1175                     c = *p++;
1176                   }
1177
1178                 if (*n >= cstart && *n <= cend)
1179                   goto matched;
1180
1181                 if (c == ']')
1182                   break;
1183               }
1184             if (!not)
1185               return (FNM_NOMATCH);
1186
1187           next_char:
1188             break;
1189
1190           matched:
1191             /* Skip the rest of the [...] that already matched.  */
1192             while (c != ']')
1193               {
1194                 if (c == '\0')
1195                   /* [... (unterminated) loses.  */
1196                   return (FNM_NOMATCH);
1197
1198                 c = *p++;
1199                 if (!(flags & FNM_NOESCAPE) && c == '\\')
1200                   /* 1003.2d11 is unclear if this is right.  %%% */
1201                   ++p;
1202               }
1203             if (not)
1204               return (FNM_NOMATCH);
1205           }
1206           break;
1207
1208         default:
1209           if (c != *n)
1210             return (FNM_NOMATCH);
1211         }
1212
1213       ++n;
1214     }
1215
1216   if (*n == '\0')
1217     return (0);
1218
1219   return (FNM_NOMATCH);
1220 }
1221
1222 #endif /* not SYSTEM_FNMATCH */
1223 \f
1224 #ifndef HAVE_TIMEGM
1225 /* timegm is a GNU extension, but lately also available on *BSD and
1226    possibly elsewhere. */
1227
1228 /* True if YEAR is a leap year. */
1229 #define ISLEAP(year)                                            \
1230   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
1231
1232 /* Number of leap years in the range [y1, y2). */
1233 #define LEAPYEARS(y1, y2)                                               \
1234   ((y2-1)/4 - (y1-1)/4) - ((y2-1)/100 - (y1-1)/100) + ((y2-1)/400 - (y1-1)/400)
1235
1236 /* Inverse of gmtime: converts struct tm to time_t, assuming the data
1237    in tm is UTC rather than local timezone.  This implementation
1238    returns the number of seconds elapsed since midnight 1970-01-01,
1239    converted to time_t.  */
1240
1241 time_t
1242 timegm (struct tm *t)
1243 {
1244   static const unsigned short int month_to_days[][13] = {
1245     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, /* normal */
1246     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }  /* leap */
1247   };
1248   const int year = 1900 + t->tm_year;
1249   unsigned long secs;  /* until 2106-02-07 for 32-bit unsigned long */
1250   int days;
1251
1252   if (year < 1970)
1253     return (time_t) -1;
1254
1255   days = 365 * (year - 1970);
1256   /* Take into account leap years between 1970 and YEAR, not counting
1257      YEAR itself.  */
1258   days += LEAPYEARS (1970, year);
1259   if (t->tm_mon < 0 || t->tm_mon >= 12)
1260     return (time_t) -1;
1261   days += month_to_days[ISLEAP (year)][t->tm_mon];
1262   days += t->tm_mday - 1;
1263
1264   secs = days * 86400 + t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec;
1265   return (time_t) secs;
1266 }
1267 #endif /* HAVE_TIMEGM */