122084Smckusick /*
261111Sbostic * Copyright (c) 1987, 1989, 1993
361111Sbostic * The Regents of the University of California. All rights reserved.
432754Sbostic *
534952Sbostic * This code is derived from software contributed to Berkeley by
643087Sbostic * Arthur David Olson of the National Cancer Institute.
734952Sbostic *
842621Sbostic * %sccs.include.redist.c%
922084Smckusick */
1022084Smckusick
1130684Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*66409Sbostic static char sccsid[] = "@(#)ctime.c 8.2 (Berkeley) 03/20/94";
1332754Sbostic #endif /* LIBC_SCCS and not lint */
1422084Smckusick
1537140Sbostic /*
1637140Sbostic ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
1737140Sbostic ** POSIX-style TZ environment variable handling from Guy Harris
1837140Sbostic ** (guy@auspex.com).
1937140Sbostic */
201959Swnj
2137140Sbostic /*LINTLIBRARY*/
221959Swnj
2337140Sbostic #include <sys/param.h>
2437140Sbostic #include <fcntl.h>
2537140Sbostic #include <time.h>
2637140Sbostic #include <tzfile.h>
2737140Sbostic #include <string.h>
2837140Sbostic #include <ctype.h>
2937140Sbostic #include <stdio.h>
3046597Sdonn #include <unistd.h>
3130608Sbostic
3237140Sbostic #ifdef __STDC__
3337140Sbostic #include <stdlib.h>
3437140Sbostic
3537140Sbostic #define P(s) s
3637140Sbostic #define alloc_size_t size_t
3737140Sbostic #define qsort_size_t size_t
3837140Sbostic #define fread_size_t size_t
3937140Sbostic #define fwrite_size_t size_t
4037140Sbostic
4137140Sbostic #else /* !defined __STDC__ */
4237140Sbostic
4339720Sbostic #define P(s) ()
4437140Sbostic
4537140Sbostic typedef char * genericptr_t;
4637140Sbostic typedef unsigned alloc_size_t;
4737140Sbostic typedef int qsort_size_t;
4837140Sbostic typedef int fread_size_t;
4937140Sbostic typedef int fwrite_size_t;
5037140Sbostic
5137140Sbostic extern char * calloc();
5237140Sbostic extern char * malloc();
5337140Sbostic extern char * realloc();
5437140Sbostic extern char * getenv();
5537140Sbostic
5637140Sbostic #endif /* !defined __STDC__ */
5737140Sbostic
5837140Sbostic extern time_t time();
5937140Sbostic
6037140Sbostic #define ACCESS_MODE O_RDONLY
6137140Sbostic #define OPEN_MODE O_RDONLY
6237140Sbostic
6337140Sbostic #ifndef WILDABBR
641959Swnj /*
6537140Sbostic ** Someone might make incorrect use of a time zone abbreviation:
6637140Sbostic ** 1. They might reference tzname[0] before calling tzset (explicitly
6737140Sbostic ** or implicitly).
6837140Sbostic ** 2. They might reference tzname[1] before calling tzset (explicitly
6937140Sbostic ** or implicitly).
7037140Sbostic ** 3. They might reference tzname[1] after setting to a time zone
7137140Sbostic ** in which Daylight Saving Time is never observed.
7237140Sbostic ** 4. They might reference tzname[0] after setting to a time zone
7337140Sbostic ** in which Standard Time is never observed.
7437140Sbostic ** 5. They might reference tm.TM_ZONE after calling offtime.
7537140Sbostic ** What's best to do in the above cases is open to debate;
7637140Sbostic ** for now, we just set things up so that in any of the five cases
7737140Sbostic ** WILDABBR is used. Another possibility: initialize tzname[0] to the
7837140Sbostic ** string "tzname[0] used before set", and similarly for the other cases.
7937140Sbostic ** And another: initialize tzname[0] to "ERA", with an explanation in the
8037140Sbostic ** manual page of what this "time zone abbreviation" means (doing this so
8137140Sbostic ** that tzname[0] has the "normal" length of three characters).
8230608Sbostic */
8337140Sbostic #define WILDABBR " "
8437140Sbostic #endif /* !defined WILDABBR */
851959Swnj
8630608Sbostic #ifndef TRUE
8730608Sbostic #define TRUE 1
8830608Sbostic #define FALSE 0
8937140Sbostic #endif /* !defined TRUE */
9030608Sbostic
9137140Sbostic static const char GMT[] = "GMT";
9230608Sbostic
9330608Sbostic struct ttinfo { /* time type information */
9430608Sbostic long tt_gmtoff; /* GMT offset in seconds */
9530608Sbostic int tt_isdst; /* used to set tm_isdst */
9630608Sbostic int tt_abbrind; /* abbreviation list index */
9737140Sbostic int tt_ttisstd; /* TRUE if transition is std time */
9813876Ssam };
9913876Ssam
10037140Sbostic struct lsinfo { /* leap second information */
10137140Sbostic time_t ls_trans; /* transition time */
10237140Sbostic long ls_corr; /* correction to apply */
10337140Sbostic };
10437140Sbostic
10530608Sbostic struct state {
10637140Sbostic int leapcnt;
10730608Sbostic int timecnt;
10830608Sbostic int typecnt;
10930608Sbostic int charcnt;
11030608Sbostic time_t ats[TZ_MAX_TIMES];
11130608Sbostic unsigned char types[TZ_MAX_TIMES];
11230608Sbostic struct ttinfo ttis[TZ_MAX_TYPES];
11337140Sbostic char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
11437140Sbostic TZ_MAX_CHARS + 1 : sizeof GMT];
11537140Sbostic struct lsinfo lsis[TZ_MAX_LEAPS];
11623720Skre };
11723720Skre
11837140Sbostic struct rule {
11937140Sbostic int r_type; /* type of rule--see below */
12037140Sbostic int r_day; /* day number of rule */
12137140Sbostic int r_week; /* week number of rule */
12237140Sbostic int r_mon; /* month number of rule */
12337140Sbostic long r_time; /* transition time of rule */
12437140Sbostic };
12530608Sbostic
12637140Sbostic #define JULIAN_DAY 0 /* Jn - Julian day */
12737140Sbostic #define DAY_OF_YEAR 1 /* n - day of year */
12837140Sbostic #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
12930608Sbostic
13037140Sbostic /*
13137140Sbostic ** Prototypes for static functions.
13237140Sbostic */
13337140Sbostic
13437140Sbostic static long detzcode P((const char * codep));
13537140Sbostic static const char * getzname P((const char * strp));
13637140Sbostic static const char * getnum P((const char * strp, int * nump, int min,
13737140Sbostic int max));
13837140Sbostic static const char * getsecs P((const char * strp, long * secsp));
13937140Sbostic static const char * getoffset P((const char * strp, long * offsetp));
14037140Sbostic static const char * getrule P((const char * strp, struct rule * rulep));
14137140Sbostic static void gmtload P((struct state * sp));
14237140Sbostic static void gmtsub P((const time_t * timep, long offset,
14337140Sbostic struct tm * tmp));
14437140Sbostic static void localsub P((const time_t * timep, long offset,
14537140Sbostic struct tm * tmp));
14637140Sbostic static void normalize P((int * tensptr, int * unitsptr, int base));
14737140Sbostic static void settzname P((void));
14837140Sbostic static time_t time1 P((struct tm * tmp, void (* funcp)(),
14937140Sbostic long offset));
15037140Sbostic static time_t time2 P((struct tm *tmp, void (* funcp)(),
15137140Sbostic long offset, int * okayp));
15237140Sbostic static void timesub P((const time_t * timep, long offset,
15337140Sbostic const struct state * sp, struct tm * tmp));
15437140Sbostic static int tmcomp P((const struct tm * atmp,
15537140Sbostic const struct tm * btmp));
15637140Sbostic static time_t transtime P((time_t janfirst, int year,
15737140Sbostic const struct rule * rulep, long offset));
15837140Sbostic static int tzload P((const char * name, struct state * sp));
15937140Sbostic static int tzparse P((const char * name, struct state * sp,
16037140Sbostic int lastditch));
16137140Sbostic
16237140Sbostic #ifdef ALL_STATE
16337140Sbostic static struct state * lclptr;
16437140Sbostic static struct state * gmtptr;
16537140Sbostic #endif /* defined ALL_STATE */
16637140Sbostic
16737140Sbostic #ifndef ALL_STATE
16837140Sbostic static struct state lclmem;
16937140Sbostic static struct state gmtmem;
17037140Sbostic #define lclptr (&lclmem)
17137140Sbostic #define gmtptr (&gmtmem)
17237140Sbostic #endif /* State Farm */
17337140Sbostic
17437140Sbostic static int lcl_is_set;
17537140Sbostic static int gmt_is_set;
17637140Sbostic
17730608Sbostic char * tzname[2] = {
17837140Sbostic WILDABBR,
17937140Sbostic WILDABBR
18012974Ssam };
18112974Ssam
18230608Sbostic #ifdef USG_COMPAT
18330608Sbostic time_t timezone = 0;
18430608Sbostic int daylight = 0;
18537140Sbostic #endif /* defined USG_COMPAT */
1861959Swnj
18737140Sbostic #ifdef ALTZONE
18837140Sbostic time_t altzone = 0;
18937140Sbostic #endif /* defined ALTZONE */
19037140Sbostic
19130608Sbostic static long
detzcode(codep)19230608Sbostic detzcode(codep)
19337140Sbostic const char * const codep;
1941959Swnj {
19530608Sbostic register long result;
19630608Sbostic register int i;
19730608Sbostic
19830608Sbostic result = 0;
19930608Sbostic for (i = 0; i < 4; ++i)
20030608Sbostic result = (result << 8) | (codep[i] & 0xff);
20130608Sbostic return result;
2021959Swnj }
2031959Swnj
20437140Sbostic static void
settzname()20537140Sbostic settzname()
2061959Swnj {
20737140Sbostic register const struct state * const sp = lclptr;
20837140Sbostic register int i;
2091959Swnj
21037140Sbostic tzname[0] = WILDABBR;
21137140Sbostic tzname[1] = WILDABBR;
21237140Sbostic #ifdef USG_COMPAT
21337140Sbostic daylight = 0;
21437140Sbostic timezone = 0;
21537140Sbostic #endif /* defined USG_COMPAT */
21637140Sbostic #ifdef ALTZONE
21737140Sbostic altzone = 0;
21837140Sbostic #endif /* defined ALTZONE */
21937140Sbostic #ifdef ALL_STATE
22037140Sbostic if (sp == NULL) {
22137140Sbostic tzname[0] = tzname[1] = GMT;
22237140Sbostic return;
22337140Sbostic }
22437140Sbostic #endif /* defined ALL_STATE */
22537140Sbostic for (i = 0; i < sp->typecnt; ++i) {
22637140Sbostic register const struct ttinfo * const ttisp = &sp->ttis[i];
22737140Sbostic
22837140Sbostic tzname[ttisp->tt_isdst] =
22937140Sbostic (char *) &sp->chars[ttisp->tt_abbrind];
23037140Sbostic #ifdef USG_COMPAT
23137140Sbostic if (ttisp->tt_isdst)
23237140Sbostic daylight = 1;
23337140Sbostic if (i == 0 || !ttisp->tt_isdst)
23437140Sbostic timezone = -(ttisp->tt_gmtoff);
23537140Sbostic #endif /* defined USG_COMPAT */
23637140Sbostic #ifdef ALTZONE
23737140Sbostic if (i == 0 || ttisp->tt_isdst)
23837140Sbostic altzone = -(ttisp->tt_gmtoff);
23937140Sbostic #endif /* defined ALTZONE */
24037140Sbostic }
24137140Sbostic /*
24237140Sbostic ** And to get the latest zone names into tzname. . .
24337140Sbostic */
24437140Sbostic for (i = 0; i < sp->timecnt; ++i) {
24537140Sbostic register const struct ttinfo * const ttisp =
24637140Sbostic &sp->ttis[sp->types[i]];
24737140Sbostic
24837140Sbostic tzname[ttisp->tt_isdst] =
24937140Sbostic (char *) &sp->chars[ttisp->tt_abbrind];
25037140Sbostic }
25137140Sbostic }
25237140Sbostic
25337140Sbostic static int
tzload(name,sp)25437140Sbostic tzload(name, sp)
25537140Sbostic register const char * name;
25637140Sbostic register struct state * const sp;
25737140Sbostic {
25837140Sbostic register const char * p;
25937140Sbostic register int i;
26037140Sbostic register int fid;
26137140Sbostic
26237140Sbostic if (name == NULL && (name = TZDEFAULT) == NULL)
26330608Sbostic return -1;
26430608Sbostic {
26537140Sbostic char fullname[FILENAME_MAX + 1];
26630608Sbostic
26737140Sbostic if (name[0] == ':')
26837140Sbostic ++name;
26940007Sbostic if (name[0] != '/') {
27037140Sbostic if ((p = TZDIR) == NULL)
27130608Sbostic return -1;
27230608Sbostic if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
27330608Sbostic return -1;
27430608Sbostic (void) strcpy(fullname, p);
27530608Sbostic (void) strcat(fullname, "/");
27630608Sbostic (void) strcat(fullname, name);
27730608Sbostic name = fullname;
27830608Sbostic }
27937140Sbostic if ((fid = open(name, OPEN_MODE)) == -1)
28030608Sbostic return -1;
28125662Sbloom }
28230608Sbostic {
28337140Sbostic register const struct tzhead * tzhp;
28437140Sbostic char buf[sizeof *sp + sizeof *tzhp];
28537140Sbostic int ttisstdcnt;
28630608Sbostic
28730608Sbostic i = read(fid, buf, sizeof buf);
28830608Sbostic if (close(fid) != 0 || i < sizeof *tzhp)
28930608Sbostic return -1;
29030608Sbostic tzhp = (struct tzhead *) buf;
29137140Sbostic ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
29237140Sbostic sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
29337140Sbostic sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
29437140Sbostic sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
29537140Sbostic sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
29637140Sbostic if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
29737140Sbostic sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
29837140Sbostic sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
29937140Sbostic sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
30037140Sbostic (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
30130608Sbostic return -1;
30230608Sbostic if (i < sizeof *tzhp +
30337140Sbostic sp->timecnt * (4 + sizeof (char)) +
30437140Sbostic sp->typecnt * (4 + 2 * sizeof (char)) +
30537140Sbostic sp->charcnt * sizeof (char) +
30637140Sbostic sp->leapcnt * 2 * 4 +
30737140Sbostic ttisstdcnt * sizeof (char))
30830608Sbostic return -1;
30930608Sbostic p = buf + sizeof *tzhp;
31037140Sbostic for (i = 0; i < sp->timecnt; ++i) {
31137140Sbostic sp->ats[i] = detzcode(p);
31230608Sbostic p += 4;
31312974Ssam }
31437140Sbostic for (i = 0; i < sp->timecnt; ++i) {
31537140Sbostic sp->types[i] = (unsigned char) *p++;
31637140Sbostic if (sp->types[i] >= sp->typecnt)
31737140Sbostic return -1;
31837140Sbostic }
31937140Sbostic for (i = 0; i < sp->typecnt; ++i) {
32030608Sbostic register struct ttinfo * ttisp;
32130608Sbostic
32237140Sbostic ttisp = &sp->ttis[i];
32330608Sbostic ttisp->tt_gmtoff = detzcode(p);
32430608Sbostic p += 4;
32530608Sbostic ttisp->tt_isdst = (unsigned char) *p++;
32637140Sbostic if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
32737140Sbostic return -1;
32830608Sbostic ttisp->tt_abbrind = (unsigned char) *p++;
32937140Sbostic if (ttisp->tt_abbrind < 0 ||
33037140Sbostic ttisp->tt_abbrind > sp->charcnt)
33137140Sbostic return -1;
33230608Sbostic }
33337140Sbostic for (i = 0; i < sp->charcnt; ++i)
33437140Sbostic sp->chars[i] = *p++;
33537140Sbostic sp->chars[i] = '\0'; /* ensure '\0' at end */
33637140Sbostic for (i = 0; i < sp->leapcnt; ++i) {
33737140Sbostic register struct lsinfo * lsisp;
33837140Sbostic
33937140Sbostic lsisp = &sp->lsis[i];
34037140Sbostic lsisp->ls_trans = detzcode(p);
34137140Sbostic p += 4;
34237140Sbostic lsisp->ls_corr = detzcode(p);
34337140Sbostic p += 4;
34437140Sbostic }
34537140Sbostic for (i = 0; i < sp->typecnt; ++i) {
34637140Sbostic register struct ttinfo * ttisp;
34737140Sbostic
34837140Sbostic ttisp = &sp->ttis[i];
34937140Sbostic if (ttisstdcnt == 0)
35037140Sbostic ttisp->tt_ttisstd = FALSE;
35137140Sbostic else {
35237140Sbostic ttisp->tt_ttisstd = *p++;
35337140Sbostic if (ttisp->tt_ttisstd != TRUE &&
35437140Sbostic ttisp->tt_ttisstd != FALSE)
35537140Sbostic return -1;
35637140Sbostic }
35737140Sbostic }
3581959Swnj }
35937140Sbostic return 0;
36037140Sbostic }
36137140Sbostic
36237140Sbostic static const int mon_lengths[2][MONSPERYEAR] = {
36337140Sbostic 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
36437140Sbostic 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
36537140Sbostic };
36637140Sbostic
36737140Sbostic static const int year_lengths[2] = {
36837140Sbostic DAYSPERNYEAR, DAYSPERLYEAR
36937140Sbostic };
37037140Sbostic
37137140Sbostic /*
37237140Sbostic ** Given a pointer into a time zone string, scan until a character that is not
37337140Sbostic ** a valid character in a zone name is found. Return a pointer to that
37437140Sbostic ** character.
37537140Sbostic */
37637140Sbostic
37737140Sbostic static const char *
getzname(strp)37837140Sbostic getzname(strp)
37937140Sbostic register const char * strp;
38037140Sbostic {
38137140Sbostic register char c;
38237140Sbostic
38337140Sbostic while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
38437140Sbostic c != '+')
38537140Sbostic ++strp;
38637140Sbostic return strp;
38737140Sbostic }
38837140Sbostic
38937140Sbostic /*
39037140Sbostic ** Given a pointer into a time zone string, extract a number from that string.
39137140Sbostic ** Check that the number is within a specified range; if it is not, return
39237140Sbostic ** NULL.
39337140Sbostic ** Otherwise, return a pointer to the first character not part of the number.
39437140Sbostic */
39537140Sbostic
39637140Sbostic static const char *
getnum(strp,nump,min,max)39737140Sbostic getnum(strp, nump, min, max)
39837140Sbostic register const char * strp;
39937140Sbostic int * const nump;
40037140Sbostic const int min;
40137140Sbostic const int max;
40237140Sbostic {
40337140Sbostic register char c;
40437140Sbostic register int num;
40537140Sbostic
40637140Sbostic if (strp == NULL || !isdigit(*strp))
40737140Sbostic return NULL;
40837140Sbostic num = 0;
40937140Sbostic while ((c = *strp) != '\0' && isdigit(c)) {
41037140Sbostic num = num * 10 + (c - '0');
41137140Sbostic if (num > max)
41237140Sbostic return NULL; /* illegal value */
41337140Sbostic ++strp;
41437140Sbostic }
41537140Sbostic if (num < min)
41637140Sbostic return NULL; /* illegal value */
41737140Sbostic *nump = num;
41837140Sbostic return strp;
41937140Sbostic }
42037140Sbostic
42137140Sbostic /*
42237140Sbostic ** Given a pointer into a time zone string, extract a number of seconds,
42337140Sbostic ** in hh[:mm[:ss]] form, from the string.
42437140Sbostic ** If any error occurs, return NULL.
42537140Sbostic ** Otherwise, return a pointer to the first character not part of the number
42637140Sbostic ** of seconds.
42737140Sbostic */
42837140Sbostic
42937140Sbostic static const char *
getsecs(strp,secsp)43037140Sbostic getsecs(strp, secsp)
43137140Sbostic register const char * strp;
43237140Sbostic long * const secsp;
43337140Sbostic {
43437140Sbostic int num;
43537140Sbostic
43637140Sbostic strp = getnum(strp, &num, 0, HOURSPERDAY);
43737140Sbostic if (strp == NULL)
43837140Sbostic return NULL;
43937140Sbostic *secsp = num * SECSPERHOUR;
44037140Sbostic if (*strp == ':') {
44137140Sbostic ++strp;
44237140Sbostic strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
44337140Sbostic if (strp == NULL)
44437140Sbostic return NULL;
44537140Sbostic *secsp += num * SECSPERMIN;
44637140Sbostic if (*strp == ':') {
44737140Sbostic ++strp;
44837140Sbostic strp = getnum(strp, &num, 0, SECSPERMIN - 1);
44937140Sbostic if (strp == NULL)
45037140Sbostic return NULL;
45137140Sbostic *secsp += num;
45237140Sbostic }
45337140Sbostic }
45437140Sbostic return strp;
45537140Sbostic }
45637140Sbostic
45737140Sbostic /*
45837140Sbostic ** Given a pointer into a time zone string, extract an offset, in
45937140Sbostic ** [+-]hh[:mm[:ss]] form, from the string.
46037140Sbostic ** If any error occurs, return NULL.
46137140Sbostic ** Otherwise, return a pointer to the first character not part of the time.
46237140Sbostic */
46337140Sbostic
46437140Sbostic static const char *
getoffset(strp,offsetp)46537140Sbostic getoffset(strp, offsetp)
46637140Sbostic register const char * strp;
46737140Sbostic long * const offsetp;
46837140Sbostic {
46937140Sbostic register int neg;
47037140Sbostic
47137140Sbostic if (*strp == '-') {
47237140Sbostic neg = 1;
47337140Sbostic ++strp;
47437140Sbostic } else if (isdigit(*strp) || *strp++ == '+')
47537140Sbostic neg = 0;
47637140Sbostic else return NULL; /* illegal offset */
47737140Sbostic strp = getsecs(strp, offsetp);
47837140Sbostic if (strp == NULL)
47937140Sbostic return NULL; /* illegal time */
48037140Sbostic if (neg)
48137140Sbostic *offsetp = -*offsetp;
48237140Sbostic return strp;
48337140Sbostic }
48437140Sbostic
48537140Sbostic /*
48637140Sbostic ** Given a pointer into a time zone string, extract a rule in the form
48737140Sbostic ** date[/time]. See POSIX section 8 for the format of "date" and "time".
48837140Sbostic ** If a valid rule is not found, return NULL.
48937140Sbostic ** Otherwise, return a pointer to the first character not part of the rule.
49037140Sbostic */
49137140Sbostic
49237140Sbostic static const char *
getrule(strp,rulep)49337140Sbostic getrule(strp, rulep)
49437140Sbostic const char * strp;
49537140Sbostic register struct rule * const rulep;
49637140Sbostic {
49737140Sbostic if (*strp == 'J') {
49837140Sbostic /*
49937140Sbostic ** Julian day.
50037140Sbostic */
50137140Sbostic rulep->r_type = JULIAN_DAY;
50237140Sbostic ++strp;
50337140Sbostic strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
50437140Sbostic } else if (*strp == 'M') {
50537140Sbostic /*
50637140Sbostic ** Month, week, day.
50737140Sbostic */
50837140Sbostic rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
50937140Sbostic ++strp;
51037140Sbostic strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
51137140Sbostic if (strp == NULL)
51237140Sbostic return NULL;
51337140Sbostic if (*strp++ != '.')
51437140Sbostic return NULL;
51537140Sbostic strp = getnum(strp, &rulep->r_week, 1, 5);
51637140Sbostic if (strp == NULL)
51737140Sbostic return NULL;
51837140Sbostic if (*strp++ != '.')
51937140Sbostic return NULL;
52037140Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
52137140Sbostic } else if (isdigit(*strp)) {
52237140Sbostic /*
52337140Sbostic ** Day of year.
52437140Sbostic */
52537140Sbostic rulep->r_type = DAY_OF_YEAR;
52637140Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
52737140Sbostic } else return NULL; /* invalid format */
52837140Sbostic if (strp == NULL)
52937140Sbostic return NULL;
53037140Sbostic if (*strp == '/') {
53137140Sbostic /*
53237140Sbostic ** Time specified.
53337140Sbostic */
53437140Sbostic ++strp;
53537140Sbostic strp = getsecs(strp, &rulep->r_time);
53637140Sbostic } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
53737140Sbostic return strp;
53837140Sbostic }
53937140Sbostic
54037140Sbostic /*
54137140Sbostic ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
54237140Sbostic ** year, a rule, and the offset from GMT at the time that rule takes effect,
54337140Sbostic ** calculate the Epoch-relative time that rule takes effect.
54437140Sbostic */
54537140Sbostic
54637140Sbostic static time_t
transtime(janfirst,year,rulep,offset)54737140Sbostic transtime(janfirst, year, rulep, offset)
54837140Sbostic const time_t janfirst;
54937140Sbostic const int year;
55037140Sbostic register const struct rule * const rulep;
55137140Sbostic const long offset;
55237140Sbostic {
55337140Sbostic register int leapyear;
55437140Sbostic register time_t value;
55537140Sbostic register int i;
55637140Sbostic int d, m1, yy0, yy1, yy2, dow;
55737140Sbostic
55837140Sbostic leapyear = isleap(year);
55937140Sbostic switch (rulep->r_type) {
56037140Sbostic
56137140Sbostic case JULIAN_DAY:
56237140Sbostic /*
56337140Sbostic ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
56437140Sbostic ** years.
56537140Sbostic ** In non-leap years, or if the day number is 59 or less, just
56637140Sbostic ** add SECSPERDAY times the day number-1 to the time of
56737140Sbostic ** January 1, midnight, to get the day.
56837140Sbostic */
56937140Sbostic value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
57037140Sbostic if (leapyear && rulep->r_day >= 60)
57137140Sbostic value += SECSPERDAY;
57237140Sbostic break;
57337140Sbostic
57437140Sbostic case DAY_OF_YEAR:
57537140Sbostic /*
57637140Sbostic ** n - day of year.
57737140Sbostic ** Just add SECSPERDAY times the day number to the time of
57837140Sbostic ** January 1, midnight, to get the day.
57937140Sbostic */
58037140Sbostic value = janfirst + rulep->r_day * SECSPERDAY;
58137140Sbostic break;
58237140Sbostic
58337140Sbostic case MONTH_NTH_DAY_OF_WEEK:
58437140Sbostic /*
58537140Sbostic ** Mm.n.d - nth "dth day" of month m.
58637140Sbostic */
58737140Sbostic value = janfirst;
58837140Sbostic for (i = 0; i < rulep->r_mon - 1; ++i)
58937140Sbostic value += mon_lengths[leapyear][i] * SECSPERDAY;
59037140Sbostic
59137140Sbostic /*
59237140Sbostic ** Use Zeller's Congruence to get day-of-week of first day of
59337140Sbostic ** month.
59437140Sbostic */
59537140Sbostic m1 = (rulep->r_mon + 9) % 12 + 1;
59637140Sbostic yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
59737140Sbostic yy1 = yy0 / 100;
59837140Sbostic yy2 = yy0 % 100;
59937140Sbostic dow = ((26 * m1 - 2) / 10 +
60037140Sbostic 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
60137140Sbostic if (dow < 0)
60237140Sbostic dow += DAYSPERWEEK;
60337140Sbostic
60437140Sbostic /*
60537140Sbostic ** "dow" is the day-of-week of the first day of the month. Get
60637140Sbostic ** the day-of-month (zero-origin) of the first "dow" day of the
60737140Sbostic ** month.
60837140Sbostic */
60937140Sbostic d = rulep->r_day - dow;
61037140Sbostic if (d < 0)
61137140Sbostic d += DAYSPERWEEK;
61237140Sbostic for (i = 1; i < rulep->r_week; ++i) {
61337140Sbostic if (d + DAYSPERWEEK >=
61437140Sbostic mon_lengths[leapyear][rulep->r_mon - 1])
61537140Sbostic break;
61637140Sbostic d += DAYSPERWEEK;
61737140Sbostic }
61837140Sbostic
61937140Sbostic /*
62037140Sbostic ** "d" is the day-of-month (zero-origin) of the day we want.
62137140Sbostic */
62237140Sbostic value += d * SECSPERDAY;
62337140Sbostic break;
62437140Sbostic }
62537140Sbostic
62630608Sbostic /*
62737140Sbostic ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
62837140Sbostic ** question. To get the Epoch-relative time of the specified local
62937140Sbostic ** time on that day, add the transition time and the current offset
63037140Sbostic ** from GMT.
63130608Sbostic */
63237140Sbostic return value + rulep->r_time + offset;
63337140Sbostic }
63437140Sbostic
63537140Sbostic /*
63637140Sbostic ** Given a POSIX section 8-style TZ string, fill in the rule tables as
63737140Sbostic ** appropriate.
63837140Sbostic */
63937140Sbostic
64037140Sbostic static int
tzparse(name,sp,lastditch)64137140Sbostic tzparse(name, sp, lastditch)
64237140Sbostic const char * name;
64337140Sbostic register struct state * const sp;
64437140Sbostic const int lastditch;
64537140Sbostic {
64637140Sbostic const char * stdname;
64737140Sbostic const char * dstname;
64837140Sbostic int stdlen;
64937140Sbostic int dstlen;
65037140Sbostic long stdoffset;
65137140Sbostic long dstoffset;
65237140Sbostic register time_t * atp;
65337140Sbostic register unsigned char * typep;
65437140Sbostic register char * cp;
65537140Sbostic register int load_result;
65637140Sbostic
65737140Sbostic stdname = name;
65837140Sbostic if (lastditch) {
65937140Sbostic stdlen = strlen(name); /* length of standard zone name */
66037140Sbostic name += stdlen;
66137140Sbostic if (stdlen >= sizeof sp->chars)
66237140Sbostic stdlen = (sizeof sp->chars) - 1;
66337140Sbostic } else {
66437140Sbostic name = getzname(name);
66537140Sbostic stdlen = name - stdname;
66637140Sbostic if (stdlen < 3)
66730608Sbostic return -1;
66837140Sbostic }
66937140Sbostic if (*name == '\0')
67039105Sbostic return -1;
67137140Sbostic else {
67237140Sbostic name = getoffset(name, &stdoffset);
67337140Sbostic if (name == NULL)
67430608Sbostic return -1;
67537140Sbostic }
67637140Sbostic load_result = tzload(TZDEFRULES, sp);
67737140Sbostic if (load_result != 0)
67837140Sbostic sp->leapcnt = 0; /* so, we're off a little */
67937140Sbostic if (*name != '\0') {
68037140Sbostic dstname = name;
68137140Sbostic name = getzname(name);
68237140Sbostic dstlen = name - dstname; /* length of DST zone name */
68337140Sbostic if (dstlen < 3)
68437140Sbostic return -1;
68537140Sbostic if (*name != '\0' && *name != ',' && *name != ';') {
68637140Sbostic name = getoffset(name, &dstoffset);
68737140Sbostic if (name == NULL)
68837140Sbostic return -1;
68937140Sbostic } else dstoffset = stdoffset - SECSPERHOUR;
69037140Sbostic if (*name == ',' || *name == ';') {
69137140Sbostic struct rule start;
69237140Sbostic struct rule end;
69337140Sbostic register int year;
69437140Sbostic register time_t janfirst;
69537140Sbostic time_t starttime;
69637140Sbostic time_t endtime;
69730608Sbostic
69837140Sbostic ++name;
69937140Sbostic if ((name = getrule(name, &start)) == NULL)
70037140Sbostic return -1;
70137140Sbostic if (*name++ != ',')
70237140Sbostic return -1;
70337140Sbostic if ((name = getrule(name, &end)) == NULL)
70437140Sbostic return -1;
70537140Sbostic if (*name != '\0')
70637140Sbostic return -1;
70737140Sbostic sp->typecnt = 2; /* standard time and DST */
70837140Sbostic /*
70937140Sbostic ** Two transitions per year, from EPOCH_YEAR to 2037.
71037140Sbostic */
71137140Sbostic sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
71237140Sbostic if (sp->timecnt > TZ_MAX_TIMES)
71337140Sbostic return -1;
71437140Sbostic sp->ttis[0].tt_gmtoff = -dstoffset;
71537140Sbostic sp->ttis[0].tt_isdst = 1;
71637140Sbostic sp->ttis[0].tt_abbrind = stdlen + 1;
71737140Sbostic sp->ttis[1].tt_gmtoff = -stdoffset;
71837140Sbostic sp->ttis[1].tt_isdst = 0;
71937140Sbostic sp->ttis[1].tt_abbrind = 0;
72037140Sbostic atp = sp->ats;
72137140Sbostic typep = sp->types;
72237140Sbostic janfirst = 0;
72337140Sbostic for (year = EPOCH_YEAR; year <= 2037; ++year) {
72437140Sbostic starttime = transtime(janfirst, year, &start,
72537140Sbostic stdoffset);
72637140Sbostic endtime = transtime(janfirst, year, &end,
72737140Sbostic dstoffset);
72837140Sbostic if (starttime > endtime) {
72937140Sbostic *atp++ = endtime;
73037140Sbostic *typep++ = 1; /* DST ends */
73137140Sbostic *atp++ = starttime;
73237140Sbostic *typep++ = 0; /* DST begins */
73337140Sbostic } else {
73437140Sbostic *atp++ = starttime;
73537140Sbostic *typep++ = 0; /* DST begins */
73637140Sbostic *atp++ = endtime;
73737140Sbostic *typep++ = 1; /* DST ends */
73837140Sbostic }
73937140Sbostic janfirst +=
74037140Sbostic year_lengths[isleap(year)] * SECSPERDAY;
74137140Sbostic }
74230608Sbostic } else {
74337140Sbostic int sawstd;
74437140Sbostic int sawdst;
74537140Sbostic long stdfix;
74637140Sbostic long dstfix;
74737140Sbostic long oldfix;
74837140Sbostic int isdst;
74937140Sbostic register int i;
75037140Sbostic
75137140Sbostic if (*name != '\0')
75237140Sbostic return -1;
75337140Sbostic if (load_result != 0)
75437140Sbostic return -1;
75537140Sbostic /*
75637140Sbostic ** Compute the difference between the real and
75737140Sbostic ** prototype standard and summer time offsets
75837140Sbostic ** from GMT, and put the real standard and summer
75937140Sbostic ** time offsets into the rules in place of the
76037140Sbostic ** prototype offsets.
76137140Sbostic */
76237140Sbostic sawstd = FALSE;
76337140Sbostic sawdst = FALSE;
76437140Sbostic stdfix = 0;
76537140Sbostic dstfix = 0;
76637140Sbostic for (i = 0; i < sp->typecnt; ++i) {
76737140Sbostic if (sp->ttis[i].tt_isdst) {
76837140Sbostic oldfix = dstfix;
76937140Sbostic dstfix =
77037140Sbostic sp->ttis[i].tt_gmtoff + dstoffset;
77137140Sbostic if (sawdst && (oldfix != dstfix))
77237140Sbostic return -1;
77337140Sbostic sp->ttis[i].tt_gmtoff = -dstoffset;
77437140Sbostic sp->ttis[i].tt_abbrind = stdlen + 1;
77537140Sbostic sawdst = TRUE;
77637140Sbostic } else {
77737140Sbostic oldfix = stdfix;
77837140Sbostic stdfix =
77937140Sbostic sp->ttis[i].tt_gmtoff + stdoffset;
78037140Sbostic if (sawstd && (oldfix != stdfix))
78137140Sbostic return -1;
78237140Sbostic sp->ttis[i].tt_gmtoff = -stdoffset;
78337140Sbostic sp->ttis[i].tt_abbrind = 0;
78437140Sbostic sawstd = TRUE;
78537140Sbostic }
78637140Sbostic }
78737140Sbostic /*
78837140Sbostic ** Make sure we have both standard and summer time.
78937140Sbostic */
79037140Sbostic if (!sawdst || !sawstd)
79137140Sbostic return -1;
79237140Sbostic /*
79337140Sbostic ** Now correct the transition times by shifting
79437140Sbostic ** them by the difference between the real and
79537140Sbostic ** prototype offsets. Note that this difference
79637140Sbostic ** can be different in standard and summer time;
79737140Sbostic ** the prototype probably has a 1-hour difference
79837140Sbostic ** between standard and summer time, but a different
79937140Sbostic ** difference can be specified in TZ.
80037140Sbostic */
80137140Sbostic isdst = FALSE; /* we start in standard time */
80237140Sbostic for (i = 0; i < sp->timecnt; ++i) {
80337140Sbostic register const struct ttinfo * ttisp;
80437140Sbostic
80537140Sbostic /*
80637140Sbostic ** If summer time is in effect, and the
80737140Sbostic ** transition time was not specified as
80837140Sbostic ** standard time, add the summer time
80937140Sbostic ** offset to the transition time;
81037140Sbostic ** otherwise, add the standard time offset
81137140Sbostic ** to the transition time.
81237140Sbostic */
81337140Sbostic ttisp = &sp->ttis[sp->types[i]];
81437140Sbostic sp->ats[i] +=
81537140Sbostic (isdst && !ttisp->tt_ttisstd) ?
81637140Sbostic dstfix : stdfix;
81737140Sbostic isdst = ttisp->tt_isdst;
81837140Sbostic }
81930608Sbostic }
82037140Sbostic } else {
82137140Sbostic dstlen = 0;
82237140Sbostic sp->typecnt = 1; /* only standard time */
82337140Sbostic sp->timecnt = 0;
82437140Sbostic sp->ttis[0].tt_gmtoff = -stdoffset;
82537140Sbostic sp->ttis[0].tt_isdst = 0;
82637140Sbostic sp->ttis[0].tt_abbrind = 0;
82730608Sbostic }
82837140Sbostic sp->charcnt = stdlen + 1;
82937140Sbostic if (dstlen != 0)
83037140Sbostic sp->charcnt += dstlen + 1;
83137140Sbostic if (sp->charcnt > sizeof sp->chars)
83230682Sbostic return -1;
83337140Sbostic cp = sp->chars;
83437140Sbostic (void) strncpy(cp, stdname, stdlen);
83537140Sbostic cp += stdlen;
83637140Sbostic *cp++ = '\0';
83737140Sbostic if (dstlen != 0) {
83837140Sbostic (void) strncpy(cp, dstname, dstlen);
83937140Sbostic *(cp + dstlen) = '\0';
84037140Sbostic }
84130682Sbostic return 0;
84230682Sbostic }
84330682Sbostic
84437140Sbostic static void
gmtload(sp)84537140Sbostic gmtload(sp)
84637140Sbostic struct state * const sp;
8471959Swnj {
84837140Sbostic if (tzload(GMT, sp) != 0)
84937140Sbostic (void) tzparse(GMT, sp, TRUE);
8501959Swnj }
8511959Swnj
85230608Sbostic void
tzset()85330608Sbostic tzset()
85430608Sbostic {
85537140Sbostic register const char * name;
85637140Sbostic void tzsetwall();
85730608Sbostic
85830608Sbostic name = getenv("TZ");
85937140Sbostic if (name == NULL) {
86037140Sbostic tzsetwall();
86137140Sbostic return;
86237140Sbostic }
86337140Sbostic lcl_is_set = TRUE;
86437140Sbostic #ifdef ALL_STATE
86537140Sbostic if (lclptr == NULL) {
86637140Sbostic lclptr = (struct state *) malloc(sizeof *lclptr);
86737140Sbostic if (lclptr == NULL) {
86837140Sbostic settzname(); /* all we can do */
86930682Sbostic return;
87037140Sbostic }
87137140Sbostic }
87237140Sbostic #endif /* defined ALL_STATE */
87337140Sbostic if (*name == '\0') {
87437140Sbostic /*
87537140Sbostic ** User wants it fast rather than right.
87637140Sbostic */
87737140Sbostic lclptr->leapcnt = 0; /* so, we're off a little */
87837140Sbostic lclptr->timecnt = 0;
87937140Sbostic lclptr->ttis[0].tt_gmtoff = 0;
88037140Sbostic lclptr->ttis[0].tt_abbrind = 0;
88137140Sbostic (void) strcpy(lclptr->chars, GMT);
88237140Sbostic } else if (tzload(name, lclptr) != 0)
88337140Sbostic if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
88439105Sbostic (void) gmtload(lclptr);
88537140Sbostic settzname();
88637140Sbostic }
88737140Sbostic
88837140Sbostic void
tzsetwall()88937140Sbostic tzsetwall()
89037140Sbostic {
89137140Sbostic lcl_is_set = TRUE;
89237140Sbostic #ifdef ALL_STATE
89337140Sbostic if (lclptr == NULL) {
89437140Sbostic lclptr = (struct state *) malloc(sizeof *lclptr);
89537140Sbostic if (lclptr == NULL) {
89637140Sbostic settzname(); /* all we can do */
89730682Sbostic return;
89837140Sbostic }
89930682Sbostic }
90037140Sbostic #endif /* defined ALL_STATE */
90137140Sbostic if (tzload((char *) NULL, lclptr) != 0)
90237140Sbostic gmtload(lclptr);
90337140Sbostic settzname();
90430608Sbostic }
90530608Sbostic
90637140Sbostic /*
90737140Sbostic ** The easy way to behave "as if no library function calls" localtime
90837140Sbostic ** is to not call it--so we drop its guts into "localsub", which can be
90937140Sbostic ** freely called. (And no, the PANS doesn't require the above behavior--
91037140Sbostic ** but it *is* desirable.)
91137140Sbostic **
91237140Sbostic ** The unused offset argument is for the benefit of mktime variants.
91337140Sbostic */
91437140Sbostic
91537140Sbostic /*ARGSUSED*/
91637140Sbostic static void
localsub(timep,offset,tmp)91737140Sbostic localsub(timep, offset, tmp)
91837140Sbostic const time_t * const timep;
91937140Sbostic const long offset;
92037140Sbostic struct tm * const tmp;
9211959Swnj {
92246597Sdonn register struct state * sp;
92337140Sbostic register const struct ttinfo * ttisp;
92430608Sbostic register int i;
92537140Sbostic const time_t t = *timep;
9261959Swnj
92737140Sbostic if (!lcl_is_set)
92837140Sbostic tzset();
92937140Sbostic sp = lclptr;
93037140Sbostic #ifdef ALL_STATE
93137140Sbostic if (sp == NULL) {
93237140Sbostic gmtsub(timep, offset, tmp);
93337140Sbostic return;
93437140Sbostic }
93537140Sbostic #endif /* defined ALL_STATE */
93637140Sbostic if (sp->timecnt == 0 || t < sp->ats[0]) {
93730608Sbostic i = 0;
93837140Sbostic while (sp->ttis[i].tt_isdst)
93937140Sbostic if (++i >= sp->typecnt) {
94030608Sbostic i = 0;
94130608Sbostic break;
94230608Sbostic }
94330608Sbostic } else {
94437140Sbostic for (i = 1; i < sp->timecnt; ++i)
94537140Sbostic if (t < sp->ats[i])
94630608Sbostic break;
94737140Sbostic i = sp->types[i - 1];
9481959Swnj }
94937140Sbostic ttisp = &sp->ttis[i];
9501959Swnj /*
95130608Sbostic ** To get (wrong) behavior that's compatible with System V Release 2.0
95230608Sbostic ** you'd replace the statement below with
95337140Sbostic ** t += ttisp->tt_gmtoff;
95437140Sbostic ** timesub(&t, 0L, sp, tmp);
95530608Sbostic */
95637140Sbostic timesub(&t, ttisp->tt_gmtoff, sp, tmp);
95730608Sbostic tmp->tm_isdst = ttisp->tt_isdst;
95837140Sbostic tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
95937140Sbostic tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
96030608Sbostic }
9611959Swnj
96230608Sbostic struct tm *
localtime(timep)96337140Sbostic localtime(timep)
96437140Sbostic const time_t * const timep;
96530608Sbostic {
96637140Sbostic static struct tm tm;
9671959Swnj
96837140Sbostic localsub(timep, 0L, &tm);
96937140Sbostic return &tm;
97030608Sbostic }
9711959Swnj
97237140Sbostic /*
97337140Sbostic ** gmtsub is to gmtime as localsub is to localtime.
97437140Sbostic */
9751959Swnj
97637140Sbostic static void
gmtsub(timep,offset,tmp)97737140Sbostic gmtsub(timep, offset, tmp)
97837140Sbostic const time_t * const timep;
97937140Sbostic const long offset;
98037140Sbostic struct tm * const tmp;
98137140Sbostic {
98237140Sbostic if (!gmt_is_set) {
98337140Sbostic gmt_is_set = TRUE;
98437140Sbostic #ifdef ALL_STATE
98537140Sbostic gmtptr = (struct state *) malloc(sizeof *gmtptr);
98637140Sbostic if (gmtptr != NULL)
98737140Sbostic #endif /* defined ALL_STATE */
98837140Sbostic gmtload(gmtptr);
98937140Sbostic }
99037140Sbostic timesub(timep, offset, gmtptr, tmp);
99137140Sbostic /*
99237140Sbostic ** Could get fancy here and deliver something such as
99337140Sbostic ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
99437140Sbostic ** but this is no time for a treasure hunt.
99537140Sbostic */
99637140Sbostic if (offset != 0)
99737140Sbostic tmp->tm_zone = WILDABBR;
99837140Sbostic else {
99937140Sbostic #ifdef ALL_STATE
100037140Sbostic if (gmtptr == NULL)
100137140Sbostic tmp->TM_ZONE = GMT;
100237140Sbostic else tmp->TM_ZONE = gmtptr->chars;
100337140Sbostic #endif /* defined ALL_STATE */
100437140Sbostic #ifndef ALL_STATE
100537140Sbostic tmp->tm_zone = gmtptr->chars;
100637140Sbostic #endif /* State Farm */
100737140Sbostic }
100837140Sbostic }
10091959Swnj
101030608Sbostic struct tm *
gmtime(timep)101137140Sbostic gmtime(timep)
101237140Sbostic const time_t * const timep;
10131959Swnj {
101430608Sbostic static struct tm tm;
10151959Swnj
101637140Sbostic gmtsub(timep, 0L, &tm);
101737140Sbostic return &tm;
101837140Sbostic }
101937140Sbostic
102037140Sbostic static void
timesub(timep,offset,sp,tmp)102137140Sbostic timesub(timep, offset, sp, tmp)
102237140Sbostic const time_t * const timep;
102337140Sbostic const long offset;
102437140Sbostic register const struct state * const sp;
102537140Sbostic register struct tm * const tmp;
102637140Sbostic {
102737140Sbostic register const struct lsinfo * lp;
102837140Sbostic register long days;
102937140Sbostic register long rem;
103037140Sbostic register int y;
103137140Sbostic register int yleap;
103237140Sbostic register const int * ip;
103337140Sbostic register long corr;
103437140Sbostic register int hit;
103537140Sbostic register int i;
103637140Sbostic
103737140Sbostic corr = 0;
103837140Sbostic hit = FALSE;
103937140Sbostic #ifdef ALL_STATE
104037140Sbostic i = (sp == NULL) ? 0 : sp->leapcnt;
104137140Sbostic #endif /* defined ALL_STATE */
104237140Sbostic #ifndef ALL_STATE
104337140Sbostic i = sp->leapcnt;
104437140Sbostic #endif /* State Farm */
104537140Sbostic while (--i >= 0) {
104637140Sbostic lp = &sp->lsis[i];
104737140Sbostic if (*timep >= lp->ls_trans) {
104837140Sbostic if (*timep == lp->ls_trans)
104937140Sbostic hit = ((i == 0 && lp->ls_corr > 0) ||
105037140Sbostic lp->ls_corr > sp->lsis[i - 1].ls_corr);
105137140Sbostic corr = lp->ls_corr;
105237140Sbostic break;
105337140Sbostic }
105437140Sbostic }
105537140Sbostic days = *timep / SECSPERDAY;
105637140Sbostic rem = *timep % SECSPERDAY;
105737140Sbostic #ifdef mc68k
105837140Sbostic if (*timep == 0x80000000) {
105937140Sbostic /*
106037140Sbostic ** A 3B1 muffs the division on the most negative number.
106137140Sbostic */
106237140Sbostic days = -24855;
106337140Sbostic rem = -11648;
106437140Sbostic }
106537140Sbostic #endif /* mc68k */
106637140Sbostic rem += (offset - corr);
106730608Sbostic while (rem < 0) {
106837140Sbostic rem += SECSPERDAY;
106930608Sbostic --days;
10701959Swnj }
107137140Sbostic while (rem >= SECSPERDAY) {
107237140Sbostic rem -= SECSPERDAY;
107330608Sbostic ++days;
107430608Sbostic }
107537140Sbostic tmp->tm_hour = (int) (rem / SECSPERHOUR);
107637140Sbostic rem = rem % SECSPERHOUR;
107737140Sbostic tmp->tm_min = (int) (rem / SECSPERMIN);
107837140Sbostic tmp->tm_sec = (int) (rem % SECSPERMIN);
107937140Sbostic if (hit)
108037140Sbostic /*
108137140Sbostic ** A positive leap second requires a special
108237140Sbostic ** representation. This uses "... ??:59:60".
108337140Sbostic */
108437140Sbostic ++(tmp->tm_sec);
108537140Sbostic tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
108630608Sbostic if (tmp->tm_wday < 0)
108737140Sbostic tmp->tm_wday += DAYSPERWEEK;
108830608Sbostic y = EPOCH_YEAR;
108930608Sbostic if (days >= 0)
109030608Sbostic for ( ; ; ) {
109130608Sbostic yleap = isleap(y);
109230608Sbostic if (days < (long) year_lengths[yleap])
109330608Sbostic break;
109430608Sbostic ++y;
109530608Sbostic days = days - (long) year_lengths[yleap];
109630608Sbostic }
109730608Sbostic else do {
109830608Sbostic --y;
109930608Sbostic yleap = isleap(y);
110030608Sbostic days = days + (long) year_lengths[yleap];
110130608Sbostic } while (days < 0);
110230608Sbostic tmp->tm_year = y - TM_YEAR_BASE;
110330608Sbostic tmp->tm_yday = (int) days;
110430608Sbostic ip = mon_lengths[yleap];
110530608Sbostic for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
110630608Sbostic days = days - (long) ip[tmp->tm_mon];
110730608Sbostic tmp->tm_mday = (int) (days + 1);
110830608Sbostic tmp->tm_isdst = 0;
110943478Sbostic tmp->tm_gmtoff = offset;
11101959Swnj }
111137140Sbostic
111237140Sbostic /*
111337140Sbostic ** A la X3J11
111437140Sbostic */
111537140Sbostic
111637140Sbostic char *
asctime(timeptr)111737140Sbostic asctime(timeptr)
111837140Sbostic register const struct tm * timeptr;
111937140Sbostic {
112037140Sbostic static const char wday_name[DAYSPERWEEK][3] = {
112137140Sbostic "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
112237140Sbostic };
112337140Sbostic static const char mon_name[MONSPERYEAR][3] = {
112437140Sbostic "Jan", "Feb", "Mar", "Apr", "May", "Jun",
112537140Sbostic "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
112637140Sbostic };
112737140Sbostic static char result[26];
112837140Sbostic
112937140Sbostic (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
113037140Sbostic wday_name[timeptr->tm_wday],
113137140Sbostic mon_name[timeptr->tm_mon],
113237140Sbostic timeptr->tm_mday, timeptr->tm_hour,
113337140Sbostic timeptr->tm_min, timeptr->tm_sec,
113437140Sbostic TM_YEAR_BASE + timeptr->tm_year);
113537140Sbostic return result;
113637140Sbostic }
113737140Sbostic
113837140Sbostic char *
ctime(timep)113937140Sbostic ctime(timep)
114037140Sbostic const time_t * const timep;
114137140Sbostic {
114237140Sbostic return asctime(localtime(timep));
114337140Sbostic }
114437140Sbostic
114537140Sbostic /*
114637140Sbostic ** Adapted from code provided by Robert Elz, who writes:
114737140Sbostic ** The "best" way to do mktime I think is based on an idea of Bob
114837140Sbostic ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
114937140Sbostic ** It does a binary search of the time_t space. Since time_t's are
115037140Sbostic ** just 32 bits, its a max of 32 iterations (even at 64 bits it
115137140Sbostic ** would still be very reasonable).
115237140Sbostic */
115337140Sbostic
115437140Sbostic #ifndef WRONG
115537140Sbostic #define WRONG (-1)
115637140Sbostic #endif /* !defined WRONG */
115737140Sbostic
115837140Sbostic static void
normalize(tensptr,unitsptr,base)115937140Sbostic normalize(tensptr, unitsptr, base)
116037140Sbostic int * const tensptr;
116137140Sbostic int * const unitsptr;
116237140Sbostic const int base;
116337140Sbostic {
116437140Sbostic if (*unitsptr >= base) {
116537140Sbostic *tensptr += *unitsptr / base;
116637140Sbostic *unitsptr %= base;
116737140Sbostic } else if (*unitsptr < 0) {
116857424Sbostic *tensptr -= 1 + (-(*unitsptr + 1)) / base;
116957424Sbostic *unitsptr = base - 1 - (-(*unitsptr + 1)) % base;
117037140Sbostic }
117137140Sbostic }
117237140Sbostic
117337140Sbostic static int
tmcomp(atmp,btmp)117437140Sbostic tmcomp(atmp, btmp)
117537140Sbostic register const struct tm * const atmp;
117637140Sbostic register const struct tm * const btmp;
117737140Sbostic {
117837140Sbostic register int result;
117937140Sbostic
118037140Sbostic if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
118137140Sbostic (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
118237140Sbostic (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
118337140Sbostic (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
118437140Sbostic (result = (atmp->tm_min - btmp->tm_min)) == 0)
118537140Sbostic result = atmp->tm_sec - btmp->tm_sec;
118637140Sbostic return result;
118737140Sbostic }
118837140Sbostic
118937140Sbostic static time_t
time2(tmp,funcp,offset,okayp)119037140Sbostic time2(tmp, funcp, offset, okayp)
119137140Sbostic struct tm * const tmp;
119237140Sbostic void (* const funcp)();
119337140Sbostic const long offset;
119437140Sbostic int * const okayp;
119537140Sbostic {
119637140Sbostic register const struct state * sp;
119737140Sbostic register int dir;
119837140Sbostic register int bits;
119937140Sbostic register int i, j ;
120037140Sbostic register int saved_seconds;
120137140Sbostic time_t newt;
120237140Sbostic time_t t;
120337140Sbostic struct tm yourtm, mytm;
120437140Sbostic
120537140Sbostic *okayp = FALSE;
120637140Sbostic yourtm = *tmp;
120737140Sbostic if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
120837140Sbostic normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
120937140Sbostic normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
121037140Sbostic normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
121137140Sbostic normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
121237140Sbostic while (yourtm.tm_mday <= 0) {
121337140Sbostic --yourtm.tm_year;
121437140Sbostic yourtm.tm_mday +=
121537140Sbostic year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
121637140Sbostic }
1217*66409Sbostic while (yourtm.tm_mday > DAYSPERLYEAR) {
1218*66409Sbostic yourtm.tm_mday -=
1219*66409Sbostic year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1220*66409Sbostic ++yourtm.tm_year;
1221*66409Sbostic }
122237140Sbostic for ( ; ; ) {
122337140Sbostic i = mon_lengths[isleap(yourtm.tm_year +
122437140Sbostic TM_YEAR_BASE)][yourtm.tm_mon];
122537140Sbostic if (yourtm.tm_mday <= i)
122637140Sbostic break;
122737140Sbostic yourtm.tm_mday -= i;
122837140Sbostic if (++yourtm.tm_mon >= MONSPERYEAR) {
122937140Sbostic yourtm.tm_mon = 0;
123037140Sbostic ++yourtm.tm_year;
123137140Sbostic }
123237140Sbostic }
123337140Sbostic saved_seconds = yourtm.tm_sec;
123437140Sbostic yourtm.tm_sec = 0;
123537140Sbostic /*
123637140Sbostic ** Calculate the number of magnitude bits in a time_t
123737140Sbostic ** (this works regardless of whether time_t is
123837140Sbostic ** signed or unsigned, though lint complains if unsigned).
123937140Sbostic */
124037140Sbostic for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
124137140Sbostic ;
124237140Sbostic /*
124337140Sbostic ** If time_t is signed, then 0 is the median value,
124437140Sbostic ** if time_t is unsigned, then 1 << bits is median.
124537140Sbostic */
124637140Sbostic t = (t < 0) ? 0 : ((time_t) 1 << bits);
124737140Sbostic for ( ; ; ) {
124837140Sbostic (*funcp)(&t, offset, &mytm);
124937140Sbostic dir = tmcomp(&mytm, &yourtm);
125037140Sbostic if (dir != 0) {
125137140Sbostic if (bits-- < 0)
125237140Sbostic return WRONG;
125337140Sbostic if (bits < 0)
125437140Sbostic --t;
125537140Sbostic else if (dir > 0)
125637140Sbostic t -= (time_t) 1 << bits;
125737140Sbostic else t += (time_t) 1 << bits;
125837140Sbostic continue;
125937140Sbostic }
126037140Sbostic if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
126137140Sbostic break;
126237140Sbostic /*
126337140Sbostic ** Right time, wrong type.
126437140Sbostic ** Hunt for right time, right type.
126537140Sbostic ** It's okay to guess wrong since the guess
126637140Sbostic ** gets checked.
126737140Sbostic */
126837140Sbostic sp = (const struct state *)
126937140Sbostic ((funcp == localsub) ? lclptr : gmtptr);
127037140Sbostic #ifdef ALL_STATE
127137140Sbostic if (sp == NULL)
127237140Sbostic return WRONG;
127337140Sbostic #endif /* defined ALL_STATE */
127437140Sbostic for (i = 0; i < sp->typecnt; ++i) {
127537140Sbostic if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
127637140Sbostic continue;
127737140Sbostic for (j = 0; j < sp->typecnt; ++j) {
127837140Sbostic if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
127937140Sbostic continue;
128037140Sbostic newt = t + sp->ttis[j].tt_gmtoff -
128137140Sbostic sp->ttis[i].tt_gmtoff;
128237140Sbostic (*funcp)(&newt, offset, &mytm);
128337140Sbostic if (tmcomp(&mytm, &yourtm) != 0)
128437140Sbostic continue;
128537140Sbostic if (mytm.tm_isdst != yourtm.tm_isdst)
128637140Sbostic continue;
128737140Sbostic /*
128837140Sbostic ** We have a match.
128937140Sbostic */
129037140Sbostic t = newt;
129137140Sbostic goto label;
129237140Sbostic }
129337140Sbostic }
129437140Sbostic return WRONG;
129537140Sbostic }
129637140Sbostic label:
129737140Sbostic t += saved_seconds;
129837140Sbostic (*funcp)(&t, offset, tmp);
129937140Sbostic *okayp = TRUE;
130037140Sbostic return t;
130137140Sbostic }
130237140Sbostic
130337140Sbostic static time_t
time1(tmp,funcp,offset)130437140Sbostic time1(tmp, funcp, offset)
130537140Sbostic struct tm * const tmp;
130637140Sbostic void (* const funcp)();
130737140Sbostic const long offset;
130837140Sbostic {
130937140Sbostic register time_t t;
131037140Sbostic register const struct state * sp;
131137140Sbostic register int samei, otheri;
131237140Sbostic int okay;
131337140Sbostic
131437140Sbostic if (tmp->tm_isdst > 1)
131538558Sbostic tmp->tm_isdst = 1;
131637140Sbostic t = time2(tmp, funcp, offset, &okay);
131737140Sbostic if (okay || tmp->tm_isdst < 0)
131837140Sbostic return t;
131937140Sbostic /*
132037140Sbostic ** We're supposed to assume that somebody took a time of one type
132137140Sbostic ** and did some math on it that yielded a "struct tm" that's bad.
132237140Sbostic ** We try to divine the type they started from and adjust to the
132337140Sbostic ** type they need.
132437140Sbostic */
132537140Sbostic sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
132637140Sbostic #ifdef ALL_STATE
132737140Sbostic if (sp == NULL)
132837140Sbostic return WRONG;
132937140Sbostic #endif /* defined ALL_STATE */
133037140Sbostic for (samei = 0; samei < sp->typecnt; ++samei) {
133137140Sbostic if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
133237140Sbostic continue;
133337140Sbostic for (otheri = 0; otheri < sp->typecnt; ++otheri) {
133437140Sbostic if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
133537140Sbostic continue;
133637140Sbostic tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
133737140Sbostic sp->ttis[samei].tt_gmtoff;
133837140Sbostic tmp->tm_isdst = !tmp->tm_isdst;
133937140Sbostic t = time2(tmp, funcp, offset, &okay);
134037140Sbostic if (okay)
134137140Sbostic return t;
134237140Sbostic tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
134337140Sbostic sp->ttis[samei].tt_gmtoff;
134437140Sbostic tmp->tm_isdst = !tmp->tm_isdst;
134537140Sbostic }
134637140Sbostic }
134737140Sbostic return WRONG;
134837140Sbostic }
134937140Sbostic
135037140Sbostic time_t
mktime(tmp)135137140Sbostic mktime(tmp)
135237140Sbostic struct tm * const tmp;
135337140Sbostic {
135437140Sbostic return time1(tmp, localsub, 0L);
135537140Sbostic }
1356