125846b40Smckusick /*
2bac379f5Sbostic * Copyright (c) 1987, 1989, 1993
3bac379f5Sbostic * The Regents of the University of California. All rights reserved.
40f8ac513Sbostic *
5da242259Sbostic * This code is derived from software contributed to Berkeley by
69c5a654fSbostic * Arthur David Olson of the National Cancer Institute.
7da242259Sbostic *
87311dd13Sbostic * %sccs.include.redist.c%
925846b40Smckusick */
1025846b40Smckusick
11f2f33c31Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*a9452ba1Sbostic static char sccsid[] = "@(#)ctime.c 8.2 (Berkeley) 03/20/94";
130f8ac513Sbostic #endif /* LIBC_SCCS and not lint */
1425846b40Smckusick
1542802380Swnj /*
163d2a30d4Sbostic ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
173d2a30d4Sbostic ** POSIX-style TZ environment variable handling from Guy Harris
183d2a30d4Sbostic ** (guy@auspex.com).
1942802380Swnj */
2042802380Swnj
213d2a30d4Sbostic /*LINTLIBRARY*/
2242802380Swnj
233d2a30d4Sbostic #include <sys/param.h>
243d2a30d4Sbostic #include <fcntl.h>
253d2a30d4Sbostic #include <time.h>
263d2a30d4Sbostic #include <tzfile.h>
273d2a30d4Sbostic #include <string.h>
283d2a30d4Sbostic #include <ctype.h>
293d2a30d4Sbostic #include <stdio.h>
30ae227ee3Sdonn #include <unistd.h>
313d2a30d4Sbostic
323d2a30d4Sbostic #ifdef __STDC__
333d2a30d4Sbostic #include <stdlib.h>
343d2a30d4Sbostic
353d2a30d4Sbostic #define P(s) s
363d2a30d4Sbostic #define alloc_size_t size_t
373d2a30d4Sbostic #define qsort_size_t size_t
383d2a30d4Sbostic #define fread_size_t size_t
393d2a30d4Sbostic #define fwrite_size_t size_t
403d2a30d4Sbostic
413d2a30d4Sbostic #else /* !defined __STDC__ */
423d2a30d4Sbostic
43cad6ce04Sbostic #define P(s) ()
443d2a30d4Sbostic
453d2a30d4Sbostic typedef char * genericptr_t;
463d2a30d4Sbostic typedef unsigned alloc_size_t;
473d2a30d4Sbostic typedef int qsort_size_t;
483d2a30d4Sbostic typedef int fread_size_t;
493d2a30d4Sbostic typedef int fwrite_size_t;
503d2a30d4Sbostic
513d2a30d4Sbostic extern char * calloc();
523d2a30d4Sbostic extern char * malloc();
533d2a30d4Sbostic extern char * realloc();
543d2a30d4Sbostic extern char * getenv();
553d2a30d4Sbostic
563d2a30d4Sbostic #endif /* !defined __STDC__ */
573d2a30d4Sbostic
583d2a30d4Sbostic extern time_t time();
593d2a30d4Sbostic
603d2a30d4Sbostic #define ACCESS_MODE O_RDONLY
613d2a30d4Sbostic #define OPEN_MODE O_RDONLY
623d2a30d4Sbostic
633d2a30d4Sbostic #ifndef WILDABBR
643d2a30d4Sbostic /*
653d2a30d4Sbostic ** Someone might make incorrect use of a time zone abbreviation:
663d2a30d4Sbostic ** 1. They might reference tzname[0] before calling tzset (explicitly
673d2a30d4Sbostic ** or implicitly).
683d2a30d4Sbostic ** 2. They might reference tzname[1] before calling tzset (explicitly
693d2a30d4Sbostic ** or implicitly).
703d2a30d4Sbostic ** 3. They might reference tzname[1] after setting to a time zone
713d2a30d4Sbostic ** in which Daylight Saving Time is never observed.
723d2a30d4Sbostic ** 4. They might reference tzname[0] after setting to a time zone
733d2a30d4Sbostic ** in which Standard Time is never observed.
743d2a30d4Sbostic ** 5. They might reference tm.TM_ZONE after calling offtime.
753d2a30d4Sbostic ** What's best to do in the above cases is open to debate;
763d2a30d4Sbostic ** for now, we just set things up so that in any of the five cases
773d2a30d4Sbostic ** WILDABBR is used. Another possibility: initialize tzname[0] to the
783d2a30d4Sbostic ** string "tzname[0] used before set", and similarly for the other cases.
793d2a30d4Sbostic ** And another: initialize tzname[0] to "ERA", with an explanation in the
803d2a30d4Sbostic ** manual page of what this "time zone abbreviation" means (doing this so
813d2a30d4Sbostic ** that tzname[0] has the "normal" length of three characters).
823d2a30d4Sbostic */
833d2a30d4Sbostic #define WILDABBR " "
843d2a30d4Sbostic #endif /* !defined WILDABBR */
8542802380Swnj
86839b9482Sbostic #ifndef TRUE
87839b9482Sbostic #define TRUE 1
88839b9482Sbostic #define FALSE 0
893d2a30d4Sbostic #endif /* !defined TRUE */
90839b9482Sbostic
913d2a30d4Sbostic static const char GMT[] = "GMT";
92839b9482Sbostic
93839b9482Sbostic struct ttinfo { /* time type information */
94839b9482Sbostic long tt_gmtoff; /* GMT offset in seconds */
95839b9482Sbostic int tt_isdst; /* used to set tm_isdst */
96839b9482Sbostic int tt_abbrind; /* abbreviation list index */
973d2a30d4Sbostic int tt_ttisstd; /* TRUE if transition is std time */
983d2a30d4Sbostic };
993d2a30d4Sbostic
1003d2a30d4Sbostic struct lsinfo { /* leap second information */
1013d2a30d4Sbostic time_t ls_trans; /* transition time */
1023d2a30d4Sbostic long ls_corr; /* correction to apply */
103839b9482Sbostic };
104839b9482Sbostic
105839b9482Sbostic struct state {
1063d2a30d4Sbostic int leapcnt;
107839b9482Sbostic int timecnt;
108839b9482Sbostic int typecnt;
109839b9482Sbostic int charcnt;
110839b9482Sbostic time_t ats[TZ_MAX_TIMES];
111839b9482Sbostic unsigned char types[TZ_MAX_TIMES];
112839b9482Sbostic struct ttinfo ttis[TZ_MAX_TYPES];
1133d2a30d4Sbostic char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
1143d2a30d4Sbostic TZ_MAX_CHARS + 1 : sizeof GMT];
1153d2a30d4Sbostic struct lsinfo lsis[TZ_MAX_LEAPS];
116839b9482Sbostic };
117839b9482Sbostic
1183d2a30d4Sbostic struct rule {
1193d2a30d4Sbostic int r_type; /* type of rule--see below */
1203d2a30d4Sbostic int r_day; /* day number of rule */
1213d2a30d4Sbostic int r_week; /* week number of rule */
1223d2a30d4Sbostic int r_mon; /* month number of rule */
1233d2a30d4Sbostic long r_time; /* transition time of rule */
1243d2a30d4Sbostic };
125839b9482Sbostic
1263d2a30d4Sbostic #define JULIAN_DAY 0 /* Jn - Julian day */
1273d2a30d4Sbostic #define DAY_OF_YEAR 1 /* n - day of year */
1283d2a30d4Sbostic #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
1293d2a30d4Sbostic
1303d2a30d4Sbostic /*
1313d2a30d4Sbostic ** Prototypes for static functions.
1323d2a30d4Sbostic */
1333d2a30d4Sbostic
1343d2a30d4Sbostic static long detzcode P((const char * codep));
1353d2a30d4Sbostic static const char * getzname P((const char * strp));
1363d2a30d4Sbostic static const char * getnum P((const char * strp, int * nump, int min,
1373d2a30d4Sbostic int max));
1383d2a30d4Sbostic static const char * getsecs P((const char * strp, long * secsp));
1393d2a30d4Sbostic static const char * getoffset P((const char * strp, long * offsetp));
1403d2a30d4Sbostic static const char * getrule P((const char * strp, struct rule * rulep));
1413d2a30d4Sbostic static void gmtload P((struct state * sp));
1423d2a30d4Sbostic static void gmtsub P((const time_t * timep, long offset,
1433d2a30d4Sbostic struct tm * tmp));
1443d2a30d4Sbostic static void localsub P((const time_t * timep, long offset,
1453d2a30d4Sbostic struct tm * tmp));
1463d2a30d4Sbostic static void normalize P((int * tensptr, int * unitsptr, int base));
1473d2a30d4Sbostic static void settzname P((void));
1483d2a30d4Sbostic static time_t time1 P((struct tm * tmp, void (* funcp)(),
1493d2a30d4Sbostic long offset));
1503d2a30d4Sbostic static time_t time2 P((struct tm *tmp, void (* funcp)(),
1513d2a30d4Sbostic long offset, int * okayp));
1523d2a30d4Sbostic static void timesub P((const time_t * timep, long offset,
1533d2a30d4Sbostic const struct state * sp, struct tm * tmp));
1543d2a30d4Sbostic static int tmcomp P((const struct tm * atmp,
1553d2a30d4Sbostic const struct tm * btmp));
1563d2a30d4Sbostic static time_t transtime P((time_t janfirst, int year,
1573d2a30d4Sbostic const struct rule * rulep, long offset));
1583d2a30d4Sbostic static int tzload P((const char * name, struct state * sp));
1593d2a30d4Sbostic static int tzparse P((const char * name, struct state * sp,
1603d2a30d4Sbostic int lastditch));
1613d2a30d4Sbostic
1623d2a30d4Sbostic #ifdef ALL_STATE
1633d2a30d4Sbostic static struct state * lclptr;
1643d2a30d4Sbostic static struct state * gmtptr;
1653d2a30d4Sbostic #endif /* defined ALL_STATE */
1663d2a30d4Sbostic
1673d2a30d4Sbostic #ifndef ALL_STATE
1683d2a30d4Sbostic static struct state lclmem;
1693d2a30d4Sbostic static struct state gmtmem;
1703d2a30d4Sbostic #define lclptr (&lclmem)
1713d2a30d4Sbostic #define gmtptr (&gmtmem)
1723d2a30d4Sbostic #endif /* State Farm */
1733d2a30d4Sbostic
1743d2a30d4Sbostic static int lcl_is_set;
1753d2a30d4Sbostic static int gmt_is_set;
176839b9482Sbostic
177839b9482Sbostic char * tzname[2] = {
1783d2a30d4Sbostic WILDABBR,
1793d2a30d4Sbostic WILDABBR
180839b9482Sbostic };
181839b9482Sbostic
182839b9482Sbostic #ifdef USG_COMPAT
183839b9482Sbostic time_t timezone = 0;
184839b9482Sbostic int daylight = 0;
1853d2a30d4Sbostic #endif /* defined USG_COMPAT */
1863d2a30d4Sbostic
1873d2a30d4Sbostic #ifdef ALTZONE
1883d2a30d4Sbostic time_t altzone = 0;
1893d2a30d4Sbostic #endif /* defined ALTZONE */
190839b9482Sbostic
191839b9482Sbostic static long
detzcode(codep)192839b9482Sbostic detzcode(codep)
1933d2a30d4Sbostic const char * const codep;
19442802380Swnj {
195839b9482Sbostic register long result;
196839b9482Sbostic register int i;
197839b9482Sbostic
198839b9482Sbostic result = 0;
199839b9482Sbostic for (i = 0; i < 4; ++i)
200839b9482Sbostic result = (result << 8) | (codep[i] & 0xff);
201839b9482Sbostic return result;
20242802380Swnj }
20342802380Swnj
2043d2a30d4Sbostic static void
settzname()2053d2a30d4Sbostic settzname()
20642802380Swnj {
2073d2a30d4Sbostic register const struct state * const sp = lclptr;
2083d2a30d4Sbostic register int i;
2093d2a30d4Sbostic
2103d2a30d4Sbostic tzname[0] = WILDABBR;
2113d2a30d4Sbostic tzname[1] = WILDABBR;
2123d2a30d4Sbostic #ifdef USG_COMPAT
2133d2a30d4Sbostic daylight = 0;
2143d2a30d4Sbostic timezone = 0;
2153d2a30d4Sbostic #endif /* defined USG_COMPAT */
2163d2a30d4Sbostic #ifdef ALTZONE
2173d2a30d4Sbostic altzone = 0;
2183d2a30d4Sbostic #endif /* defined ALTZONE */
2193d2a30d4Sbostic #ifdef ALL_STATE
2203d2a30d4Sbostic if (sp == NULL) {
2213d2a30d4Sbostic tzname[0] = tzname[1] = GMT;
2223d2a30d4Sbostic return;
2233d2a30d4Sbostic }
2243d2a30d4Sbostic #endif /* defined ALL_STATE */
2253d2a30d4Sbostic for (i = 0; i < sp->typecnt; ++i) {
2263d2a30d4Sbostic register const struct ttinfo * const ttisp = &sp->ttis[i];
2273d2a30d4Sbostic
2283d2a30d4Sbostic tzname[ttisp->tt_isdst] =
2293d2a30d4Sbostic (char *) &sp->chars[ttisp->tt_abbrind];
2303d2a30d4Sbostic #ifdef USG_COMPAT
2313d2a30d4Sbostic if (ttisp->tt_isdst)
2323d2a30d4Sbostic daylight = 1;
2333d2a30d4Sbostic if (i == 0 || !ttisp->tt_isdst)
2343d2a30d4Sbostic timezone = -(ttisp->tt_gmtoff);
2353d2a30d4Sbostic #endif /* defined USG_COMPAT */
2363d2a30d4Sbostic #ifdef ALTZONE
2373d2a30d4Sbostic if (i == 0 || ttisp->tt_isdst)
2383d2a30d4Sbostic altzone = -(ttisp->tt_gmtoff);
2393d2a30d4Sbostic #endif /* defined ALTZONE */
2403d2a30d4Sbostic }
2413d2a30d4Sbostic /*
2423d2a30d4Sbostic ** And to get the latest zone names into tzname. . .
2433d2a30d4Sbostic */
2443d2a30d4Sbostic for (i = 0; i < sp->timecnt; ++i) {
2453d2a30d4Sbostic register const struct ttinfo * const ttisp =
2463d2a30d4Sbostic &sp->ttis[sp->types[i]];
2473d2a30d4Sbostic
2483d2a30d4Sbostic tzname[ttisp->tt_isdst] =
2493d2a30d4Sbostic (char *) &sp->chars[ttisp->tt_abbrind];
2503d2a30d4Sbostic }
2513d2a30d4Sbostic }
2523d2a30d4Sbostic
2533d2a30d4Sbostic static int
tzload(name,sp)2543d2a30d4Sbostic tzload(name, sp)
2553d2a30d4Sbostic register const char * name;
2563d2a30d4Sbostic register struct state * const sp;
2573d2a30d4Sbostic {
2583d2a30d4Sbostic register const char * p;
259839b9482Sbostic register int i;
260839b9482Sbostic register int fid;
261839b9482Sbostic
2623d2a30d4Sbostic if (name == NULL && (name = TZDEFAULT) == NULL)
263839b9482Sbostic return -1;
264839b9482Sbostic {
2653d2a30d4Sbostic char fullname[FILENAME_MAX + 1];
266839b9482Sbostic
2673d2a30d4Sbostic if (name[0] == ':')
2683d2a30d4Sbostic ++name;
2697e1c7d44Sbostic if (name[0] != '/') {
2703d2a30d4Sbostic if ((p = TZDIR) == NULL)
271839b9482Sbostic return -1;
272839b9482Sbostic if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
273839b9482Sbostic return -1;
274839b9482Sbostic (void) strcpy(fullname, p);
275839b9482Sbostic (void) strcat(fullname, "/");
276839b9482Sbostic (void) strcat(fullname, name);
277839b9482Sbostic name = fullname;
278839b9482Sbostic }
2793d2a30d4Sbostic if ((fid = open(name, OPEN_MODE)) == -1)
280839b9482Sbostic return -1;
281839b9482Sbostic }
282839b9482Sbostic {
2833d2a30d4Sbostic register const struct tzhead * tzhp;
2843d2a30d4Sbostic char buf[sizeof *sp + sizeof *tzhp];
2853d2a30d4Sbostic int ttisstdcnt;
286839b9482Sbostic
287839b9482Sbostic i = read(fid, buf, sizeof buf);
288839b9482Sbostic if (close(fid) != 0 || i < sizeof *tzhp)
289839b9482Sbostic return -1;
290839b9482Sbostic tzhp = (struct tzhead *) buf;
2913d2a30d4Sbostic ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
2923d2a30d4Sbostic sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
2933d2a30d4Sbostic sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
2943d2a30d4Sbostic sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
2953d2a30d4Sbostic sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
2963d2a30d4Sbostic if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
2973d2a30d4Sbostic sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
2983d2a30d4Sbostic sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
2993d2a30d4Sbostic sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
3003d2a30d4Sbostic (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
301839b9482Sbostic return -1;
302839b9482Sbostic if (i < sizeof *tzhp +
3033d2a30d4Sbostic sp->timecnt * (4 + sizeof (char)) +
3043d2a30d4Sbostic sp->typecnt * (4 + 2 * sizeof (char)) +
3053d2a30d4Sbostic sp->charcnt * sizeof (char) +
3063d2a30d4Sbostic sp->leapcnt * 2 * 4 +
3073d2a30d4Sbostic ttisstdcnt * sizeof (char))
308839b9482Sbostic return -1;
309839b9482Sbostic p = buf + sizeof *tzhp;
3103d2a30d4Sbostic for (i = 0; i < sp->timecnt; ++i) {
3113d2a30d4Sbostic sp->ats[i] = detzcode(p);
312839b9482Sbostic p += 4;
313839b9482Sbostic }
3143d2a30d4Sbostic for (i = 0; i < sp->timecnt; ++i) {
3153d2a30d4Sbostic sp->types[i] = (unsigned char) *p++;
3163d2a30d4Sbostic if (sp->types[i] >= sp->typecnt)
3173d2a30d4Sbostic return -1;
3183d2a30d4Sbostic }
3193d2a30d4Sbostic for (i = 0; i < sp->typecnt; ++i) {
320839b9482Sbostic register struct ttinfo * ttisp;
321839b9482Sbostic
3223d2a30d4Sbostic ttisp = &sp->ttis[i];
323839b9482Sbostic ttisp->tt_gmtoff = detzcode(p);
324839b9482Sbostic p += 4;
325839b9482Sbostic ttisp->tt_isdst = (unsigned char) *p++;
3263d2a30d4Sbostic if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
3273d2a30d4Sbostic return -1;
328839b9482Sbostic ttisp->tt_abbrind = (unsigned char) *p++;
3293d2a30d4Sbostic if (ttisp->tt_abbrind < 0 ||
3303d2a30d4Sbostic ttisp->tt_abbrind > sp->charcnt)
331839b9482Sbostic return -1;
3323d2a30d4Sbostic }
3333d2a30d4Sbostic for (i = 0; i < sp->charcnt; ++i)
3343d2a30d4Sbostic sp->chars[i] = *p++;
3353d2a30d4Sbostic sp->chars[i] = '\0'; /* ensure '\0' at end */
3363d2a30d4Sbostic for (i = 0; i < sp->leapcnt; ++i) {
3373d2a30d4Sbostic register struct lsinfo * lsisp;
3383d2a30d4Sbostic
3393d2a30d4Sbostic lsisp = &sp->lsis[i];
3403d2a30d4Sbostic lsisp->ls_trans = detzcode(p);
3413d2a30d4Sbostic p += 4;
3423d2a30d4Sbostic lsisp->ls_corr = detzcode(p);
3433d2a30d4Sbostic p += 4;
3443d2a30d4Sbostic }
3453d2a30d4Sbostic for (i = 0; i < sp->typecnt; ++i) {
346839b9482Sbostic register struct ttinfo * ttisp;
347839b9482Sbostic
3483d2a30d4Sbostic ttisp = &sp->ttis[i];
3493d2a30d4Sbostic if (ttisstdcnt == 0)
3503d2a30d4Sbostic ttisp->tt_ttisstd = FALSE;
3513d2a30d4Sbostic else {
3523d2a30d4Sbostic ttisp->tt_ttisstd = *p++;
3533d2a30d4Sbostic if (ttisp->tt_ttisstd != TRUE &&
3543d2a30d4Sbostic ttisp->tt_ttisstd != FALSE)
35553c215e7Sbostic return -1;
3563d2a30d4Sbostic }
3573d2a30d4Sbostic }
3583d2a30d4Sbostic }
35953c215e7Sbostic return 0;
36053c215e7Sbostic }
36153c215e7Sbostic
3623d2a30d4Sbostic static const int mon_lengths[2][MONSPERYEAR] = {
3633d2a30d4Sbostic 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
3643d2a30d4Sbostic 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3653d2a30d4Sbostic };
3663d2a30d4Sbostic
3673d2a30d4Sbostic static const int year_lengths[2] = {
3683d2a30d4Sbostic DAYSPERNYEAR, DAYSPERLYEAR
3693d2a30d4Sbostic };
3703d2a30d4Sbostic
3713d2a30d4Sbostic /*
3723d2a30d4Sbostic ** Given a pointer into a time zone string, scan until a character that is not
3733d2a30d4Sbostic ** a valid character in a zone name is found. Return a pointer to that
3743d2a30d4Sbostic ** character.
3753d2a30d4Sbostic */
3763d2a30d4Sbostic
3773d2a30d4Sbostic static const char *
getzname(strp)3783d2a30d4Sbostic getzname(strp)
3793d2a30d4Sbostic register const char * strp;
380839b9482Sbostic {
3813d2a30d4Sbostic register char c;
3823d2a30d4Sbostic
3833d2a30d4Sbostic while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
3843d2a30d4Sbostic c != '+')
3853d2a30d4Sbostic ++strp;
3863d2a30d4Sbostic return strp;
3873d2a30d4Sbostic }
3883d2a30d4Sbostic
3893d2a30d4Sbostic /*
3903d2a30d4Sbostic ** Given a pointer into a time zone string, extract a number from that string.
3913d2a30d4Sbostic ** Check that the number is within a specified range; if it is not, return
3923d2a30d4Sbostic ** NULL.
3933d2a30d4Sbostic ** Otherwise, return a pointer to the first character not part of the number.
3943d2a30d4Sbostic */
3953d2a30d4Sbostic
3963d2a30d4Sbostic static const char *
getnum(strp,nump,min,max)3973d2a30d4Sbostic getnum(strp, nump, min, max)
3983d2a30d4Sbostic register const char * strp;
3993d2a30d4Sbostic int * const nump;
4003d2a30d4Sbostic const int min;
4013d2a30d4Sbostic const int max;
4023d2a30d4Sbostic {
4033d2a30d4Sbostic register char c;
4043d2a30d4Sbostic register int num;
4053d2a30d4Sbostic
4063d2a30d4Sbostic if (strp == NULL || !isdigit(*strp))
4073d2a30d4Sbostic return NULL;
4083d2a30d4Sbostic num = 0;
4093d2a30d4Sbostic while ((c = *strp) != '\0' && isdigit(c)) {
4103d2a30d4Sbostic num = num * 10 + (c - '0');
4113d2a30d4Sbostic if (num > max)
4123d2a30d4Sbostic return NULL; /* illegal value */
4133d2a30d4Sbostic ++strp;
4143d2a30d4Sbostic }
4153d2a30d4Sbostic if (num < min)
4163d2a30d4Sbostic return NULL; /* illegal value */
4173d2a30d4Sbostic *nump = num;
4183d2a30d4Sbostic return strp;
4193d2a30d4Sbostic }
4203d2a30d4Sbostic
4213d2a30d4Sbostic /*
4223d2a30d4Sbostic ** Given a pointer into a time zone string, extract a number of seconds,
4233d2a30d4Sbostic ** in hh[:mm[:ss]] form, from the string.
4243d2a30d4Sbostic ** If any error occurs, return NULL.
4253d2a30d4Sbostic ** Otherwise, return a pointer to the first character not part of the number
4263d2a30d4Sbostic ** of seconds.
4273d2a30d4Sbostic */
4283d2a30d4Sbostic
4293d2a30d4Sbostic static const char *
getsecs(strp,secsp)4303d2a30d4Sbostic getsecs(strp, secsp)
4313d2a30d4Sbostic register const char * strp;
4323d2a30d4Sbostic long * const secsp;
4333d2a30d4Sbostic {
4343d2a30d4Sbostic int num;
4353d2a30d4Sbostic
4363d2a30d4Sbostic strp = getnum(strp, &num, 0, HOURSPERDAY);
4373d2a30d4Sbostic if (strp == NULL)
4383d2a30d4Sbostic return NULL;
4393d2a30d4Sbostic *secsp = num * SECSPERHOUR;
4403d2a30d4Sbostic if (*strp == ':') {
4413d2a30d4Sbostic ++strp;
4423d2a30d4Sbostic strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
4433d2a30d4Sbostic if (strp == NULL)
4443d2a30d4Sbostic return NULL;
4453d2a30d4Sbostic *secsp += num * SECSPERMIN;
4463d2a30d4Sbostic if (*strp == ':') {
4473d2a30d4Sbostic ++strp;
4483d2a30d4Sbostic strp = getnum(strp, &num, 0, SECSPERMIN - 1);
4493d2a30d4Sbostic if (strp == NULL)
4503d2a30d4Sbostic return NULL;
4513d2a30d4Sbostic *secsp += num;
4523d2a30d4Sbostic }
4533d2a30d4Sbostic }
4543d2a30d4Sbostic return strp;
4553d2a30d4Sbostic }
4563d2a30d4Sbostic
4573d2a30d4Sbostic /*
4583d2a30d4Sbostic ** Given a pointer into a time zone string, extract an offset, in
4593d2a30d4Sbostic ** [+-]hh[:mm[:ss]] form, from the string.
4603d2a30d4Sbostic ** If any error occurs, return NULL.
4613d2a30d4Sbostic ** Otherwise, return a pointer to the first character not part of the time.
4623d2a30d4Sbostic */
4633d2a30d4Sbostic
4643d2a30d4Sbostic static const char *
getoffset(strp,offsetp)4653d2a30d4Sbostic getoffset(strp, offsetp)
4663d2a30d4Sbostic register const char * strp;
4673d2a30d4Sbostic long * const offsetp;
4683d2a30d4Sbostic {
4693d2a30d4Sbostic register int neg;
4703d2a30d4Sbostic
4713d2a30d4Sbostic if (*strp == '-') {
4723d2a30d4Sbostic neg = 1;
4733d2a30d4Sbostic ++strp;
4743d2a30d4Sbostic } else if (isdigit(*strp) || *strp++ == '+')
4753d2a30d4Sbostic neg = 0;
4763d2a30d4Sbostic else return NULL; /* illegal offset */
4773d2a30d4Sbostic strp = getsecs(strp, offsetp);
4783d2a30d4Sbostic if (strp == NULL)
4793d2a30d4Sbostic return NULL; /* illegal time */
4803d2a30d4Sbostic if (neg)
4813d2a30d4Sbostic *offsetp = -*offsetp;
4823d2a30d4Sbostic return strp;
4833d2a30d4Sbostic }
4843d2a30d4Sbostic
4853d2a30d4Sbostic /*
4863d2a30d4Sbostic ** Given a pointer into a time zone string, extract a rule in the form
4873d2a30d4Sbostic ** date[/time]. See POSIX section 8 for the format of "date" and "time".
4883d2a30d4Sbostic ** If a valid rule is not found, return NULL.
4893d2a30d4Sbostic ** Otherwise, return a pointer to the first character not part of the rule.
4903d2a30d4Sbostic */
4913d2a30d4Sbostic
4923d2a30d4Sbostic static const char *
getrule(strp,rulep)4933d2a30d4Sbostic getrule(strp, rulep)
4943d2a30d4Sbostic const char * strp;
4953d2a30d4Sbostic register struct rule * const rulep;
4963d2a30d4Sbostic {
4973d2a30d4Sbostic if (*strp == 'J') {
4983d2a30d4Sbostic /*
4993d2a30d4Sbostic ** Julian day.
5003d2a30d4Sbostic */
5013d2a30d4Sbostic rulep->r_type = JULIAN_DAY;
5023d2a30d4Sbostic ++strp;
5033d2a30d4Sbostic strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
5043d2a30d4Sbostic } else if (*strp == 'M') {
5053d2a30d4Sbostic /*
5063d2a30d4Sbostic ** Month, week, day.
5073d2a30d4Sbostic */
5083d2a30d4Sbostic rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
5093d2a30d4Sbostic ++strp;
5103d2a30d4Sbostic strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
5113d2a30d4Sbostic if (strp == NULL)
5123d2a30d4Sbostic return NULL;
5133d2a30d4Sbostic if (*strp++ != '.')
5143d2a30d4Sbostic return NULL;
5153d2a30d4Sbostic strp = getnum(strp, &rulep->r_week, 1, 5);
5163d2a30d4Sbostic if (strp == NULL)
5173d2a30d4Sbostic return NULL;
5183d2a30d4Sbostic if (*strp++ != '.')
5193d2a30d4Sbostic return NULL;
5203d2a30d4Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
5213d2a30d4Sbostic } else if (isdigit(*strp)) {
5223d2a30d4Sbostic /*
5233d2a30d4Sbostic ** Day of year.
5243d2a30d4Sbostic */
5253d2a30d4Sbostic rulep->r_type = DAY_OF_YEAR;
5263d2a30d4Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
5273d2a30d4Sbostic } else return NULL; /* invalid format */
5283d2a30d4Sbostic if (strp == NULL)
5293d2a30d4Sbostic return NULL;
5303d2a30d4Sbostic if (*strp == '/') {
5313d2a30d4Sbostic /*
5323d2a30d4Sbostic ** Time specified.
5333d2a30d4Sbostic */
5343d2a30d4Sbostic ++strp;
5353d2a30d4Sbostic strp = getsecs(strp, &rulep->r_time);
5363d2a30d4Sbostic } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
5373d2a30d4Sbostic return strp;
5383d2a30d4Sbostic }
5393d2a30d4Sbostic
5403d2a30d4Sbostic /*
5413d2a30d4Sbostic ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
5423d2a30d4Sbostic ** year, a rule, and the offset from GMT at the time that rule takes effect,
5433d2a30d4Sbostic ** calculate the Epoch-relative time that rule takes effect.
5443d2a30d4Sbostic */
5453d2a30d4Sbostic
5463d2a30d4Sbostic static time_t
transtime(janfirst,year,rulep,offset)5473d2a30d4Sbostic transtime(janfirst, year, rulep, offset)
5483d2a30d4Sbostic const time_t janfirst;
5493d2a30d4Sbostic const int year;
5503d2a30d4Sbostic register const struct rule * const rulep;
5513d2a30d4Sbostic const long offset;
5523d2a30d4Sbostic {
5533d2a30d4Sbostic register int leapyear;
5543d2a30d4Sbostic register time_t value;
5553d2a30d4Sbostic register int i;
5563d2a30d4Sbostic int d, m1, yy0, yy1, yy2, dow;
5573d2a30d4Sbostic
5583d2a30d4Sbostic leapyear = isleap(year);
5593d2a30d4Sbostic switch (rulep->r_type) {
5603d2a30d4Sbostic
5613d2a30d4Sbostic case JULIAN_DAY:
5623d2a30d4Sbostic /*
5633d2a30d4Sbostic ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
5643d2a30d4Sbostic ** years.
5653d2a30d4Sbostic ** In non-leap years, or if the day number is 59 or less, just
5663d2a30d4Sbostic ** add SECSPERDAY times the day number-1 to the time of
5673d2a30d4Sbostic ** January 1, midnight, to get the day.
5683d2a30d4Sbostic */
5693d2a30d4Sbostic value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
5703d2a30d4Sbostic if (leapyear && rulep->r_day >= 60)
5713d2a30d4Sbostic value += SECSPERDAY;
5723d2a30d4Sbostic break;
5733d2a30d4Sbostic
5743d2a30d4Sbostic case DAY_OF_YEAR:
5753d2a30d4Sbostic /*
5763d2a30d4Sbostic ** n - day of year.
5773d2a30d4Sbostic ** Just add SECSPERDAY times the day number to the time of
5783d2a30d4Sbostic ** January 1, midnight, to get the day.
5793d2a30d4Sbostic */
5803d2a30d4Sbostic value = janfirst + rulep->r_day * SECSPERDAY;
5813d2a30d4Sbostic break;
5823d2a30d4Sbostic
5833d2a30d4Sbostic case MONTH_NTH_DAY_OF_WEEK:
5843d2a30d4Sbostic /*
5853d2a30d4Sbostic ** Mm.n.d - nth "dth day" of month m.
5863d2a30d4Sbostic */
5873d2a30d4Sbostic value = janfirst;
5883d2a30d4Sbostic for (i = 0; i < rulep->r_mon - 1; ++i)
5893d2a30d4Sbostic value += mon_lengths[leapyear][i] * SECSPERDAY;
5903d2a30d4Sbostic
5913d2a30d4Sbostic /*
5923d2a30d4Sbostic ** Use Zeller's Congruence to get day-of-week of first day of
5933d2a30d4Sbostic ** month.
5943d2a30d4Sbostic */
5953d2a30d4Sbostic m1 = (rulep->r_mon + 9) % 12 + 1;
5963d2a30d4Sbostic yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
5973d2a30d4Sbostic yy1 = yy0 / 100;
5983d2a30d4Sbostic yy2 = yy0 % 100;
5993d2a30d4Sbostic dow = ((26 * m1 - 2) / 10 +
6003d2a30d4Sbostic 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
6013d2a30d4Sbostic if (dow < 0)
6023d2a30d4Sbostic dow += DAYSPERWEEK;
6033d2a30d4Sbostic
6043d2a30d4Sbostic /*
6053d2a30d4Sbostic ** "dow" is the day-of-week of the first day of the month. Get
6063d2a30d4Sbostic ** the day-of-month (zero-origin) of the first "dow" day of the
6073d2a30d4Sbostic ** month.
6083d2a30d4Sbostic */
6093d2a30d4Sbostic d = rulep->r_day - dow;
6103d2a30d4Sbostic if (d < 0)
6113d2a30d4Sbostic d += DAYSPERWEEK;
6123d2a30d4Sbostic for (i = 1; i < rulep->r_week; ++i) {
6133d2a30d4Sbostic if (d + DAYSPERWEEK >=
6143d2a30d4Sbostic mon_lengths[leapyear][rulep->r_mon - 1])
6153d2a30d4Sbostic break;
6163d2a30d4Sbostic d += DAYSPERWEEK;
6173d2a30d4Sbostic }
6183d2a30d4Sbostic
6193d2a30d4Sbostic /*
6203d2a30d4Sbostic ** "d" is the day-of-month (zero-origin) of the day we want.
6213d2a30d4Sbostic */
6223d2a30d4Sbostic value += d * SECSPERDAY;
6233d2a30d4Sbostic break;
6243d2a30d4Sbostic }
6253d2a30d4Sbostic
6263d2a30d4Sbostic /*
6273d2a30d4Sbostic ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
6283d2a30d4Sbostic ** question. To get the Epoch-relative time of the specified local
6293d2a30d4Sbostic ** time on that day, add the transition time and the current offset
6303d2a30d4Sbostic ** from GMT.
6313d2a30d4Sbostic */
6323d2a30d4Sbostic return value + rulep->r_time + offset;
6333d2a30d4Sbostic }
6343d2a30d4Sbostic
6353d2a30d4Sbostic /*
6363d2a30d4Sbostic ** Given a POSIX section 8-style TZ string, fill in the rule tables as
6373d2a30d4Sbostic ** appropriate.
6383d2a30d4Sbostic */
6393d2a30d4Sbostic
6403d2a30d4Sbostic static int
tzparse(name,sp,lastditch)6413d2a30d4Sbostic tzparse(name, sp, lastditch)
6423d2a30d4Sbostic const char * name;
6433d2a30d4Sbostic register struct state * const sp;
6443d2a30d4Sbostic const int lastditch;
6453d2a30d4Sbostic {
6463d2a30d4Sbostic const char * stdname;
6473d2a30d4Sbostic const char * dstname;
6483d2a30d4Sbostic int stdlen;
6493d2a30d4Sbostic int dstlen;
6503d2a30d4Sbostic long stdoffset;
6513d2a30d4Sbostic long dstoffset;
6523d2a30d4Sbostic register time_t * atp;
6533d2a30d4Sbostic register unsigned char * typep;
6543d2a30d4Sbostic register char * cp;
6553d2a30d4Sbostic register int load_result;
6563d2a30d4Sbostic
6573d2a30d4Sbostic stdname = name;
6583d2a30d4Sbostic if (lastditch) {
6593d2a30d4Sbostic stdlen = strlen(name); /* length of standard zone name */
6603d2a30d4Sbostic name += stdlen;
6613d2a30d4Sbostic if (stdlen >= sizeof sp->chars)
6623d2a30d4Sbostic stdlen = (sizeof sp->chars) - 1;
6633d2a30d4Sbostic } else {
6643d2a30d4Sbostic name = getzname(name);
6653d2a30d4Sbostic stdlen = name - stdname;
6663d2a30d4Sbostic if (stdlen < 3)
6673d2a30d4Sbostic return -1;
6683d2a30d4Sbostic }
6693d2a30d4Sbostic if (*name == '\0')
670297a6844Sbostic return -1;
6713d2a30d4Sbostic else {
6723d2a30d4Sbostic name = getoffset(name, &stdoffset);
6733d2a30d4Sbostic if (name == NULL)
6743d2a30d4Sbostic return -1;
6753d2a30d4Sbostic }
6763d2a30d4Sbostic load_result = tzload(TZDEFRULES, sp);
6773d2a30d4Sbostic if (load_result != 0)
6783d2a30d4Sbostic sp->leapcnt = 0; /* so, we're off a little */
6793d2a30d4Sbostic if (*name != '\0') {
6803d2a30d4Sbostic dstname = name;
6813d2a30d4Sbostic name = getzname(name);
6823d2a30d4Sbostic dstlen = name - dstname; /* length of DST zone name */
6833d2a30d4Sbostic if (dstlen < 3)
6843d2a30d4Sbostic return -1;
6853d2a30d4Sbostic if (*name != '\0' && *name != ',' && *name != ';') {
6863d2a30d4Sbostic name = getoffset(name, &dstoffset);
6873d2a30d4Sbostic if (name == NULL)
6883d2a30d4Sbostic return -1;
6893d2a30d4Sbostic } else dstoffset = stdoffset - SECSPERHOUR;
6903d2a30d4Sbostic if (*name == ',' || *name == ';') {
6913d2a30d4Sbostic struct rule start;
6923d2a30d4Sbostic struct rule end;
6933d2a30d4Sbostic register int year;
6943d2a30d4Sbostic register time_t janfirst;
6953d2a30d4Sbostic time_t starttime;
6963d2a30d4Sbostic time_t endtime;
6973d2a30d4Sbostic
6983d2a30d4Sbostic ++name;
6993d2a30d4Sbostic if ((name = getrule(name, &start)) == NULL)
7003d2a30d4Sbostic return -1;
7013d2a30d4Sbostic if (*name++ != ',')
7023d2a30d4Sbostic return -1;
7033d2a30d4Sbostic if ((name = getrule(name, &end)) == NULL)
7043d2a30d4Sbostic return -1;
7053d2a30d4Sbostic if (*name != '\0')
7063d2a30d4Sbostic return -1;
7073d2a30d4Sbostic sp->typecnt = 2; /* standard time and DST */
7083d2a30d4Sbostic /*
7093d2a30d4Sbostic ** Two transitions per year, from EPOCH_YEAR to 2037.
7103d2a30d4Sbostic */
7113d2a30d4Sbostic sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
7123d2a30d4Sbostic if (sp->timecnt > TZ_MAX_TIMES)
7133d2a30d4Sbostic return -1;
7143d2a30d4Sbostic sp->ttis[0].tt_gmtoff = -dstoffset;
7153d2a30d4Sbostic sp->ttis[0].tt_isdst = 1;
7163d2a30d4Sbostic sp->ttis[0].tt_abbrind = stdlen + 1;
7173d2a30d4Sbostic sp->ttis[1].tt_gmtoff = -stdoffset;
7183d2a30d4Sbostic sp->ttis[1].tt_isdst = 0;
7193d2a30d4Sbostic sp->ttis[1].tt_abbrind = 0;
7203d2a30d4Sbostic atp = sp->ats;
7213d2a30d4Sbostic typep = sp->types;
7223d2a30d4Sbostic janfirst = 0;
7233d2a30d4Sbostic for (year = EPOCH_YEAR; year <= 2037; ++year) {
7243d2a30d4Sbostic starttime = transtime(janfirst, year, &start,
7253d2a30d4Sbostic stdoffset);
7263d2a30d4Sbostic endtime = transtime(janfirst, year, &end,
7273d2a30d4Sbostic dstoffset);
7283d2a30d4Sbostic if (starttime > endtime) {
7293d2a30d4Sbostic *atp++ = endtime;
7303d2a30d4Sbostic *typep++ = 1; /* DST ends */
7313d2a30d4Sbostic *atp++ = starttime;
7323d2a30d4Sbostic *typep++ = 0; /* DST begins */
7333d2a30d4Sbostic } else {
7343d2a30d4Sbostic *atp++ = starttime;
7353d2a30d4Sbostic *typep++ = 0; /* DST begins */
7363d2a30d4Sbostic *atp++ = endtime;
7373d2a30d4Sbostic *typep++ = 1; /* DST ends */
7383d2a30d4Sbostic }
7393d2a30d4Sbostic janfirst +=
7403d2a30d4Sbostic year_lengths[isleap(year)] * SECSPERDAY;
7413d2a30d4Sbostic }
7423d2a30d4Sbostic } else {
7433d2a30d4Sbostic int sawstd;
7443d2a30d4Sbostic int sawdst;
7453d2a30d4Sbostic long stdfix;
7463d2a30d4Sbostic long dstfix;
7473d2a30d4Sbostic long oldfix;
7483d2a30d4Sbostic int isdst;
7493d2a30d4Sbostic register int i;
7503d2a30d4Sbostic
7513d2a30d4Sbostic if (*name != '\0')
7523d2a30d4Sbostic return -1;
7533d2a30d4Sbostic if (load_result != 0)
7543d2a30d4Sbostic return -1;
7553d2a30d4Sbostic /*
7563d2a30d4Sbostic ** Compute the difference between the real and
7573d2a30d4Sbostic ** prototype standard and summer time offsets
7583d2a30d4Sbostic ** from GMT, and put the real standard and summer
7593d2a30d4Sbostic ** time offsets into the rules in place of the
7603d2a30d4Sbostic ** prototype offsets.
7613d2a30d4Sbostic */
7623d2a30d4Sbostic sawstd = FALSE;
7633d2a30d4Sbostic sawdst = FALSE;
7643d2a30d4Sbostic stdfix = 0;
7653d2a30d4Sbostic dstfix = 0;
7663d2a30d4Sbostic for (i = 0; i < sp->typecnt; ++i) {
7673d2a30d4Sbostic if (sp->ttis[i].tt_isdst) {
7683d2a30d4Sbostic oldfix = dstfix;
7693d2a30d4Sbostic dstfix =
7703d2a30d4Sbostic sp->ttis[i].tt_gmtoff + dstoffset;
7713d2a30d4Sbostic if (sawdst && (oldfix != dstfix))
7723d2a30d4Sbostic return -1;
7733d2a30d4Sbostic sp->ttis[i].tt_gmtoff = -dstoffset;
7743d2a30d4Sbostic sp->ttis[i].tt_abbrind = stdlen + 1;
7753d2a30d4Sbostic sawdst = TRUE;
7763d2a30d4Sbostic } else {
7773d2a30d4Sbostic oldfix = stdfix;
7783d2a30d4Sbostic stdfix =
7793d2a30d4Sbostic sp->ttis[i].tt_gmtoff + stdoffset;
7803d2a30d4Sbostic if (sawstd && (oldfix != stdfix))
7813d2a30d4Sbostic return -1;
7823d2a30d4Sbostic sp->ttis[i].tt_gmtoff = -stdoffset;
7833d2a30d4Sbostic sp->ttis[i].tt_abbrind = 0;
7843d2a30d4Sbostic sawstd = TRUE;
7853d2a30d4Sbostic }
7863d2a30d4Sbostic }
7873d2a30d4Sbostic /*
7883d2a30d4Sbostic ** Make sure we have both standard and summer time.
7893d2a30d4Sbostic */
7903d2a30d4Sbostic if (!sawdst || !sawstd)
7913d2a30d4Sbostic return -1;
7923d2a30d4Sbostic /*
7933d2a30d4Sbostic ** Now correct the transition times by shifting
7943d2a30d4Sbostic ** them by the difference between the real and
7953d2a30d4Sbostic ** prototype offsets. Note that this difference
7963d2a30d4Sbostic ** can be different in standard and summer time;
7973d2a30d4Sbostic ** the prototype probably has a 1-hour difference
7983d2a30d4Sbostic ** between standard and summer time, but a different
7993d2a30d4Sbostic ** difference can be specified in TZ.
8003d2a30d4Sbostic */
8013d2a30d4Sbostic isdst = FALSE; /* we start in standard time */
8023d2a30d4Sbostic for (i = 0; i < sp->timecnt; ++i) {
8033d2a30d4Sbostic register const struct ttinfo * ttisp;
8043d2a30d4Sbostic
8053d2a30d4Sbostic /*
8063d2a30d4Sbostic ** If summer time is in effect, and the
8073d2a30d4Sbostic ** transition time was not specified as
8083d2a30d4Sbostic ** standard time, add the summer time
8093d2a30d4Sbostic ** offset to the transition time;
8103d2a30d4Sbostic ** otherwise, add the standard time offset
8113d2a30d4Sbostic ** to the transition time.
8123d2a30d4Sbostic */
8133d2a30d4Sbostic ttisp = &sp->ttis[sp->types[i]];
8143d2a30d4Sbostic sp->ats[i] +=
8153d2a30d4Sbostic (isdst && !ttisp->tt_ttisstd) ?
8163d2a30d4Sbostic dstfix : stdfix;
8173d2a30d4Sbostic isdst = ttisp->tt_isdst;
8183d2a30d4Sbostic }
8193d2a30d4Sbostic }
8203d2a30d4Sbostic } else {
8213d2a30d4Sbostic dstlen = 0;
8223d2a30d4Sbostic sp->typecnt = 1; /* only standard time */
8233d2a30d4Sbostic sp->timecnt = 0;
8243d2a30d4Sbostic sp->ttis[0].tt_gmtoff = -stdoffset;
8253d2a30d4Sbostic sp->ttis[0].tt_isdst = 0;
8263d2a30d4Sbostic sp->ttis[0].tt_abbrind = 0;
8273d2a30d4Sbostic }
8283d2a30d4Sbostic sp->charcnt = stdlen + 1;
8293d2a30d4Sbostic if (dstlen != 0)
8303d2a30d4Sbostic sp->charcnt += dstlen + 1;
8313d2a30d4Sbostic if (sp->charcnt > sizeof sp->chars)
8323d2a30d4Sbostic return -1;
8333d2a30d4Sbostic cp = sp->chars;
8343d2a30d4Sbostic (void) strncpy(cp, stdname, stdlen);
8353d2a30d4Sbostic cp += stdlen;
8363d2a30d4Sbostic *cp++ = '\0';
8373d2a30d4Sbostic if (dstlen != 0) {
8383d2a30d4Sbostic (void) strncpy(cp, dstname, dstlen);
8393d2a30d4Sbostic *(cp + dstlen) = '\0';
8403d2a30d4Sbostic }
8413d2a30d4Sbostic return 0;
8423d2a30d4Sbostic }
8433d2a30d4Sbostic
8443d2a30d4Sbostic static void
gmtload(sp)8453d2a30d4Sbostic gmtload(sp)
8463d2a30d4Sbostic struct state * const sp;
8473d2a30d4Sbostic {
8483d2a30d4Sbostic if (tzload(GMT, sp) != 0)
8493d2a30d4Sbostic (void) tzparse(GMT, sp, TRUE);
850839b9482Sbostic }
851839b9482Sbostic
852839b9482Sbostic void
tzset()853839b9482Sbostic tzset()
854839b9482Sbostic {
8553d2a30d4Sbostic register const char * name;
8563d2a30d4Sbostic void tzsetwall();
857839b9482Sbostic
858839b9482Sbostic name = getenv("TZ");
8593d2a30d4Sbostic if (name == NULL) {
8603d2a30d4Sbostic tzsetwall();
86153c215e7Sbostic return;
86253c215e7Sbostic }
8633d2a30d4Sbostic lcl_is_set = TRUE;
8643d2a30d4Sbostic #ifdef ALL_STATE
8653d2a30d4Sbostic if (lclptr == NULL) {
8663d2a30d4Sbostic lclptr = (struct state *) malloc(sizeof *lclptr);
8673d2a30d4Sbostic if (lclptr == NULL) {
8683d2a30d4Sbostic settzname(); /* all we can do */
8693d2a30d4Sbostic return;
8703d2a30d4Sbostic }
8713d2a30d4Sbostic }
8723d2a30d4Sbostic #endif /* defined ALL_STATE */
8733d2a30d4Sbostic if (*name == '\0') {
8743d2a30d4Sbostic /*
8753d2a30d4Sbostic ** User wants it fast rather than right.
8763d2a30d4Sbostic */
8773d2a30d4Sbostic lclptr->leapcnt = 0; /* so, we're off a little */
8783d2a30d4Sbostic lclptr->timecnt = 0;
8793d2a30d4Sbostic lclptr->ttis[0].tt_gmtoff = 0;
8803d2a30d4Sbostic lclptr->ttis[0].tt_abbrind = 0;
8813d2a30d4Sbostic (void) strcpy(lclptr->chars, GMT);
8823d2a30d4Sbostic } else if (tzload(name, lclptr) != 0)
8833d2a30d4Sbostic if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
884297a6844Sbostic (void) gmtload(lclptr);
8853d2a30d4Sbostic settzname();
886839b9482Sbostic }
887839b9482Sbostic
8883d2a30d4Sbostic void
tzsetwall()8893d2a30d4Sbostic tzsetwall()
890839b9482Sbostic {
8913d2a30d4Sbostic lcl_is_set = TRUE;
8923d2a30d4Sbostic #ifdef ALL_STATE
8933d2a30d4Sbostic if (lclptr == NULL) {
8943d2a30d4Sbostic lclptr = (struct state *) malloc(sizeof *lclptr);
8953d2a30d4Sbostic if (lclptr == NULL) {
8963d2a30d4Sbostic settzname(); /* all we can do */
8973d2a30d4Sbostic return;
8983d2a30d4Sbostic }
8993d2a30d4Sbostic }
9003d2a30d4Sbostic #endif /* defined ALL_STATE */
9013d2a30d4Sbostic if (tzload((char *) NULL, lclptr) != 0)
9023d2a30d4Sbostic gmtload(lclptr);
9033d2a30d4Sbostic settzname();
9043d2a30d4Sbostic }
905839b9482Sbostic
9063d2a30d4Sbostic /*
9073d2a30d4Sbostic ** The easy way to behave "as if no library function calls" localtime
9083d2a30d4Sbostic ** is to not call it--so we drop its guts into "localsub", which can be
9093d2a30d4Sbostic ** freely called. (And no, the PANS doesn't require the above behavior--
9103d2a30d4Sbostic ** but it *is* desirable.)
9113d2a30d4Sbostic **
9123d2a30d4Sbostic ** The unused offset argument is for the benefit of mktime variants.
9133d2a30d4Sbostic */
9143d2a30d4Sbostic
9153d2a30d4Sbostic /*ARGSUSED*/
9163d2a30d4Sbostic static void
localsub(timep,offset,tmp)9173d2a30d4Sbostic localsub(timep, offset, tmp)
9183d2a30d4Sbostic const time_t * const timep;
9193d2a30d4Sbostic const long offset;
9203d2a30d4Sbostic struct tm * const tmp;
9213d2a30d4Sbostic {
922ae227ee3Sdonn register struct state * sp;
9233d2a30d4Sbostic register const struct ttinfo * ttisp;
9243d2a30d4Sbostic register int i;
9253d2a30d4Sbostic const time_t t = *timep;
9263d2a30d4Sbostic
9273d2a30d4Sbostic if (!lcl_is_set)
9283d2a30d4Sbostic tzset();
9293d2a30d4Sbostic sp = lclptr;
9303d2a30d4Sbostic #ifdef ALL_STATE
9313d2a30d4Sbostic if (sp == NULL) {
9323d2a30d4Sbostic gmtsub(timep, offset, tmp);
9333d2a30d4Sbostic return;
9343d2a30d4Sbostic }
9353d2a30d4Sbostic #endif /* defined ALL_STATE */
9363d2a30d4Sbostic if (sp->timecnt == 0 || t < sp->ats[0]) {
937839b9482Sbostic i = 0;
9383d2a30d4Sbostic while (sp->ttis[i].tt_isdst)
9393d2a30d4Sbostic if (++i >= sp->typecnt) {
940839b9482Sbostic i = 0;
941839b9482Sbostic break;
942839b9482Sbostic }
943839b9482Sbostic } else {
9443d2a30d4Sbostic for (i = 1; i < sp->timecnt; ++i)
9453d2a30d4Sbostic if (t < sp->ats[i])
946839b9482Sbostic break;
9473d2a30d4Sbostic i = sp->types[i - 1];
948839b9482Sbostic }
9493d2a30d4Sbostic ttisp = &sp->ttis[i];
950839b9482Sbostic /*
951839b9482Sbostic ** To get (wrong) behavior that's compatible with System V Release 2.0
952839b9482Sbostic ** you'd replace the statement below with
9533d2a30d4Sbostic ** t += ttisp->tt_gmtoff;
9543d2a30d4Sbostic ** timesub(&t, 0L, sp, tmp);
955839b9482Sbostic */
9563d2a30d4Sbostic timesub(&t, ttisp->tt_gmtoff, sp, tmp);
957839b9482Sbostic tmp->tm_isdst = ttisp->tt_isdst;
9583d2a30d4Sbostic tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
9593d2a30d4Sbostic tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
960839b9482Sbostic }
961839b9482Sbostic
962839b9482Sbostic struct tm *
localtime(timep)9633d2a30d4Sbostic localtime(timep)
9643d2a30d4Sbostic const time_t * const timep;
965839b9482Sbostic {
9663d2a30d4Sbostic static struct tm tm;
967839b9482Sbostic
9683d2a30d4Sbostic localsub(timep, 0L, &tm);
9693d2a30d4Sbostic return &tm;
970839b9482Sbostic }
971839b9482Sbostic
9723d2a30d4Sbostic /*
9733d2a30d4Sbostic ** gmtsub is to gmtime as localsub is to localtime.
9743d2a30d4Sbostic */
975839b9482Sbostic
9763d2a30d4Sbostic static void
gmtsub(timep,offset,tmp)9773d2a30d4Sbostic gmtsub(timep, offset, tmp)
9783d2a30d4Sbostic const time_t * const timep;
9793d2a30d4Sbostic const long offset;
9803d2a30d4Sbostic struct tm * const tmp;
9813d2a30d4Sbostic {
9823d2a30d4Sbostic if (!gmt_is_set) {
9833d2a30d4Sbostic gmt_is_set = TRUE;
9843d2a30d4Sbostic #ifdef ALL_STATE
9853d2a30d4Sbostic gmtptr = (struct state *) malloc(sizeof *gmtptr);
9863d2a30d4Sbostic if (gmtptr != NULL)
9873d2a30d4Sbostic #endif /* defined ALL_STATE */
9883d2a30d4Sbostic gmtload(gmtptr);
9893d2a30d4Sbostic }
9903d2a30d4Sbostic timesub(timep, offset, gmtptr, tmp);
9913d2a30d4Sbostic /*
9923d2a30d4Sbostic ** Could get fancy here and deliver something such as
9933d2a30d4Sbostic ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
9943d2a30d4Sbostic ** but this is no time for a treasure hunt.
9953d2a30d4Sbostic */
9963d2a30d4Sbostic if (offset != 0)
9973d2a30d4Sbostic tmp->tm_zone = WILDABBR;
9983d2a30d4Sbostic else {
9993d2a30d4Sbostic #ifdef ALL_STATE
10003d2a30d4Sbostic if (gmtptr == NULL)
10013d2a30d4Sbostic tmp->TM_ZONE = GMT;
10023d2a30d4Sbostic else tmp->TM_ZONE = gmtptr->chars;
10033d2a30d4Sbostic #endif /* defined ALL_STATE */
10043d2a30d4Sbostic #ifndef ALL_STATE
10053d2a30d4Sbostic tmp->tm_zone = gmtptr->chars;
10063d2a30d4Sbostic #endif /* State Farm */
10073d2a30d4Sbostic }
10083d2a30d4Sbostic }
1009839b9482Sbostic
1010839b9482Sbostic struct tm *
gmtime(timep)10113d2a30d4Sbostic gmtime(timep)
10123d2a30d4Sbostic const time_t * const timep;
1013839b9482Sbostic {
10143d2a30d4Sbostic static struct tm tm;
10153d2a30d4Sbostic
10163d2a30d4Sbostic gmtsub(timep, 0L, &tm);
10173d2a30d4Sbostic return &tm;
10183d2a30d4Sbostic }
10193d2a30d4Sbostic
10203d2a30d4Sbostic static void
timesub(timep,offset,sp,tmp)10213d2a30d4Sbostic timesub(timep, offset, sp, tmp)
10223d2a30d4Sbostic const time_t * const timep;
10233d2a30d4Sbostic const long offset;
10243d2a30d4Sbostic register const struct state * const sp;
10253d2a30d4Sbostic register struct tm * const tmp;
10263d2a30d4Sbostic {
10273d2a30d4Sbostic register const struct lsinfo * lp;
1028839b9482Sbostic register long days;
1029839b9482Sbostic register long rem;
1030839b9482Sbostic register int y;
1031839b9482Sbostic register int yleap;
10323d2a30d4Sbostic register const int * ip;
10333d2a30d4Sbostic register long corr;
10343d2a30d4Sbostic register int hit;
10353d2a30d4Sbostic register int i;
1036839b9482Sbostic
10373d2a30d4Sbostic corr = 0;
10383d2a30d4Sbostic hit = FALSE;
10393d2a30d4Sbostic #ifdef ALL_STATE
10403d2a30d4Sbostic i = (sp == NULL) ? 0 : sp->leapcnt;
10413d2a30d4Sbostic #endif /* defined ALL_STATE */
10423d2a30d4Sbostic #ifndef ALL_STATE
10433d2a30d4Sbostic i = sp->leapcnt;
10443d2a30d4Sbostic #endif /* State Farm */
10453d2a30d4Sbostic while (--i >= 0) {
10463d2a30d4Sbostic lp = &sp->lsis[i];
10473d2a30d4Sbostic if (*timep >= lp->ls_trans) {
10483d2a30d4Sbostic if (*timep == lp->ls_trans)
10493d2a30d4Sbostic hit = ((i == 0 && lp->ls_corr > 0) ||
10503d2a30d4Sbostic lp->ls_corr > sp->lsis[i - 1].ls_corr);
10513d2a30d4Sbostic corr = lp->ls_corr;
10523d2a30d4Sbostic break;
10533d2a30d4Sbostic }
10543d2a30d4Sbostic }
10553d2a30d4Sbostic days = *timep / SECSPERDAY;
10563d2a30d4Sbostic rem = *timep % SECSPERDAY;
10573d2a30d4Sbostic #ifdef mc68k
10583d2a30d4Sbostic if (*timep == 0x80000000) {
10593d2a30d4Sbostic /*
10603d2a30d4Sbostic ** A 3B1 muffs the division on the most negative number.
10613d2a30d4Sbostic */
10623d2a30d4Sbostic days = -24855;
10633d2a30d4Sbostic rem = -11648;
10643d2a30d4Sbostic }
10653d2a30d4Sbostic #endif /* mc68k */
10663d2a30d4Sbostic rem += (offset - corr);
1067839b9482Sbostic while (rem < 0) {
10683d2a30d4Sbostic rem += SECSPERDAY;
1069839b9482Sbostic --days;
1070839b9482Sbostic }
10713d2a30d4Sbostic while (rem >= SECSPERDAY) {
10723d2a30d4Sbostic rem -= SECSPERDAY;
1073839b9482Sbostic ++days;
1074839b9482Sbostic }
10753d2a30d4Sbostic tmp->tm_hour = (int) (rem / SECSPERHOUR);
10763d2a30d4Sbostic rem = rem % SECSPERHOUR;
10773d2a30d4Sbostic tmp->tm_min = (int) (rem / SECSPERMIN);
10783d2a30d4Sbostic tmp->tm_sec = (int) (rem % SECSPERMIN);
10793d2a30d4Sbostic if (hit)
10803d2a30d4Sbostic /*
10813d2a30d4Sbostic ** A positive leap second requires a special
10823d2a30d4Sbostic ** representation. This uses "... ??:59:60".
10833d2a30d4Sbostic */
10843d2a30d4Sbostic ++(tmp->tm_sec);
10853d2a30d4Sbostic tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1086839b9482Sbostic if (tmp->tm_wday < 0)
10873d2a30d4Sbostic tmp->tm_wday += DAYSPERWEEK;
1088839b9482Sbostic y = EPOCH_YEAR;
1089839b9482Sbostic if (days >= 0)
1090839b9482Sbostic for ( ; ; ) {
1091839b9482Sbostic yleap = isleap(y);
1092839b9482Sbostic if (days < (long) year_lengths[yleap])
1093839b9482Sbostic break;
1094839b9482Sbostic ++y;
1095839b9482Sbostic days = days - (long) year_lengths[yleap];
1096839b9482Sbostic }
1097839b9482Sbostic else do {
1098839b9482Sbostic --y;
1099839b9482Sbostic yleap = isleap(y);
1100839b9482Sbostic days = days + (long) year_lengths[yleap];
1101839b9482Sbostic } while (days < 0);
1102839b9482Sbostic tmp->tm_year = y - TM_YEAR_BASE;
1103839b9482Sbostic tmp->tm_yday = (int) days;
1104839b9482Sbostic ip = mon_lengths[yleap];
1105839b9482Sbostic for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1106839b9482Sbostic days = days - (long) ip[tmp->tm_mon];
1107839b9482Sbostic tmp->tm_mday = (int) (days + 1);
1108839b9482Sbostic tmp->tm_isdst = 0;
1109b810d286Sbostic tmp->tm_gmtoff = offset;
11103d2a30d4Sbostic }
11113d2a30d4Sbostic
11123d2a30d4Sbostic /*
11133d2a30d4Sbostic ** A la X3J11
11143d2a30d4Sbostic */
11153d2a30d4Sbostic
11163d2a30d4Sbostic char *
asctime(timeptr)11173d2a30d4Sbostic asctime(timeptr)
11183d2a30d4Sbostic register const struct tm * timeptr;
11193d2a30d4Sbostic {
11203d2a30d4Sbostic static const char wday_name[DAYSPERWEEK][3] = {
11213d2a30d4Sbostic "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
11223d2a30d4Sbostic };
11233d2a30d4Sbostic static const char mon_name[MONSPERYEAR][3] = {
11243d2a30d4Sbostic "Jan", "Feb", "Mar", "Apr", "May", "Jun",
11253d2a30d4Sbostic "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
11263d2a30d4Sbostic };
11273d2a30d4Sbostic static char result[26];
11283d2a30d4Sbostic
11293d2a30d4Sbostic (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
11303d2a30d4Sbostic wday_name[timeptr->tm_wday],
11313d2a30d4Sbostic mon_name[timeptr->tm_mon],
11323d2a30d4Sbostic timeptr->tm_mday, timeptr->tm_hour,
11333d2a30d4Sbostic timeptr->tm_min, timeptr->tm_sec,
11343d2a30d4Sbostic TM_YEAR_BASE + timeptr->tm_year);
11353d2a30d4Sbostic return result;
11363d2a30d4Sbostic }
11373d2a30d4Sbostic
11383d2a30d4Sbostic char *
ctime(timep)11393d2a30d4Sbostic ctime(timep)
11403d2a30d4Sbostic const time_t * const timep;
11413d2a30d4Sbostic {
11423d2a30d4Sbostic return asctime(localtime(timep));
11433d2a30d4Sbostic }
11443d2a30d4Sbostic
11453d2a30d4Sbostic /*
11463d2a30d4Sbostic ** Adapted from code provided by Robert Elz, who writes:
11473d2a30d4Sbostic ** The "best" way to do mktime I think is based on an idea of Bob
11483d2a30d4Sbostic ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
11493d2a30d4Sbostic ** It does a binary search of the time_t space. Since time_t's are
11503d2a30d4Sbostic ** just 32 bits, its a max of 32 iterations (even at 64 bits it
11513d2a30d4Sbostic ** would still be very reasonable).
11523d2a30d4Sbostic */
11533d2a30d4Sbostic
11543d2a30d4Sbostic #ifndef WRONG
11553d2a30d4Sbostic #define WRONG (-1)
11563d2a30d4Sbostic #endif /* !defined WRONG */
11573d2a30d4Sbostic
11583d2a30d4Sbostic static void
normalize(tensptr,unitsptr,base)11593d2a30d4Sbostic normalize(tensptr, unitsptr, base)
11603d2a30d4Sbostic int * const tensptr;
11613d2a30d4Sbostic int * const unitsptr;
11623d2a30d4Sbostic const int base;
11633d2a30d4Sbostic {
11643d2a30d4Sbostic if (*unitsptr >= base) {
11653d2a30d4Sbostic *tensptr += *unitsptr / base;
11663d2a30d4Sbostic *unitsptr %= base;
11673d2a30d4Sbostic } else if (*unitsptr < 0) {
11681484bbd6Sbostic *tensptr -= 1 + (-(*unitsptr + 1)) / base;
11691484bbd6Sbostic *unitsptr = base - 1 - (-(*unitsptr + 1)) % base;
11703d2a30d4Sbostic }
11713d2a30d4Sbostic }
11723d2a30d4Sbostic
11733d2a30d4Sbostic static int
tmcomp(atmp,btmp)11743d2a30d4Sbostic tmcomp(atmp, btmp)
11753d2a30d4Sbostic register const struct tm * const atmp;
11763d2a30d4Sbostic register const struct tm * const btmp;
11773d2a30d4Sbostic {
11783d2a30d4Sbostic register int result;
11793d2a30d4Sbostic
11803d2a30d4Sbostic if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
11813d2a30d4Sbostic (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
11823d2a30d4Sbostic (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
11833d2a30d4Sbostic (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
11843d2a30d4Sbostic (result = (atmp->tm_min - btmp->tm_min)) == 0)
11853d2a30d4Sbostic result = atmp->tm_sec - btmp->tm_sec;
11863d2a30d4Sbostic return result;
11873d2a30d4Sbostic }
11883d2a30d4Sbostic
11893d2a30d4Sbostic static time_t
time2(tmp,funcp,offset,okayp)11903d2a30d4Sbostic time2(tmp, funcp, offset, okayp)
11913d2a30d4Sbostic struct tm * const tmp;
11923d2a30d4Sbostic void (* const funcp)();
11933d2a30d4Sbostic const long offset;
11943d2a30d4Sbostic int * const okayp;
11953d2a30d4Sbostic {
11963d2a30d4Sbostic register const struct state * sp;
11973d2a30d4Sbostic register int dir;
11983d2a30d4Sbostic register int bits;
11993d2a30d4Sbostic register int i, j ;
12003d2a30d4Sbostic register int saved_seconds;
12013d2a30d4Sbostic time_t newt;
12023d2a30d4Sbostic time_t t;
12033d2a30d4Sbostic struct tm yourtm, mytm;
12043d2a30d4Sbostic
12053d2a30d4Sbostic *okayp = FALSE;
12063d2a30d4Sbostic yourtm = *tmp;
12073d2a30d4Sbostic if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
12083d2a30d4Sbostic normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
12093d2a30d4Sbostic normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
12103d2a30d4Sbostic normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
12113d2a30d4Sbostic normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
12123d2a30d4Sbostic while (yourtm.tm_mday <= 0) {
12133d2a30d4Sbostic --yourtm.tm_year;
12143d2a30d4Sbostic yourtm.tm_mday +=
12153d2a30d4Sbostic year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
12163d2a30d4Sbostic }
1217*a9452ba1Sbostic while (yourtm.tm_mday > DAYSPERLYEAR) {
1218*a9452ba1Sbostic yourtm.tm_mday -=
1219*a9452ba1Sbostic year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1220*a9452ba1Sbostic ++yourtm.tm_year;
1221*a9452ba1Sbostic }
12223d2a30d4Sbostic for ( ; ; ) {
12233d2a30d4Sbostic i = mon_lengths[isleap(yourtm.tm_year +
12243d2a30d4Sbostic TM_YEAR_BASE)][yourtm.tm_mon];
12253d2a30d4Sbostic if (yourtm.tm_mday <= i)
12263d2a30d4Sbostic break;
12273d2a30d4Sbostic yourtm.tm_mday -= i;
12283d2a30d4Sbostic if (++yourtm.tm_mon >= MONSPERYEAR) {
12293d2a30d4Sbostic yourtm.tm_mon = 0;
12303d2a30d4Sbostic ++yourtm.tm_year;
12313d2a30d4Sbostic }
12323d2a30d4Sbostic }
12333d2a30d4Sbostic saved_seconds = yourtm.tm_sec;
12343d2a30d4Sbostic yourtm.tm_sec = 0;
12353d2a30d4Sbostic /*
12363d2a30d4Sbostic ** Calculate the number of magnitude bits in a time_t
12373d2a30d4Sbostic ** (this works regardless of whether time_t is
12383d2a30d4Sbostic ** signed or unsigned, though lint complains if unsigned).
12393d2a30d4Sbostic */
12403d2a30d4Sbostic for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
12413d2a30d4Sbostic ;
12423d2a30d4Sbostic /*
12433d2a30d4Sbostic ** If time_t is signed, then 0 is the median value,
12443d2a30d4Sbostic ** if time_t is unsigned, then 1 << bits is median.
12453d2a30d4Sbostic */
12463d2a30d4Sbostic t = (t < 0) ? 0 : ((time_t) 1 << bits);
12473d2a30d4Sbostic for ( ; ; ) {
12483d2a30d4Sbostic (*funcp)(&t, offset, &mytm);
12493d2a30d4Sbostic dir = tmcomp(&mytm, &yourtm);
12503d2a30d4Sbostic if (dir != 0) {
12513d2a30d4Sbostic if (bits-- < 0)
12523d2a30d4Sbostic return WRONG;
12533d2a30d4Sbostic if (bits < 0)
12543d2a30d4Sbostic --t;
12553d2a30d4Sbostic else if (dir > 0)
12563d2a30d4Sbostic t -= (time_t) 1 << bits;
12573d2a30d4Sbostic else t += (time_t) 1 << bits;
12583d2a30d4Sbostic continue;
12593d2a30d4Sbostic }
12603d2a30d4Sbostic if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
12613d2a30d4Sbostic break;
12623d2a30d4Sbostic /*
12633d2a30d4Sbostic ** Right time, wrong type.
12643d2a30d4Sbostic ** Hunt for right time, right type.
12653d2a30d4Sbostic ** It's okay to guess wrong since the guess
12663d2a30d4Sbostic ** gets checked.
12673d2a30d4Sbostic */
12683d2a30d4Sbostic sp = (const struct state *)
12693d2a30d4Sbostic ((funcp == localsub) ? lclptr : gmtptr);
12703d2a30d4Sbostic #ifdef ALL_STATE
12713d2a30d4Sbostic if (sp == NULL)
12723d2a30d4Sbostic return WRONG;
12733d2a30d4Sbostic #endif /* defined ALL_STATE */
12743d2a30d4Sbostic for (i = 0; i < sp->typecnt; ++i) {
12753d2a30d4Sbostic if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
12763d2a30d4Sbostic continue;
12773d2a30d4Sbostic for (j = 0; j < sp->typecnt; ++j) {
12783d2a30d4Sbostic if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
12793d2a30d4Sbostic continue;
12803d2a30d4Sbostic newt = t + sp->ttis[j].tt_gmtoff -
12813d2a30d4Sbostic sp->ttis[i].tt_gmtoff;
12823d2a30d4Sbostic (*funcp)(&newt, offset, &mytm);
12833d2a30d4Sbostic if (tmcomp(&mytm, &yourtm) != 0)
12843d2a30d4Sbostic continue;
12853d2a30d4Sbostic if (mytm.tm_isdst != yourtm.tm_isdst)
12863d2a30d4Sbostic continue;
12873d2a30d4Sbostic /*
12883d2a30d4Sbostic ** We have a match.
12893d2a30d4Sbostic */
12903d2a30d4Sbostic t = newt;
12913d2a30d4Sbostic goto label;
12923d2a30d4Sbostic }
12933d2a30d4Sbostic }
12943d2a30d4Sbostic return WRONG;
12953d2a30d4Sbostic }
12963d2a30d4Sbostic label:
12973d2a30d4Sbostic t += saved_seconds;
12983d2a30d4Sbostic (*funcp)(&t, offset, tmp);
12993d2a30d4Sbostic *okayp = TRUE;
13003d2a30d4Sbostic return t;
13013d2a30d4Sbostic }
13023d2a30d4Sbostic
13033d2a30d4Sbostic static time_t
time1(tmp,funcp,offset)13043d2a30d4Sbostic time1(tmp, funcp, offset)
13053d2a30d4Sbostic struct tm * const tmp;
13063d2a30d4Sbostic void (* const funcp)();
13073d2a30d4Sbostic const long offset;
13083d2a30d4Sbostic {
13093d2a30d4Sbostic register time_t t;
13103d2a30d4Sbostic register const struct state * sp;
13113d2a30d4Sbostic register int samei, otheri;
13123d2a30d4Sbostic int okay;
13133d2a30d4Sbostic
13143d2a30d4Sbostic if (tmp->tm_isdst > 1)
1315c65326f3Sbostic tmp->tm_isdst = 1;
13163d2a30d4Sbostic t = time2(tmp, funcp, offset, &okay);
13173d2a30d4Sbostic if (okay || tmp->tm_isdst < 0)
13183d2a30d4Sbostic return t;
13193d2a30d4Sbostic /*
13203d2a30d4Sbostic ** We're supposed to assume that somebody took a time of one type
13213d2a30d4Sbostic ** and did some math on it that yielded a "struct tm" that's bad.
13223d2a30d4Sbostic ** We try to divine the type they started from and adjust to the
13233d2a30d4Sbostic ** type they need.
13243d2a30d4Sbostic */
13253d2a30d4Sbostic sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
13263d2a30d4Sbostic #ifdef ALL_STATE
13273d2a30d4Sbostic if (sp == NULL)
13283d2a30d4Sbostic return WRONG;
13293d2a30d4Sbostic #endif /* defined ALL_STATE */
13303d2a30d4Sbostic for (samei = 0; samei < sp->typecnt; ++samei) {
13313d2a30d4Sbostic if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
13323d2a30d4Sbostic continue;
13333d2a30d4Sbostic for (otheri = 0; otheri < sp->typecnt; ++otheri) {
13343d2a30d4Sbostic if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
13353d2a30d4Sbostic continue;
13363d2a30d4Sbostic tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
13373d2a30d4Sbostic sp->ttis[samei].tt_gmtoff;
13383d2a30d4Sbostic tmp->tm_isdst = !tmp->tm_isdst;
13393d2a30d4Sbostic t = time2(tmp, funcp, offset, &okay);
13403d2a30d4Sbostic if (okay)
13413d2a30d4Sbostic return t;
13423d2a30d4Sbostic tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
13433d2a30d4Sbostic sp->ttis[samei].tt_gmtoff;
13443d2a30d4Sbostic tmp->tm_isdst = !tmp->tm_isdst;
13453d2a30d4Sbostic }
13463d2a30d4Sbostic }
13473d2a30d4Sbostic return WRONG;
13483d2a30d4Sbostic }
13493d2a30d4Sbostic
13503d2a30d4Sbostic time_t
mktime(tmp)13513d2a30d4Sbostic mktime(tmp)
13523d2a30d4Sbostic struct tm * const tmp;
13533d2a30d4Sbostic {
13543d2a30d4Sbostic return time1(tmp, localsub, 0L);
13553d2a30d4Sbostic }
1356