122084Smckusick /* 2*61111Sbostic * Copyright (c) 1987, 1989, 1993 3*61111Sbostic * 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*61111Sbostic static char sccsid[] = "@(#)ctime.c 8.1 (Berkeley) 06/04/93"; 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 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 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 * 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 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 * 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 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 * 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 * 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 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 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 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 } 121737140Sbostic for ( ; ; ) { 121837140Sbostic i = mon_lengths[isleap(yourtm.tm_year + 121937140Sbostic TM_YEAR_BASE)][yourtm.tm_mon]; 122037140Sbostic if (yourtm.tm_mday <= i) 122137140Sbostic break; 122237140Sbostic yourtm.tm_mday -= i; 122337140Sbostic if (++yourtm.tm_mon >= MONSPERYEAR) { 122437140Sbostic yourtm.tm_mon = 0; 122537140Sbostic ++yourtm.tm_year; 122637140Sbostic } 122737140Sbostic } 122837140Sbostic saved_seconds = yourtm.tm_sec; 122937140Sbostic yourtm.tm_sec = 0; 123037140Sbostic /* 123137140Sbostic ** Calculate the number of magnitude bits in a time_t 123237140Sbostic ** (this works regardless of whether time_t is 123337140Sbostic ** signed or unsigned, though lint complains if unsigned). 123437140Sbostic */ 123537140Sbostic for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 123637140Sbostic ; 123737140Sbostic /* 123837140Sbostic ** If time_t is signed, then 0 is the median value, 123937140Sbostic ** if time_t is unsigned, then 1 << bits is median. 124037140Sbostic */ 124137140Sbostic t = (t < 0) ? 0 : ((time_t) 1 << bits); 124237140Sbostic for ( ; ; ) { 124337140Sbostic (*funcp)(&t, offset, &mytm); 124437140Sbostic dir = tmcomp(&mytm, &yourtm); 124537140Sbostic if (dir != 0) { 124637140Sbostic if (bits-- < 0) 124737140Sbostic return WRONG; 124837140Sbostic if (bits < 0) 124937140Sbostic --t; 125037140Sbostic else if (dir > 0) 125137140Sbostic t -= (time_t) 1 << bits; 125237140Sbostic else t += (time_t) 1 << bits; 125337140Sbostic continue; 125437140Sbostic } 125537140Sbostic if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 125637140Sbostic break; 125737140Sbostic /* 125837140Sbostic ** Right time, wrong type. 125937140Sbostic ** Hunt for right time, right type. 126037140Sbostic ** It's okay to guess wrong since the guess 126137140Sbostic ** gets checked. 126237140Sbostic */ 126337140Sbostic sp = (const struct state *) 126437140Sbostic ((funcp == localsub) ? lclptr : gmtptr); 126537140Sbostic #ifdef ALL_STATE 126637140Sbostic if (sp == NULL) 126737140Sbostic return WRONG; 126837140Sbostic #endif /* defined ALL_STATE */ 126937140Sbostic for (i = 0; i < sp->typecnt; ++i) { 127037140Sbostic if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 127137140Sbostic continue; 127237140Sbostic for (j = 0; j < sp->typecnt; ++j) { 127337140Sbostic if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 127437140Sbostic continue; 127537140Sbostic newt = t + sp->ttis[j].tt_gmtoff - 127637140Sbostic sp->ttis[i].tt_gmtoff; 127737140Sbostic (*funcp)(&newt, offset, &mytm); 127837140Sbostic if (tmcomp(&mytm, &yourtm) != 0) 127937140Sbostic continue; 128037140Sbostic if (mytm.tm_isdst != yourtm.tm_isdst) 128137140Sbostic continue; 128237140Sbostic /* 128337140Sbostic ** We have a match. 128437140Sbostic */ 128537140Sbostic t = newt; 128637140Sbostic goto label; 128737140Sbostic } 128837140Sbostic } 128937140Sbostic return WRONG; 129037140Sbostic } 129137140Sbostic label: 129237140Sbostic t += saved_seconds; 129337140Sbostic (*funcp)(&t, offset, tmp); 129437140Sbostic *okayp = TRUE; 129537140Sbostic return t; 129637140Sbostic } 129737140Sbostic 129837140Sbostic static time_t 129937140Sbostic time1(tmp, funcp, offset) 130037140Sbostic struct tm * const tmp; 130137140Sbostic void (* const funcp)(); 130237140Sbostic const long offset; 130337140Sbostic { 130437140Sbostic register time_t t; 130537140Sbostic register const struct state * sp; 130637140Sbostic register int samei, otheri; 130737140Sbostic int okay; 130837140Sbostic 130937140Sbostic if (tmp->tm_isdst > 1) 131038558Sbostic tmp->tm_isdst = 1; 131137140Sbostic t = time2(tmp, funcp, offset, &okay); 131237140Sbostic if (okay || tmp->tm_isdst < 0) 131337140Sbostic return t; 131437140Sbostic /* 131537140Sbostic ** We're supposed to assume that somebody took a time of one type 131637140Sbostic ** and did some math on it that yielded a "struct tm" that's bad. 131737140Sbostic ** We try to divine the type they started from and adjust to the 131837140Sbostic ** type they need. 131937140Sbostic */ 132037140Sbostic sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 132137140Sbostic #ifdef ALL_STATE 132237140Sbostic if (sp == NULL) 132337140Sbostic return WRONG; 132437140Sbostic #endif /* defined ALL_STATE */ 132537140Sbostic for (samei = 0; samei < sp->typecnt; ++samei) { 132637140Sbostic if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 132737140Sbostic continue; 132837140Sbostic for (otheri = 0; otheri < sp->typecnt; ++otheri) { 132937140Sbostic if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 133037140Sbostic continue; 133137140Sbostic tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 133237140Sbostic sp->ttis[samei].tt_gmtoff; 133337140Sbostic tmp->tm_isdst = !tmp->tm_isdst; 133437140Sbostic t = time2(tmp, funcp, offset, &okay); 133537140Sbostic if (okay) 133637140Sbostic return t; 133737140Sbostic tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 133837140Sbostic sp->ttis[samei].tt_gmtoff; 133937140Sbostic tmp->tm_isdst = !tmp->tm_isdst; 134037140Sbostic } 134137140Sbostic } 134237140Sbostic return WRONG; 134337140Sbostic } 134437140Sbostic 134537140Sbostic time_t 134637140Sbostic mktime(tmp) 134737140Sbostic struct tm * const tmp; 134837140Sbostic { 134937140Sbostic return time1(tmp, localsub, 0L); 135037140Sbostic } 1351