122084Smckusick /* 2*37140Sbostic * Copyright (c) 1987, 1989 Regents of the University of California. 332754Sbostic * All rights reserved. 432754Sbostic * 534952Sbostic * This code is derived from software contributed to Berkeley by 634952Sbostic * Arthur Olson. 734952Sbostic * 832754Sbostic * Redistribution and use in source and binary forms are permitted 934821Sbostic * provided that the above copyright notice and this paragraph are 1034821Sbostic * duplicated in all such forms and that any documentation, 1134821Sbostic * advertising materials, and other materials related to such 1234821Sbostic * distribution and use acknowledge that the software was developed 1334821Sbostic * by the University of California, Berkeley. The name of the 1434821Sbostic * University may not be used to endorse or promote products derived 1534821Sbostic * from this software without specific prior written permission. 1634821Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734821Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834821Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1922084Smckusick */ 2022084Smckusick 2130684Sbostic #if defined(LIBC_SCCS) && !defined(lint) 22*37140Sbostic static char sccsid[] = "@(#)ctime.c 5.15 (Berkeley) 03/12/89"; 2332754Sbostic #endif /* LIBC_SCCS and not lint */ 2422084Smckusick 25*37140Sbostic /* 26*37140Sbostic ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 27*37140Sbostic ** POSIX-style TZ environment variable handling from Guy Harris 28*37140Sbostic ** (guy@auspex.com). 29*37140Sbostic */ 301959Swnj 31*37140Sbostic /*LINTLIBRARY*/ 321959Swnj 33*37140Sbostic #include <sys/param.h> 34*37140Sbostic #include <fcntl.h> 35*37140Sbostic #include <time.h> 36*37140Sbostic #include <tzfile.h> 37*37140Sbostic #include <string.h> 38*37140Sbostic #include <ctype.h> 39*37140Sbostic #include <stdio.h> 4030608Sbostic 41*37140Sbostic #ifdef __STDC__ 42*37140Sbostic #include <stdlib.h> 43*37140Sbostic 44*37140Sbostic #define P(s) s 45*37140Sbostic #define alloc_size_t size_t 46*37140Sbostic #define qsort_size_t size_t 47*37140Sbostic #define fread_size_t size_t 48*37140Sbostic #define fwrite_size_t size_t 49*37140Sbostic 50*37140Sbostic #else /* !defined __STDC__ */ 51*37140Sbostic 52*37140Sbostic #define ASTERISK * 53*37140Sbostic #define P(s) (/ASTERISK s ASTERISK/) 54*37140Sbostic #define const 55*37140Sbostic #define volatile 56*37140Sbostic 57*37140Sbostic typedef char * genericptr_t; 58*37140Sbostic typedef unsigned alloc_size_t; 59*37140Sbostic typedef int qsort_size_t; 60*37140Sbostic typedef int fread_size_t; 61*37140Sbostic typedef int fwrite_size_t; 62*37140Sbostic 63*37140Sbostic extern char * calloc(); 64*37140Sbostic extern char * malloc(); 65*37140Sbostic extern char * realloc(); 66*37140Sbostic extern char * getenv(); 67*37140Sbostic 68*37140Sbostic #endif /* !defined __STDC__ */ 69*37140Sbostic 70*37140Sbostic extern time_t time(); 71*37140Sbostic 72*37140Sbostic #define FILENAME_MAX MAXPATHLEN 73*37140Sbostic #define ACCESS_MODE O_RDONLY 74*37140Sbostic #define OPEN_MODE O_RDONLY 75*37140Sbostic 76*37140Sbostic #ifndef WILDABBR 771959Swnj /* 78*37140Sbostic ** Someone might make incorrect use of a time zone abbreviation: 79*37140Sbostic ** 1. They might reference tzname[0] before calling tzset (explicitly 80*37140Sbostic ** or implicitly). 81*37140Sbostic ** 2. They might reference tzname[1] before calling tzset (explicitly 82*37140Sbostic ** or implicitly). 83*37140Sbostic ** 3. They might reference tzname[1] after setting to a time zone 84*37140Sbostic ** in which Daylight Saving Time is never observed. 85*37140Sbostic ** 4. They might reference tzname[0] after setting to a time zone 86*37140Sbostic ** in which Standard Time is never observed. 87*37140Sbostic ** 5. They might reference tm.TM_ZONE after calling offtime. 88*37140Sbostic ** What's best to do in the above cases is open to debate; 89*37140Sbostic ** for now, we just set things up so that in any of the five cases 90*37140Sbostic ** WILDABBR is used. Another possibility: initialize tzname[0] to the 91*37140Sbostic ** string "tzname[0] used before set", and similarly for the other cases. 92*37140Sbostic ** And another: initialize tzname[0] to "ERA", with an explanation in the 93*37140Sbostic ** manual page of what this "time zone abbreviation" means (doing this so 94*37140Sbostic ** that tzname[0] has the "normal" length of three characters). 9530608Sbostic */ 96*37140Sbostic #define WILDABBR " " 97*37140Sbostic #endif /* !defined WILDABBR */ 981959Swnj 9930608Sbostic #ifndef TRUE 10030608Sbostic #define TRUE 1 10130608Sbostic #define FALSE 0 102*37140Sbostic #endif /* !defined TRUE */ 10330608Sbostic 104*37140Sbostic static const char GMT[] = "GMT"; 10530608Sbostic 10630608Sbostic struct ttinfo { /* time type information */ 10730608Sbostic long tt_gmtoff; /* GMT offset in seconds */ 10830608Sbostic int tt_isdst; /* used to set tm_isdst */ 10930608Sbostic int tt_abbrind; /* abbreviation list index */ 110*37140Sbostic int tt_ttisstd; /* TRUE if transition is std time */ 11113876Ssam }; 11213876Ssam 113*37140Sbostic struct lsinfo { /* leap second information */ 114*37140Sbostic time_t ls_trans; /* transition time */ 115*37140Sbostic long ls_corr; /* correction to apply */ 116*37140Sbostic }; 117*37140Sbostic 11830608Sbostic struct state { 119*37140Sbostic int leapcnt; 12030608Sbostic int timecnt; 12130608Sbostic int typecnt; 12230608Sbostic int charcnt; 12330608Sbostic time_t ats[TZ_MAX_TIMES]; 12430608Sbostic unsigned char types[TZ_MAX_TIMES]; 12530608Sbostic struct ttinfo ttis[TZ_MAX_TYPES]; 126*37140Sbostic char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? 127*37140Sbostic TZ_MAX_CHARS + 1 : sizeof GMT]; 128*37140Sbostic struct lsinfo lsis[TZ_MAX_LEAPS]; 12923720Skre }; 13023720Skre 131*37140Sbostic struct rule { 132*37140Sbostic int r_type; /* type of rule--see below */ 133*37140Sbostic int r_day; /* day number of rule */ 134*37140Sbostic int r_week; /* week number of rule */ 135*37140Sbostic int r_mon; /* month number of rule */ 136*37140Sbostic long r_time; /* transition time of rule */ 137*37140Sbostic }; 13830608Sbostic 139*37140Sbostic #define JULIAN_DAY 0 /* Jn - Julian day */ 140*37140Sbostic #define DAY_OF_YEAR 1 /* n - day of year */ 141*37140Sbostic #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 14230608Sbostic 143*37140Sbostic /* 144*37140Sbostic ** Prototypes for static functions. 145*37140Sbostic */ 146*37140Sbostic 147*37140Sbostic static long detzcode P((const char * codep)); 148*37140Sbostic static const char * getzname P((const char * strp)); 149*37140Sbostic static const char * getnum P((const char * strp, int * nump, int min, 150*37140Sbostic int max)); 151*37140Sbostic static const char * getsecs P((const char * strp, long * secsp)); 152*37140Sbostic static const char * getoffset P((const char * strp, long * offsetp)); 153*37140Sbostic static const char * getrule P((const char * strp, struct rule * rulep)); 154*37140Sbostic static void gmtload P((struct state * sp)); 155*37140Sbostic static void gmtsub P((const time_t * timep, long offset, 156*37140Sbostic struct tm * tmp)); 157*37140Sbostic static void localsub P((const time_t * timep, long offset, 158*37140Sbostic struct tm * tmp)); 159*37140Sbostic static void normalize P((int * tensptr, int * unitsptr, int base)); 160*37140Sbostic static void settzname P((void)); 161*37140Sbostic static time_t time1 P((struct tm * tmp, void (* funcp)(), 162*37140Sbostic long offset)); 163*37140Sbostic static time_t time2 P((struct tm *tmp, void (* funcp)(), 164*37140Sbostic long offset, int * okayp)); 165*37140Sbostic static void timesub P((const time_t * timep, long offset, 166*37140Sbostic const struct state * sp, struct tm * tmp)); 167*37140Sbostic static int tmcomp P((const struct tm * atmp, 168*37140Sbostic const struct tm * btmp)); 169*37140Sbostic static time_t transtime P((time_t janfirst, int year, 170*37140Sbostic const struct rule * rulep, long offset)); 171*37140Sbostic static int tzload P((const char * name, struct state * sp)); 172*37140Sbostic static int tzparse P((const char * name, struct state * sp, 173*37140Sbostic int lastditch)); 174*37140Sbostic 175*37140Sbostic #ifdef ALL_STATE 176*37140Sbostic static struct state * lclptr; 177*37140Sbostic static struct state * gmtptr; 178*37140Sbostic #endif /* defined ALL_STATE */ 179*37140Sbostic 180*37140Sbostic #ifndef ALL_STATE 181*37140Sbostic static struct state lclmem; 182*37140Sbostic static struct state gmtmem; 183*37140Sbostic #define lclptr (&lclmem) 184*37140Sbostic #define gmtptr (&gmtmem) 185*37140Sbostic #endif /* State Farm */ 186*37140Sbostic 187*37140Sbostic static int lcl_is_set; 188*37140Sbostic static int gmt_is_set; 189*37140Sbostic 19030608Sbostic char * tzname[2] = { 191*37140Sbostic WILDABBR, 192*37140Sbostic WILDABBR 19312974Ssam }; 19412974Ssam 19530608Sbostic #ifdef USG_COMPAT 19630608Sbostic time_t timezone = 0; 19730608Sbostic int daylight = 0; 198*37140Sbostic #endif /* defined USG_COMPAT */ 1991959Swnj 200*37140Sbostic #ifdef ALTZONE 201*37140Sbostic time_t altzone = 0; 202*37140Sbostic #endif /* defined ALTZONE */ 203*37140Sbostic 20430608Sbostic static long 20530608Sbostic detzcode(codep) 206*37140Sbostic const char * const codep; 2071959Swnj { 20830608Sbostic register long result; 20930608Sbostic register int i; 21030608Sbostic 21130608Sbostic result = 0; 21230608Sbostic for (i = 0; i < 4; ++i) 21330608Sbostic result = (result << 8) | (codep[i] & 0xff); 21430608Sbostic return result; 2151959Swnj } 2161959Swnj 217*37140Sbostic static void 218*37140Sbostic settzname() 2191959Swnj { 220*37140Sbostic register const struct state * const sp = lclptr; 221*37140Sbostic register int i; 2221959Swnj 223*37140Sbostic tzname[0] = WILDABBR; 224*37140Sbostic tzname[1] = WILDABBR; 225*37140Sbostic #ifdef USG_COMPAT 226*37140Sbostic daylight = 0; 227*37140Sbostic timezone = 0; 228*37140Sbostic #endif /* defined USG_COMPAT */ 229*37140Sbostic #ifdef ALTZONE 230*37140Sbostic altzone = 0; 231*37140Sbostic #endif /* defined ALTZONE */ 232*37140Sbostic #ifdef ALL_STATE 233*37140Sbostic if (sp == NULL) { 234*37140Sbostic tzname[0] = tzname[1] = GMT; 235*37140Sbostic return; 236*37140Sbostic } 237*37140Sbostic #endif /* defined ALL_STATE */ 238*37140Sbostic for (i = 0; i < sp->typecnt; ++i) { 239*37140Sbostic register const struct ttinfo * const ttisp = &sp->ttis[i]; 240*37140Sbostic 241*37140Sbostic tzname[ttisp->tt_isdst] = 242*37140Sbostic (char *) &sp->chars[ttisp->tt_abbrind]; 243*37140Sbostic #ifdef USG_COMPAT 244*37140Sbostic if (ttisp->tt_isdst) 245*37140Sbostic daylight = 1; 246*37140Sbostic if (i == 0 || !ttisp->tt_isdst) 247*37140Sbostic timezone = -(ttisp->tt_gmtoff); 248*37140Sbostic #endif /* defined USG_COMPAT */ 249*37140Sbostic #ifdef ALTZONE 250*37140Sbostic if (i == 0 || ttisp->tt_isdst) 251*37140Sbostic altzone = -(ttisp->tt_gmtoff); 252*37140Sbostic #endif /* defined ALTZONE */ 253*37140Sbostic } 254*37140Sbostic /* 255*37140Sbostic ** And to get the latest zone names into tzname. . . 256*37140Sbostic */ 257*37140Sbostic for (i = 0; i < sp->timecnt; ++i) { 258*37140Sbostic register const struct ttinfo * const ttisp = 259*37140Sbostic &sp->ttis[sp->types[i]]; 260*37140Sbostic 261*37140Sbostic tzname[ttisp->tt_isdst] = 262*37140Sbostic (char *) &sp->chars[ttisp->tt_abbrind]; 263*37140Sbostic } 264*37140Sbostic } 265*37140Sbostic 266*37140Sbostic static int 267*37140Sbostic tzload(name, sp) 268*37140Sbostic register const char * name; 269*37140Sbostic register struct state * const sp; 270*37140Sbostic { 271*37140Sbostic register const char * p; 272*37140Sbostic register int i; 273*37140Sbostic register int fid; 274*37140Sbostic 275*37140Sbostic if (name == NULL && (name = TZDEFAULT) == NULL) 27630608Sbostic return -1; 27730608Sbostic { 278*37140Sbostic register int doaccess; 279*37140Sbostic char fullname[FILENAME_MAX + 1]; 28030608Sbostic 281*37140Sbostic if (name[0] == ':') 282*37140Sbostic ++name; 28330608Sbostic doaccess = name[0] == '/'; 28430608Sbostic if (!doaccess) { 285*37140Sbostic if ((p = TZDIR) == NULL) 28630608Sbostic return -1; 28730608Sbostic if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 28830608Sbostic return -1; 28930608Sbostic (void) strcpy(fullname, p); 29030608Sbostic (void) strcat(fullname, "/"); 29130608Sbostic (void) strcat(fullname, name); 29230608Sbostic /* 29330608Sbostic ** Set doaccess if '.' (as in "../") shows up in name. 29430608Sbostic */ 295*37140Sbostic if (strchr(name, '.') != NULL) 296*37140Sbostic doaccess = TRUE; 29730608Sbostic name = fullname; 29830608Sbostic } 299*37140Sbostic if (doaccess && access(name, ACCESS_MODE) != 0) 30030608Sbostic return -1; 301*37140Sbostic if ((fid = open(name, OPEN_MODE)) == -1) 30230608Sbostic return -1; 30325662Sbloom } 30430608Sbostic { 305*37140Sbostic register const struct tzhead * tzhp; 306*37140Sbostic char buf[sizeof *sp + sizeof *tzhp]; 307*37140Sbostic int ttisstdcnt; 30830608Sbostic 30930608Sbostic i = read(fid, buf, sizeof buf); 31030608Sbostic if (close(fid) != 0 || i < sizeof *tzhp) 31130608Sbostic return -1; 31230608Sbostic tzhp = (struct tzhead *) buf; 313*37140Sbostic ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); 314*37140Sbostic sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); 315*37140Sbostic sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); 316*37140Sbostic sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); 317*37140Sbostic sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); 318*37140Sbostic if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 319*37140Sbostic sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 320*37140Sbostic sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 321*37140Sbostic sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 322*37140Sbostic (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) 32330608Sbostic return -1; 32430608Sbostic if (i < sizeof *tzhp + 325*37140Sbostic sp->timecnt * (4 + sizeof (char)) + 326*37140Sbostic sp->typecnt * (4 + 2 * sizeof (char)) + 327*37140Sbostic sp->charcnt * sizeof (char) + 328*37140Sbostic sp->leapcnt * 2 * 4 + 329*37140Sbostic ttisstdcnt * sizeof (char)) 33030608Sbostic return -1; 33130608Sbostic p = buf + sizeof *tzhp; 332*37140Sbostic for (i = 0; i < sp->timecnt; ++i) { 333*37140Sbostic sp->ats[i] = detzcode(p); 33430608Sbostic p += 4; 33512974Ssam } 336*37140Sbostic for (i = 0; i < sp->timecnt; ++i) { 337*37140Sbostic sp->types[i] = (unsigned char) *p++; 338*37140Sbostic if (sp->types[i] >= sp->typecnt) 339*37140Sbostic return -1; 340*37140Sbostic } 341*37140Sbostic for (i = 0; i < sp->typecnt; ++i) { 34230608Sbostic register struct ttinfo * ttisp; 34330608Sbostic 344*37140Sbostic ttisp = &sp->ttis[i]; 34530608Sbostic ttisp->tt_gmtoff = detzcode(p); 34630608Sbostic p += 4; 34730608Sbostic ttisp->tt_isdst = (unsigned char) *p++; 348*37140Sbostic if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 349*37140Sbostic return -1; 35030608Sbostic ttisp->tt_abbrind = (unsigned char) *p++; 351*37140Sbostic if (ttisp->tt_abbrind < 0 || 352*37140Sbostic ttisp->tt_abbrind > sp->charcnt) 353*37140Sbostic return -1; 35430608Sbostic } 355*37140Sbostic for (i = 0; i < sp->charcnt; ++i) 356*37140Sbostic sp->chars[i] = *p++; 357*37140Sbostic sp->chars[i] = '\0'; /* ensure '\0' at end */ 358*37140Sbostic for (i = 0; i < sp->leapcnt; ++i) { 359*37140Sbostic register struct lsinfo * lsisp; 360*37140Sbostic 361*37140Sbostic lsisp = &sp->lsis[i]; 362*37140Sbostic lsisp->ls_trans = detzcode(p); 363*37140Sbostic p += 4; 364*37140Sbostic lsisp->ls_corr = detzcode(p); 365*37140Sbostic p += 4; 366*37140Sbostic } 367*37140Sbostic for (i = 0; i < sp->typecnt; ++i) { 368*37140Sbostic register struct ttinfo * ttisp; 369*37140Sbostic 370*37140Sbostic ttisp = &sp->ttis[i]; 371*37140Sbostic if (ttisstdcnt == 0) 372*37140Sbostic ttisp->tt_ttisstd = FALSE; 373*37140Sbostic else { 374*37140Sbostic ttisp->tt_ttisstd = *p++; 375*37140Sbostic if (ttisp->tt_ttisstd != TRUE && 376*37140Sbostic ttisp->tt_ttisstd != FALSE) 377*37140Sbostic return -1; 378*37140Sbostic } 379*37140Sbostic } 3801959Swnj } 381*37140Sbostic return 0; 382*37140Sbostic } 383*37140Sbostic 384*37140Sbostic static const int mon_lengths[2][MONSPERYEAR] = { 385*37140Sbostic 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 386*37140Sbostic 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 387*37140Sbostic }; 388*37140Sbostic 389*37140Sbostic static const int year_lengths[2] = { 390*37140Sbostic DAYSPERNYEAR, DAYSPERLYEAR 391*37140Sbostic }; 392*37140Sbostic 393*37140Sbostic /* 394*37140Sbostic ** Given a pointer into a time zone string, scan until a character that is not 395*37140Sbostic ** a valid character in a zone name is found. Return a pointer to that 396*37140Sbostic ** character. 397*37140Sbostic */ 398*37140Sbostic 399*37140Sbostic static const char * 400*37140Sbostic getzname(strp) 401*37140Sbostic register const char * strp; 402*37140Sbostic { 403*37140Sbostic register char c; 404*37140Sbostic 405*37140Sbostic while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && 406*37140Sbostic c != '+') 407*37140Sbostic ++strp; 408*37140Sbostic return strp; 409*37140Sbostic } 410*37140Sbostic 411*37140Sbostic /* 412*37140Sbostic ** Given a pointer into a time zone string, extract a number from that string. 413*37140Sbostic ** Check that the number is within a specified range; if it is not, return 414*37140Sbostic ** NULL. 415*37140Sbostic ** Otherwise, return a pointer to the first character not part of the number. 416*37140Sbostic */ 417*37140Sbostic 418*37140Sbostic static const char * 419*37140Sbostic getnum(strp, nump, min, max) 420*37140Sbostic register const char * strp; 421*37140Sbostic int * const nump; 422*37140Sbostic const int min; 423*37140Sbostic const int max; 424*37140Sbostic { 425*37140Sbostic register char c; 426*37140Sbostic register int num; 427*37140Sbostic 428*37140Sbostic if (strp == NULL || !isdigit(*strp)) 429*37140Sbostic return NULL; 430*37140Sbostic num = 0; 431*37140Sbostic while ((c = *strp) != '\0' && isdigit(c)) { 432*37140Sbostic num = num * 10 + (c - '0'); 433*37140Sbostic if (num > max) 434*37140Sbostic return NULL; /* illegal value */ 435*37140Sbostic ++strp; 436*37140Sbostic } 437*37140Sbostic if (num < min) 438*37140Sbostic return NULL; /* illegal value */ 439*37140Sbostic *nump = num; 440*37140Sbostic return strp; 441*37140Sbostic } 442*37140Sbostic 443*37140Sbostic /* 444*37140Sbostic ** Given a pointer into a time zone string, extract a number of seconds, 445*37140Sbostic ** in hh[:mm[:ss]] form, from the string. 446*37140Sbostic ** If any error occurs, return NULL. 447*37140Sbostic ** Otherwise, return a pointer to the first character not part of the number 448*37140Sbostic ** of seconds. 449*37140Sbostic */ 450*37140Sbostic 451*37140Sbostic static const char * 452*37140Sbostic getsecs(strp, secsp) 453*37140Sbostic register const char * strp; 454*37140Sbostic long * const secsp; 455*37140Sbostic { 456*37140Sbostic int num; 457*37140Sbostic 458*37140Sbostic strp = getnum(strp, &num, 0, HOURSPERDAY); 459*37140Sbostic if (strp == NULL) 460*37140Sbostic return NULL; 461*37140Sbostic *secsp = num * SECSPERHOUR; 462*37140Sbostic if (*strp == ':') { 463*37140Sbostic ++strp; 464*37140Sbostic strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 465*37140Sbostic if (strp == NULL) 466*37140Sbostic return NULL; 467*37140Sbostic *secsp += num * SECSPERMIN; 468*37140Sbostic if (*strp == ':') { 469*37140Sbostic ++strp; 470*37140Sbostic strp = getnum(strp, &num, 0, SECSPERMIN - 1); 471*37140Sbostic if (strp == NULL) 472*37140Sbostic return NULL; 473*37140Sbostic *secsp += num; 474*37140Sbostic } 475*37140Sbostic } 476*37140Sbostic return strp; 477*37140Sbostic } 478*37140Sbostic 479*37140Sbostic /* 480*37140Sbostic ** Given a pointer into a time zone string, extract an offset, in 481*37140Sbostic ** [+-]hh[:mm[:ss]] form, from the string. 482*37140Sbostic ** If any error occurs, return NULL. 483*37140Sbostic ** Otherwise, return a pointer to the first character not part of the time. 484*37140Sbostic */ 485*37140Sbostic 486*37140Sbostic static const char * 487*37140Sbostic getoffset(strp, offsetp) 488*37140Sbostic register const char * strp; 489*37140Sbostic long * const offsetp; 490*37140Sbostic { 491*37140Sbostic register int neg; 492*37140Sbostic 493*37140Sbostic if (*strp == '-') { 494*37140Sbostic neg = 1; 495*37140Sbostic ++strp; 496*37140Sbostic } else if (isdigit(*strp) || *strp++ == '+') 497*37140Sbostic neg = 0; 498*37140Sbostic else return NULL; /* illegal offset */ 499*37140Sbostic strp = getsecs(strp, offsetp); 500*37140Sbostic if (strp == NULL) 501*37140Sbostic return NULL; /* illegal time */ 502*37140Sbostic if (neg) 503*37140Sbostic *offsetp = -*offsetp; 504*37140Sbostic return strp; 505*37140Sbostic } 506*37140Sbostic 507*37140Sbostic /* 508*37140Sbostic ** Given a pointer into a time zone string, extract a rule in the form 509*37140Sbostic ** date[/time]. See POSIX section 8 for the format of "date" and "time". 510*37140Sbostic ** If a valid rule is not found, return NULL. 511*37140Sbostic ** Otherwise, return a pointer to the first character not part of the rule. 512*37140Sbostic */ 513*37140Sbostic 514*37140Sbostic static const char * 515*37140Sbostic getrule(strp, rulep) 516*37140Sbostic const char * strp; 517*37140Sbostic register struct rule * const rulep; 518*37140Sbostic { 519*37140Sbostic if (*strp == 'J') { 520*37140Sbostic /* 521*37140Sbostic ** Julian day. 522*37140Sbostic */ 523*37140Sbostic rulep->r_type = JULIAN_DAY; 524*37140Sbostic ++strp; 525*37140Sbostic strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 526*37140Sbostic } else if (*strp == 'M') { 527*37140Sbostic /* 528*37140Sbostic ** Month, week, day. 529*37140Sbostic */ 530*37140Sbostic rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 531*37140Sbostic ++strp; 532*37140Sbostic strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 533*37140Sbostic if (strp == NULL) 534*37140Sbostic return NULL; 535*37140Sbostic if (*strp++ != '.') 536*37140Sbostic return NULL; 537*37140Sbostic strp = getnum(strp, &rulep->r_week, 1, 5); 538*37140Sbostic if (strp == NULL) 539*37140Sbostic return NULL; 540*37140Sbostic if (*strp++ != '.') 541*37140Sbostic return NULL; 542*37140Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 543*37140Sbostic } else if (isdigit(*strp)) { 544*37140Sbostic /* 545*37140Sbostic ** Day of year. 546*37140Sbostic */ 547*37140Sbostic rulep->r_type = DAY_OF_YEAR; 548*37140Sbostic strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 549*37140Sbostic } else return NULL; /* invalid format */ 550*37140Sbostic if (strp == NULL) 551*37140Sbostic return NULL; 552*37140Sbostic if (*strp == '/') { 553*37140Sbostic /* 554*37140Sbostic ** Time specified. 555*37140Sbostic */ 556*37140Sbostic ++strp; 557*37140Sbostic strp = getsecs(strp, &rulep->r_time); 558*37140Sbostic } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 559*37140Sbostic return strp; 560*37140Sbostic } 561*37140Sbostic 562*37140Sbostic /* 563*37140Sbostic ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 564*37140Sbostic ** year, a rule, and the offset from GMT at the time that rule takes effect, 565*37140Sbostic ** calculate the Epoch-relative time that rule takes effect. 566*37140Sbostic */ 567*37140Sbostic 568*37140Sbostic static time_t 569*37140Sbostic transtime(janfirst, year, rulep, offset) 570*37140Sbostic const time_t janfirst; 571*37140Sbostic const int year; 572*37140Sbostic register const struct rule * const rulep; 573*37140Sbostic const long offset; 574*37140Sbostic { 575*37140Sbostic register int leapyear; 576*37140Sbostic register time_t value; 577*37140Sbostic register int i; 578*37140Sbostic int d, m1, yy0, yy1, yy2, dow; 579*37140Sbostic 580*37140Sbostic leapyear = isleap(year); 581*37140Sbostic switch (rulep->r_type) { 582*37140Sbostic 583*37140Sbostic case JULIAN_DAY: 584*37140Sbostic /* 585*37140Sbostic ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 586*37140Sbostic ** years. 587*37140Sbostic ** In non-leap years, or if the day number is 59 or less, just 588*37140Sbostic ** add SECSPERDAY times the day number-1 to the time of 589*37140Sbostic ** January 1, midnight, to get the day. 590*37140Sbostic */ 591*37140Sbostic value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 592*37140Sbostic if (leapyear && rulep->r_day >= 60) 593*37140Sbostic value += SECSPERDAY; 594*37140Sbostic break; 595*37140Sbostic 596*37140Sbostic case DAY_OF_YEAR: 597*37140Sbostic /* 598*37140Sbostic ** n - day of year. 599*37140Sbostic ** Just add SECSPERDAY times the day number to the time of 600*37140Sbostic ** January 1, midnight, to get the day. 601*37140Sbostic */ 602*37140Sbostic value = janfirst + rulep->r_day * SECSPERDAY; 603*37140Sbostic break; 604*37140Sbostic 605*37140Sbostic case MONTH_NTH_DAY_OF_WEEK: 606*37140Sbostic /* 607*37140Sbostic ** Mm.n.d - nth "dth day" of month m. 608*37140Sbostic */ 609*37140Sbostic value = janfirst; 610*37140Sbostic for (i = 0; i < rulep->r_mon - 1; ++i) 611*37140Sbostic value += mon_lengths[leapyear][i] * SECSPERDAY; 612*37140Sbostic 613*37140Sbostic /* 614*37140Sbostic ** Use Zeller's Congruence to get day-of-week of first day of 615*37140Sbostic ** month. 616*37140Sbostic */ 617*37140Sbostic m1 = (rulep->r_mon + 9) % 12 + 1; 618*37140Sbostic yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 619*37140Sbostic yy1 = yy0 / 100; 620*37140Sbostic yy2 = yy0 % 100; 621*37140Sbostic dow = ((26 * m1 - 2) / 10 + 622*37140Sbostic 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 623*37140Sbostic if (dow < 0) 624*37140Sbostic dow += DAYSPERWEEK; 625*37140Sbostic 626*37140Sbostic /* 627*37140Sbostic ** "dow" is the day-of-week of the first day of the month. Get 628*37140Sbostic ** the day-of-month (zero-origin) of the first "dow" day of the 629*37140Sbostic ** month. 630*37140Sbostic */ 631*37140Sbostic d = rulep->r_day - dow; 632*37140Sbostic if (d < 0) 633*37140Sbostic d += DAYSPERWEEK; 634*37140Sbostic for (i = 1; i < rulep->r_week; ++i) { 635*37140Sbostic if (d + DAYSPERWEEK >= 636*37140Sbostic mon_lengths[leapyear][rulep->r_mon - 1]) 637*37140Sbostic break; 638*37140Sbostic d += DAYSPERWEEK; 639*37140Sbostic } 640*37140Sbostic 641*37140Sbostic /* 642*37140Sbostic ** "d" is the day-of-month (zero-origin) of the day we want. 643*37140Sbostic */ 644*37140Sbostic value += d * SECSPERDAY; 645*37140Sbostic break; 646*37140Sbostic } 647*37140Sbostic 64830608Sbostic /* 649*37140Sbostic ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 650*37140Sbostic ** question. To get the Epoch-relative time of the specified local 651*37140Sbostic ** time on that day, add the transition time and the current offset 652*37140Sbostic ** from GMT. 65330608Sbostic */ 654*37140Sbostic return value + rulep->r_time + offset; 655*37140Sbostic } 656*37140Sbostic 657*37140Sbostic /* 658*37140Sbostic ** Given a POSIX section 8-style TZ string, fill in the rule tables as 659*37140Sbostic ** appropriate. 660*37140Sbostic */ 661*37140Sbostic 662*37140Sbostic static int 663*37140Sbostic tzparse(name, sp, lastditch) 664*37140Sbostic const char * name; 665*37140Sbostic register struct state * const sp; 666*37140Sbostic const int lastditch; 667*37140Sbostic { 668*37140Sbostic const char * stdname; 669*37140Sbostic const char * dstname; 670*37140Sbostic int stdlen; 671*37140Sbostic int dstlen; 672*37140Sbostic long stdoffset; 673*37140Sbostic long dstoffset; 674*37140Sbostic register time_t * atp; 675*37140Sbostic register unsigned char * typep; 676*37140Sbostic register char * cp; 677*37140Sbostic register int load_result; 678*37140Sbostic 679*37140Sbostic stdname = name; 680*37140Sbostic if (lastditch) { 681*37140Sbostic stdlen = strlen(name); /* length of standard zone name */ 682*37140Sbostic name += stdlen; 683*37140Sbostic if (stdlen >= sizeof sp->chars) 684*37140Sbostic stdlen = (sizeof sp->chars) - 1; 685*37140Sbostic } else { 686*37140Sbostic name = getzname(name); 687*37140Sbostic stdlen = name - stdname; 688*37140Sbostic if (stdlen < 3) 68930608Sbostic return -1; 690*37140Sbostic } 691*37140Sbostic if (*name == '\0') 692*37140Sbostic stdoffset = 0; 693*37140Sbostic else { 694*37140Sbostic name = getoffset(name, &stdoffset); 695*37140Sbostic if (name == NULL) 69630608Sbostic return -1; 697*37140Sbostic } 698*37140Sbostic load_result = tzload(TZDEFRULES, sp); 699*37140Sbostic if (load_result != 0) 700*37140Sbostic sp->leapcnt = 0; /* so, we're off a little */ 701*37140Sbostic if (*name != '\0') { 702*37140Sbostic dstname = name; 703*37140Sbostic name = getzname(name); 704*37140Sbostic dstlen = name - dstname; /* length of DST zone name */ 705*37140Sbostic if (dstlen < 3) 706*37140Sbostic return -1; 707*37140Sbostic if (*name != '\0' && *name != ',' && *name != ';') { 708*37140Sbostic name = getoffset(name, &dstoffset); 709*37140Sbostic if (name == NULL) 710*37140Sbostic return -1; 711*37140Sbostic } else dstoffset = stdoffset - SECSPERHOUR; 712*37140Sbostic if (*name == ',' || *name == ';') { 713*37140Sbostic struct rule start; 714*37140Sbostic struct rule end; 715*37140Sbostic register int year; 716*37140Sbostic register time_t janfirst; 717*37140Sbostic time_t starttime; 718*37140Sbostic time_t endtime; 71930608Sbostic 720*37140Sbostic ++name; 721*37140Sbostic if ((name = getrule(name, &start)) == NULL) 722*37140Sbostic return -1; 723*37140Sbostic if (*name++ != ',') 724*37140Sbostic return -1; 725*37140Sbostic if ((name = getrule(name, &end)) == NULL) 726*37140Sbostic return -1; 727*37140Sbostic if (*name != '\0') 728*37140Sbostic return -1; 729*37140Sbostic sp->typecnt = 2; /* standard time and DST */ 730*37140Sbostic /* 731*37140Sbostic ** Two transitions per year, from EPOCH_YEAR to 2037. 732*37140Sbostic */ 733*37140Sbostic sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 734*37140Sbostic if (sp->timecnt > TZ_MAX_TIMES) 735*37140Sbostic return -1; 736*37140Sbostic sp->ttis[0].tt_gmtoff = -dstoffset; 737*37140Sbostic sp->ttis[0].tt_isdst = 1; 738*37140Sbostic sp->ttis[0].tt_abbrind = stdlen + 1; 739*37140Sbostic sp->ttis[1].tt_gmtoff = -stdoffset; 740*37140Sbostic sp->ttis[1].tt_isdst = 0; 741*37140Sbostic sp->ttis[1].tt_abbrind = 0; 742*37140Sbostic atp = sp->ats; 743*37140Sbostic typep = sp->types; 744*37140Sbostic janfirst = 0; 745*37140Sbostic for (year = EPOCH_YEAR; year <= 2037; ++year) { 746*37140Sbostic starttime = transtime(janfirst, year, &start, 747*37140Sbostic stdoffset); 748*37140Sbostic endtime = transtime(janfirst, year, &end, 749*37140Sbostic dstoffset); 750*37140Sbostic if (starttime > endtime) { 751*37140Sbostic *atp++ = endtime; 752*37140Sbostic *typep++ = 1; /* DST ends */ 753*37140Sbostic *atp++ = starttime; 754*37140Sbostic *typep++ = 0; /* DST begins */ 755*37140Sbostic } else { 756*37140Sbostic *atp++ = starttime; 757*37140Sbostic *typep++ = 0; /* DST begins */ 758*37140Sbostic *atp++ = endtime; 759*37140Sbostic *typep++ = 1; /* DST ends */ 760*37140Sbostic } 761*37140Sbostic janfirst += 762*37140Sbostic year_lengths[isleap(year)] * SECSPERDAY; 763*37140Sbostic } 76430608Sbostic } else { 765*37140Sbostic int sawstd; 766*37140Sbostic int sawdst; 767*37140Sbostic long stdfix; 768*37140Sbostic long dstfix; 769*37140Sbostic long oldfix; 770*37140Sbostic int isdst; 771*37140Sbostic register int i; 772*37140Sbostic 773*37140Sbostic if (*name != '\0') 774*37140Sbostic return -1; 775*37140Sbostic if (load_result != 0) 776*37140Sbostic return -1; 777*37140Sbostic /* 778*37140Sbostic ** Compute the difference between the real and 779*37140Sbostic ** prototype standard and summer time offsets 780*37140Sbostic ** from GMT, and put the real standard and summer 781*37140Sbostic ** time offsets into the rules in place of the 782*37140Sbostic ** prototype offsets. 783*37140Sbostic */ 784*37140Sbostic sawstd = FALSE; 785*37140Sbostic sawdst = FALSE; 786*37140Sbostic stdfix = 0; 787*37140Sbostic dstfix = 0; 788*37140Sbostic for (i = 0; i < sp->typecnt; ++i) { 789*37140Sbostic if (sp->ttis[i].tt_isdst) { 790*37140Sbostic oldfix = dstfix; 791*37140Sbostic dstfix = 792*37140Sbostic sp->ttis[i].tt_gmtoff + dstoffset; 793*37140Sbostic if (sawdst && (oldfix != dstfix)) 794*37140Sbostic return -1; 795*37140Sbostic sp->ttis[i].tt_gmtoff = -dstoffset; 796*37140Sbostic sp->ttis[i].tt_abbrind = stdlen + 1; 797*37140Sbostic sawdst = TRUE; 798*37140Sbostic } else { 799*37140Sbostic oldfix = stdfix; 800*37140Sbostic stdfix = 801*37140Sbostic sp->ttis[i].tt_gmtoff + stdoffset; 802*37140Sbostic if (sawstd && (oldfix != stdfix)) 803*37140Sbostic return -1; 804*37140Sbostic sp->ttis[i].tt_gmtoff = -stdoffset; 805*37140Sbostic sp->ttis[i].tt_abbrind = 0; 806*37140Sbostic sawstd = TRUE; 807*37140Sbostic } 808*37140Sbostic } 809*37140Sbostic /* 810*37140Sbostic ** Make sure we have both standard and summer time. 811*37140Sbostic */ 812*37140Sbostic if (!sawdst || !sawstd) 813*37140Sbostic return -1; 814*37140Sbostic /* 815*37140Sbostic ** Now correct the transition times by shifting 816*37140Sbostic ** them by the difference between the real and 817*37140Sbostic ** prototype offsets. Note that this difference 818*37140Sbostic ** can be different in standard and summer time; 819*37140Sbostic ** the prototype probably has a 1-hour difference 820*37140Sbostic ** between standard and summer time, but a different 821*37140Sbostic ** difference can be specified in TZ. 822*37140Sbostic */ 823*37140Sbostic isdst = FALSE; /* we start in standard time */ 824*37140Sbostic for (i = 0; i < sp->timecnt; ++i) { 825*37140Sbostic register const struct ttinfo * ttisp; 826*37140Sbostic 827*37140Sbostic /* 828*37140Sbostic ** If summer time is in effect, and the 829*37140Sbostic ** transition time was not specified as 830*37140Sbostic ** standard time, add the summer time 831*37140Sbostic ** offset to the transition time; 832*37140Sbostic ** otherwise, add the standard time offset 833*37140Sbostic ** to the transition time. 834*37140Sbostic */ 835*37140Sbostic ttisp = &sp->ttis[sp->types[i]]; 836*37140Sbostic sp->ats[i] += 837*37140Sbostic (isdst && !ttisp->tt_ttisstd) ? 838*37140Sbostic dstfix : stdfix; 839*37140Sbostic isdst = ttisp->tt_isdst; 840*37140Sbostic } 84130608Sbostic } 842*37140Sbostic } else { 843*37140Sbostic dstlen = 0; 844*37140Sbostic sp->typecnt = 1; /* only standard time */ 845*37140Sbostic sp->timecnt = 0; 846*37140Sbostic sp->ttis[0].tt_gmtoff = -stdoffset; 847*37140Sbostic sp->ttis[0].tt_isdst = 0; 848*37140Sbostic sp->ttis[0].tt_abbrind = 0; 84930608Sbostic } 850*37140Sbostic sp->charcnt = stdlen + 1; 851*37140Sbostic if (dstlen != 0) 852*37140Sbostic sp->charcnt += dstlen + 1; 853*37140Sbostic if (sp->charcnt > sizeof sp->chars) 85430682Sbostic return -1; 855*37140Sbostic cp = sp->chars; 856*37140Sbostic (void) strncpy(cp, stdname, stdlen); 857*37140Sbostic cp += stdlen; 858*37140Sbostic *cp++ = '\0'; 859*37140Sbostic if (dstlen != 0) { 860*37140Sbostic (void) strncpy(cp, dstname, dstlen); 861*37140Sbostic *(cp + dstlen) = '\0'; 862*37140Sbostic } 86330682Sbostic return 0; 86430682Sbostic } 86530682Sbostic 866*37140Sbostic static void 867*37140Sbostic gmtload(sp) 868*37140Sbostic struct state * const sp; 8691959Swnj { 870*37140Sbostic if (tzload(GMT, sp) != 0) 871*37140Sbostic (void) tzparse(GMT, sp, TRUE); 8721959Swnj } 8731959Swnj 87430608Sbostic void 87530608Sbostic tzset() 87630608Sbostic { 877*37140Sbostic register const char * name; 878*37140Sbostic void tzsetwall(); 87930608Sbostic 88030608Sbostic name = getenv("TZ"); 881*37140Sbostic if (name == NULL) { 882*37140Sbostic tzsetwall(); 883*37140Sbostic return; 884*37140Sbostic } 885*37140Sbostic lcl_is_set = TRUE; 886*37140Sbostic #ifdef ALL_STATE 887*37140Sbostic if (lclptr == NULL) { 888*37140Sbostic lclptr = (struct state *) malloc(sizeof *lclptr); 889*37140Sbostic if (lclptr == NULL) { 890*37140Sbostic settzname(); /* all we can do */ 89130682Sbostic return; 892*37140Sbostic } 893*37140Sbostic } 894*37140Sbostic #endif /* defined ALL_STATE */ 895*37140Sbostic if (*name == '\0') { 896*37140Sbostic /* 897*37140Sbostic ** User wants it fast rather than right. 898*37140Sbostic */ 899*37140Sbostic lclptr->leapcnt = 0; /* so, we're off a little */ 900*37140Sbostic lclptr->timecnt = 0; 901*37140Sbostic lclptr->ttis[0].tt_gmtoff = 0; 902*37140Sbostic lclptr->ttis[0].tt_abbrind = 0; 903*37140Sbostic (void) strcpy(lclptr->chars, GMT); 904*37140Sbostic } else if (tzload(name, lclptr) != 0) 905*37140Sbostic if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 906*37140Sbostic (void) tzparse(name, lclptr, TRUE); 907*37140Sbostic settzname(); 908*37140Sbostic } 909*37140Sbostic 910*37140Sbostic void 911*37140Sbostic tzsetwall() 912*37140Sbostic { 913*37140Sbostic lcl_is_set = TRUE; 914*37140Sbostic #ifdef ALL_STATE 915*37140Sbostic if (lclptr == NULL) { 916*37140Sbostic lclptr = (struct state *) malloc(sizeof *lclptr); 917*37140Sbostic if (lclptr == NULL) { 918*37140Sbostic settzname(); /* all we can do */ 91930682Sbostic return; 920*37140Sbostic } 92130682Sbostic } 922*37140Sbostic #endif /* defined ALL_STATE */ 923*37140Sbostic if (tzload((char *) NULL, lclptr) != 0) 924*37140Sbostic gmtload(lclptr); 925*37140Sbostic settzname(); 92630608Sbostic } 92730608Sbostic 928*37140Sbostic /* 929*37140Sbostic ** The easy way to behave "as if no library function calls" localtime 930*37140Sbostic ** is to not call it--so we drop its guts into "localsub", which can be 931*37140Sbostic ** freely called. (And no, the PANS doesn't require the above behavior-- 932*37140Sbostic ** but it *is* desirable.) 933*37140Sbostic ** 934*37140Sbostic ** The unused offset argument is for the benefit of mktime variants. 935*37140Sbostic */ 936*37140Sbostic 937*37140Sbostic /*ARGSUSED*/ 938*37140Sbostic static void 939*37140Sbostic localsub(timep, offset, tmp) 940*37140Sbostic const time_t * const timep; 941*37140Sbostic const long offset; 942*37140Sbostic struct tm * const tmp; 9431959Swnj { 944*37140Sbostic register const struct state * sp; 945*37140Sbostic register const struct ttinfo * ttisp; 94630608Sbostic register int i; 947*37140Sbostic const time_t t = *timep; 9481959Swnj 949*37140Sbostic if (!lcl_is_set) 950*37140Sbostic tzset(); 951*37140Sbostic sp = lclptr; 952*37140Sbostic #ifdef ALL_STATE 953*37140Sbostic if (sp == NULL) { 954*37140Sbostic gmtsub(timep, offset, tmp); 955*37140Sbostic return; 956*37140Sbostic } 957*37140Sbostic #endif /* defined ALL_STATE */ 958*37140Sbostic if (sp->timecnt == 0 || t < sp->ats[0]) { 95930608Sbostic i = 0; 960*37140Sbostic while (sp->ttis[i].tt_isdst) 961*37140Sbostic if (++i >= sp->typecnt) { 96230608Sbostic i = 0; 96330608Sbostic break; 96430608Sbostic } 96530608Sbostic } else { 966*37140Sbostic for (i = 1; i < sp->timecnt; ++i) 967*37140Sbostic if (t < sp->ats[i]) 96830608Sbostic break; 969*37140Sbostic i = sp->types[i - 1]; 9701959Swnj } 971*37140Sbostic ttisp = &sp->ttis[i]; 9721959Swnj /* 97330608Sbostic ** To get (wrong) behavior that's compatible with System V Release 2.0 97430608Sbostic ** you'd replace the statement below with 975*37140Sbostic ** t += ttisp->tt_gmtoff; 976*37140Sbostic ** timesub(&t, 0L, sp, tmp); 97730608Sbostic */ 978*37140Sbostic timesub(&t, ttisp->tt_gmtoff, sp, tmp); 97930608Sbostic tmp->tm_isdst = ttisp->tt_isdst; 980*37140Sbostic tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; 981*37140Sbostic tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; 98230608Sbostic } 9831959Swnj 98430608Sbostic struct tm * 985*37140Sbostic localtime(timep) 986*37140Sbostic const time_t * const timep; 98730608Sbostic { 988*37140Sbostic static struct tm tm; 9891959Swnj 990*37140Sbostic localsub(timep, 0L, &tm); 991*37140Sbostic return &tm; 99230608Sbostic } 9931959Swnj 994*37140Sbostic /* 995*37140Sbostic ** gmtsub is to gmtime as localsub is to localtime. 996*37140Sbostic */ 9971959Swnj 998*37140Sbostic static void 999*37140Sbostic gmtsub(timep, offset, tmp) 1000*37140Sbostic const time_t * const timep; 1001*37140Sbostic const long offset; 1002*37140Sbostic struct tm * const tmp; 1003*37140Sbostic { 1004*37140Sbostic if (!gmt_is_set) { 1005*37140Sbostic gmt_is_set = TRUE; 1006*37140Sbostic #ifdef ALL_STATE 1007*37140Sbostic gmtptr = (struct state *) malloc(sizeof *gmtptr); 1008*37140Sbostic if (gmtptr != NULL) 1009*37140Sbostic #endif /* defined ALL_STATE */ 1010*37140Sbostic gmtload(gmtptr); 1011*37140Sbostic } 1012*37140Sbostic timesub(timep, offset, gmtptr, tmp); 1013*37140Sbostic /* 1014*37140Sbostic ** Could get fancy here and deliver something such as 1015*37140Sbostic ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 1016*37140Sbostic ** but this is no time for a treasure hunt. 1017*37140Sbostic */ 1018*37140Sbostic if (offset != 0) 1019*37140Sbostic tmp->tm_zone = WILDABBR; 1020*37140Sbostic else { 1021*37140Sbostic #ifdef ALL_STATE 1022*37140Sbostic if (gmtptr == NULL) 1023*37140Sbostic tmp->TM_ZONE = GMT; 1024*37140Sbostic else tmp->TM_ZONE = gmtptr->chars; 1025*37140Sbostic #endif /* defined ALL_STATE */ 1026*37140Sbostic #ifndef ALL_STATE 1027*37140Sbostic tmp->tm_zone = gmtptr->chars; 1028*37140Sbostic #endif /* State Farm */ 1029*37140Sbostic } 1030*37140Sbostic } 10311959Swnj 103230608Sbostic struct tm * 1033*37140Sbostic gmtime(timep) 1034*37140Sbostic const time_t * const timep; 10351959Swnj { 103630608Sbostic static struct tm tm; 10371959Swnj 1038*37140Sbostic gmtsub(timep, 0L, &tm); 1039*37140Sbostic return &tm; 1040*37140Sbostic } 1041*37140Sbostic 1042*37140Sbostic #ifdef STD_INSPIRED 1043*37140Sbostic 1044*37140Sbostic struct tm * 1045*37140Sbostic offtime(timep, offset) 1046*37140Sbostic const time_t * const timep; 1047*37140Sbostic const long offset; 1048*37140Sbostic { 1049*37140Sbostic static struct tm tm; 1050*37140Sbostic 1051*37140Sbostic gmtsub(timep, offset, &tm); 1052*37140Sbostic return &tm; 1053*37140Sbostic } 1054*37140Sbostic 1055*37140Sbostic #endif /* defined STD_INSPIRED */ 1056*37140Sbostic 1057*37140Sbostic static void 1058*37140Sbostic timesub(timep, offset, sp, tmp) 1059*37140Sbostic const time_t * const timep; 1060*37140Sbostic const long offset; 1061*37140Sbostic register const struct state * const sp; 1062*37140Sbostic register struct tm * const tmp; 1063*37140Sbostic { 1064*37140Sbostic register const struct lsinfo * lp; 1065*37140Sbostic register long days; 1066*37140Sbostic register long rem; 1067*37140Sbostic register int y; 1068*37140Sbostic register int yleap; 1069*37140Sbostic register const int * ip; 1070*37140Sbostic register long corr; 1071*37140Sbostic register int hit; 1072*37140Sbostic register int i; 1073*37140Sbostic 1074*37140Sbostic corr = 0; 1075*37140Sbostic hit = FALSE; 1076*37140Sbostic #ifdef ALL_STATE 1077*37140Sbostic i = (sp == NULL) ? 0 : sp->leapcnt; 1078*37140Sbostic #endif /* defined ALL_STATE */ 1079*37140Sbostic #ifndef ALL_STATE 1080*37140Sbostic i = sp->leapcnt; 1081*37140Sbostic #endif /* State Farm */ 1082*37140Sbostic while (--i >= 0) { 1083*37140Sbostic lp = &sp->lsis[i]; 1084*37140Sbostic if (*timep >= lp->ls_trans) { 1085*37140Sbostic if (*timep == lp->ls_trans) 1086*37140Sbostic hit = ((i == 0 && lp->ls_corr > 0) || 1087*37140Sbostic lp->ls_corr > sp->lsis[i - 1].ls_corr); 1088*37140Sbostic corr = lp->ls_corr; 1089*37140Sbostic break; 1090*37140Sbostic } 1091*37140Sbostic } 1092*37140Sbostic days = *timep / SECSPERDAY; 1093*37140Sbostic rem = *timep % SECSPERDAY; 1094*37140Sbostic #ifdef mc68k 1095*37140Sbostic if (*timep == 0x80000000) { 1096*37140Sbostic /* 1097*37140Sbostic ** A 3B1 muffs the division on the most negative number. 1098*37140Sbostic */ 1099*37140Sbostic days = -24855; 1100*37140Sbostic rem = -11648; 1101*37140Sbostic } 1102*37140Sbostic #endif /* mc68k */ 1103*37140Sbostic rem += (offset - corr); 110430608Sbostic while (rem < 0) { 1105*37140Sbostic rem += SECSPERDAY; 110630608Sbostic --days; 11071959Swnj } 1108*37140Sbostic while (rem >= SECSPERDAY) { 1109*37140Sbostic rem -= SECSPERDAY; 111030608Sbostic ++days; 111130608Sbostic } 1112*37140Sbostic tmp->tm_hour = (int) (rem / SECSPERHOUR); 1113*37140Sbostic rem = rem % SECSPERHOUR; 1114*37140Sbostic tmp->tm_min = (int) (rem / SECSPERMIN); 1115*37140Sbostic tmp->tm_sec = (int) (rem % SECSPERMIN); 1116*37140Sbostic if (hit) 1117*37140Sbostic /* 1118*37140Sbostic ** A positive leap second requires a special 1119*37140Sbostic ** representation. This uses "... ??:59:60". 1120*37140Sbostic */ 1121*37140Sbostic ++(tmp->tm_sec); 1122*37140Sbostic tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 112330608Sbostic if (tmp->tm_wday < 0) 1124*37140Sbostic tmp->tm_wday += DAYSPERWEEK; 112530608Sbostic y = EPOCH_YEAR; 112630608Sbostic if (days >= 0) 112730608Sbostic for ( ; ; ) { 112830608Sbostic yleap = isleap(y); 112930608Sbostic if (days < (long) year_lengths[yleap]) 113030608Sbostic break; 113130608Sbostic ++y; 113230608Sbostic days = days - (long) year_lengths[yleap]; 113330608Sbostic } 113430608Sbostic else do { 113530608Sbostic --y; 113630608Sbostic yleap = isleap(y); 113730608Sbostic days = days + (long) year_lengths[yleap]; 113830608Sbostic } while (days < 0); 113930608Sbostic tmp->tm_year = y - TM_YEAR_BASE; 114030608Sbostic tmp->tm_yday = (int) days; 114130608Sbostic ip = mon_lengths[yleap]; 114230608Sbostic for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 114330608Sbostic days = days - (long) ip[tmp->tm_mon]; 114430608Sbostic tmp->tm_mday = (int) (days + 1); 114530608Sbostic tmp->tm_isdst = 0; 1146*37140Sbostic #ifdef TM_GMTOFF 1147*37140Sbostic tmp->TM_GMTOFF = offset; 1148*37140Sbostic #endif /* defined TM_GMTOFF */ 11491959Swnj } 1150*37140Sbostic 1151*37140Sbostic /* 1152*37140Sbostic ** A la X3J11 1153*37140Sbostic */ 1154*37140Sbostic 1155*37140Sbostic char * 1156*37140Sbostic asctime(timeptr) 1157*37140Sbostic register const struct tm * timeptr; 1158*37140Sbostic { 1159*37140Sbostic static const char wday_name[DAYSPERWEEK][3] = { 1160*37140Sbostic "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 1161*37140Sbostic }; 1162*37140Sbostic static const char mon_name[MONSPERYEAR][3] = { 1163*37140Sbostic "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1164*37140Sbostic "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 1165*37140Sbostic }; 1166*37140Sbostic static char result[26]; 1167*37140Sbostic 1168*37140Sbostic (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n", 1169*37140Sbostic wday_name[timeptr->tm_wday], 1170*37140Sbostic mon_name[timeptr->tm_mon], 1171*37140Sbostic timeptr->tm_mday, timeptr->tm_hour, 1172*37140Sbostic timeptr->tm_min, timeptr->tm_sec, 1173*37140Sbostic TM_YEAR_BASE + timeptr->tm_year); 1174*37140Sbostic return result; 1175*37140Sbostic } 1176*37140Sbostic 1177*37140Sbostic char * 1178*37140Sbostic ctime(timep) 1179*37140Sbostic const time_t * const timep; 1180*37140Sbostic { 1181*37140Sbostic return asctime(localtime(timep)); 1182*37140Sbostic } 1183*37140Sbostic 1184*37140Sbostic /* 1185*37140Sbostic ** Adapted from code provided by Robert Elz, who writes: 1186*37140Sbostic ** The "best" way to do mktime I think is based on an idea of Bob 1187*37140Sbostic ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 1188*37140Sbostic ** It does a binary search of the time_t space. Since time_t's are 1189*37140Sbostic ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1190*37140Sbostic ** would still be very reasonable). 1191*37140Sbostic */ 1192*37140Sbostic 1193*37140Sbostic #ifndef WRONG 1194*37140Sbostic #define WRONG (-1) 1195*37140Sbostic #endif /* !defined WRONG */ 1196*37140Sbostic 1197*37140Sbostic static void 1198*37140Sbostic normalize(tensptr, unitsptr, base) 1199*37140Sbostic int * const tensptr; 1200*37140Sbostic int * const unitsptr; 1201*37140Sbostic const int base; 1202*37140Sbostic { 1203*37140Sbostic if (*unitsptr >= base) { 1204*37140Sbostic *tensptr += *unitsptr / base; 1205*37140Sbostic *unitsptr %= base; 1206*37140Sbostic } else if (*unitsptr < 0) { 1207*37140Sbostic --*tensptr; 1208*37140Sbostic *unitsptr += base; 1209*37140Sbostic if (*unitsptr < 0) { 1210*37140Sbostic *tensptr -= 1 + (-*unitsptr) / base; 1211*37140Sbostic *unitsptr = base - (-*unitsptr) % base; 1212*37140Sbostic } 1213*37140Sbostic } 1214*37140Sbostic } 1215*37140Sbostic 1216*37140Sbostic static int 1217*37140Sbostic tmcomp(atmp, btmp) 1218*37140Sbostic register const struct tm * const atmp; 1219*37140Sbostic register const struct tm * const btmp; 1220*37140Sbostic { 1221*37140Sbostic register int result; 1222*37140Sbostic 1223*37140Sbostic if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1224*37140Sbostic (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1225*37140Sbostic (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1226*37140Sbostic (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1227*37140Sbostic (result = (atmp->tm_min - btmp->tm_min)) == 0) 1228*37140Sbostic result = atmp->tm_sec - btmp->tm_sec; 1229*37140Sbostic return result; 1230*37140Sbostic } 1231*37140Sbostic 1232*37140Sbostic static time_t 1233*37140Sbostic time2(tmp, funcp, offset, okayp) 1234*37140Sbostic struct tm * const tmp; 1235*37140Sbostic void (* const funcp)(); 1236*37140Sbostic const long offset; 1237*37140Sbostic int * const okayp; 1238*37140Sbostic { 1239*37140Sbostic register const struct state * sp; 1240*37140Sbostic register int dir; 1241*37140Sbostic register int bits; 1242*37140Sbostic register int i, j ; 1243*37140Sbostic register int saved_seconds; 1244*37140Sbostic time_t newt; 1245*37140Sbostic time_t t; 1246*37140Sbostic struct tm yourtm, mytm; 1247*37140Sbostic 1248*37140Sbostic *okayp = FALSE; 1249*37140Sbostic yourtm = *tmp; 1250*37140Sbostic if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) 1251*37140Sbostic normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); 1252*37140Sbostic normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); 1253*37140Sbostic normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); 1254*37140Sbostic normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); 1255*37140Sbostic while (yourtm.tm_mday <= 0) { 1256*37140Sbostic --yourtm.tm_year; 1257*37140Sbostic yourtm.tm_mday += 1258*37140Sbostic year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; 1259*37140Sbostic } 1260*37140Sbostic for ( ; ; ) { 1261*37140Sbostic i = mon_lengths[isleap(yourtm.tm_year + 1262*37140Sbostic TM_YEAR_BASE)][yourtm.tm_mon]; 1263*37140Sbostic if (yourtm.tm_mday <= i) 1264*37140Sbostic break; 1265*37140Sbostic yourtm.tm_mday -= i; 1266*37140Sbostic if (++yourtm.tm_mon >= MONSPERYEAR) { 1267*37140Sbostic yourtm.tm_mon = 0; 1268*37140Sbostic ++yourtm.tm_year; 1269*37140Sbostic } 1270*37140Sbostic } 1271*37140Sbostic saved_seconds = yourtm.tm_sec; 1272*37140Sbostic yourtm.tm_sec = 0; 1273*37140Sbostic /* 1274*37140Sbostic ** Calculate the number of magnitude bits in a time_t 1275*37140Sbostic ** (this works regardless of whether time_t is 1276*37140Sbostic ** signed or unsigned, though lint complains if unsigned). 1277*37140Sbostic */ 1278*37140Sbostic for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 1279*37140Sbostic ; 1280*37140Sbostic /* 1281*37140Sbostic ** If time_t is signed, then 0 is the median value, 1282*37140Sbostic ** if time_t is unsigned, then 1 << bits is median. 1283*37140Sbostic */ 1284*37140Sbostic t = (t < 0) ? 0 : ((time_t) 1 << bits); 1285*37140Sbostic for ( ; ; ) { 1286*37140Sbostic (*funcp)(&t, offset, &mytm); 1287*37140Sbostic dir = tmcomp(&mytm, &yourtm); 1288*37140Sbostic if (dir != 0) { 1289*37140Sbostic if (bits-- < 0) 1290*37140Sbostic return WRONG; 1291*37140Sbostic if (bits < 0) 1292*37140Sbostic --t; 1293*37140Sbostic else if (dir > 0) 1294*37140Sbostic t -= (time_t) 1 << bits; 1295*37140Sbostic else t += (time_t) 1 << bits; 1296*37140Sbostic continue; 1297*37140Sbostic } 1298*37140Sbostic if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 1299*37140Sbostic break; 1300*37140Sbostic /* 1301*37140Sbostic ** Right time, wrong type. 1302*37140Sbostic ** Hunt for right time, right type. 1303*37140Sbostic ** It's okay to guess wrong since the guess 1304*37140Sbostic ** gets checked. 1305*37140Sbostic */ 1306*37140Sbostic sp = (const struct state *) 1307*37140Sbostic ((funcp == localsub) ? lclptr : gmtptr); 1308*37140Sbostic #ifdef ALL_STATE 1309*37140Sbostic if (sp == NULL) 1310*37140Sbostic return WRONG; 1311*37140Sbostic #endif /* defined ALL_STATE */ 1312*37140Sbostic for (i = 0; i < sp->typecnt; ++i) { 1313*37140Sbostic if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 1314*37140Sbostic continue; 1315*37140Sbostic for (j = 0; j < sp->typecnt; ++j) { 1316*37140Sbostic if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 1317*37140Sbostic continue; 1318*37140Sbostic newt = t + sp->ttis[j].tt_gmtoff - 1319*37140Sbostic sp->ttis[i].tt_gmtoff; 1320*37140Sbostic (*funcp)(&newt, offset, &mytm); 1321*37140Sbostic if (tmcomp(&mytm, &yourtm) != 0) 1322*37140Sbostic continue; 1323*37140Sbostic if (mytm.tm_isdst != yourtm.tm_isdst) 1324*37140Sbostic continue; 1325*37140Sbostic /* 1326*37140Sbostic ** We have a match. 1327*37140Sbostic */ 1328*37140Sbostic t = newt; 1329*37140Sbostic goto label; 1330*37140Sbostic } 1331*37140Sbostic } 1332*37140Sbostic return WRONG; 1333*37140Sbostic } 1334*37140Sbostic label: 1335*37140Sbostic t += saved_seconds; 1336*37140Sbostic (*funcp)(&t, offset, tmp); 1337*37140Sbostic *okayp = TRUE; 1338*37140Sbostic return t; 1339*37140Sbostic } 1340*37140Sbostic 1341*37140Sbostic static time_t 1342*37140Sbostic time1(tmp, funcp, offset) 1343*37140Sbostic struct tm * const tmp; 1344*37140Sbostic void (* const funcp)(); 1345*37140Sbostic const long offset; 1346*37140Sbostic { 1347*37140Sbostic register time_t t; 1348*37140Sbostic register const struct state * sp; 1349*37140Sbostic register int samei, otheri; 1350*37140Sbostic int okay; 1351*37140Sbostic 1352*37140Sbostic if (tmp->tm_isdst > 1) 1353*37140Sbostic return WRONG; 1354*37140Sbostic t = time2(tmp, funcp, offset, &okay); 1355*37140Sbostic if (okay || tmp->tm_isdst < 0) 1356*37140Sbostic return t; 1357*37140Sbostic /* 1358*37140Sbostic ** We're supposed to assume that somebody took a time of one type 1359*37140Sbostic ** and did some math on it that yielded a "struct tm" that's bad. 1360*37140Sbostic ** We try to divine the type they started from and adjust to the 1361*37140Sbostic ** type they need. 1362*37140Sbostic */ 1363*37140Sbostic sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 1364*37140Sbostic #ifdef ALL_STATE 1365*37140Sbostic if (sp == NULL) 1366*37140Sbostic return WRONG; 1367*37140Sbostic #endif /* defined ALL_STATE */ 1368*37140Sbostic for (samei = 0; samei < sp->typecnt; ++samei) { 1369*37140Sbostic if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 1370*37140Sbostic continue; 1371*37140Sbostic for (otheri = 0; otheri < sp->typecnt; ++otheri) { 1372*37140Sbostic if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 1373*37140Sbostic continue; 1374*37140Sbostic tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 1375*37140Sbostic sp->ttis[samei].tt_gmtoff; 1376*37140Sbostic tmp->tm_isdst = !tmp->tm_isdst; 1377*37140Sbostic t = time2(tmp, funcp, offset, &okay); 1378*37140Sbostic if (okay) 1379*37140Sbostic return t; 1380*37140Sbostic tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 1381*37140Sbostic sp->ttis[samei].tt_gmtoff; 1382*37140Sbostic tmp->tm_isdst = !tmp->tm_isdst; 1383*37140Sbostic } 1384*37140Sbostic } 1385*37140Sbostic return WRONG; 1386*37140Sbostic } 1387*37140Sbostic 1388*37140Sbostic time_t 1389*37140Sbostic mktime(tmp) 1390*37140Sbostic struct tm * const tmp; 1391*37140Sbostic { 1392*37140Sbostic return time1(tmp, localsub, 0L); 1393*37140Sbostic } 1394*37140Sbostic 1395*37140Sbostic time_t 1396*37140Sbostic timegm(tmp) 1397*37140Sbostic struct tm * const tmp; 1398*37140Sbostic { 1399*37140Sbostic return time1(tmp, gmtsub, 0L); 1400*37140Sbostic } 1401*37140Sbostic 1402*37140Sbostic time_t 1403*37140Sbostic timeoff(tmp, offset) 1404*37140Sbostic struct tm * const tmp; 1405*37140Sbostic const long offset; 1406*37140Sbostic { 1407*37140Sbostic 1408*37140Sbostic return time1(tmp, gmtsub, offset); 1409*37140Sbostic } 1410