localtime.c revision 192625
117209Swollman/* 217209Swollman** This file is in the public domain, so clarified as of 3192625Sedwin** 1996-06-05 by Arthur David Olson. 417209Swollman*/ 515923Sscrappy 6111010Snectar#include <sys/cdefs.h> 72708Swollman#ifndef lint 82708Swollman#ifndef NOID 9192625Sedwinstatic char elsieid[] __unused = "@(#)localtime.c 8.9"; 102708Swollman#endif /* !defined NOID */ 112708Swollman#endif /* !defined lint */ 1292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdtime/localtime.c 192625 2009-05-23 06:31:50Z edwin $"); 132708Swollman 142708Swollman/* 15192625Sedwin** Leap second handling from Bradley White. 16192625Sedwin** POSIX-style TZ environment variable handling from Guy Harris. 172708Swollman*/ 182708Swollman 192708Swollman/*LINTLIBRARY*/ 202708Swollman 2171579Sdeischen#include "namespace.h" 2218834Swollman#include <sys/types.h> 2318834Swollman#include <sys/stat.h> 2471579Sdeischen#include <fcntl.h> 2571579Sdeischen#include <pthread.h> 2671579Sdeischen#include "private.h" 2771579Sdeischen#include "un-namespace.h" 2818834Swollman 292708Swollman#include "tzfile.h" 30192625Sedwin#include "float.h" /* for FLT_MAX and DBL_MAX */ 312708Swollman 32192625Sedwin#ifndef TZ_ABBR_MAX_LEN 33192625Sedwin#define TZ_ABBR_MAX_LEN 16 34192625Sedwin#endif /* !defined TZ_ABBR_MAX_LEN */ 35192625Sedwin 36192625Sedwin#ifndef TZ_ABBR_CHAR_SET 37192625Sedwin#define TZ_ABBR_CHAR_SET \ 38192625Sedwin "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" 39192625Sedwin#endif /* !defined TZ_ABBR_CHAR_SET */ 40192625Sedwin 41192625Sedwin#ifndef TZ_ABBR_ERR_CHAR 42192625Sedwin#define TZ_ABBR_ERR_CHAR '_' 43192625Sedwin#endif /* !defined TZ_ABBR_ERR_CHAR */ 44192625Sedwin 4571579Sdeischen#include "libc_private.h" 4671579Sdeischen 4771579Sdeischen#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 4871579Sdeischen#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 4971579Sdeischen 50177824Sdavidxu#define _RWLOCK_RDLOCK(x) \ 51177824Sdavidxu do { \ 52177824Sdavidxu if (__isthreaded) _pthread_rwlock_rdlock(x); \ 53177824Sdavidxu } while (0) 54177824Sdavidxu 55177824Sdavidxu#define _RWLOCK_WRLOCK(x) \ 56177824Sdavidxu do { \ 57177824Sdavidxu if (__isthreaded) _pthread_rwlock_wrlock(x); \ 58177824Sdavidxu } while (0) 59177824Sdavidxu 60177824Sdavidxu#define _RWLOCK_UNLOCK(x) \ 61177824Sdavidxu do { \ 62177824Sdavidxu if (__isthreaded) _pthread_rwlock_unlock(x); \ 63177824Sdavidxu } while (0) 64177824Sdavidxu 659936Swollman/* 669936Swollman** SunOS 4.1.1 headers lack O_BINARY. 679936Swollman*/ 682708Swollman 692708Swollman#ifdef O_BINARY 702708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 712708Swollman#endif /* defined O_BINARY */ 722708Swollman#ifndef O_BINARY 732708Swollman#define OPEN_MODE O_RDONLY 742708Swollman#endif /* !defined O_BINARY */ 752708Swollman 762708Swollman#ifndef WILDABBR 772708Swollman/* 782708Swollman** Someone might make incorrect use of a time zone abbreviation: 792708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 809936Swollman** or implicitly). 812708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 829936Swollman** or implicitly). 832708Swollman** 3. They might reference tzname[1] after setting to a time zone 842708Swollman** in which Daylight Saving Time is never observed. 852708Swollman** 4. They might reference tzname[0] after setting to a time zone 862708Swollman** in which Standard Time is never observed. 872708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 882708Swollman** What's best to do in the above cases is open to debate; 892708Swollman** for now, we just set things up so that in any of the five cases 90192625Sedwin** WILDABBR is used. Another possibility: initialize tzname[0] to the 912708Swollman** string "tzname[0] used before set", and similarly for the other cases. 92192625Sedwin** And another: initialize tzname[0] to "ERA", with an explanation in the 932708Swollman** manual page of what this "time zone abbreviation" means (doing this so 942708Swollman** that tzname[0] has the "normal" length of three characters). 952708Swollman*/ 962708Swollman#define WILDABBR " " 972708Swollman#endif /* !defined WILDABBR */ 982708Swollman 99192625Sedwinstatic char wildabbr[] = WILDABBR; 1002708Swollman 101130332Skensmith/* 102130332Skensmith * In June 2004 it was decided UTC was a more appropriate default time 103130332Skensmith * zone than GMT. 104130332Skensmith */ 1059936Swollman 106130332Skensmithstatic const char gmt[] = "UTC"; 107130332Skensmith 108130461Sstefanf/* 109130461Sstefanf** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. 110130461Sstefanf** We default to US rules as of 1999-08-17. 111130461Sstefanf** POSIX 1003.1 section 8.1.1 says that the default DST rules are 112130461Sstefanf** implementation dependent; for historical reasons, US rules are a 113130461Sstefanf** common default. 114130461Sstefanf*/ 115130461Sstefanf#ifndef TZDEFRULESTRING 116130461Sstefanf#define TZDEFRULESTRING ",M4.1.0,M10.5.0" 117130461Sstefanf#endif /* !defined TZDEFDST */ 118130461Sstefanf 1192708Swollmanstruct ttinfo { /* time type information */ 120130461Sstefanf long tt_gmtoff; /* UTC offset in seconds */ 1212708Swollman int tt_isdst; /* used to set tm_isdst */ 1222708Swollman int tt_abbrind; /* abbreviation list index */ 1232708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 124130461Sstefanf int tt_ttisgmt; /* TRUE if transition is UTC */ 1252708Swollman}; 1262708Swollman 1272708Swollmanstruct lsinfo { /* leap second information */ 1282708Swollman time_t ls_trans; /* transition time */ 1292708Swollman long ls_corr; /* correction to apply */ 1302708Swollman}; 1312708Swollman 1322708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 1332708Swollman 1342708Swollman#ifdef TZNAME_MAX 1352708Swollman#define MY_TZNAME_MAX TZNAME_MAX 1362708Swollman#endif /* defined TZNAME_MAX */ 1372708Swollman#ifndef TZNAME_MAX 1382708Swollman#define MY_TZNAME_MAX 255 1392708Swollman#endif /* !defined TZNAME_MAX */ 1402708Swollman 1412708Swollmanstruct state { 1422708Swollman int leapcnt; 1432708Swollman int timecnt; 1442708Swollman int typecnt; 1452708Swollman int charcnt; 146192625Sedwin int goback; 147192625Sedwin int goahead; 1482708Swollman time_t ats[TZ_MAX_TIMES]; 1492708Swollman unsigned char types[TZ_MAX_TIMES]; 1502708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 1519936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 1522708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 1532708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 1542708Swollman}; 1552708Swollman 1562708Swollmanstruct rule { 1572708Swollman int r_type; /* type of rule--see below */ 1582708Swollman int r_day; /* day number of rule */ 1592708Swollman int r_week; /* week number of rule */ 1602708Swollman int r_mon; /* month number of rule */ 1612708Swollman long r_time; /* transition time of rule */ 1622708Swollman}; 1632708Swollman 1642708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1652708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1662708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1672708Swollman 1682708Swollman/* 1692708Swollman** Prototypes for static functions. 1702708Swollman*/ 1712708Swollman 17297423Salfredstatic long detzcode(const char * codep); 173192625Sedwinstatic time_t detzcode64(const char * codep); 174192625Sedwinstatic int differ_by_repeat(time_t t1, time_t t0); 17597423Salfredstatic const char * getzname(const char * strp); 176192625Sedwinstatic const char * getqzname(const char * strp, const int delim); 17797423Salfredstatic const char * getnum(const char * strp, int * nump, int min, 17897423Salfred int max); 17997423Salfredstatic const char * getsecs(const char * strp, long * secsp); 18097423Salfredstatic const char * getoffset(const char * strp, long * offsetp); 18197423Salfredstatic const char * getrule(const char * strp, struct rule * rulep); 18297423Salfredstatic void gmtload(struct state * sp); 183192625Sedwinstatic struct tm * gmtsub(const time_t * timep, long offset, 18497423Salfred struct tm * tmp); 185192625Sedwinstatic struct tm * localsub(const time_t * timep, long offset, 18697423Salfred struct tm * tmp); 18797423Salfredstatic int increment_overflow(int * number, int delta); 188192625Sedwinstatic int leaps_thru_end_of(int y); 189192625Sedwinstatic int long_increment_overflow(long * number, int delta); 190192625Sedwinstatic int long_normalize_overflow(long * tensptr, 191192625Sedwin int * unitsptr, int base); 19297423Salfredstatic int normalize_overflow(int * tensptr, int * unitsptr, 19397423Salfred int base); 19497423Salfredstatic void settzname(void); 19597423Salfredstatic time_t time1(struct tm * tmp, 196192625Sedwin struct tm * (*funcp)(const time_t *, 19797423Salfred long, struct tm *), 19897423Salfred long offset); 19997423Salfredstatic time_t time2(struct tm *tmp, 200192625Sedwin struct tm * (*funcp)(const time_t *, 20197423Salfred long, struct tm*), 20297423Salfred long offset, int * okayp); 203130461Sstefanfstatic time_t time2sub(struct tm *tmp, 204192625Sedwin struct tm * (*funcp)(const time_t *, 205130461Sstefanf long, struct tm*), 206130461Sstefanf long offset, int * okayp, int do_norm_secs); 207192625Sedwinstatic struct tm * timesub(const time_t * timep, long offset, 20897423Salfred const struct state * sp, struct tm * tmp); 20997423Salfredstatic int tmcomp(const struct tm * atmp, 21097423Salfred const struct tm * btmp); 21197423Salfredstatic time_t transtime(time_t janfirst, int year, 21297423Salfred const struct rule * rulep, long offset); 213192625Sedwinstatic int typesequiv(const struct state * sp, int a, int b); 214192625Sedwinstatic int tzload(const char * name, struct state * sp, 215192625Sedwin int doextend); 21697423Salfredstatic int tzparse(const char * name, struct state * sp, 21797423Salfred int lastditch); 2182708Swollman 2192708Swollman#ifdef ALL_STATE 2202708Swollmanstatic struct state * lclptr; 2212708Swollmanstatic struct state * gmtptr; 2222708Swollman#endif /* defined ALL_STATE */ 2232708Swollman 2242708Swollman#ifndef ALL_STATE 2252708Swollmanstatic struct state lclmem; 2262708Swollmanstatic struct state gmtmem; 2272708Swollman#define lclptr (&lclmem) 2282708Swollman#define gmtptr (&gmtmem) 2292708Swollman#endif /* State Farm */ 2302708Swollman 2319936Swollman#ifndef TZ_STRLEN_MAX 2329936Swollman#define TZ_STRLEN_MAX 255 2339936Swollman#endif /* !defined TZ_STRLEN_MAX */ 2349936Swollman 2359936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 2362708Swollmanstatic int lcl_is_set; 2372708Swollmanstatic int gmt_is_set; 238177824Sdavidxustatic pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; 23971579Sdeischenstatic pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; 2402708Swollman 2412708Swollmanchar * tzname[2] = { 2429936Swollman wildabbr, 2439936Swollman wildabbr 2442708Swollman}; 2452708Swollman 2469936Swollman/* 2479936Swollman** Section 4.12.3 of X3.159-1989 requires that 2489936Swollman** Except for the strftime function, these functions [asctime, 2499936Swollman** ctime, gmtime, localtime] return values in one of two static 2509936Swollman** objects: a broken-down time structure and an array of char. 251192625Sedwin** Thanks to Paul Eggert for noting this. 2529936Swollman*/ 2539936Swollman 2549936Swollmanstatic struct tm tm; 2559936Swollman 2562708Swollman#ifdef USG_COMPAT 2572708Swollmantime_t timezone = 0; 2582708Swollmanint daylight = 0; 2592708Swollman#endif /* defined USG_COMPAT */ 2602708Swollman 2612708Swollman#ifdef ALTZONE 2622708Swollmantime_t altzone = 0; 2632708Swollman#endif /* defined ALTZONE */ 2642708Swollman 2652708Swollmanstatic long 2662708Swollmandetzcode(codep) 2672708Swollmanconst char * const codep; 2682708Swollman{ 26992889Sobrien long result; 27092889Sobrien int i; 2712708Swollman 272192625Sedwin result = (codep[0] & 0x80) ? ~0L : 0; 2732708Swollman for (i = 0; i < 4; ++i) 2742708Swollman result = (result << 8) | (codep[i] & 0xff); 2752708Swollman return result; 2762708Swollman} 2772708Swollman 278192625Sedwinstatic time_t 279192625Sedwindetzcode64(codep) 280192625Sedwinconst char * const codep; 281192625Sedwin{ 282192625Sedwin register time_t result; 283192625Sedwin register int i; 284192625Sedwin 285192625Sedwin result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; 286192625Sedwin for (i = 0; i < 8; ++i) 287192625Sedwin result = result * 256 + (codep[i] & 0xff); 288192625Sedwin return result; 289192625Sedwin} 290192625Sedwin 2912708Swollmanstatic void 29297423Salfredsettzname(void) 2932708Swollman{ 29492889Sobrien struct state * sp = lclptr; 29592889Sobrien int i; 2962708Swollman 2979936Swollman tzname[0] = wildabbr; 2989936Swollman tzname[1] = wildabbr; 2992708Swollman#ifdef USG_COMPAT 3002708Swollman daylight = 0; 3012708Swollman timezone = 0; 3022708Swollman#endif /* defined USG_COMPAT */ 3032708Swollman#ifdef ALTZONE 3042708Swollman altzone = 0; 3052708Swollman#endif /* defined ALTZONE */ 3062708Swollman#ifdef ALL_STATE 3072708Swollman if (sp == NULL) { 3089936Swollman tzname[0] = tzname[1] = gmt; 3092708Swollman return; 3102708Swollman } 3112708Swollman#endif /* defined ALL_STATE */ 3122708Swollman for (i = 0; i < sp->typecnt; ++i) { 31392889Sobrien const struct ttinfo * const ttisp = &sp->ttis[i]; 3142708Swollman 3152708Swollman tzname[ttisp->tt_isdst] = 3169936Swollman &sp->chars[ttisp->tt_abbrind]; 3172708Swollman#ifdef USG_COMPAT 3182708Swollman if (ttisp->tt_isdst) 3192708Swollman daylight = 1; 3202708Swollman if (i == 0 || !ttisp->tt_isdst) 3212708Swollman timezone = -(ttisp->tt_gmtoff); 3222708Swollman#endif /* defined USG_COMPAT */ 3232708Swollman#ifdef ALTZONE 3242708Swollman if (i == 0 || ttisp->tt_isdst) 3252708Swollman altzone = -(ttisp->tt_gmtoff); 3262708Swollman#endif /* defined ALTZONE */ 3272708Swollman } 3282708Swollman /* 3292708Swollman ** And to get the latest zone names into tzname. . . 3302708Swollman */ 3312708Swollman for (i = 0; i < sp->timecnt; ++i) { 33292889Sobrien const struct ttinfo * const ttisp = 3332708Swollman &sp->ttis[ 3342708Swollman sp->types[i]]; 3352708Swollman 3362708Swollman tzname[ttisp->tt_isdst] = 3379936Swollman &sp->chars[ttisp->tt_abbrind]; 3382708Swollman } 339192625Sedwin /* 340192625Sedwin ** Finally, scrub the abbreviations. 341192625Sedwin ** First, replace bogus characters. 342192625Sedwin */ 343192625Sedwin for (i = 0; i < sp->charcnt; ++i) 344192625Sedwin if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) 345192625Sedwin sp->chars[i] = TZ_ABBR_ERR_CHAR; 346192625Sedwin /* 347192625Sedwin ** Second, truncate long abbreviations. 348192625Sedwin */ 349192625Sedwin for (i = 0; i < sp->typecnt; ++i) { 350192625Sedwin register const struct ttinfo * const ttisp = &sp->ttis[i]; 351192625Sedwin register char * cp = &sp->chars[ttisp->tt_abbrind]; 352192625Sedwin 353192625Sedwin if (strlen(cp) > TZ_ABBR_MAX_LEN && 354192625Sedwin strcmp(cp, GRANDPARENTED) != 0) 355192625Sedwin *(cp + TZ_ABBR_MAX_LEN) = '\0'; 356192625Sedwin } 3572708Swollman} 3582708Swollman 3592708Swollmanstatic int 360192625Sedwindiffer_by_repeat(t1, t0) 361192625Sedwinconst time_t t1; 362192625Sedwinconst time_t t0; 363192625Sedwin{ 364192625Sedwin int_fast64_t _t0 = t0; 365192625Sedwin int_fast64_t _t1 = t1; 366192625Sedwin 367192625Sedwin if (TYPE_INTEGRAL(time_t) && 368192625Sedwin TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) 369192625Sedwin return 0; 370192625Sedwin //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT); 371192625Sedwin return _t1 - _t0 == SECSPERREPEAT; 372192625Sedwin} 373192625Sedwin 374192625Sedwinstatic int 375192625Sedwintzload(name, sp, doextend) 37692889Sobrienconst char * name; 37792889Sobrienstruct state * const sp; 378192625Sedwinregister const int doextend; 3792708Swollman{ 38092889Sobrien const char * p; 38192889Sobrien int i; 38292889Sobrien int fid; 383192625Sedwin int stored; 384192625Sedwin int nread; 385192625Sedwin union { 386192625Sedwin struct tzhead tzhead; 387192625Sedwin char buf[2 * sizeof(struct tzhead) + 388192625Sedwin 2 * sizeof *sp + 389192625Sedwin 4 * TZ_MAX_TIMES]; 390192625Sedwin } u; 3912708Swollman 39239327Simp /* XXX The following is from OpenBSD, and I'm not sure it is correct */ 39339327Simp if (name != NULL && issetugid() != 0) 39439327Simp if ((name[0] == ':' && name[1] == '/') || 39539327Simp name[0] == '/' || strchr(name, '.')) 39639327Simp name = NULL; 3972708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 3982708Swollman return -1; 3992708Swollman { 40092889Sobrien int doaccess; 40118834Swollman struct stat stab; 4029936Swollman /* 4039936Swollman ** Section 4.9.1 of the C standard says that 4049936Swollman ** "FILENAME_MAX expands to an integral constant expression 40518834Swollman ** that is the size needed for an array of char large enough 4069936Swollman ** to hold the longest file name string that the implementation 4079936Swollman ** guarantees can be opened." 4089936Swollman */ 4092708Swollman char fullname[FILENAME_MAX + 1]; 4102708Swollman 4112708Swollman if (name[0] == ':') 4122708Swollman ++name; 4132708Swollman doaccess = name[0] == '/'; 4142708Swollman if (!doaccess) { 4152708Swollman if ((p = TZDIR) == NULL) 4162708Swollman return -1; 41739327Simp if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname) 4182708Swollman return -1; 4192708Swollman (void) strcpy(fullname, p); 4202708Swollman (void) strcat(fullname, "/"); 4212708Swollman (void) strcat(fullname, name); 4222708Swollman /* 4232708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 4242708Swollman */ 4252708Swollman if (strchr(name, '.') != NULL) 4262708Swollman doaccess = TRUE; 4272708Swollman name = fullname; 4282708Swollman } 42924253Simp if (doaccess && access(name, R_OK) != 0) 43039327Simp return -1; 43156698Sjasone if ((fid = _open(name, OPEN_MODE)) == -1) 4322708Swollman return -1; 43395989Swollman if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) { 43495989Swollman _close(fid); 43518834Swollman return -1; 43695989Swollman } 4372708Swollman } 438192625Sedwin nread = _read(fid, u.buf, sizeof u.buf); 439192625Sedwin if (_close(fid) < 0 || nread <= 0) 440192625Sedwin return -1; 441192625Sedwin for (stored = 4; stored <= 8; stored *= 2) { 4429936Swollman int ttisstdcnt; 4439936Swollman int ttisgmtcnt; 4442708Swollman 445130461Sstefanf ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); 446130461Sstefanf ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); 447130461Sstefanf sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); 448130461Sstefanf sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); 449130461Sstefanf sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); 450130461Sstefanf sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); 451130461Sstefanf p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; 4522708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 4532708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 4542708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 4552708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 4569936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 4579936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 4582708Swollman return -1; 459192625Sedwin if (nread - (p - u.buf) < 460192625Sedwin sp->timecnt * stored + /* ats */ 4619936Swollman sp->timecnt + /* types */ 462192625Sedwin sp->typecnt * 6 + /* ttinfos */ 4639936Swollman sp->charcnt + /* chars */ 464192625Sedwin sp->leapcnt * (stored + 4) + /* lsinfos */ 4659936Swollman ttisstdcnt + /* ttisstds */ 4669936Swollman ttisgmtcnt) /* ttisgmts */ 4672708Swollman return -1; 4682708Swollman for (i = 0; i < sp->timecnt; ++i) { 469192625Sedwin sp->ats[i] = (stored == 4) ? 470192625Sedwin detzcode(p) : detzcode64(p); 471192625Sedwin p += stored; 4722708Swollman } 4732708Swollman for (i = 0; i < sp->timecnt; ++i) { 4742708Swollman sp->types[i] = (unsigned char) *p++; 4752708Swollman if (sp->types[i] >= sp->typecnt) 4762708Swollman return -1; 4772708Swollman } 4782708Swollman for (i = 0; i < sp->typecnt; ++i) { 47992889Sobrien struct ttinfo * ttisp; 4802708Swollman 4812708Swollman ttisp = &sp->ttis[i]; 4822708Swollman ttisp->tt_gmtoff = detzcode(p); 4832708Swollman p += 4; 4842708Swollman ttisp->tt_isdst = (unsigned char) *p++; 4852708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 4862708Swollman return -1; 4872708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 4882708Swollman if (ttisp->tt_abbrind < 0 || 4892708Swollman ttisp->tt_abbrind > sp->charcnt) 4902708Swollman return -1; 4912708Swollman } 4922708Swollman for (i = 0; i < sp->charcnt; ++i) 4932708Swollman sp->chars[i] = *p++; 4942708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 4952708Swollman for (i = 0; i < sp->leapcnt; ++i) { 49692889Sobrien struct lsinfo * lsisp; 4972708Swollman 4982708Swollman lsisp = &sp->lsis[i]; 499192625Sedwin lsisp->ls_trans = (stored == 4) ? 500192625Sedwin detzcode(p) : detzcode64(p); 501192625Sedwin p += stored; 5022708Swollman lsisp->ls_corr = detzcode(p); 5032708Swollman p += 4; 5042708Swollman } 5052708Swollman for (i = 0; i < sp->typecnt; ++i) { 50692889Sobrien struct ttinfo * ttisp; 5072708Swollman 5082708Swollman ttisp = &sp->ttis[i]; 5092708Swollman if (ttisstdcnt == 0) 5102708Swollman ttisp->tt_ttisstd = FALSE; 5112708Swollman else { 5122708Swollman ttisp->tt_ttisstd = *p++; 5132708Swollman if (ttisp->tt_ttisstd != TRUE && 5142708Swollman ttisp->tt_ttisstd != FALSE) 5152708Swollman return -1; 5162708Swollman } 5172708Swollman } 5189936Swollman for (i = 0; i < sp->typecnt; ++i) { 51992889Sobrien struct ttinfo * ttisp; 5209936Swollman 5219936Swollman ttisp = &sp->ttis[i]; 5229936Swollman if (ttisgmtcnt == 0) 5239936Swollman ttisp->tt_ttisgmt = FALSE; 5249936Swollman else { 5259936Swollman ttisp->tt_ttisgmt = *p++; 5269936Swollman if (ttisp->tt_ttisgmt != TRUE && 5279936Swollman ttisp->tt_ttisgmt != FALSE) 5289936Swollman return -1; 5299936Swollman } 5309936Swollman } 531192625Sedwin /* 532192625Sedwin ** Out-of-sort ats should mean we're running on a 533192625Sedwin ** signed time_t system but using a data file with 534192625Sedwin ** unsigned values (or vice versa). 535192625Sedwin */ 536192625Sedwin for (i = 0; i < sp->timecnt - 2; ++i) 537192625Sedwin if (sp->ats[i] > sp->ats[i + 1]) { 538192625Sedwin ++i; 539192625Sedwin if (TYPE_SIGNED(time_t)) { 540192625Sedwin /* 541192625Sedwin ** Ignore the end (easy). 542192625Sedwin */ 543192625Sedwin sp->timecnt = i; 544192625Sedwin } else { 545192625Sedwin /* 546192625Sedwin ** Ignore the beginning (harder). 547192625Sedwin */ 548192625Sedwin register int j; 549192625Sedwin 550192625Sedwin for (j = 0; j + i < sp->timecnt; ++j) { 551192625Sedwin sp->ats[j] = sp->ats[j + i]; 552192625Sedwin sp->types[j] = sp->types[j + i]; 553192625Sedwin } 554192625Sedwin sp->timecnt = j; 555192625Sedwin } 556192625Sedwin break; 557192625Sedwin } 558192625Sedwin /* 559192625Sedwin ** If this is an old file, we're done. 560192625Sedwin */ 561192625Sedwin if (u.tzhead.tzh_version[0] == '\0') 562192625Sedwin break; 563192625Sedwin nread -= p - u.buf; 564192625Sedwin for (i = 0; i < nread; ++i) 565192625Sedwin u.buf[i] = p[i]; 566192625Sedwin /* 567192625Sedwin ** If this is a narrow integer time_t system, we're done. 568192625Sedwin */ 569192625Sedwin if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t)) 570192625Sedwin break; 5712708Swollman } 572192625Sedwin if (doextend && nread > 2 && 573192625Sedwin u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && 574192625Sedwin sp->typecnt + 2 <= TZ_MAX_TYPES) { 575192625Sedwin struct state ts; 576192625Sedwin register int result; 577192625Sedwin 578192625Sedwin u.buf[nread - 1] = '\0'; 579192625Sedwin result = tzparse(&u.buf[1], &ts, FALSE); 580192625Sedwin if (result == 0 && ts.typecnt == 2 && 581192625Sedwin sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { 582192625Sedwin for (i = 0; i < 2; ++i) 583192625Sedwin ts.ttis[i].tt_abbrind += 584192625Sedwin sp->charcnt; 585192625Sedwin for (i = 0; i < ts.charcnt; ++i) 586192625Sedwin sp->chars[sp->charcnt++] = 587192625Sedwin ts.chars[i]; 588192625Sedwin i = 0; 589192625Sedwin while (i < ts.timecnt && 590192625Sedwin ts.ats[i] <= 591192625Sedwin sp->ats[sp->timecnt - 1]) 592192625Sedwin ++i; 593192625Sedwin while (i < ts.timecnt && 594192625Sedwin sp->timecnt < TZ_MAX_TIMES) { 595192625Sedwin sp->ats[sp->timecnt] = 596192625Sedwin ts.ats[i]; 597192625Sedwin sp->types[sp->timecnt] = 598192625Sedwin sp->typecnt + 599192625Sedwin ts.types[i]; 600192625Sedwin ++sp->timecnt; 601192625Sedwin ++i; 602192625Sedwin } 603192625Sedwin sp->ttis[sp->typecnt++] = ts.ttis[0]; 604192625Sedwin sp->ttis[sp->typecnt++] = ts.ttis[1]; 605192625Sedwin } 606192625Sedwin } 607192625Sedwin sp->goback = sp->goahead = FALSE; 608192625Sedwin if (sp->timecnt > 1) { 609192625Sedwin for (i = 1; i < sp->timecnt; ++i) 610192625Sedwin if (typesequiv(sp, sp->types[i], sp->types[0]) && 611192625Sedwin differ_by_repeat(sp->ats[i], sp->ats[0])) { 612192625Sedwin sp->goback = TRUE; 613192625Sedwin break; 614192625Sedwin } 615192625Sedwin for (i = sp->timecnt - 2; i >= 0; --i) 616192625Sedwin if (typesequiv(sp, sp->types[sp->timecnt - 1], 617192625Sedwin sp->types[i]) && 618192625Sedwin differ_by_repeat(sp->ats[sp->timecnt - 1], 619192625Sedwin sp->ats[i])) { 620192625Sedwin sp->goahead = TRUE; 621192625Sedwin break; 622192625Sedwin } 623192625Sedwin } 6242708Swollman return 0; 6252708Swollman} 6262708Swollman 627192625Sedwinstatic int 628192625Sedwintypesequiv(sp, a, b) 629192625Sedwinconst struct state * const sp; 630192625Sedwinconst int a; 631192625Sedwinconst int b; 632192625Sedwin{ 633192625Sedwin register int result; 634192625Sedwin 635192625Sedwin if (sp == NULL || 636192625Sedwin a < 0 || a >= sp->typecnt || 637192625Sedwin b < 0 || b >= sp->typecnt) 638192625Sedwin result = FALSE; 639192625Sedwin else { 640192625Sedwin register const struct ttinfo * ap = &sp->ttis[a]; 641192625Sedwin register const struct ttinfo * bp = &sp->ttis[b]; 642192625Sedwin result = ap->tt_gmtoff == bp->tt_gmtoff && 643192625Sedwin ap->tt_isdst == bp->tt_isdst && 644192625Sedwin ap->tt_ttisstd == bp->tt_ttisstd && 645192625Sedwin ap->tt_ttisgmt == bp->tt_ttisgmt && 646192625Sedwin strcmp(&sp->chars[ap->tt_abbrind], 647192625Sedwin &sp->chars[bp->tt_abbrind]) == 0; 648192625Sedwin } 649192625Sedwin return result; 650192625Sedwin} 651192625Sedwin 6522708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 6532708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 6542708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 6552708Swollman}; 6562708Swollman 6572708Swollmanstatic const int year_lengths[2] = { 6582708Swollman DAYSPERNYEAR, DAYSPERLYEAR 6592708Swollman}; 6602708Swollman 6612708Swollman/* 6622708Swollman** Given a pointer into a time zone string, scan until a character that is not 663192625Sedwin** a valid character in a zone name is found. Return a pointer to that 6642708Swollman** character. 6652708Swollman*/ 6662708Swollman 6672708Swollmanstatic const char * 6682708Swollmangetzname(strp) 66992889Sobrienconst char * strp; 6702708Swollman{ 67192889Sobrien char c; 6722708Swollman 67317209Swollman while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 6742708Swollman c != '+') 6752708Swollman ++strp; 6762708Swollman return strp; 6772708Swollman} 6782708Swollman 6792708Swollman/* 680192625Sedwin** Given a pointer into an extended time zone string, scan until the ending 681192625Sedwin** delimiter of the zone name is located. Return a pointer to the delimiter. 682192625Sedwin** 683192625Sedwin** As with getzname above, the legal character set is actually quite 684192625Sedwin** restricted, with other characters producing undefined results. 685192625Sedwin** We don't do any checking here; checking is done later in common-case code. 686192625Sedwin*/ 687192625Sedwin 688192625Sedwinstatic const char * 689192625Sedwingetqzname(register const char *strp, const int delim) 690192625Sedwin{ 691192625Sedwin register int c; 692192625Sedwin 693192625Sedwin while ((c = *strp) != '\0' && c != delim) 694192625Sedwin ++strp; 695192625Sedwin return strp; 696192625Sedwin} 697192625Sedwin 698192625Sedwin/* 6992708Swollman** Given a pointer into a time zone string, extract a number from that string. 7002708Swollman** Check that the number is within a specified range; if it is not, return 7012708Swollman** NULL. 7022708Swollman** Otherwise, return a pointer to the first character not part of the number. 7032708Swollman*/ 7042708Swollman 7052708Swollmanstatic const char * 7062708Swollmangetnum(strp, nump, min, max) 70792889Sobrienconst char * strp; 7082708Swollmanint * const nump; 7092708Swollmanconst int min; 7102708Swollmanconst int max; 7112708Swollman{ 71292889Sobrien char c; 71392889Sobrien int num; 7142708Swollman 71517209Swollman if (strp == NULL || !is_digit(c = *strp)) 7162708Swollman return NULL; 7172708Swollman num = 0; 71817209Swollman do { 7192708Swollman num = num * 10 + (c - '0'); 7202708Swollman if (num > max) 7212708Swollman return NULL; /* illegal value */ 72217209Swollman c = *++strp; 72317209Swollman } while (is_digit(c)); 7242708Swollman if (num < min) 7252708Swollman return NULL; /* illegal value */ 7262708Swollman *nump = num; 7272708Swollman return strp; 7282708Swollman} 7292708Swollman 7302708Swollman/* 7312708Swollman** Given a pointer into a time zone string, extract a number of seconds, 7322708Swollman** in hh[:mm[:ss]] form, from the string. 7332708Swollman** If any error occurs, return NULL. 7342708Swollman** Otherwise, return a pointer to the first character not part of the number 7352708Swollman** of seconds. 7362708Swollman*/ 7372708Swollman 7382708Swollmanstatic const char * 7392708Swollmangetsecs(strp, secsp) 74092889Sobrienconst char * strp; 7412708Swollmanlong * const secsp; 7422708Swollman{ 7432708Swollman int num; 7442708Swollman 7459936Swollman /* 7469936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 7479936Swollman ** "M10.4.6/26", which does not conform to Posix, 7489936Swollman ** but which specifies the equivalent of 7499936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 7509936Swollman */ 7519936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 7522708Swollman if (strp == NULL) 7532708Swollman return NULL; 7549936Swollman *secsp = num * (long) SECSPERHOUR; 7552708Swollman if (*strp == ':') { 7562708Swollman ++strp; 7572708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 7582708Swollman if (strp == NULL) 7592708Swollman return NULL; 7602708Swollman *secsp += num * SECSPERMIN; 7612708Swollman if (*strp == ':') { 7622708Swollman ++strp; 763192625Sedwin /* `SECSPERMIN' allows for leap seconds. */ 7649936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 7652708Swollman if (strp == NULL) 7662708Swollman return NULL; 7672708Swollman *secsp += num; 7682708Swollman } 7692708Swollman } 7702708Swollman return strp; 7712708Swollman} 7722708Swollman 7732708Swollman/* 7742708Swollman** Given a pointer into a time zone string, extract an offset, in 7752708Swollman** [+-]hh[:mm[:ss]] form, from the string. 7762708Swollman** If any error occurs, return NULL. 7772708Swollman** Otherwise, return a pointer to the first character not part of the time. 7782708Swollman*/ 7792708Swollman 7802708Swollmanstatic const char * 7812708Swollmangetoffset(strp, offsetp) 78292889Sobrienconst char * strp; 7832708Swollmanlong * const offsetp; 7842708Swollman{ 78592889Sobrien int neg = 0; 7862708Swollman 7872708Swollman if (*strp == '-') { 7882708Swollman neg = 1; 7892708Swollman ++strp; 79017209Swollman } else if (*strp == '+') 79117209Swollman ++strp; 7922708Swollman strp = getsecs(strp, offsetp); 7932708Swollman if (strp == NULL) 7942708Swollman return NULL; /* illegal time */ 7952708Swollman if (neg) 7962708Swollman *offsetp = -*offsetp; 7972708Swollman return strp; 7982708Swollman} 7992708Swollman 8002708Swollman/* 8012708Swollman** Given a pointer into a time zone string, extract a rule in the form 802192625Sedwin** date[/time]. See POSIX section 8 for the format of "date" and "time". 8032708Swollman** If a valid rule is not found, return NULL. 8042708Swollman** Otherwise, return a pointer to the first character not part of the rule. 8052708Swollman*/ 8062708Swollman 8072708Swollmanstatic const char * 8082708Swollmangetrule(strp, rulep) 8092708Swollmanconst char * strp; 81092889Sobrienstruct rule * const rulep; 8112708Swollman{ 8122708Swollman if (*strp == 'J') { 8132708Swollman /* 8142708Swollman ** Julian day. 8152708Swollman */ 8162708Swollman rulep->r_type = JULIAN_DAY; 8172708Swollman ++strp; 8182708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 8192708Swollman } else if (*strp == 'M') { 8202708Swollman /* 8212708Swollman ** Month, week, day. 8222708Swollman */ 8232708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 8242708Swollman ++strp; 8252708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 8262708Swollman if (strp == NULL) 8272708Swollman return NULL; 8282708Swollman if (*strp++ != '.') 8292708Swollman return NULL; 8302708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 8312708Swollman if (strp == NULL) 8322708Swollman return NULL; 8332708Swollman if (*strp++ != '.') 8342708Swollman return NULL; 8352708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 83617209Swollman } else if (is_digit(*strp)) { 8372708Swollman /* 8382708Swollman ** Day of year. 8392708Swollman */ 8402708Swollman rulep->r_type = DAY_OF_YEAR; 8412708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 8422708Swollman } else return NULL; /* invalid format */ 8432708Swollman if (strp == NULL) 8442708Swollman return NULL; 8452708Swollman if (*strp == '/') { 8462708Swollman /* 8472708Swollman ** Time specified. 8482708Swollman */ 8492708Swollman ++strp; 8502708Swollman strp = getsecs(strp, &rulep->r_time); 8512708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 8522708Swollman return strp; 8532708Swollman} 8542708Swollman 8552708Swollman/* 856130461Sstefanf** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the 857130461Sstefanf** year, a rule, and the offset from UTC at the time that rule takes effect, 8582708Swollman** calculate the Epoch-relative time that rule takes effect. 8592708Swollman*/ 8602708Swollman 8612708Swollmanstatic time_t 8622708Swollmantranstime(janfirst, year, rulep, offset) 8632708Swollmanconst time_t janfirst; 8642708Swollmanconst int year; 86592889Sobrienconst struct rule * const rulep; 8662708Swollmanconst long offset; 8672708Swollman{ 86892889Sobrien int leapyear; 86992889Sobrien time_t value; 87092889Sobrien int i; 8712708Swollman int d, m1, yy0, yy1, yy2, dow; 8722708Swollman 8739936Swollman INITIALIZE(value); 8742708Swollman leapyear = isleap(year); 8752708Swollman switch (rulep->r_type) { 8762708Swollman 8772708Swollman case JULIAN_DAY: 8782708Swollman /* 8792708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 8802708Swollman ** years. 8812708Swollman ** In non-leap years, or if the day number is 59 or less, just 8822708Swollman ** add SECSPERDAY times the day number-1 to the time of 8832708Swollman ** January 1, midnight, to get the day. 8842708Swollman */ 8852708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 8862708Swollman if (leapyear && rulep->r_day >= 60) 8872708Swollman value += SECSPERDAY; 8882708Swollman break; 8892708Swollman 8902708Swollman case DAY_OF_YEAR: 8912708Swollman /* 8922708Swollman ** n - day of year. 8932708Swollman ** Just add SECSPERDAY times the day number to the time of 8942708Swollman ** January 1, midnight, to get the day. 8952708Swollman */ 8962708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 8972708Swollman break; 8982708Swollman 8992708Swollman case MONTH_NTH_DAY_OF_WEEK: 9002708Swollman /* 9012708Swollman ** Mm.n.d - nth "dth day" of month m. 9022708Swollman */ 9032708Swollman value = janfirst; 9042708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 9052708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 9062708Swollman 9072708Swollman /* 9082708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 9092708Swollman ** month. 9102708Swollman */ 9112708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 9122708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 9132708Swollman yy1 = yy0 / 100; 9142708Swollman yy2 = yy0 % 100; 9152708Swollman dow = ((26 * m1 - 2) / 10 + 9162708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 9172708Swollman if (dow < 0) 9182708Swollman dow += DAYSPERWEEK; 9192708Swollman 9202708Swollman /* 921192625Sedwin ** "dow" is the day-of-week of the first day of the month. Get 9222708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 9232708Swollman ** month. 9242708Swollman */ 9252708Swollman d = rulep->r_day - dow; 9262708Swollman if (d < 0) 9272708Swollman d += DAYSPERWEEK; 9282708Swollman for (i = 1; i < rulep->r_week; ++i) { 9292708Swollman if (d + DAYSPERWEEK >= 9302708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 9312708Swollman break; 9322708Swollman d += DAYSPERWEEK; 9332708Swollman } 9342708Swollman 9352708Swollman /* 9362708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 9372708Swollman */ 9382708Swollman value += d * SECSPERDAY; 9392708Swollman break; 9402708Swollman } 9412708Swollman 9422708Swollman /* 943130461Sstefanf ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in 944192625Sedwin ** question. To get the Epoch-relative time of the specified local 9452708Swollman ** time on that day, add the transition time and the current offset 946130461Sstefanf ** from UTC. 9472708Swollman */ 9482708Swollman return value + rulep->r_time + offset; 9492708Swollman} 9502708Swollman 9512708Swollman/* 9522708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 9532708Swollman** appropriate. 9542708Swollman*/ 9552708Swollman 9562708Swollmanstatic int 9572708Swollmantzparse(name, sp, lastditch) 9582708Swollmanconst char * name; 95992889Sobrienstruct state * const sp; 9602708Swollmanconst int lastditch; 9612708Swollman{ 9622708Swollman const char * stdname; 9632708Swollman const char * dstname; 9649936Swollman size_t stdlen; 9659936Swollman size_t dstlen; 9662708Swollman long stdoffset; 9672708Swollman long dstoffset; 96892889Sobrien time_t * atp; 96992889Sobrien unsigned char * typep; 97092889Sobrien char * cp; 97192889Sobrien int load_result; 9722708Swollman 9739936Swollman INITIALIZE(dstname); 9742708Swollman stdname = name; 9752708Swollman if (lastditch) { 9762708Swollman stdlen = strlen(name); /* length of standard zone name */ 9772708Swollman name += stdlen; 9782708Swollman if (stdlen >= sizeof sp->chars) 9792708Swollman stdlen = (sizeof sp->chars) - 1; 98021659Swollman stdoffset = 0; 9812708Swollman } else { 982192625Sedwin if (*name == '<') { 983192625Sedwin name++; 984192625Sedwin stdname = name; 985192625Sedwin name = getqzname(name, '>'); 986192625Sedwin if (*name != '>') 987192625Sedwin return (-1); 988192625Sedwin stdlen = name - stdname; 989192625Sedwin name++; 990192625Sedwin } else { 991192625Sedwin name = getzname(name); 992192625Sedwin stdlen = name - stdname; 993192625Sedwin } 99421659Swollman if (*name == '\0') 99521659Swollman return -1; /* was "stdoffset = 0;" */ 99621659Swollman else { 99721659Swollman name = getoffset(name, &stdoffset); 99821659Swollman if (name == NULL) 99921659Swollman return -1; 100021659Swollman } 10012708Swollman } 1002192625Sedwin load_result = tzload(TZDEFRULES, sp, FALSE); 10032708Swollman if (load_result != 0) 10042708Swollman sp->leapcnt = 0; /* so, we're off a little */ 10052708Swollman if (*name != '\0') { 1006192625Sedwin if (*name == '<') { 1007192625Sedwin dstname = ++name; 1008192625Sedwin name = getqzname(name, '>'); 1009192625Sedwin if (*name != '>') 1010192625Sedwin return -1; 1011192625Sedwin dstlen = name - dstname; 1012192625Sedwin name++; 1013192625Sedwin } else { 1014192625Sedwin dstname = name; 1015192625Sedwin name = getzname(name); 1016192625Sedwin dstlen = name - dstname; /* length of DST zone name */ 1017192625Sedwin } 10182708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 10192708Swollman name = getoffset(name, &dstoffset); 10202708Swollman if (name == NULL) 10212708Swollman return -1; 10222708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 1023130461Sstefanf if (*name == '\0' && load_result != 0) 1024130461Sstefanf name = TZDEFRULESTRING; 10252708Swollman if (*name == ',' || *name == ';') { 10262708Swollman struct rule start; 10272708Swollman struct rule end; 102892889Sobrien int year; 102992889Sobrien time_t janfirst; 10302708Swollman time_t starttime; 10312708Swollman time_t endtime; 10322708Swollman 10332708Swollman ++name; 10342708Swollman if ((name = getrule(name, &start)) == NULL) 10352708Swollman return -1; 10362708Swollman if (*name++ != ',') 10372708Swollman return -1; 10382708Swollman if ((name = getrule(name, &end)) == NULL) 10392708Swollman return -1; 10402708Swollman if (*name != '\0') 10412708Swollman return -1; 10422708Swollman sp->typecnt = 2; /* standard time and DST */ 10432708Swollman /* 1044192625Sedwin ** Two transitions per year, from EPOCH_YEAR forward. 10452708Swollman */ 10462708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 10472708Swollman sp->ttis[0].tt_isdst = 1; 10482708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 10492708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 10502708Swollman sp->ttis[1].tt_isdst = 0; 10512708Swollman sp->ttis[1].tt_abbrind = 0; 10522708Swollman atp = sp->ats; 10532708Swollman typep = sp->types; 10542708Swollman janfirst = 0; 1055192625Sedwin sp->timecnt = 0; 1056192625Sedwin for (year = EPOCH_YEAR; 1057192625Sedwin sp->timecnt + 2 <= TZ_MAX_TIMES; 1058192625Sedwin ++year) { 1059192625Sedwin time_t newfirst; 1060192625Sedwin 10612708Swollman starttime = transtime(janfirst, year, &start, 10622708Swollman stdoffset); 10632708Swollman endtime = transtime(janfirst, year, &end, 10642708Swollman dstoffset); 10652708Swollman if (starttime > endtime) { 10662708Swollman *atp++ = endtime; 10672708Swollman *typep++ = 1; /* DST ends */ 10682708Swollman *atp++ = starttime; 10692708Swollman *typep++ = 0; /* DST begins */ 10702708Swollman } else { 10712708Swollman *atp++ = starttime; 10722708Swollman *typep++ = 0; /* DST begins */ 10732708Swollman *atp++ = endtime; 10742708Swollman *typep++ = 1; /* DST ends */ 10752708Swollman } 1076192625Sedwin sp->timecnt += 2; 1077192625Sedwin newfirst = janfirst; 1078192625Sedwin newfirst += year_lengths[isleap(year)] * 10792708Swollman SECSPERDAY; 1080192625Sedwin if (newfirst <= janfirst) 1081192625Sedwin break; 1082192625Sedwin janfirst = newfirst; 10832708Swollman } 10842708Swollman } else { 108592889Sobrien long theirstdoffset; 108692889Sobrien long theirdstoffset; 108792889Sobrien long theiroffset; 108892889Sobrien int isdst; 108992889Sobrien int i; 109092889Sobrien int j; 10912708Swollman 10922708Swollman if (*name != '\0') 10932708Swollman return -1; 10942708Swollman /* 10959936Swollman ** Initial values of theirstdoffset and theirdstoffset. 10962708Swollman */ 10979936Swollman theirstdoffset = 0; 10989936Swollman for (i = 0; i < sp->timecnt; ++i) { 10999936Swollman j = sp->types[i]; 11009936Swollman if (!sp->ttis[j].tt_isdst) { 110117209Swollman theirstdoffset = 110217209Swollman -sp->ttis[j].tt_gmtoff; 11039936Swollman break; 11042708Swollman } 11052708Swollman } 11069936Swollman theirdstoffset = 0; 11079936Swollman for (i = 0; i < sp->timecnt; ++i) { 11089936Swollman j = sp->types[i]; 11099936Swollman if (sp->ttis[j].tt_isdst) { 111017209Swollman theirdstoffset = 111117209Swollman -sp->ttis[j].tt_gmtoff; 11129936Swollman break; 11139936Swollman } 11149936Swollman } 11152708Swollman /* 11169936Swollman ** Initially we're assumed to be in standard time. 11172708Swollman */ 11189936Swollman isdst = FALSE; 11199936Swollman theiroffset = theirstdoffset; 11202708Swollman /* 11219936Swollman ** Now juggle transition times and types 11229936Swollman ** tracking offsets as you do. 11232708Swollman */ 11242708Swollman for (i = 0; i < sp->timecnt; ++i) { 11259936Swollman j = sp->types[i]; 11269936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 11279936Swollman if (sp->ttis[j].tt_ttisgmt) { 11289936Swollman /* No adjustment to transition time */ 11299936Swollman } else { 11309936Swollman /* 11319936Swollman ** If summer time is in effect, and the 11329936Swollman ** transition time was not specified as 11339936Swollman ** standard time, add the summer time 11349936Swollman ** offset to the transition time; 11359936Swollman ** otherwise, add the standard time 11369936Swollman ** offset to the transition time. 11379936Swollman */ 11389936Swollman /* 11399936Swollman ** Transitions from DST to DDST 11409936Swollman ** will effectively disappear since 11419936Swollman ** POSIX provides for only one DST 11429936Swollman ** offset. 11439936Swollman */ 11449936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 11459936Swollman sp->ats[i] += dstoffset - 11469936Swollman theirdstoffset; 11479936Swollman } else { 11489936Swollman sp->ats[i] += stdoffset - 11499936Swollman theirstdoffset; 11509936Swollman } 11519936Swollman } 11529936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 11539936Swollman if (sp->ttis[j].tt_isdst) 11549936Swollman theirdstoffset = theiroffset; 11559936Swollman else theirstdoffset = theiroffset; 11562708Swollman } 11579936Swollman /* 11589936Swollman ** Finally, fill in ttis. 11599936Swollman ** ttisstd and ttisgmt need not be handled. 11609936Swollman */ 11619936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 11629936Swollman sp->ttis[0].tt_isdst = FALSE; 11639936Swollman sp->ttis[0].tt_abbrind = 0; 11649936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 11659936Swollman sp->ttis[1].tt_isdst = TRUE; 11669936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 1167130461Sstefanf sp->typecnt = 2; 11682708Swollman } 11692708Swollman } else { 11702708Swollman dstlen = 0; 11712708Swollman sp->typecnt = 1; /* only standard time */ 11722708Swollman sp->timecnt = 0; 11732708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 11742708Swollman sp->ttis[0].tt_isdst = 0; 11752708Swollman sp->ttis[0].tt_abbrind = 0; 11762708Swollman } 11772708Swollman sp->charcnt = stdlen + 1; 11782708Swollman if (dstlen != 0) 11792708Swollman sp->charcnt += dstlen + 1; 1180130461Sstefanf if ((size_t) sp->charcnt > sizeof sp->chars) 11812708Swollman return -1; 11822708Swollman cp = sp->chars; 11832708Swollman (void) strncpy(cp, stdname, stdlen); 11842708Swollman cp += stdlen; 11852708Swollman *cp++ = '\0'; 11862708Swollman if (dstlen != 0) { 11872708Swollman (void) strncpy(cp, dstname, dstlen); 11882708Swollman *(cp + dstlen) = '\0'; 11892708Swollman } 11902708Swollman return 0; 11912708Swollman} 11922708Swollman 11932708Swollmanstatic void 11942708Swollmangmtload(sp) 11952708Swollmanstruct state * const sp; 11962708Swollman{ 1197192625Sedwin if (tzload(gmt, sp, TRUE) != 0) 11989936Swollman (void) tzparse(gmt, sp, TRUE); 11992708Swollman} 12002708Swollman 120171579Sdeischenstatic void 1202177824Sdavidxutzsetwall_basic(int rdlocked) 12032708Swollman{ 1204177824Sdavidxu if (!rdlocked) 1205177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1206177824Sdavidxu if (lcl_is_set < 0) { 1207177824Sdavidxu if (!rdlocked) 1208177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 12099936Swollman return; 1210177824Sdavidxu } 1211177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1212177824Sdavidxu 1213177824Sdavidxu _RWLOCK_WRLOCK(&lcl_rwlock); 12149936Swollman lcl_is_set = -1; 12159936Swollman 12162708Swollman#ifdef ALL_STATE 12172708Swollman if (lclptr == NULL) { 12182708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 12192708Swollman if (lclptr == NULL) { 12202708Swollman settzname(); /* all we can do */ 1221177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1222177824Sdavidxu if (rdlocked) 1223177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12242708Swollman return; 12252708Swollman } 12262708Swollman } 12272708Swollman#endif /* defined ALL_STATE */ 1228192625Sedwin if (tzload((char *) NULL, lclptr, TRUE) != 0) 12292708Swollman gmtload(lclptr); 12302708Swollman settzname(); 1231177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1232177824Sdavidxu 1233177824Sdavidxu if (rdlocked) 1234177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12352708Swollman} 12362708Swollman 12372708Swollmanvoid 123897423Salfredtzsetwall(void) 123913545Sjulian{ 1240177824Sdavidxu tzsetwall_basic(0); 124113545Sjulian} 124213545Sjulian 124313545Sjulianstatic void 1244177824Sdavidxutzset_basic(int rdlocked) 12452708Swollman{ 124692889Sobrien const char * name; 12472708Swollman 12482708Swollman name = getenv("TZ"); 12492708Swollman if (name == NULL) { 1250177824Sdavidxu tzsetwall_basic(rdlocked); 12512708Swollman return; 12522708Swollman } 12539936Swollman 1254177824Sdavidxu if (!rdlocked) 1255177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1256177824Sdavidxu if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { 1257177824Sdavidxu if (!rdlocked) 1258177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 12599936Swollman return; 1260177824Sdavidxu } 1261177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1262177824Sdavidxu 1263177824Sdavidxu _RWLOCK_WRLOCK(&lcl_rwlock); 1264130461Sstefanf lcl_is_set = strlen(name) < sizeof lcl_TZname; 12659936Swollman if (lcl_is_set) 12669936Swollman (void) strcpy(lcl_TZname, name); 12679936Swollman 12682708Swollman#ifdef ALL_STATE 12692708Swollman if (lclptr == NULL) { 12702708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 12712708Swollman if (lclptr == NULL) { 12722708Swollman settzname(); /* all we can do */ 1273177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1274177824Sdavidxu if (rdlocked) 1275177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12762708Swollman return; 12772708Swollman } 12782708Swollman } 12792708Swollman#endif /* defined ALL_STATE */ 12802708Swollman if (*name == '\0') { 12812708Swollman /* 12822708Swollman ** User wants it fast rather than right. 12832708Swollman */ 12842708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 12852708Swollman lclptr->timecnt = 0; 1286130461Sstefanf lclptr->typecnt = 0; 1287130461Sstefanf lclptr->ttis[0].tt_isdst = 0; 12882708Swollman lclptr->ttis[0].tt_gmtoff = 0; 12892708Swollman lclptr->ttis[0].tt_abbrind = 0; 12909936Swollman (void) strcpy(lclptr->chars, gmt); 1291192625Sedwin } else if (tzload(name, lclptr, TRUE) != 0) 12922708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 12932708Swollman (void) gmtload(lclptr); 12942708Swollman settzname(); 1295177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1296177824Sdavidxu 1297177824Sdavidxu if (rdlocked) 1298177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12992708Swollman} 13002708Swollman 130113545Sjulianvoid 130297423Salfredtzset(void) 130313545Sjulian{ 1304177824Sdavidxu tzset_basic(0); 130513545Sjulian} 130613545Sjulian 13072708Swollman/* 13082708Swollman** The easy way to behave "as if no library function calls" localtime 13092708Swollman** is to not call it--so we drop its guts into "localsub", which can be 1310192625Sedwin** freely called. (And no, the PANS doesn't require the above behavior-- 13112708Swollman** but it *is* desirable.) 13122708Swollman** 13132708Swollman** The unused offset argument is for the benefit of mktime variants. 13142708Swollman*/ 13152708Swollman 13162708Swollman/*ARGSUSED*/ 1317192625Sedwinstatic struct tm * 13182708Swollmanlocalsub(timep, offset, tmp) 13192708Swollmanconst time_t * const timep; 13202708Swollmanconst long offset; 13212708Swollmanstruct tm * const tmp; 13222708Swollman{ 132392889Sobrien struct state * sp; 132492889Sobrien const struct ttinfo * ttisp; 132592889Sobrien int i; 1326192625Sedwin struct tm * result; 1327192625Sedwin const time_t t = *timep; 13282708Swollman 13292708Swollman sp = lclptr; 13302708Swollman#ifdef ALL_STATE 1331192625Sedwin if (sp == NULL) 1332192625Sedwin return gmtsub(timep, offset, tmp); 1333192625Sedwin#endif /* defined ALL_STATE */ 1334192625Sedwin if ((sp->goback && t < sp->ats[0]) || 1335192625Sedwin (sp->goahead && t > sp->ats[sp->timecnt - 1])) { 1336192625Sedwin time_t newt = t; 1337192625Sedwin register time_t seconds; 1338192625Sedwin register time_t tcycles; 1339192625Sedwin register int_fast64_t icycles; 1340192625Sedwin 1341192625Sedwin if (t < sp->ats[0]) 1342192625Sedwin seconds = sp->ats[0] - t; 1343192625Sedwin else seconds = t - sp->ats[sp->timecnt - 1]; 1344192625Sedwin --seconds; 1345192625Sedwin tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; 1346192625Sedwin ++tcycles; 1347192625Sedwin icycles = tcycles; 1348192625Sedwin if (tcycles - icycles >= 1 || icycles - tcycles >= 1) 1349192625Sedwin return NULL; 1350192625Sedwin seconds = icycles; 1351192625Sedwin seconds *= YEARSPERREPEAT; 1352192625Sedwin seconds *= AVGSECSPERYEAR; 1353192625Sedwin if (t < sp->ats[0]) 1354192625Sedwin newt += seconds; 1355192625Sedwin else newt -= seconds; 1356192625Sedwin if (newt < sp->ats[0] || 1357192625Sedwin newt > sp->ats[sp->timecnt - 1]) 1358192625Sedwin return NULL; /* "cannot happen" */ 1359192625Sedwin result = localsub(&newt, offset, tmp); 1360192625Sedwin if (result == tmp) { 1361192625Sedwin register time_t newy; 1362192625Sedwin 1363192625Sedwin newy = tmp->tm_year; 1364192625Sedwin if (t < sp->ats[0]) 1365192625Sedwin newy -= icycles * YEARSPERREPEAT; 1366192625Sedwin else newy += icycles * YEARSPERREPEAT; 1367192625Sedwin tmp->tm_year = newy; 1368192625Sedwin if (tmp->tm_year != newy) 1369192625Sedwin return NULL; 1370192625Sedwin } 1371192625Sedwin return result; 13722708Swollman } 13732708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 13742708Swollman i = 0; 13752708Swollman while (sp->ttis[i].tt_isdst) 13762708Swollman if (++i >= sp->typecnt) { 13772708Swollman i = 0; 13782708Swollman break; 13792708Swollman } 13802708Swollman } else { 1381192625Sedwin register int lo = 1; 1382192625Sedwin register int hi = sp->timecnt; 1383192625Sedwin 1384192625Sedwin while (lo < hi) { 1385192625Sedwin register int mid = (lo + hi) >> 1; 1386192625Sedwin 1387192625Sedwin if (t < sp->ats[mid]) 1388192625Sedwin hi = mid; 1389192625Sedwin else lo = mid + 1; 1390192625Sedwin } 1391192625Sedwin i = (int) sp->types[lo - 1]; 13922708Swollman } 13932708Swollman ttisp = &sp->ttis[i]; 13942708Swollman /* 13952708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 13962708Swollman ** you'd replace the statement below with 13972708Swollman ** t += ttisp->tt_gmtoff; 13982708Swollman ** timesub(&t, 0L, sp, tmp); 13992708Swollman */ 1400192625Sedwin result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); 14012708Swollman tmp->tm_isdst = ttisp->tt_isdst; 14029936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 14032708Swollman#ifdef TM_ZONE 14049936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 14052708Swollman#endif /* defined TM_ZONE */ 1406192625Sedwin return result; 14072708Swollman} 14082708Swollman 140919636Shsustruct tm * 14102708Swollmanlocaltime(timep) 14112708Swollmanconst time_t * const timep; 14122708Swollman{ 141371579Sdeischen static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 141413545Sjulian static pthread_key_t localtime_key = -1; 141513545Sjulian struct tm *p_tm; 141613545Sjulian 141771579Sdeischen if (__isthreaded != 0) { 141871579Sdeischen if (localtime_key < 0) { 1419174766Simp _pthread_mutex_lock(&localtime_mutex); 1420174766Simp if (localtime_key < 0) { 1421174766Simp if (_pthread_key_create(&localtime_key, free) < 0) { 1422174766Simp _pthread_mutex_unlock(&localtime_mutex); 1423174766Simp return(NULL); 1424174766Simp } 142571579Sdeischen } 1426174766Simp _pthread_mutex_unlock(&localtime_mutex); 142713545Sjulian } 142871579Sdeischen p_tm = _pthread_getspecific(localtime_key); 142971579Sdeischen if (p_tm == NULL) { 143071579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 143171579Sdeischen == NULL) 143271579Sdeischen return(NULL); 143371579Sdeischen _pthread_setspecific(localtime_key, p_tm); 143471579Sdeischen } 1435177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1436177824Sdavidxu tzset_basic(1); 143771579Sdeischen localsub(timep, 0L, p_tm); 1438177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 143971579Sdeischen return(p_tm); 144071579Sdeischen } else { 1441177824Sdavidxu tzset_basic(0); 144271579Sdeischen localsub(timep, 0L, &tm); 144371579Sdeischen return(&tm); 144413545Sjulian } 14452708Swollman} 14462708Swollman 14472708Swollman/* 1448130461Sstefanf** Re-entrant version of localtime. 1449130461Sstefanf*/ 1450130461Sstefanf 1451130461Sstefanfstruct tm * 1452192625Sedwinlocaltime_r(timep, tmp) 1453130461Sstefanfconst time_t * const timep; 1454192625Sedwinstruct tm * tmp; 1455130461Sstefanf{ 1456177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1457177824Sdavidxu tzset_basic(1); 1458192625Sedwin localsub(timep, 0L, tmp); 1459177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1460192625Sedwin return tmp; 1461130461Sstefanf} 1462130461Sstefanf 1463130461Sstefanf/* 14642708Swollman** gmtsub is to gmtime as localsub is to localtime. 14652708Swollman*/ 14662708Swollman 1467192625Sedwinstatic struct tm * 14682708Swollmangmtsub(timep, offset, tmp) 14692708Swollmanconst time_t * const timep; 14702708Swollmanconst long offset; 14712708Swollmanstruct tm * const tmp; 14722708Swollman{ 1473192625Sedwin register struct tm * result; 1474192625Sedwin 14752708Swollman if (!gmt_is_set) { 1476174766Simp _MUTEX_LOCK(&gmt_mutex); 1477174766Simp if (!gmt_is_set) { 14782708Swollman#ifdef ALL_STATE 1479174766Simp gmtptr = (struct state *) malloc(sizeof *gmtptr); 1480174766Simp if (gmtptr != NULL) 14812708Swollman#endif /* defined ALL_STATE */ 1482174766Simp gmtload(gmtptr); 1483174766Simp gmt_is_set = TRUE; 1484174766Simp } 1485174766Simp _MUTEX_UNLOCK(&gmt_mutex); 14862708Swollman } 1487192625Sedwin result = timesub(timep, offset, gmtptr, tmp); 14882708Swollman#ifdef TM_ZONE 14892708Swollman /* 14902708Swollman ** Could get fancy here and deliver something such as 1491130461Sstefanf ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, 14922708Swollman ** but this is no time for a treasure hunt. 14932708Swollman */ 14942708Swollman if (offset != 0) 14959936Swollman tmp->TM_ZONE = wildabbr; 14962708Swollman else { 14972708Swollman#ifdef ALL_STATE 14982708Swollman if (gmtptr == NULL) 14999936Swollman tmp->TM_ZONE = gmt; 15002708Swollman else tmp->TM_ZONE = gmtptr->chars; 15012708Swollman#endif /* defined ALL_STATE */ 15022708Swollman#ifndef ALL_STATE 15032708Swollman tmp->TM_ZONE = gmtptr->chars; 15042708Swollman#endif /* State Farm */ 15052708Swollman } 15062708Swollman#endif /* defined TM_ZONE */ 1507192625Sedwin return result; 15082708Swollman} 15092708Swollman 15102708Swollmanstruct tm * 15112708Swollmangmtime(timep) 15122708Swollmanconst time_t * const timep; 15132708Swollman{ 151471579Sdeischen static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 151513545Sjulian static pthread_key_t gmtime_key = -1; 151613545Sjulian struct tm *p_tm; 151713545Sjulian 151871579Sdeischen if (__isthreaded != 0) { 151971579Sdeischen if (gmtime_key < 0) { 1520174766Simp _pthread_mutex_lock(&gmtime_mutex); 1521174766Simp if (gmtime_key < 0) { 1522174766Simp if (_pthread_key_create(&gmtime_key, free) < 0) { 1523174766Simp _pthread_mutex_unlock(&gmtime_mutex); 1524174766Simp return(NULL); 1525174766Simp } 152671579Sdeischen } 1527174766Simp _pthread_mutex_unlock(&gmtime_mutex); 152813545Sjulian } 152971579Sdeischen /* 153071579Sdeischen * Changed to follow POSIX.1 threads standard, which 153171579Sdeischen * is what BSD currently has. 153271579Sdeischen */ 153371579Sdeischen if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { 153471579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 153571579Sdeischen == NULL) { 153671579Sdeischen return(NULL); 153771579Sdeischen } 153871579Sdeischen _pthread_setspecific(gmtime_key, p_tm); 153913545Sjulian } 154071579Sdeischen gmtsub(timep, 0L, p_tm); 154171579Sdeischen return(p_tm); 154213545Sjulian } 154371579Sdeischen else { 154471579Sdeischen gmtsub(timep, 0L, &tm); 154571579Sdeischen return(&tm); 154671579Sdeischen } 15472708Swollman} 15482708Swollman 1549130461Sstefanf/* 1550130461Sstefanf* Re-entrant version of gmtime. 1551130461Sstefanf*/ 1552130461Sstefanf 155319636Shsustruct tm * 1554192625Sedwingmtime_r(timep, tmp) 1555130461Sstefanfconst time_t * const timep; 1556192625Sedwinstruct tm * tmp; 155713545Sjulian{ 1558192625Sedwin return gmtsub(timep, 0L, tmp); 155913545Sjulian} 156013545Sjulian 15612708Swollman#ifdef STD_INSPIRED 15622708Swollman 15632708Swollmanstruct tm * 15642708Swollmanofftime(timep, offset) 15652708Swollmanconst time_t * const timep; 15662708Swollmanconst long offset; 15672708Swollman{ 1568192625Sedwin return gmtsub(timep, offset, &tm); 15692708Swollman} 15702708Swollman 15712708Swollman#endif /* defined STD_INSPIRED */ 15722708Swollman 1573192625Sedwin/* 1574192625Sedwin** Return the number of leap years through the end of the given year 1575192625Sedwin** where, to make the math easy, the answer for year zero is defined as zero. 1576192625Sedwin*/ 1577192625Sedwin 1578192625Sedwinstatic int 1579192625Sedwinleaps_thru_end_of(y) 1580192625Sedwinregister const int y; 1581192625Sedwin{ 1582192625Sedwin return (y >= 0) ? (y / 4 - y / 100 + y / 400) : 1583192625Sedwin -(leaps_thru_end_of(-(y + 1)) + 1); 1584192625Sedwin} 1585192625Sedwin 1586192625Sedwinstatic struct tm * 15872708Swollmantimesub(timep, offset, sp, tmp) 15882708Swollmanconst time_t * const timep; 15892708Swollmanconst long offset; 159092889Sobrienconst struct state * const sp; 159192889Sobrienstruct tm * const tmp; 15922708Swollman{ 159392889Sobrien const struct lsinfo * lp; 1594192625Sedwin time_t tdays; 1595192625Sedwin int idays; /* unsigned would be so 2003 */ 159692889Sobrien long rem; 1597192625Sedwin int y; 159892889Sobrien const int * ip; 159992889Sobrien long corr; 160092889Sobrien int hit; 160192889Sobrien int i; 16022708Swollman 16032708Swollman corr = 0; 16042708Swollman hit = 0; 16052708Swollman#ifdef ALL_STATE 16062708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 16072708Swollman#endif /* defined ALL_STATE */ 16082708Swollman#ifndef ALL_STATE 16092708Swollman i = sp->leapcnt; 16102708Swollman#endif /* State Farm */ 16112708Swollman while (--i >= 0) { 16122708Swollman lp = &sp->lsis[i]; 16132708Swollman if (*timep >= lp->ls_trans) { 16142708Swollman if (*timep == lp->ls_trans) { 16152708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 16162708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 16172708Swollman if (hit) 16182708Swollman while (i > 0 && 16192708Swollman sp->lsis[i].ls_trans == 16202708Swollman sp->lsis[i - 1].ls_trans + 1 && 16212708Swollman sp->lsis[i].ls_corr == 16222708Swollman sp->lsis[i - 1].ls_corr + 1) { 16232708Swollman ++hit; 16242708Swollman --i; 16252708Swollman } 16262708Swollman } 16272708Swollman corr = lp->ls_corr; 16282708Swollman break; 16292708Swollman } 16302708Swollman } 1631192625Sedwin y = EPOCH_YEAR; 1632192625Sedwin tdays = *timep / SECSPERDAY; 1633192625Sedwin rem = *timep - tdays * SECSPERDAY; 1634192625Sedwin while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { 1635192625Sedwin int newy; 1636192625Sedwin register time_t tdelta; 1637192625Sedwin register int idelta; 1638192625Sedwin register int leapdays; 1639192625Sedwin 1640192625Sedwin tdelta = tdays / DAYSPERLYEAR; 1641192625Sedwin idelta = tdelta; 1642192625Sedwin if (tdelta - idelta >= 1 || idelta - tdelta >= 1) 1643192625Sedwin return NULL; 1644192625Sedwin if (idelta == 0) 1645192625Sedwin idelta = (tdays < 0) ? -1 : 1; 1646192625Sedwin newy = y; 1647192625Sedwin if (increment_overflow(&newy, idelta)) 1648192625Sedwin return NULL; 1649192625Sedwin leapdays = leaps_thru_end_of(newy - 1) - 1650192625Sedwin leaps_thru_end_of(y - 1); 1651192625Sedwin tdays -= ((time_t) newy - y) * DAYSPERNYEAR; 1652192625Sedwin tdays -= leapdays; 1653192625Sedwin y = newy; 16542708Swollman } 1655192625Sedwin { 1656192625Sedwin register long seconds; 1657192625Sedwin 1658192625Sedwin seconds = tdays * SECSPERDAY + 0.5; 1659192625Sedwin tdays = seconds / SECSPERDAY; 1660192625Sedwin rem += seconds - tdays * SECSPERDAY; 1661192625Sedwin } 1662192625Sedwin /* 1663192625Sedwin ** Given the range, we can now fearlessly cast... 1664192625Sedwin */ 1665192625Sedwin idays = tdays; 1666192625Sedwin rem += offset - corr; 16672708Swollman while (rem < 0) { 16682708Swollman rem += SECSPERDAY; 1669192625Sedwin --idays; 16702708Swollman } 16712708Swollman while (rem >= SECSPERDAY) { 16722708Swollman rem -= SECSPERDAY; 1673192625Sedwin ++idays; 16742708Swollman } 1675192625Sedwin while (idays < 0) { 1676192625Sedwin if (increment_overflow(&y, -1)) 1677192625Sedwin return NULL; 1678192625Sedwin idays += year_lengths[isleap(y)]; 1679192625Sedwin } 1680192625Sedwin while (idays >= year_lengths[isleap(y)]) { 1681192625Sedwin idays -= year_lengths[isleap(y)]; 1682192625Sedwin if (increment_overflow(&y, 1)) 1683192625Sedwin return NULL; 1684192625Sedwin } 1685192625Sedwin tmp->tm_year = y; 1686192625Sedwin if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) 1687192625Sedwin return NULL; 1688192625Sedwin tmp->tm_yday = idays; 1689192625Sedwin /* 1690192625Sedwin ** The "extra" mods below avoid overflow problems. 1691192625Sedwin */ 1692192625Sedwin tmp->tm_wday = EPOCH_WDAY + 1693192625Sedwin ((y - EPOCH_YEAR) % DAYSPERWEEK) * 1694192625Sedwin (DAYSPERNYEAR % DAYSPERWEEK) + 1695192625Sedwin leaps_thru_end_of(y - 1) - 1696192625Sedwin leaps_thru_end_of(EPOCH_YEAR - 1) + 1697192625Sedwin idays; 1698192625Sedwin tmp->tm_wday %= DAYSPERWEEK; 1699192625Sedwin if (tmp->tm_wday < 0) 1700192625Sedwin tmp->tm_wday += DAYSPERWEEK; 17012708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 1702192625Sedwin rem %= SECSPERHOUR; 17032708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 170417209Swollman /* 170517209Swollman ** A positive leap second requires a special 1706192625Sedwin ** representation. This uses "... ??:59:60" et seq. 170717209Swollman */ 170817209Swollman tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 1709192625Sedwin ip = mon_lengths[isleap(y)]; 1710192625Sedwin for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1711192625Sedwin idays -= ip[tmp->tm_mon]; 1712192625Sedwin tmp->tm_mday = (int) (idays + 1); 17132708Swollman tmp->tm_isdst = 0; 17142708Swollman#ifdef TM_GMTOFF 17152708Swollman tmp->TM_GMTOFF = offset; 17162708Swollman#endif /* defined TM_GMTOFF */ 1717192625Sedwin return tmp; 17182708Swollman} 17192708Swollman 17202708Swollmanchar * 17212708Swollmanctime(timep) 17222708Swollmanconst time_t * const timep; 17232708Swollman{ 17249936Swollman/* 17259936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 1726130461Sstefanf** The ctime function converts the calendar time pointed to by timer 1727192625Sedwin** to local time in the form of a string. It is equivalent to 17289936Swollman** asctime(localtime(timer)) 17299936Swollman*/ 17302708Swollman return asctime(localtime(timep)); 17312708Swollman} 17322708Swollman 173335285Sphkchar * 173435285Sphkctime_r(timep, buf) 173535285Sphkconst time_t * const timep; 1736130461Sstefanfchar * buf; 173735285Sphk{ 1738192625Sedwin struct tm mytm; 1739130461Sstefanf 1740192625Sedwin return asctime_r(localtime_r(timep, &mytm), buf); 174135285Sphk} 174235285Sphk 17432708Swollman/* 17442708Swollman** Adapted from code provided by Robert Elz, who writes: 17452708Swollman** The "best" way to do mktime I think is based on an idea of Bob 174617209Swollman** Kridle's (so its said...) from a long time ago. 1747192625Sedwin** It does a binary search of the time_t space. Since time_t's are 17482708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 17492708Swollman** would still be very reasonable). 17502708Swollman*/ 17512708Swollman 17522708Swollman#ifndef WRONG 17532708Swollman#define WRONG (-1) 17542708Swollman#endif /* !defined WRONG */ 17552708Swollman 17562708Swollman/* 1757192625Sedwin** Simplified normalize logic courtesy Paul Eggert. 17582708Swollman*/ 17592708Swollman 17602708Swollmanstatic int 17612708Swollmanincrement_overflow(number, delta) 17622708Swollmanint * number; 17632708Swollmanint delta; 17642708Swollman{ 17659936Swollman int number0; 17668870Srgrimes 17672708Swollman number0 = *number; 17682708Swollman *number += delta; 17692708Swollman return (*number < number0) != (delta < 0); 17702708Swollman} 17712708Swollman 17722708Swollmanstatic int 1773192625Sedwinlong_increment_overflow(number, delta) 1774192625Sedwinlong * number; 1775192625Sedwinint delta; 1776192625Sedwin{ 1777192625Sedwin long number0; 1778192625Sedwin 1779192625Sedwin number0 = *number; 1780192625Sedwin *number += delta; 1781192625Sedwin return (*number < number0) != (delta < 0); 1782192625Sedwin} 1783192625Sedwin 1784192625Sedwinstatic int 17852708Swollmannormalize_overflow(tensptr, unitsptr, base) 17862708Swollmanint * const tensptr; 17872708Swollmanint * const unitsptr; 17882708Swollmanconst int base; 17892708Swollman{ 179092889Sobrien int tensdelta; 17912708Swollman 17922708Swollman tensdelta = (*unitsptr >= 0) ? 17932708Swollman (*unitsptr / base) : 17942708Swollman (-1 - (-1 - *unitsptr) / base); 17952708Swollman *unitsptr -= tensdelta * base; 17962708Swollman return increment_overflow(tensptr, tensdelta); 17972708Swollman} 17982708Swollman 17992708Swollmanstatic int 1800192625Sedwinlong_normalize_overflow(tensptr, unitsptr, base) 1801192625Sedwinlong * const tensptr; 1802192625Sedwinint * const unitsptr; 1803192625Sedwinconst int base; 1804192625Sedwin{ 1805192625Sedwin register int tensdelta; 1806192625Sedwin 1807192625Sedwin tensdelta = (*unitsptr >= 0) ? 1808192625Sedwin (*unitsptr / base) : 1809192625Sedwin (-1 - (-1 - *unitsptr) / base); 1810192625Sedwin *unitsptr -= tensdelta * base; 1811192625Sedwin return long_increment_overflow(tensptr, tensdelta); 1812192625Sedwin} 1813192625Sedwin 1814192625Sedwinstatic int 18152708Swollmantmcomp(atmp, btmp) 181692889Sobrienconst struct tm * const atmp; 181792889Sobrienconst struct tm * const btmp; 18182708Swollman{ 181992889Sobrien int result; 18202708Swollman 18212708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 18222708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 18232708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 18242708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 18252708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 18262708Swollman result = atmp->tm_sec - btmp->tm_sec; 18272708Swollman return result; 18282708Swollman} 18292708Swollman 18302708Swollmanstatic time_t 1831130461Sstefanftime2sub(tmp, funcp, offset, okayp, do_norm_secs) 18322708Swollmanstruct tm * const tmp; 1833192625Sedwinstruct tm * (* const funcp)(const time_t*, long, struct tm*); 18342708Swollmanconst long offset; 18352708Swollmanint * const okayp; 1836130461Sstefanfconst int do_norm_secs; 18372708Swollman{ 183892889Sobrien const struct state * sp; 183992889Sobrien int dir; 1840192625Sedwin int i, j; 184192889Sobrien int saved_seconds; 1842192625Sedwin long li; 1843192625Sedwin time_t lo; 1844192625Sedwin time_t hi; 1845192625Sedwin long y; 1846192625Sedwin time_t newt; 1847192625Sedwin time_t t; 1848192625Sedwin struct tm yourtm, mytm; 18492708Swollman 18502708Swollman *okayp = FALSE; 18512708Swollman yourtm = *tmp; 1852130461Sstefanf if (do_norm_secs) { 1853130461Sstefanf if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, 1854130461Sstefanf SECSPERMIN)) 1855130461Sstefanf return WRONG; 1856130461Sstefanf } 18572708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 18582708Swollman return WRONG; 18592708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 18602708Swollman return WRONG; 1861192625Sedwin y = yourtm.tm_year; 1862192625Sedwin if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) 18632708Swollman return WRONG; 18642708Swollman /* 1865192625Sedwin ** Turn y into an actual year number for now. 18662708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 18672708Swollman */ 1868192625Sedwin if (long_increment_overflow(&y, TM_YEAR_BASE)) 18692708Swollman return WRONG; 18702708Swollman while (yourtm.tm_mday <= 0) { 1871192625Sedwin if (long_increment_overflow(&y, -1)) 18722708Swollman return WRONG; 1873192625Sedwin li = y + (1 < yourtm.tm_mon); 1874192625Sedwin yourtm.tm_mday += year_lengths[isleap(li)]; 18752708Swollman } 18762708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 1877192625Sedwin li = y + (1 < yourtm.tm_mon); 1878192625Sedwin yourtm.tm_mday -= year_lengths[isleap(li)]; 1879192625Sedwin if (long_increment_overflow(&y, 1)) 18802708Swollman return WRONG; 18812708Swollman } 18822708Swollman for ( ; ; ) { 1883192625Sedwin i = mon_lengths[isleap(y)][yourtm.tm_mon]; 18842708Swollman if (yourtm.tm_mday <= i) 18852708Swollman break; 18862708Swollman yourtm.tm_mday -= i; 18872708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 18882708Swollman yourtm.tm_mon = 0; 1889192625Sedwin if (long_increment_overflow(&y, 1)) 18902708Swollman return WRONG; 18912708Swollman } 18922708Swollman } 1893192625Sedwin if (long_increment_overflow(&y, -TM_YEAR_BASE)) 18942708Swollman return WRONG; 1895192625Sedwin yourtm.tm_year = y; 1896192625Sedwin if (yourtm.tm_year != y) 1897192625Sedwin return WRONG; 1898134231Speter /* Don't go below 1900 for POLA */ 1899134231Speter if (yourtm.tm_year < 0) 1900134231Speter return WRONG; 190177785Swollman if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) 190277785Swollman saved_seconds = 0; 1903192625Sedwin else if (y + TM_YEAR_BASE < EPOCH_YEAR) { 19042708Swollman /* 19052708Swollman ** We can't set tm_sec to 0, because that might push the 19062708Swollman ** time below the minimum representable time. 19072708Swollman ** Set tm_sec to 59 instead. 19082708Swollman ** This assumes that the minimum representable time is 19092708Swollman ** not in the same minute that a leap second was deleted from, 19102708Swollman ** which is a safer assumption than using 58 would be. 19112708Swollman */ 19122708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 19132708Swollman return WRONG; 19142708Swollman saved_seconds = yourtm.tm_sec; 19152708Swollman yourtm.tm_sec = SECSPERMIN - 1; 19162708Swollman } else { 19172708Swollman saved_seconds = yourtm.tm_sec; 19182708Swollman yourtm.tm_sec = 0; 19192708Swollman } 19202708Swollman /* 1921192625Sedwin ** Do a binary search (this works whatever time_t's type is). 19222708Swollman */ 1923192625Sedwin if (!TYPE_SIGNED(time_t)) { 1924192625Sedwin lo = 0; 1925192625Sedwin hi = lo - 1; 1926192625Sedwin } else if (!TYPE_INTEGRAL(time_t)) { 1927192625Sedwin if (sizeof(time_t) > sizeof(float)) 1928192625Sedwin hi = (time_t) DBL_MAX; 1929192625Sedwin else hi = (time_t) FLT_MAX; 1930192625Sedwin lo = -hi; 1931192625Sedwin } else { 1932192625Sedwin lo = 1; 1933192625Sedwin for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) 1934192625Sedwin lo *= 2; 1935192625Sedwin hi = -(lo + 1); 1936192625Sedwin } 19372708Swollman for ( ; ; ) { 1938192625Sedwin t = lo / 2 + hi / 2; 1939192625Sedwin if (t < lo) 1940192625Sedwin t = lo; 1941192625Sedwin else if (t > hi) 1942192625Sedwin t = hi; 1943192625Sedwin if ((*funcp)(&t, offset, &mytm) == NULL) { 1944192625Sedwin /* 1945192625Sedwin ** Assume that t is too extreme to be represented in 1946192625Sedwin ** a struct tm; arrange things so that it is less 1947192625Sedwin ** extreme on the next pass. 1948192625Sedwin */ 1949192625Sedwin dir = (t > 0) ? 1 : -1; 1950192625Sedwin } else dir = tmcomp(&mytm, &yourtm); 19512708Swollman if (dir != 0) { 1952192625Sedwin if (t == lo) { 1953192625Sedwin ++t; 1954192625Sedwin if (t <= lo) 1955192625Sedwin return WRONG; 1956192625Sedwin ++lo; 1957192625Sedwin } else if (t == hi) { 1958192625Sedwin --t; 1959192625Sedwin if (t >= hi) 1960192625Sedwin return WRONG; 1961192625Sedwin --hi; 1962192625Sedwin } 1963192625Sedwin if (lo > hi) 19642708Swollman return WRONG; 1965192625Sedwin if (dir > 0) 1966192625Sedwin hi = t; 1967192625Sedwin else lo = t; 19682708Swollman continue; 19692708Swollman } 19702708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 19712708Swollman break; 19722708Swollman /* 19732708Swollman ** Right time, wrong type. 19742708Swollman ** Hunt for right time, right type. 19752708Swollman ** It's okay to guess wrong since the guess 19762708Swollman ** gets checked. 19772708Swollman */ 1978192625Sedwin sp = (const struct state *) 1979192625Sedwin ((funcp == localsub) ? lclptr : gmtptr); 19802708Swollman#ifdef ALL_STATE 19812708Swollman if (sp == NULL) 19822708Swollman return WRONG; 19832708Swollman#endif /* defined ALL_STATE */ 198417209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 19852708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 19862708Swollman continue; 198717209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 19882708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 19892708Swollman continue; 19902708Swollman newt = t + sp->ttis[j].tt_gmtoff - 19912708Swollman sp->ttis[i].tt_gmtoff; 1992192625Sedwin if ((*funcp)(&newt, offset, &mytm) == NULL) 1993192625Sedwin continue; 19942708Swollman if (tmcomp(&mytm, &yourtm) != 0) 19952708Swollman continue; 19962708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 19972708Swollman continue; 19982708Swollman /* 19992708Swollman ** We have a match. 20002708Swollman */ 20012708Swollman t = newt; 20022708Swollman goto label; 20032708Swollman } 20042708Swollman } 20052708Swollman return WRONG; 20062708Swollman } 20072708Swollmanlabel: 20082708Swollman newt = t + saved_seconds; 20092708Swollman if ((newt < t) != (saved_seconds < 0)) 20102708Swollman return WRONG; 20112708Swollman t = newt; 2012192625Sedwin if ((*funcp)(&t, offset, tmp)) 2013192625Sedwin *okayp = TRUE; 20142708Swollman return t; 20152708Swollman} 20162708Swollman 20172708Swollmanstatic time_t 2018130461Sstefanftime2(tmp, funcp, offset, okayp) 2019130461Sstefanfstruct tm * const tmp; 2020192625Sedwinstruct tm * (* const funcp)(const time_t*, long, struct tm*); 2021130461Sstefanfconst long offset; 2022130461Sstefanfint * const okayp; 2023130461Sstefanf{ 2024130461Sstefanf time_t t; 2025130461Sstefanf 2026130461Sstefanf /* 2027130461Sstefanf ** First try without normalization of seconds 2028130461Sstefanf ** (in case tm_sec contains a value associated with a leap second). 2029130461Sstefanf ** If that fails, try with normalization of seconds. 2030130461Sstefanf */ 2031130461Sstefanf t = time2sub(tmp, funcp, offset, okayp, FALSE); 2032130461Sstefanf return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); 2033130461Sstefanf} 2034130461Sstefanf 2035130461Sstefanfstatic time_t 20362708Swollmantime1(tmp, funcp, offset) 20372708Swollmanstruct tm * const tmp; 2038192625Sedwinstruct tm * (* const funcp)(const time_t *, long, struct tm *); 20392708Swollmanconst long offset; 20402708Swollman{ 204192889Sobrien time_t t; 204292889Sobrien const struct state * sp; 204392889Sobrien int samei, otheri; 2044130461Sstefanf int sameind, otherind; 2045130461Sstefanf int i; 2046130461Sstefanf int nseen; 2047130461Sstefanf int seen[TZ_MAX_TYPES]; 2048130461Sstefanf int types[TZ_MAX_TYPES]; 20492708Swollman int okay; 20502708Swollman 20512708Swollman if (tmp->tm_isdst > 1) 20522708Swollman tmp->tm_isdst = 1; 20532708Swollman t = time2(tmp, funcp, offset, &okay); 20542708Swollman#ifdef PCTS 20552708Swollman /* 2056192625Sedwin ** PCTS code courtesy Grant Sullivan. 20572708Swollman */ 20582708Swollman if (okay) 20592708Swollman return t; 20602708Swollman if (tmp->tm_isdst < 0) 20612708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 20622708Swollman#endif /* defined PCTS */ 20632708Swollman#ifndef PCTS 20642708Swollman if (okay || tmp->tm_isdst < 0) 20652708Swollman return t; 20662708Swollman#endif /* !defined PCTS */ 20672708Swollman /* 20682708Swollman ** We're supposed to assume that somebody took a time of one type 20692708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 20702708Swollman ** We try to divine the type they started from and adjust to the 20712708Swollman ** type they need. 20722708Swollman */ 2073192625Sedwin sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 20742708Swollman#ifdef ALL_STATE 20752708Swollman if (sp == NULL) 20762708Swollman return WRONG; 20772708Swollman#endif /* defined ALL_STATE */ 2078130461Sstefanf for (i = 0; i < sp->typecnt; ++i) 2079130461Sstefanf seen[i] = FALSE; 2080130461Sstefanf nseen = 0; 2081130461Sstefanf for (i = sp->timecnt - 1; i >= 0; --i) 2082130461Sstefanf if (!seen[sp->types[i]]) { 2083130461Sstefanf seen[sp->types[i]] = TRUE; 2084130461Sstefanf types[nseen++] = sp->types[i]; 2085130461Sstefanf } 2086130461Sstefanf for (sameind = 0; sameind < nseen; ++sameind) { 2087130461Sstefanf samei = types[sameind]; 20882708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 20892708Swollman continue; 2090130461Sstefanf for (otherind = 0; otherind < nseen; ++otherind) { 2091130461Sstefanf otheri = types[otherind]; 20922708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 20932708Swollman continue; 20942708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 20952708Swollman sp->ttis[samei].tt_gmtoff; 20962708Swollman tmp->tm_isdst = !tmp->tm_isdst; 20972708Swollman t = time2(tmp, funcp, offset, &okay); 20982708Swollman if (okay) 20992708Swollman return t; 21002708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 21012708Swollman sp->ttis[samei].tt_gmtoff; 21022708Swollman tmp->tm_isdst = !tmp->tm_isdst; 21032708Swollman } 21042708Swollman } 21052708Swollman return WRONG; 21062708Swollman} 21072708Swollman 21082708Swollmantime_t 21092708Swollmanmktime(tmp) 21102708Swollmanstruct tm * const tmp; 21112708Swollman{ 211213545Sjulian time_t mktime_return_value; 2113177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 2114177824Sdavidxu tzset_basic(1); 211513545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 2116177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 211713545Sjulian return(mktime_return_value); 21182708Swollman} 21192708Swollman 21202708Swollman#ifdef STD_INSPIRED 21212708Swollman 21222708Swollmantime_t 21232708Swollmantimelocal(tmp) 21242708Swollmanstruct tm * const tmp; 21252708Swollman{ 21262708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 21272708Swollman return mktime(tmp); 21282708Swollman} 21292708Swollman 21302708Swollmantime_t 21312708Swollmantimegm(tmp) 21322708Swollmanstruct tm * const tmp; 21332708Swollman{ 21342708Swollman tmp->tm_isdst = 0; 21352708Swollman return time1(tmp, gmtsub, 0L); 21362708Swollman} 21372708Swollman 21382708Swollmantime_t 21392708Swollmantimeoff(tmp, offset) 21402708Swollmanstruct tm * const tmp; 21412708Swollmanconst long offset; 21422708Swollman{ 21432708Swollman tmp->tm_isdst = 0; 21442708Swollman return time1(tmp, gmtsub, offset); 21452708Swollman} 21462708Swollman 21472708Swollman#endif /* defined STD_INSPIRED */ 21482708Swollman 21492708Swollman#ifdef CMUCS 21502708Swollman 21512708Swollman/* 21522708Swollman** The following is supplied for compatibility with 21532708Swollman** previous versions of the CMUCS runtime library. 21542708Swollman*/ 21552708Swollman 21562708Swollmanlong 21572708Swollmangtime(tmp) 21582708Swollmanstruct tm * const tmp; 21592708Swollman{ 21602708Swollman const time_t t = mktime(tmp); 21612708Swollman 21622708Swollman if (t == WRONG) 21632708Swollman return -1; 21642708Swollman return t; 21652708Swollman} 21662708Swollman 21672708Swollman#endif /* defined CMUCS */ 21682708Swollman 21692708Swollman/* 21702708Swollman** XXX--is the below the right way to conditionalize?? 21712708Swollman*/ 21722708Swollman 21732708Swollman#ifdef STD_INSPIRED 21742708Swollman 21752708Swollman/* 21762708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 2177130461Sstefanf** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which 21782708Swollman** is not the case if we are accounting for leap seconds. 21792708Swollman** So, we provide the following conversion routines for use 21802708Swollman** when exchanging timestamps with POSIX conforming systems. 21812708Swollman*/ 21822708Swollman 21832708Swollmanstatic long 21842708Swollmanleapcorr(timep) 21852708Swollmantime_t * timep; 21862708Swollman{ 218792889Sobrien struct state * sp; 218892889Sobrien struct lsinfo * lp; 218992889Sobrien int i; 21902708Swollman 21912708Swollman sp = lclptr; 21922708Swollman i = sp->leapcnt; 21932708Swollman while (--i >= 0) { 21942708Swollman lp = &sp->lsis[i]; 21952708Swollman if (*timep >= lp->ls_trans) 21962708Swollman return lp->ls_corr; 21972708Swollman } 21982708Swollman return 0; 21992708Swollman} 22002708Swollman 22012708Swollmantime_t 22022708Swollmantime2posix(t) 22032708Swollmantime_t t; 22042708Swollman{ 22059936Swollman tzset(); 22062708Swollman return t - leapcorr(&t); 22072708Swollman} 22082708Swollman 22092708Swollmantime_t 22102708Swollmanposix2time(t) 22112708Swollmantime_t t; 22122708Swollman{ 22132708Swollman time_t x; 22142708Swollman time_t y; 22152708Swollman 22169936Swollman tzset(); 22172708Swollman /* 22182708Swollman ** For a positive leap second hit, the result 2219192625Sedwin ** is not unique. For a negative leap second 22202708Swollman ** hit, the corresponding time doesn't exist, 22212708Swollman ** so we return an adjacent second. 22222708Swollman */ 22232708Swollman x = t + leapcorr(&t); 22242708Swollman y = x - leapcorr(&x); 22252708Swollman if (y < t) { 22262708Swollman do { 22272708Swollman x++; 22282708Swollman y = x - leapcorr(&x); 22292708Swollman } while (y < t); 22302708Swollman if (t != y) 22312708Swollman return x - 1; 22322708Swollman } else if (y > t) { 22332708Swollman do { 22342708Swollman --x; 22352708Swollman y = x - leapcorr(&x); 22362708Swollman } while (y > t); 22372708Swollman if (t != y) 22382708Swollman return x + 1; 22392708Swollman } 22402708Swollman return x; 22412708Swollman} 22422708Swollman 22432708Swollman#endif /* defined STD_INSPIRED */ 2244