1 /* Replacements for routines missing on some systems.
2 Copyright (C) 1995-2005 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
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.
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.
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.
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. */
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
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. */
59 #ifndef HAVE_STRCASECMP
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. */
65 strcasecmp (const char *s1, const char *s2)
67 register const unsigned char *p1 = (const unsigned char *) s1;
68 register const unsigned char *p2 = (const unsigned char *) s2;
85 #endif /* not HAVE_STRCASECMP */
87 #ifndef HAVE_STRNCASECMP
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. */
94 strncasecmp (const char *s1, const char *s2, size_t n)
96 register const unsigned char *p1 = (const unsigned char *) s1;
97 register const unsigned char *p2 = (const unsigned char *) s2;
100 if (p1 == p2 || n == 0)
105 c1 = TOLOWER (*p1++);
106 c2 = TOLOWER (*p2++);
107 if (c1 == '\0' || c1 != c2)
113 #endif /* not HAVE_STRNCASECMP */
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. */
119 #ifndef HAVE_STRPTIME
120 /* From GNU libc 2.1.3. */
121 /* Ulrich, thanks for helping me out with this! --hniksic */
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. */
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. */
134 # define __P(args) args
137 #if ! HAVE_LOCALTIME_R && ! defined localtime_r
139 # define localtime_r __localtime_r
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 *));
149 struct tm *l = localtime (t);
155 # endif /* ! _LIBC */
156 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
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; \
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))
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) \
179 if (*rp < '0' || *rp > '9') \
183 val += *rp++ - '0'; \
184 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
185 if (val < from || val > to) \
189 /* Added check for __GNUC__ extensions here for Wget. --abbotti */
190 # if defined __GNUC__ && __GNUC__ >= 2
191 # define get_alt_number(from, to, n) \
193 __label__ do_normal; \
194 if (*decided != raw) \
196 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
204 while (*alts != '\0') \
206 size_t len = strlen (alts); \
207 if (strncasecmp (alts, rp, len) == 0) \
214 if (*decided == not && ! any) \
216 /* If we haven't read anything it's an error. */ \
219 /* Correct the premature multiplication. */ \
225 } while (--__n > 0 && val * 10 <= to); \
226 if (val < from || val > to) \
232 get_number (from, to, n); \
237 # define get_alt_number(from, to, n) \
239 if (*decided != raw) \
241 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
249 while (*alts != '\0') \
251 size_t len = strlen (alts); \
252 if (strncasecmp (alts, rp, len) == 0) \
259 if (*decided == not && ! any) \
261 /* If we haven't read anything it's an error. */ \
264 /* Correct the premature multiplication. */ \
270 } while (--__n > 0 && val * 10 <= to); \
271 if (val < from || val > to) \
277 get_number (from, to, n); \
280 # endif /* defined __GNUC__ && __GNUC__ >= 2 */
282 # define get_alt_number(from, to, n) \
283 /* We don't have the alternate representation. */ \
284 get_number(from, to, n)
286 #define recursive(new_fmt) \
287 (*(new_fmt) != '\0' \
288 && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)
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];
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)
309 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
311 static char const weekday_name[][10] =
313 "Sunday", "Monday", "Tuesday", "Wednesday",
314 "Thursday", "Friday", "Saturday"
316 static char const ab_weekday_name[][4] =
318 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
320 static char const month_name[][10] =
322 "January", "February", "March", "April", "May", "June",
323 "July", "August", "September", "October", "November", "December"
325 static char const ab_month_name[][4] =
327 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
328 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
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"
337 const unsigned short int __mon_yday[2][13];
338 # ifndef NEED_MON_YDAY
339 # define NEED_MON_YDAY
343 /* Status of lookup: do we use the locale data or the raw data? */
344 enum locale_status { not, loc, raw };
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))
354 /* Compute the day of the week. */
356 day_of_the_week (struct tm *tm)
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
361 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
363 + (365 * (tm->tm_year - 70))
365 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
366 + (((corr_year / 4) / 25) / 4)
367 + __mon_yday[0][tm->tm_mon]
369 tm->tm_wday = ((wday % 7) + 7) % 7;
372 /* Compute the day of the year. */
374 day_of_the_year (struct tm *tm)
376 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
377 + (tm->tm_mday - 1));
384 strptime_internal __P ((const char *buf, const char *format, struct tm *tm,
385 enum locale_status *decided));
391 strptime_internal (rp, fmt, tm, decided)
395 enum locale_status *decided;
398 const char *rp_backup;
403 int century, want_century;
404 int have_wday, want_xday;
406 int have_mon, have_mday;
411 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
415 /* A white space in the format string matches 0 more or white
416 space in the input string. */
419 while (ISSPACE (*rp))
425 /* Any character but `%' must be matched by the same character
426 in the iput string. */
429 match_char (*fmt++, *rp++);
435 /* We need this for handling the `E' modifier. */
440 /* Make back up of current processing pointer. */
447 /* Match the `%' character itself. */
448 match_char ('%', *rp++);
452 /* Match day of week. */
453 for (cnt = 0; cnt < 7; ++cnt)
458 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
461 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
466 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
469 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
470 ab_weekday_name[cnt]))
477 && (match_string (weekday_name[cnt], rp)
478 || match_string (ab_weekday_name[cnt], rp)))
485 /* Does not match a weekday name. */
493 /* Match month name. */
494 for (cnt = 0; cnt < 12; ++cnt)
499 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
502 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
507 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
510 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
517 if (match_string (month_name[cnt], rp)
518 || match_string (ab_month_name[cnt], rp))
525 /* Does not match a month name. */
531 /* Match locale's date and time format. */
535 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
544 if (*decided == not &&
545 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
553 if (!recursive (HERE_D_T_FMT))
558 /* Match century number. */
559 get_number (0, 99, 2);
565 /* Match day of month. */
566 get_number (1, 31, 2);
572 if (!recursive ("%Y-%m-%d"))
580 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
590 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
600 /* Match standard day format. */
601 if (!recursive (HERE_D_FMT))
607 /* Match hour in 24-hour clock. */
608 get_number (0, 23, 2);
613 /* Match hour in 12-hour clock. */
614 get_number (1, 12, 2);
615 tm->tm_hour = val % 12;
619 /* Match day number of year. */
620 get_number (1, 366, 3);
621 tm->tm_yday = val - 1;
625 /* Match number of month. */
626 get_number (1, 12, 2);
627 tm->tm_mon = val - 1;
633 get_number (0, 59, 2);
638 /* Match any white space. */
639 while (ISSPACE (*rp))
643 /* Match locale's equivalent of AM/PM. */
647 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
649 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
653 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
655 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
663 if (!match_string (HERE_AM_STR, rp))
665 if (match_string (HERE_PM_STR, rp))
675 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
684 if (*decided == not &&
685 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
693 if (!recursive (HERE_T_FMT_AMPM))
697 if (!recursive ("%H:%M"))
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
707 if (*rp < '0' || *rp > '9')
708 /* We need at least one digit. */
716 while (*rp >= '0' && *rp <= '9');
718 if (localtime_r (&secs, tm) == NULL)
719 /* Error in function. */
724 get_number (0, 61, 2);
731 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
740 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
749 if (!recursive (HERE_T_FMT))
753 get_number (1, 7, 1);
754 tm->tm_wday = val % 7;
758 get_number (0, 99, 2);
759 /* XXX This cannot determine any field in TM. */
762 if (*rp < '0' || *rp > '9')
764 /* XXX Ignore the number since we would need some more
765 information to compute a real date. */
768 while (*rp >= '0' && *rp <= '9');
773 get_number (0, 53, 2);
774 /* XXX This cannot determine any field in TM without some
778 /* Match number of weekday. */
779 get_number (0, 6, 1);
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. */
794 /* Match year including century number. */
795 get_number (0, 9999, 4);
796 tm->tm_year = val - 1900;
801 /* XXX How to handle this? */
808 /* Match locale's alternate date and time format. */
811 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
814 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
816 if (!recursive (fmt))
825 if (strcmp (fmt, HERE_D_T_FMT))
832 /* The C locale has no era information, so use the
833 normal representation. */
834 if (!recursive (HERE_D_T_FMT))
841 /* Match name of base year in locale's alternate
843 /* XXX This is currently not implemented. It should
844 use the value _NL_CURRENT (LC_TIME, ERA). */
849 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
852 fmt = _NL_CURRENT (LC_TIME, D_FMT);
854 if (!recursive (fmt))
863 if (strcmp (fmt, HERE_D_FMT))
869 if (!recursive (HERE_D_FMT))
875 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
878 fmt = _NL_CURRENT (LC_TIME, T_FMT);
880 if (!recursive (fmt))
889 if (strcmp (fmt, HERE_T_FMT))
895 if (!recursive (HERE_T_FMT))
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. */
917 /* Match day of month using alternate numeric symbols. */
918 get_alt_number (1, 31, 2);
924 /* Match hour in 24-hour clock using alternate numeric
926 get_alt_number (0, 23, 2);
931 /* Match hour in 12-hour clock using alternate numeric
933 get_alt_number (1, 12, 2);
934 tm->tm_hour = val - 1;
938 /* Match month using alternate numeric symbols. */
939 get_alt_number (1, 12, 2);
940 tm->tm_mon = val - 1;
945 /* Match minutes using alternate numeric symbols. */
946 get_alt_number (0, 59, 2);
950 /* Match seconds using alternate numeric symbols. */
951 get_alt_number (0, 61, 2);
957 get_alt_number (0, 53, 2);
958 /* XXX This cannot determine any field in TM without
959 further information. */
962 /* Match number of weekday using alternate numeric symbols. */
963 get_alt_number (0, 6, 1);
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;
988 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
990 /* Only the century, but not the year. Strange, but so be it. */
991 tm->tm_year = (century - 19) * 100;
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 */
998 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1001 tm->tm_mon = t_mon - 1;
1003 tm->tm_mday = tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1;
1005 day_of_the_week (tm);
1007 if (want_xday && !have_yday)
1008 day_of_the_year (tm);
1015 strptime (buf, format, tm)
1020 enum locale_status decided;
1026 return strptime_internal (buf, format, tm, &decided);
1028 #endif /* not HAVE_STRPTIME */
1030 #ifdef NEED_MON_YDAY
1031 const unsigned short int __mon_yday[2][13] =
1034 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
1036 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
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.
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. */
1053 #ifndef SYSTEM_FNMATCH
1055 #define __FNM_FLAGS (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD)
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.) */
1064 fnmatch (const char *pattern, const char *string, int flags)
1066 register const char *p = pattern, *n = string;
1069 if ((flags & ~__FNM_FLAGS) != 0)
1075 while ((c = *p++) != '\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);
1090 if (!(flags & FNM_NOESCAPE))
1093 return (FNM_NOMATCH);
1097 if ((flags & FNM_PERIOD) && *n == '.' &&
1098 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
1099 return (FNM_NOMATCH);
1101 for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
1102 if (((flags & FNM_PATHNAME) && *n == '/') ||
1103 (c == '?' && *n == '\0'))
1104 return (FNM_NOMATCH);
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)
1115 return (FNM_NOMATCH);
1120 /* Nonzero if the sense of the character class is
1125 return (FNM_NOMATCH);
1127 if ((flags & FNM_PERIOD) && *n == '.' &&
1128 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
1129 return (FNM_NOMATCH);
1131 /* Make sure there is a closing `]'. If there isn't,
1132 the `[' is just a character to be matched. */
1134 register const char *np;
1136 for (np = p; np && *np && *np != ']'; np++);
1141 return (FNM_NOMATCH);
1146 not = (*p == '!' || *p == '^');
1153 register char cstart = c, cend = c;
1155 if (!(flags & FNM_NOESCAPE) && c == '\\')
1156 cstart = cend = *p++;
1159 /* [ (unterminated) loses. */
1160 return (FNM_NOMATCH);
1164 if ((flags & FNM_PATHNAME) && c == '/')
1165 /* [/] can never match. */
1166 return (FNM_NOMATCH);
1168 if (c == '-' && *p != ']')
1171 if (!(flags & FNM_NOESCAPE) && cend == '\\')
1174 return (FNM_NOMATCH);
1178 if (*n >= cstart && *n <= cend)
1185 return (FNM_NOMATCH);
1191 /* Skip the rest of the [...] that already matched. */
1195 /* [... (unterminated) loses. */
1196 return (FNM_NOMATCH);
1199 if (!(flags & FNM_NOESCAPE) && c == '\\')
1200 /* 1003.2d11 is unclear if this is right. %%% */
1204 return (FNM_NOMATCH);
1210 return (FNM_NOMATCH);
1219 return (FNM_NOMATCH);
1222 #endif /* not SYSTEM_FNMATCH */
1225 /* timegm is a GNU extension, but lately also available on *BSD and
1226 possibly elsewhere. */
1228 /* Inverse of gmtime: converts struct tm to time_t, assuming the data
1229 in tm is UTC rather than local timezone.
1231 mktime is similar but assumes struct tm, also known as the
1232 "broken-down" form of time, is in local time zone. This
1233 implementation of timegm uses mktime to make the conversion
1234 understanding that an offset will be introduced by the local time
1237 It then measures the introduced offset by applying gmtime to the
1238 initial result and applying mktime to the resulting "broken-down"
1239 form. The difference between the two mktime results is the
1240 measured offset which is then subtracted from the initial mktime
1241 result to yield a calendar time which is the value returned.
1243 tm_isdst in struct tm is set to 0 to force mktime to introduce a
1244 consistent offset (the non DST offset) since tm and tm+o might be
1245 on opposite sides of a DST change.
1247 Some implementations of mktime return -1 for the nonexistent
1248 localtime hour at the beginning of DST. In this event, use
1249 mktime(tm - 1hr) + 3600.
1253 gmtime(t+o) --> tm+o
1254 mktime(tm+o) --> t+2o
1255 t+o - (t+2o - t+o) = t
1257 Contributed by Roger Beeman, with the help of Mark Baushke and
1258 other experts at CISCO. Further improved by Roger with assistance
1259 from Edward J. Sabol based on input by Jamie Zawinski. */
1262 timegm (struct tm *t)
1273 return -1; /* can't deal with contents of T */
1284 return -1; /* can't deal with output from gmtime */
1287 return (tl - (tb - tl));
1289 #endif /* HAVE_TIMEGM */