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 9214411Sedwinstatic char elsieid[] __unused = "@(#)localtime.c 8.14"; 102708Swollman#endif /* !defined NOID */ 112708Swollman#endif /* !defined lint */ 1292986Sobrien__FBSDID("$FreeBSD$"); 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> 24197189Sedwin#include <errno.h> 2571579Sdeischen#include <fcntl.h> 2671579Sdeischen#include <pthread.h> 2771579Sdeischen#include "private.h" 2871579Sdeischen#include "un-namespace.h" 2918834Swollman 302708Swollman#include "tzfile.h" 31192625Sedwin#include "float.h" /* for FLT_MAX and DBL_MAX */ 322708Swollman 33192625Sedwin#ifndef TZ_ABBR_MAX_LEN 34192625Sedwin#define TZ_ABBR_MAX_LEN 16 35192625Sedwin#endif /* !defined TZ_ABBR_MAX_LEN */ 36192625Sedwin 37192625Sedwin#ifndef TZ_ABBR_CHAR_SET 38192625Sedwin#define TZ_ABBR_CHAR_SET \ 39192625Sedwin "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" 40192625Sedwin#endif /* !defined TZ_ABBR_CHAR_SET */ 41192625Sedwin 42192625Sedwin#ifndef TZ_ABBR_ERR_CHAR 43192625Sedwin#define TZ_ABBR_ERR_CHAR '_' 44192625Sedwin#endif /* !defined TZ_ABBR_ERR_CHAR */ 45192625Sedwin 4671579Sdeischen#include "libc_private.h" 4771579Sdeischen 4871579Sdeischen#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 4971579Sdeischen#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 5071579Sdeischen 51177824Sdavidxu#define _RWLOCK_RDLOCK(x) \ 52177824Sdavidxu do { \ 53177824Sdavidxu if (__isthreaded) _pthread_rwlock_rdlock(x); \ 54177824Sdavidxu } while (0) 55177824Sdavidxu 56177824Sdavidxu#define _RWLOCK_WRLOCK(x) \ 57177824Sdavidxu do { \ 58177824Sdavidxu if (__isthreaded) _pthread_rwlock_wrlock(x); \ 59177824Sdavidxu } while (0) 60177824Sdavidxu 61177824Sdavidxu#define _RWLOCK_UNLOCK(x) \ 62177824Sdavidxu do { \ 63177824Sdavidxu if (__isthreaded) _pthread_rwlock_unlock(x); \ 64177824Sdavidxu } while (0) 65177824Sdavidxu 669936Swollman/* 679936Swollman** SunOS 4.1.1 headers lack O_BINARY. 689936Swollman*/ 692708Swollman 702708Swollman#ifdef O_BINARY 712708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 722708Swollman#endif /* defined O_BINARY */ 732708Swollman#ifndef O_BINARY 742708Swollman#define OPEN_MODE O_RDONLY 752708Swollman#endif /* !defined O_BINARY */ 762708Swollman 772708Swollman#ifndef WILDABBR 782708Swollman/* 792708Swollman** Someone might make incorrect use of a time zone abbreviation: 802708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 819936Swollman** or implicitly). 822708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 839936Swollman** or implicitly). 842708Swollman** 3. They might reference tzname[1] after setting to a time zone 852708Swollman** in which Daylight Saving Time is never observed. 862708Swollman** 4. They might reference tzname[0] after setting to a time zone 872708Swollman** in which Standard Time is never observed. 882708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 892708Swollman** What's best to do in the above cases is open to debate; 902708Swollman** for now, we just set things up so that in any of the five cases 91192625Sedwin** WILDABBR is used. Another possibility: initialize tzname[0] to the 922708Swollman** string "tzname[0] used before set", and similarly for the other cases. 93192625Sedwin** And another: initialize tzname[0] to "ERA", with an explanation in the 942708Swollman** manual page of what this "time zone abbreviation" means (doing this so 952708Swollman** that tzname[0] has the "normal" length of three characters). 962708Swollman*/ 972708Swollman#define WILDABBR " " 982708Swollman#endif /* !defined WILDABBR */ 992708Swollman 100192625Sedwinstatic char wildabbr[] = WILDABBR; 1012708Swollman 102130332Skensmith/* 103130332Skensmith * In June 2004 it was decided UTC was a more appropriate default time 104130332Skensmith * zone than GMT. 105130332Skensmith */ 1069936Swollman 107130332Skensmithstatic const char gmt[] = "UTC"; 108130332Skensmith 109130461Sstefanf/* 110130461Sstefanf** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. 111130461Sstefanf** We default to US rules as of 1999-08-17. 112130461Sstefanf** POSIX 1003.1 section 8.1.1 says that the default DST rules are 113130461Sstefanf** implementation dependent; for historical reasons, US rules are a 114130461Sstefanf** common default. 115130461Sstefanf*/ 116130461Sstefanf#ifndef TZDEFRULESTRING 117130461Sstefanf#define TZDEFRULESTRING ",M4.1.0,M10.5.0" 118130461Sstefanf#endif /* !defined TZDEFDST */ 119130461Sstefanf 1202708Swollmanstruct ttinfo { /* time type information */ 121130461Sstefanf long tt_gmtoff; /* UTC offset in seconds */ 1222708Swollman int tt_isdst; /* used to set tm_isdst */ 1232708Swollman int tt_abbrind; /* abbreviation list index */ 1242708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 125130461Sstefanf int tt_ttisgmt; /* TRUE if transition is UTC */ 1262708Swollman}; 1272708Swollman 1282708Swollmanstruct lsinfo { /* leap second information */ 1292708Swollman time_t ls_trans; /* transition time */ 1302708Swollman long ls_corr; /* correction to apply */ 1312708Swollman}; 1322708Swollman 1332708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 1342708Swollman 1352708Swollman#ifdef TZNAME_MAX 1362708Swollman#define MY_TZNAME_MAX TZNAME_MAX 1372708Swollman#endif /* defined TZNAME_MAX */ 1382708Swollman#ifndef TZNAME_MAX 1392708Swollman#define MY_TZNAME_MAX 255 1402708Swollman#endif /* !defined TZNAME_MAX */ 1412708Swollman 1422708Swollmanstruct state { 1432708Swollman int leapcnt; 1442708Swollman int timecnt; 1452708Swollman int typecnt; 1462708Swollman int charcnt; 147192625Sedwin int goback; 148192625Sedwin int goahead; 1492708Swollman time_t ats[TZ_MAX_TIMES]; 1502708Swollman unsigned char types[TZ_MAX_TIMES]; 1512708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 1529936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 1532708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 1542708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 1552708Swollman}; 1562708Swollman 1572708Swollmanstruct rule { 1582708Swollman int r_type; /* type of rule--see below */ 1592708Swollman int r_day; /* day number of rule */ 1602708Swollman int r_week; /* week number of rule */ 1612708Swollman int r_mon; /* month number of rule */ 1622708Swollman long r_time; /* transition time of rule */ 1632708Swollman}; 1642708Swollman 1652708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1662708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1672708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1682708Swollman 1692708Swollman/* 1702708Swollman** Prototypes for static functions. 1712708Swollman*/ 1722708Swollman 17397423Salfredstatic long detzcode(const char * codep); 174192625Sedwinstatic time_t detzcode64(const char * codep); 175192625Sedwinstatic int differ_by_repeat(time_t t1, time_t t0); 17697423Salfredstatic const char * getzname(const char * strp); 177192625Sedwinstatic const char * getqzname(const char * strp, const int delim); 17897423Salfredstatic const char * getnum(const char * strp, int * nump, int min, 17997423Salfred int max); 18097423Salfredstatic const char * getsecs(const char * strp, long * secsp); 18197423Salfredstatic const char * getoffset(const char * strp, long * offsetp); 18297423Salfredstatic const char * getrule(const char * strp, struct rule * rulep); 18397423Salfredstatic void gmtload(struct state * sp); 184192625Sedwinstatic struct tm * gmtsub(const time_t * timep, long offset, 18597423Salfred struct tm * tmp); 186192625Sedwinstatic struct tm * localsub(const time_t * timep, long offset, 18797423Salfred struct tm * tmp); 18897423Salfredstatic int increment_overflow(int * number, int delta); 189192625Sedwinstatic int leaps_thru_end_of(int y); 190192625Sedwinstatic int long_increment_overflow(long * number, int delta); 191192625Sedwinstatic int long_normalize_overflow(long * tensptr, 192192625Sedwin int * unitsptr, int base); 19397423Salfredstatic int normalize_overflow(int * tensptr, int * unitsptr, 19497423Salfred int base); 19597423Salfredstatic void settzname(void); 19697423Salfredstatic time_t time1(struct tm * tmp, 197192625Sedwin struct tm * (*funcp)(const time_t *, 19897423Salfred long, struct tm *), 19997423Salfred long offset); 20097423Salfredstatic time_t time2(struct tm *tmp, 201192625Sedwin struct tm * (*funcp)(const time_t *, 20297423Salfred long, struct tm*), 20397423Salfred long offset, int * okayp); 204130461Sstefanfstatic time_t time2sub(struct tm *tmp, 205192625Sedwin struct tm * (*funcp)(const time_t *, 206130461Sstefanf long, struct tm*), 207130461Sstefanf long offset, int * okayp, int do_norm_secs); 208192625Sedwinstatic struct tm * timesub(const time_t * timep, long offset, 20997423Salfred const struct state * sp, struct tm * tmp); 21097423Salfredstatic int tmcomp(const struct tm * atmp, 21197423Salfred const struct tm * btmp); 21297423Salfredstatic time_t transtime(time_t janfirst, int year, 21397423Salfred const struct rule * rulep, long offset); 214192625Sedwinstatic int typesequiv(const struct state * sp, int a, int b); 215192625Sedwinstatic int tzload(const char * name, struct state * sp, 216192625Sedwin int doextend); 21797423Salfredstatic int tzparse(const char * name, struct state * sp, 21897423Salfred int lastditch); 2192708Swollman 2202708Swollman#ifdef ALL_STATE 2212708Swollmanstatic struct state * lclptr; 2222708Swollmanstatic struct state * gmtptr; 2232708Swollman#endif /* defined ALL_STATE */ 2242708Swollman 2252708Swollman#ifndef ALL_STATE 2262708Swollmanstatic struct state lclmem; 2272708Swollmanstatic struct state gmtmem; 2282708Swollman#define lclptr (&lclmem) 2292708Swollman#define gmtptr (&gmtmem) 2302708Swollman#endif /* State Farm */ 2312708Swollman 2329936Swollman#ifndef TZ_STRLEN_MAX 2339936Swollman#define TZ_STRLEN_MAX 255 2349936Swollman#endif /* !defined TZ_STRLEN_MAX */ 2359936Swollman 2369936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 2372708Swollmanstatic int lcl_is_set; 238199607Sjhbstatic pthread_once_t gmt_once = PTHREAD_ONCE_INIT; 239177824Sdavidxustatic pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; 240201270Sjhbstatic pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; 241201270Sjhbstatic pthread_key_t gmtime_key; 242201270Sjhbstatic int gmtime_key_error; 243200797Sjhbstatic pthread_once_t localtime_once = PTHREAD_ONCE_INIT; 244200797Sjhbstatic pthread_key_t localtime_key; 245200797Sjhbstatic int localtime_key_error; 2462708Swollman 2472708Swollmanchar * tzname[2] = { 2489936Swollman wildabbr, 2499936Swollman wildabbr 2502708Swollman}; 2512708Swollman 2529936Swollman/* 2539936Swollman** Section 4.12.3 of X3.159-1989 requires that 2549936Swollman** Except for the strftime function, these functions [asctime, 2559936Swollman** ctime, gmtime, localtime] return values in one of two static 2569936Swollman** objects: a broken-down time structure and an array of char. 257192625Sedwin** Thanks to Paul Eggert for noting this. 2589936Swollman*/ 2599936Swollman 2609936Swollmanstatic struct tm tm; 2619936Swollman 2622708Swollman#ifdef USG_COMPAT 2632708Swollmantime_t timezone = 0; 2642708Swollmanint daylight = 0; 2652708Swollman#endif /* defined USG_COMPAT */ 2662708Swollman 2672708Swollman#ifdef ALTZONE 2682708Swollmantime_t altzone = 0; 2692708Swollman#endif /* defined ALTZONE */ 2702708Swollman 2712708Swollmanstatic long 2722708Swollmandetzcode(codep) 2732708Swollmanconst char * const codep; 2742708Swollman{ 27592889Sobrien long result; 27692889Sobrien int i; 2772708Swollman 278192625Sedwin result = (codep[0] & 0x80) ? ~0L : 0; 2792708Swollman for (i = 0; i < 4; ++i) 2802708Swollman result = (result << 8) | (codep[i] & 0xff); 2812708Swollman return result; 2822708Swollman} 2832708Swollman 284192625Sedwinstatic time_t 285192625Sedwindetzcode64(codep) 286192625Sedwinconst char * const codep; 287192625Sedwin{ 288192625Sedwin register time_t result; 289192625Sedwin register int i; 290192625Sedwin 291192625Sedwin result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; 292192625Sedwin for (i = 0; i < 8; ++i) 293192625Sedwin result = result * 256 + (codep[i] & 0xff); 294192625Sedwin return result; 295192625Sedwin} 296192625Sedwin 2972708Swollmanstatic void 29897423Salfredsettzname(void) 2992708Swollman{ 30092889Sobrien struct state * sp = lclptr; 30192889Sobrien int i; 3022708Swollman 3039936Swollman tzname[0] = wildabbr; 3049936Swollman tzname[1] = wildabbr; 3052708Swollman#ifdef USG_COMPAT 3062708Swollman daylight = 0; 3072708Swollman timezone = 0; 3082708Swollman#endif /* defined USG_COMPAT */ 3092708Swollman#ifdef ALTZONE 3102708Swollman altzone = 0; 3112708Swollman#endif /* defined ALTZONE */ 3122708Swollman#ifdef ALL_STATE 3132708Swollman if (sp == NULL) { 3149936Swollman tzname[0] = tzname[1] = gmt; 3152708Swollman return; 3162708Swollman } 3172708Swollman#endif /* defined ALL_STATE */ 318214411Sedwin /* 319214411Sedwin ** And to get the latest zone names into tzname. . . 320214411Sedwin */ 3212708Swollman for (i = 0; i < sp->typecnt; ++i) { 322214411Sedwin const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]]; 3232708Swollman 3242708Swollman tzname[ttisp->tt_isdst] = 3259936Swollman &sp->chars[ttisp->tt_abbrind]; 3262708Swollman#ifdef USG_COMPAT 3272708Swollman if (ttisp->tt_isdst) 3282708Swollman daylight = 1; 329214411Sedwin if (!ttisp->tt_isdst) 3302708Swollman timezone = -(ttisp->tt_gmtoff); 3312708Swollman#endif /* defined USG_COMPAT */ 3322708Swollman#ifdef ALTZONE 333214411Sedwin if (ttisp->tt_isdst) 3342708Swollman altzone = -(ttisp->tt_gmtoff); 3352708Swollman#endif /* defined ALTZONE */ 3362708Swollman } 3372708Swollman /* 338192625Sedwin ** Finally, scrub the abbreviations. 339192625Sedwin ** First, replace bogus characters. 340192625Sedwin */ 341192625Sedwin for (i = 0; i < sp->charcnt; ++i) 342192625Sedwin if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) 343192625Sedwin sp->chars[i] = TZ_ABBR_ERR_CHAR; 344192625Sedwin /* 345192625Sedwin ** Second, truncate long abbreviations. 346192625Sedwin */ 347192625Sedwin for (i = 0; i < sp->typecnt; ++i) { 348192625Sedwin register const struct ttinfo * const ttisp = &sp->ttis[i]; 349192625Sedwin register char * cp = &sp->chars[ttisp->tt_abbrind]; 350192625Sedwin 351192625Sedwin if (strlen(cp) > TZ_ABBR_MAX_LEN && 352192625Sedwin strcmp(cp, GRANDPARENTED) != 0) 353192625Sedwin *(cp + TZ_ABBR_MAX_LEN) = '\0'; 354192625Sedwin } 3552708Swollman} 3562708Swollman 3572708Swollmanstatic int 358192625Sedwindiffer_by_repeat(t1, t0) 359192625Sedwinconst time_t t1; 360192625Sedwinconst time_t t0; 361192625Sedwin{ 362192625Sedwin int_fast64_t _t0 = t0; 363192625Sedwin int_fast64_t _t1 = t1; 364192625Sedwin 365192625Sedwin if (TYPE_INTEGRAL(time_t) && 366192625Sedwin TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) 367192625Sedwin return 0; 368192625Sedwin //turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT); 369192625Sedwin return _t1 - _t0 == SECSPERREPEAT; 370192625Sedwin} 371192625Sedwin 372192625Sedwinstatic int 373192625Sedwintzload(name, sp, doextend) 37492889Sobrienconst char * name; 37592889Sobrienstruct state * const sp; 376192625Sedwinregister const int doextend; 3772708Swollman{ 37892889Sobrien const char * p; 37992889Sobrien int i; 38092889Sobrien int fid; 381192625Sedwin int stored; 382192625Sedwin int nread; 383225677Skib int res; 384192625Sedwin union { 385192625Sedwin struct tzhead tzhead; 386192625Sedwin char buf[2 * sizeof(struct tzhead) + 387192625Sedwin 2 * sizeof *sp + 388192625Sedwin 4 * TZ_MAX_TIMES]; 389225677Skib } *u; 3902708Swollman 391225677Skib u = NULL; 392225677Skib res = -1; 393214411Sedwin sp->goback = sp->goahead = FALSE; 394214411Sedwin 39539327Simp /* XXX The following is from OpenBSD, and I'm not sure it is correct */ 39639327Simp if (name != NULL && issetugid() != 0) 39739327Simp if ((name[0] == ':' && name[1] == '/') || 39839327Simp name[0] == '/' || strchr(name, '.')) 39939327Simp name = NULL; 4002708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 4012708Swollman return -1; 4022708Swollman { 40392889Sobrien int doaccess; 40418834Swollman struct stat stab; 4059936Swollman /* 4069936Swollman ** Section 4.9.1 of the C standard says that 4079936Swollman ** "FILENAME_MAX expands to an integral constant expression 40818834Swollman ** that is the size needed for an array of char large enough 4099936Swollman ** to hold the longest file name string that the implementation 4109936Swollman ** guarantees can be opened." 4119936Swollman */ 412225677Skib char *fullname; 4132708Swollman 414225677Skib fullname = malloc(FILENAME_MAX + 1); 415225677Skib if (fullname == NULL) 416225677Skib goto out; 417225677Skib 4182708Swollman if (name[0] == ':') 4192708Swollman ++name; 4202708Swollman doaccess = name[0] == '/'; 4212708Swollman if (!doaccess) { 422225677Skib if ((p = TZDIR) == NULL) { 423225677Skib free(fullname); 4242708Swollman return -1; 425225677Skib } 426225677Skib if (strlen(p) + 1 + strlen(name) >= FILENAME_MAX) { 427225677Skib free(fullname); 4282708Swollman return -1; 429225677Skib } 4302708Swollman (void) strcpy(fullname, p); 4312708Swollman (void) strcat(fullname, "/"); 4322708Swollman (void) strcat(fullname, name); 4332708Swollman /* 4342708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 4352708Swollman */ 4362708Swollman if (strchr(name, '.') != NULL) 4372708Swollman doaccess = TRUE; 4382708Swollman name = fullname; 4392708Swollman } 440225677Skib if (doaccess && access(name, R_OK) != 0) { 441225677Skib free(fullname); 44239327Simp return -1; 443225677Skib } 444225677Skib if ((fid = _open(name, OPEN_MODE)) == -1) { 445225677Skib free(fullname); 4462708Swollman return -1; 447225677Skib } 44895989Swollman if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) { 449225677Skib free(fullname); 45095989Swollman _close(fid); 45118834Swollman return -1; 45295989Swollman } 453226929Strociny free(fullname); 4542708Swollman } 455225677Skib u = malloc(sizeof(*u)); 456225677Skib if (u == NULL) 457225677Skib goto out; 458225677Skib nread = _read(fid, u->buf, sizeof u->buf); 459192625Sedwin if (_close(fid) < 0 || nread <= 0) 460225677Skib goto out; 461192625Sedwin for (stored = 4; stored <= 8; stored *= 2) { 4629936Swollman int ttisstdcnt; 4639936Swollman int ttisgmtcnt; 4642708Swollman 465225677Skib ttisstdcnt = (int) detzcode(u->tzhead.tzh_ttisstdcnt); 466225677Skib ttisgmtcnt = (int) detzcode(u->tzhead.tzh_ttisgmtcnt); 467225677Skib sp->leapcnt = (int) detzcode(u->tzhead.tzh_leapcnt); 468225677Skib sp->timecnt = (int) detzcode(u->tzhead.tzh_timecnt); 469225677Skib sp->typecnt = (int) detzcode(u->tzhead.tzh_typecnt); 470225677Skib sp->charcnt = (int) detzcode(u->tzhead.tzh_charcnt); 471225677Skib p = u->tzhead.tzh_charcnt + sizeof u->tzhead.tzh_charcnt; 4722708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 4732708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 4742708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 4752708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 4769936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 4779936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 478225677Skib goto out; 479225677Skib if (nread - (p - u->buf) < 480192625Sedwin sp->timecnt * stored + /* ats */ 4819936Swollman sp->timecnt + /* types */ 482192625Sedwin sp->typecnt * 6 + /* ttinfos */ 4839936Swollman sp->charcnt + /* chars */ 484192625Sedwin sp->leapcnt * (stored + 4) + /* lsinfos */ 4859936Swollman ttisstdcnt + /* ttisstds */ 4869936Swollman ttisgmtcnt) /* ttisgmts */ 487225677Skib goto out; 4882708Swollman for (i = 0; i < sp->timecnt; ++i) { 489192625Sedwin sp->ats[i] = (stored == 4) ? 490192625Sedwin detzcode(p) : detzcode64(p); 491192625Sedwin p += stored; 4922708Swollman } 4932708Swollman for (i = 0; i < sp->timecnt; ++i) { 4942708Swollman sp->types[i] = (unsigned char) *p++; 4952708Swollman if (sp->types[i] >= sp->typecnt) 496225677Skib goto out; 4972708Swollman } 4982708Swollman for (i = 0; i < sp->typecnt; ++i) { 49992889Sobrien struct ttinfo * ttisp; 5002708Swollman 5012708Swollman ttisp = &sp->ttis[i]; 5022708Swollman ttisp->tt_gmtoff = detzcode(p); 5032708Swollman p += 4; 5042708Swollman ttisp->tt_isdst = (unsigned char) *p++; 5052708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 506225677Skib goto out; 5072708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 5082708Swollman if (ttisp->tt_abbrind < 0 || 5092708Swollman ttisp->tt_abbrind > sp->charcnt) 510225677Skib goto out; 5112708Swollman } 5122708Swollman for (i = 0; i < sp->charcnt; ++i) 5132708Swollman sp->chars[i] = *p++; 5142708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 5152708Swollman for (i = 0; i < sp->leapcnt; ++i) { 51692889Sobrien struct lsinfo * lsisp; 5172708Swollman 5182708Swollman lsisp = &sp->lsis[i]; 519192625Sedwin lsisp->ls_trans = (stored == 4) ? 520192625Sedwin detzcode(p) : detzcode64(p); 521192625Sedwin p += stored; 5222708Swollman lsisp->ls_corr = detzcode(p); 5232708Swollman p += 4; 5242708Swollman } 5252708Swollman for (i = 0; i < sp->typecnt; ++i) { 52692889Sobrien struct ttinfo * ttisp; 5272708Swollman 5282708Swollman ttisp = &sp->ttis[i]; 5292708Swollman if (ttisstdcnt == 0) 5302708Swollman ttisp->tt_ttisstd = FALSE; 5312708Swollman else { 5322708Swollman ttisp->tt_ttisstd = *p++; 5332708Swollman if (ttisp->tt_ttisstd != TRUE && 5342708Swollman ttisp->tt_ttisstd != FALSE) 535225677Skib goto out; 5362708Swollman } 5372708Swollman } 5389936Swollman for (i = 0; i < sp->typecnt; ++i) { 53992889Sobrien struct ttinfo * ttisp; 5409936Swollman 5419936Swollman ttisp = &sp->ttis[i]; 5429936Swollman if (ttisgmtcnt == 0) 5439936Swollman ttisp->tt_ttisgmt = FALSE; 5449936Swollman else { 5459936Swollman ttisp->tt_ttisgmt = *p++; 5469936Swollman if (ttisp->tt_ttisgmt != TRUE && 5479936Swollman ttisp->tt_ttisgmt != FALSE) 548225677Skib goto out; 5499936Swollman } 5509936Swollman } 551192625Sedwin /* 552192625Sedwin ** Out-of-sort ats should mean we're running on a 553192625Sedwin ** signed time_t system but using a data file with 554192625Sedwin ** unsigned values (or vice versa). 555192625Sedwin */ 556192625Sedwin for (i = 0; i < sp->timecnt - 2; ++i) 557192625Sedwin if (sp->ats[i] > sp->ats[i + 1]) { 558192625Sedwin ++i; 559192625Sedwin if (TYPE_SIGNED(time_t)) { 560192625Sedwin /* 561192625Sedwin ** Ignore the end (easy). 562192625Sedwin */ 563192625Sedwin sp->timecnt = i; 564192625Sedwin } else { 565192625Sedwin /* 566192625Sedwin ** Ignore the beginning (harder). 567192625Sedwin */ 568192625Sedwin register int j; 569192625Sedwin 570192625Sedwin for (j = 0; j + i < sp->timecnt; ++j) { 571192625Sedwin sp->ats[j] = sp->ats[j + i]; 572192625Sedwin sp->types[j] = sp->types[j + i]; 573192625Sedwin } 574192625Sedwin sp->timecnt = j; 575192625Sedwin } 576192625Sedwin break; 577192625Sedwin } 578192625Sedwin /* 579192625Sedwin ** If this is an old file, we're done. 580192625Sedwin */ 581225677Skib if (u->tzhead.tzh_version[0] == '\0') 582192625Sedwin break; 583225677Skib nread -= p - u->buf; 584192625Sedwin for (i = 0; i < nread; ++i) 585225677Skib u->buf[i] = p[i]; 586192625Sedwin /* 587192625Sedwin ** If this is a narrow integer time_t system, we're done. 588192625Sedwin */ 589192625Sedwin if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t)) 590192625Sedwin break; 5912708Swollman } 592192625Sedwin if (doextend && nread > 2 && 593225677Skib u->buf[0] == '\n' && u->buf[nread - 1] == '\n' && 594192625Sedwin sp->typecnt + 2 <= TZ_MAX_TYPES) { 595225677Skib struct state *ts; 596192625Sedwin register int result; 597192625Sedwin 598225677Skib ts = malloc(sizeof(*ts)); 599225677Skib if (ts == NULL) 600225677Skib goto out; 601225677Skib u->buf[nread - 1] = '\0'; 602225677Skib result = tzparse(&u->buf[1], ts, FALSE); 603225677Skib if (result == 0 && ts->typecnt == 2 && 604225677Skib sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) { 605192625Sedwin for (i = 0; i < 2; ++i) 606225677Skib ts->ttis[i].tt_abbrind += 607192625Sedwin sp->charcnt; 608225677Skib for (i = 0; i < ts->charcnt; ++i) 609192625Sedwin sp->chars[sp->charcnt++] = 610225677Skib ts->chars[i]; 611192625Sedwin i = 0; 612225677Skib while (i < ts->timecnt && 613225677Skib ts->ats[i] <= 614192625Sedwin sp->ats[sp->timecnt - 1]) 615192625Sedwin ++i; 616225677Skib while (i < ts->timecnt && 617192625Sedwin sp->timecnt < TZ_MAX_TIMES) { 618192625Sedwin sp->ats[sp->timecnt] = 619225677Skib ts->ats[i]; 620192625Sedwin sp->types[sp->timecnt] = 621192625Sedwin sp->typecnt + 622225677Skib ts->types[i]; 623192625Sedwin ++sp->timecnt; 624192625Sedwin ++i; 625192625Sedwin } 626225677Skib sp->ttis[sp->typecnt++] = ts->ttis[0]; 627225677Skib sp->ttis[sp->typecnt++] = ts->ttis[1]; 628192625Sedwin } 629225677Skib free(ts); 630192625Sedwin } 631192625Sedwin if (sp->timecnt > 1) { 632192625Sedwin for (i = 1; i < sp->timecnt; ++i) 633192625Sedwin if (typesequiv(sp, sp->types[i], sp->types[0]) && 634192625Sedwin differ_by_repeat(sp->ats[i], sp->ats[0])) { 635192625Sedwin sp->goback = TRUE; 636192625Sedwin break; 637192625Sedwin } 638192625Sedwin for (i = sp->timecnt - 2; i >= 0; --i) 639192625Sedwin if (typesequiv(sp, sp->types[sp->timecnt - 1], 640192625Sedwin sp->types[i]) && 641192625Sedwin differ_by_repeat(sp->ats[sp->timecnt - 1], 642192625Sedwin sp->ats[i])) { 643192625Sedwin sp->goahead = TRUE; 644192625Sedwin break; 645192625Sedwin } 646192625Sedwin } 647225677Skib res = 0; 648225677Skibout: 649225677Skib free(u); 650225677Skib return (res); 6512708Swollman} 6522708Swollman 653192625Sedwinstatic int 654192625Sedwintypesequiv(sp, a, b) 655192625Sedwinconst struct state * const sp; 656192625Sedwinconst int a; 657192625Sedwinconst int b; 658192625Sedwin{ 659192625Sedwin register int result; 660192625Sedwin 661192625Sedwin if (sp == NULL || 662192625Sedwin a < 0 || a >= sp->typecnt || 663192625Sedwin b < 0 || b >= sp->typecnt) 664192625Sedwin result = FALSE; 665192625Sedwin else { 666192625Sedwin register const struct ttinfo * ap = &sp->ttis[a]; 667192625Sedwin register const struct ttinfo * bp = &sp->ttis[b]; 668192625Sedwin result = ap->tt_gmtoff == bp->tt_gmtoff && 669192625Sedwin ap->tt_isdst == bp->tt_isdst && 670192625Sedwin ap->tt_ttisstd == bp->tt_ttisstd && 671192625Sedwin ap->tt_ttisgmt == bp->tt_ttisgmt && 672192625Sedwin strcmp(&sp->chars[ap->tt_abbrind], 673192625Sedwin &sp->chars[bp->tt_abbrind]) == 0; 674192625Sedwin } 675192625Sedwin return result; 676192625Sedwin} 677192625Sedwin 6782708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 6792708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 6802708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 6812708Swollman}; 6822708Swollman 6832708Swollmanstatic const int year_lengths[2] = { 6842708Swollman DAYSPERNYEAR, DAYSPERLYEAR 6852708Swollman}; 6862708Swollman 6872708Swollman/* 6882708Swollman** Given a pointer into a time zone string, scan until a character that is not 689192625Sedwin** a valid character in a zone name is found. Return a pointer to that 6902708Swollman** character. 6912708Swollman*/ 6922708Swollman 6932708Swollmanstatic const char * 6942708Swollmangetzname(strp) 69592889Sobrienconst char * strp; 6962708Swollman{ 69792889Sobrien char c; 6982708Swollman 69917209Swollman while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 7002708Swollman c != '+') 7012708Swollman ++strp; 7022708Swollman return strp; 7032708Swollman} 7042708Swollman 7052708Swollman/* 706192625Sedwin** Given a pointer into an extended time zone string, scan until the ending 707192625Sedwin** delimiter of the zone name is located. Return a pointer to the delimiter. 708192625Sedwin** 709192625Sedwin** As with getzname above, the legal character set is actually quite 710192625Sedwin** restricted, with other characters producing undefined results. 711192625Sedwin** We don't do any checking here; checking is done later in common-case code. 712192625Sedwin*/ 713192625Sedwin 714192625Sedwinstatic const char * 715192625Sedwingetqzname(register const char *strp, const int delim) 716192625Sedwin{ 717192625Sedwin register int c; 718192625Sedwin 719192625Sedwin while ((c = *strp) != '\0' && c != delim) 720192625Sedwin ++strp; 721192625Sedwin return strp; 722192625Sedwin} 723192625Sedwin 724192625Sedwin/* 7252708Swollman** Given a pointer into a time zone string, extract a number from that string. 7262708Swollman** Check that the number is within a specified range; if it is not, return 7272708Swollman** NULL. 7282708Swollman** Otherwise, return a pointer to the first character not part of the number. 7292708Swollman*/ 7302708Swollman 7312708Swollmanstatic const char * 7322708Swollmangetnum(strp, nump, min, max) 73392889Sobrienconst char * strp; 7342708Swollmanint * const nump; 7352708Swollmanconst int min; 7362708Swollmanconst int max; 7372708Swollman{ 73892889Sobrien char c; 73992889Sobrien int num; 7402708Swollman 74117209Swollman if (strp == NULL || !is_digit(c = *strp)) 7422708Swollman return NULL; 7432708Swollman num = 0; 74417209Swollman do { 7452708Swollman num = num * 10 + (c - '0'); 7462708Swollman if (num > max) 7472708Swollman return NULL; /* illegal value */ 74817209Swollman c = *++strp; 74917209Swollman } while (is_digit(c)); 7502708Swollman if (num < min) 7512708Swollman return NULL; /* illegal value */ 7522708Swollman *nump = num; 7532708Swollman return strp; 7542708Swollman} 7552708Swollman 7562708Swollman/* 7572708Swollman** Given a pointer into a time zone string, extract a number of seconds, 7582708Swollman** in hh[:mm[:ss]] form, from the string. 7592708Swollman** If any error occurs, return NULL. 7602708Swollman** Otherwise, return a pointer to the first character not part of the number 7612708Swollman** of seconds. 7622708Swollman*/ 7632708Swollman 7642708Swollmanstatic const char * 7652708Swollmangetsecs(strp, secsp) 76692889Sobrienconst char * strp; 7672708Swollmanlong * const secsp; 7682708Swollman{ 7692708Swollman int num; 7702708Swollman 7719936Swollman /* 7729936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 7739936Swollman ** "M10.4.6/26", which does not conform to Posix, 7749936Swollman ** but which specifies the equivalent of 7759936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 7769936Swollman */ 7779936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 7782708Swollman if (strp == NULL) 7792708Swollman return NULL; 7809936Swollman *secsp = num * (long) SECSPERHOUR; 7812708Swollman if (*strp == ':') { 7822708Swollman ++strp; 7832708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 7842708Swollman if (strp == NULL) 7852708Swollman return NULL; 7862708Swollman *secsp += num * SECSPERMIN; 7872708Swollman if (*strp == ':') { 7882708Swollman ++strp; 789192625Sedwin /* `SECSPERMIN' allows for leap seconds. */ 7909936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 7912708Swollman if (strp == NULL) 7922708Swollman return NULL; 7932708Swollman *secsp += num; 7942708Swollman } 7952708Swollman } 7962708Swollman return strp; 7972708Swollman} 7982708Swollman 7992708Swollman/* 8002708Swollman** Given a pointer into a time zone string, extract an offset, in 8012708Swollman** [+-]hh[:mm[:ss]] form, from the string. 8022708Swollman** If any error occurs, return NULL. 8032708Swollman** Otherwise, return a pointer to the first character not part of the time. 8042708Swollman*/ 8052708Swollman 8062708Swollmanstatic const char * 8072708Swollmangetoffset(strp, offsetp) 80892889Sobrienconst char * strp; 8092708Swollmanlong * const offsetp; 8102708Swollman{ 81192889Sobrien int neg = 0; 8122708Swollman 8132708Swollman if (*strp == '-') { 8142708Swollman neg = 1; 8152708Swollman ++strp; 81617209Swollman } else if (*strp == '+') 81717209Swollman ++strp; 8182708Swollman strp = getsecs(strp, offsetp); 8192708Swollman if (strp == NULL) 8202708Swollman return NULL; /* illegal time */ 8212708Swollman if (neg) 8222708Swollman *offsetp = -*offsetp; 8232708Swollman return strp; 8242708Swollman} 8252708Swollman 8262708Swollman/* 8272708Swollman** Given a pointer into a time zone string, extract a rule in the form 828192625Sedwin** date[/time]. See POSIX section 8 for the format of "date" and "time". 8292708Swollman** If a valid rule is not found, return NULL. 8302708Swollman** Otherwise, return a pointer to the first character not part of the rule. 8312708Swollman*/ 8322708Swollman 8332708Swollmanstatic const char * 8342708Swollmangetrule(strp, rulep) 8352708Swollmanconst char * strp; 83692889Sobrienstruct rule * const rulep; 8372708Swollman{ 8382708Swollman if (*strp == 'J') { 8392708Swollman /* 8402708Swollman ** Julian day. 8412708Swollman */ 8422708Swollman rulep->r_type = JULIAN_DAY; 8432708Swollman ++strp; 8442708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 8452708Swollman } else if (*strp == 'M') { 8462708Swollman /* 8472708Swollman ** Month, week, day. 8482708Swollman */ 8492708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 8502708Swollman ++strp; 8512708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 8522708Swollman if (strp == NULL) 8532708Swollman return NULL; 8542708Swollman if (*strp++ != '.') 8552708Swollman return NULL; 8562708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 8572708Swollman if (strp == NULL) 8582708Swollman return NULL; 8592708Swollman if (*strp++ != '.') 8602708Swollman return NULL; 8612708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 86217209Swollman } else if (is_digit(*strp)) { 8632708Swollman /* 8642708Swollman ** Day of year. 8652708Swollman */ 8662708Swollman rulep->r_type = DAY_OF_YEAR; 8672708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 8682708Swollman } else return NULL; /* invalid format */ 8692708Swollman if (strp == NULL) 8702708Swollman return NULL; 8712708Swollman if (*strp == '/') { 8722708Swollman /* 8732708Swollman ** Time specified. 8742708Swollman */ 8752708Swollman ++strp; 8762708Swollman strp = getsecs(strp, &rulep->r_time); 8772708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 8782708Swollman return strp; 8792708Swollman} 8802708Swollman 8812708Swollman/* 882130461Sstefanf** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the 883130461Sstefanf** year, a rule, and the offset from UTC at the time that rule takes effect, 8842708Swollman** calculate the Epoch-relative time that rule takes effect. 8852708Swollman*/ 8862708Swollman 8872708Swollmanstatic time_t 8882708Swollmantranstime(janfirst, year, rulep, offset) 8892708Swollmanconst time_t janfirst; 8902708Swollmanconst int year; 89192889Sobrienconst struct rule * const rulep; 8922708Swollmanconst long offset; 8932708Swollman{ 89492889Sobrien int leapyear; 89592889Sobrien time_t value; 89692889Sobrien int i; 8972708Swollman int d, m1, yy0, yy1, yy2, dow; 8982708Swollman 8999936Swollman INITIALIZE(value); 9002708Swollman leapyear = isleap(year); 9012708Swollman switch (rulep->r_type) { 9022708Swollman 9032708Swollman case JULIAN_DAY: 9042708Swollman /* 9052708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 9062708Swollman ** years. 9072708Swollman ** In non-leap years, or if the day number is 59 or less, just 9082708Swollman ** add SECSPERDAY times the day number-1 to the time of 9092708Swollman ** January 1, midnight, to get the day. 9102708Swollman */ 9112708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 9122708Swollman if (leapyear && rulep->r_day >= 60) 9132708Swollman value += SECSPERDAY; 9142708Swollman break; 9152708Swollman 9162708Swollman case DAY_OF_YEAR: 9172708Swollman /* 9182708Swollman ** n - day of year. 9192708Swollman ** Just add SECSPERDAY times the day number to the time of 9202708Swollman ** January 1, midnight, to get the day. 9212708Swollman */ 9222708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 9232708Swollman break; 9242708Swollman 9252708Swollman case MONTH_NTH_DAY_OF_WEEK: 9262708Swollman /* 9272708Swollman ** Mm.n.d - nth "dth day" of month m. 9282708Swollman */ 9292708Swollman value = janfirst; 9302708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 9312708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 9322708Swollman 9332708Swollman /* 9342708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 9352708Swollman ** month. 9362708Swollman */ 9372708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 9382708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 9392708Swollman yy1 = yy0 / 100; 9402708Swollman yy2 = yy0 % 100; 9412708Swollman dow = ((26 * m1 - 2) / 10 + 9422708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 9432708Swollman if (dow < 0) 9442708Swollman dow += DAYSPERWEEK; 9452708Swollman 9462708Swollman /* 947192625Sedwin ** "dow" is the day-of-week of the first day of the month. Get 9482708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 9492708Swollman ** month. 9502708Swollman */ 9512708Swollman d = rulep->r_day - dow; 9522708Swollman if (d < 0) 9532708Swollman d += DAYSPERWEEK; 9542708Swollman for (i = 1; i < rulep->r_week; ++i) { 9552708Swollman if (d + DAYSPERWEEK >= 9562708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 9572708Swollman break; 9582708Swollman d += DAYSPERWEEK; 9592708Swollman } 9602708Swollman 9612708Swollman /* 9622708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 9632708Swollman */ 9642708Swollman value += d * SECSPERDAY; 9652708Swollman break; 9662708Swollman } 9672708Swollman 9682708Swollman /* 969130461Sstefanf ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in 970192625Sedwin ** question. To get the Epoch-relative time of the specified local 9712708Swollman ** time on that day, add the transition time and the current offset 972130461Sstefanf ** from UTC. 9732708Swollman */ 9742708Swollman return value + rulep->r_time + offset; 9752708Swollman} 9762708Swollman 9772708Swollman/* 9782708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 9792708Swollman** appropriate. 9802708Swollman*/ 9812708Swollman 9822708Swollmanstatic int 9832708Swollmantzparse(name, sp, lastditch) 9842708Swollmanconst char * name; 98592889Sobrienstruct state * const sp; 9862708Swollmanconst int lastditch; 9872708Swollman{ 9882708Swollman const char * stdname; 9892708Swollman const char * dstname; 9909936Swollman size_t stdlen; 9919936Swollman size_t dstlen; 9922708Swollman long stdoffset; 9932708Swollman long dstoffset; 99492889Sobrien time_t * atp; 99592889Sobrien unsigned char * typep; 99692889Sobrien char * cp; 99792889Sobrien int load_result; 9982708Swollman 9999936Swollman INITIALIZE(dstname); 10002708Swollman stdname = name; 10012708Swollman if (lastditch) { 10022708Swollman stdlen = strlen(name); /* length of standard zone name */ 10032708Swollman name += stdlen; 10042708Swollman if (stdlen >= sizeof sp->chars) 10052708Swollman stdlen = (sizeof sp->chars) - 1; 100621659Swollman stdoffset = 0; 10072708Swollman } else { 1008192625Sedwin if (*name == '<') { 1009192625Sedwin name++; 1010192625Sedwin stdname = name; 1011192625Sedwin name = getqzname(name, '>'); 1012192625Sedwin if (*name != '>') 1013192625Sedwin return (-1); 1014192625Sedwin stdlen = name - stdname; 1015192625Sedwin name++; 1016192625Sedwin } else { 1017192625Sedwin name = getzname(name); 1018192625Sedwin stdlen = name - stdname; 1019192625Sedwin } 102021659Swollman if (*name == '\0') 102121659Swollman return -1; /* was "stdoffset = 0;" */ 102221659Swollman else { 102321659Swollman name = getoffset(name, &stdoffset); 102421659Swollman if (name == NULL) 102521659Swollman return -1; 102621659Swollman } 10272708Swollman } 1028192625Sedwin load_result = tzload(TZDEFRULES, sp, FALSE); 10292708Swollman if (load_result != 0) 10302708Swollman sp->leapcnt = 0; /* so, we're off a little */ 10312708Swollman if (*name != '\0') { 1032192625Sedwin if (*name == '<') { 1033192625Sedwin dstname = ++name; 1034192625Sedwin name = getqzname(name, '>'); 1035192625Sedwin if (*name != '>') 1036192625Sedwin return -1; 1037192625Sedwin dstlen = name - dstname; 1038192625Sedwin name++; 1039192625Sedwin } else { 1040192625Sedwin dstname = name; 1041192625Sedwin name = getzname(name); 1042192625Sedwin dstlen = name - dstname; /* length of DST zone name */ 1043192625Sedwin } 10442708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 10452708Swollman name = getoffset(name, &dstoffset); 10462708Swollman if (name == NULL) 10472708Swollman return -1; 10482708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 1049130461Sstefanf if (*name == '\0' && load_result != 0) 1050130461Sstefanf name = TZDEFRULESTRING; 10512708Swollman if (*name == ',' || *name == ';') { 10522708Swollman struct rule start; 10532708Swollman struct rule end; 105492889Sobrien int year; 105592889Sobrien time_t janfirst; 10562708Swollman time_t starttime; 10572708Swollman time_t endtime; 10582708Swollman 10592708Swollman ++name; 10602708Swollman if ((name = getrule(name, &start)) == NULL) 10612708Swollman return -1; 10622708Swollman if (*name++ != ',') 10632708Swollman return -1; 10642708Swollman if ((name = getrule(name, &end)) == NULL) 10652708Swollman return -1; 10662708Swollman if (*name != '\0') 10672708Swollman return -1; 10682708Swollman sp->typecnt = 2; /* standard time and DST */ 10692708Swollman /* 1070192625Sedwin ** Two transitions per year, from EPOCH_YEAR forward. 10712708Swollman */ 10722708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 10732708Swollman sp->ttis[0].tt_isdst = 1; 10742708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 10752708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 10762708Swollman sp->ttis[1].tt_isdst = 0; 10772708Swollman sp->ttis[1].tt_abbrind = 0; 10782708Swollman atp = sp->ats; 10792708Swollman typep = sp->types; 10802708Swollman janfirst = 0; 1081192625Sedwin sp->timecnt = 0; 1082192625Sedwin for (year = EPOCH_YEAR; 1083192625Sedwin sp->timecnt + 2 <= TZ_MAX_TIMES; 1084192625Sedwin ++year) { 1085192625Sedwin time_t newfirst; 1086192625Sedwin 10872708Swollman starttime = transtime(janfirst, year, &start, 10882708Swollman stdoffset); 10892708Swollman endtime = transtime(janfirst, year, &end, 10902708Swollman dstoffset); 10912708Swollman if (starttime > endtime) { 10922708Swollman *atp++ = endtime; 10932708Swollman *typep++ = 1; /* DST ends */ 10942708Swollman *atp++ = starttime; 10952708Swollman *typep++ = 0; /* DST begins */ 10962708Swollman } else { 10972708Swollman *atp++ = starttime; 10982708Swollman *typep++ = 0; /* DST begins */ 10992708Swollman *atp++ = endtime; 11002708Swollman *typep++ = 1; /* DST ends */ 11012708Swollman } 1102192625Sedwin sp->timecnt += 2; 1103192625Sedwin newfirst = janfirst; 1104192625Sedwin newfirst += year_lengths[isleap(year)] * 11052708Swollman SECSPERDAY; 1106192625Sedwin if (newfirst <= janfirst) 1107192625Sedwin break; 1108192625Sedwin janfirst = newfirst; 11092708Swollman } 11102708Swollman } else { 111192889Sobrien long theirstdoffset; 111292889Sobrien long theirdstoffset; 111392889Sobrien long theiroffset; 111492889Sobrien int isdst; 111592889Sobrien int i; 111692889Sobrien int j; 11172708Swollman 11182708Swollman if (*name != '\0') 11192708Swollman return -1; 11202708Swollman /* 11219936Swollman ** Initial values of theirstdoffset and theirdstoffset. 11222708Swollman */ 11239936Swollman theirstdoffset = 0; 11249936Swollman for (i = 0; i < sp->timecnt; ++i) { 11259936Swollman j = sp->types[i]; 11269936Swollman if (!sp->ttis[j].tt_isdst) { 112717209Swollman theirstdoffset = 112817209Swollman -sp->ttis[j].tt_gmtoff; 11299936Swollman break; 11302708Swollman } 11312708Swollman } 11329936Swollman theirdstoffset = 0; 11339936Swollman for (i = 0; i < sp->timecnt; ++i) { 11349936Swollman j = sp->types[i]; 11359936Swollman if (sp->ttis[j].tt_isdst) { 113617209Swollman theirdstoffset = 113717209Swollman -sp->ttis[j].tt_gmtoff; 11389936Swollman break; 11399936Swollman } 11409936Swollman } 11412708Swollman /* 11429936Swollman ** Initially we're assumed to be in standard time. 11432708Swollman */ 11449936Swollman isdst = FALSE; 11459936Swollman theiroffset = theirstdoffset; 11462708Swollman /* 11479936Swollman ** Now juggle transition times and types 11489936Swollman ** tracking offsets as you do. 11492708Swollman */ 11502708Swollman for (i = 0; i < sp->timecnt; ++i) { 11519936Swollman j = sp->types[i]; 11529936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 11539936Swollman if (sp->ttis[j].tt_ttisgmt) { 11549936Swollman /* No adjustment to transition time */ 11559936Swollman } else { 11569936Swollman /* 11579936Swollman ** If summer time is in effect, and the 11589936Swollman ** transition time was not specified as 11599936Swollman ** standard time, add the summer time 11609936Swollman ** offset to the transition time; 11619936Swollman ** otherwise, add the standard time 11629936Swollman ** offset to the transition time. 11639936Swollman */ 11649936Swollman /* 11659936Swollman ** Transitions from DST to DDST 11669936Swollman ** will effectively disappear since 11679936Swollman ** POSIX provides for only one DST 11689936Swollman ** offset. 11699936Swollman */ 11709936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 11719936Swollman sp->ats[i] += dstoffset - 11729936Swollman theirdstoffset; 11739936Swollman } else { 11749936Swollman sp->ats[i] += stdoffset - 11759936Swollman theirstdoffset; 11769936Swollman } 11779936Swollman } 11789936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 11799936Swollman if (sp->ttis[j].tt_isdst) 11809936Swollman theirdstoffset = theiroffset; 11819936Swollman else theirstdoffset = theiroffset; 11822708Swollman } 11839936Swollman /* 11849936Swollman ** Finally, fill in ttis. 11859936Swollman ** ttisstd and ttisgmt need not be handled. 11869936Swollman */ 11879936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 11889936Swollman sp->ttis[0].tt_isdst = FALSE; 11899936Swollman sp->ttis[0].tt_abbrind = 0; 11909936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 11919936Swollman sp->ttis[1].tt_isdst = TRUE; 11929936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 1193130461Sstefanf sp->typecnt = 2; 11942708Swollman } 11952708Swollman } else { 11962708Swollman dstlen = 0; 11972708Swollman sp->typecnt = 1; /* only standard time */ 11982708Swollman sp->timecnt = 0; 11992708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 12002708Swollman sp->ttis[0].tt_isdst = 0; 12012708Swollman sp->ttis[0].tt_abbrind = 0; 12022708Swollman } 12032708Swollman sp->charcnt = stdlen + 1; 12042708Swollman if (dstlen != 0) 12052708Swollman sp->charcnt += dstlen + 1; 1206130461Sstefanf if ((size_t) sp->charcnt > sizeof sp->chars) 12072708Swollman return -1; 12082708Swollman cp = sp->chars; 12092708Swollman (void) strncpy(cp, stdname, stdlen); 12102708Swollman cp += stdlen; 12112708Swollman *cp++ = '\0'; 12122708Swollman if (dstlen != 0) { 12132708Swollman (void) strncpy(cp, dstname, dstlen); 12142708Swollman *(cp + dstlen) = '\0'; 12152708Swollman } 12162708Swollman return 0; 12172708Swollman} 12182708Swollman 12192708Swollmanstatic void 12202708Swollmangmtload(sp) 12212708Swollmanstruct state * const sp; 12222708Swollman{ 1223192625Sedwin if (tzload(gmt, sp, TRUE) != 0) 12249936Swollman (void) tzparse(gmt, sp, TRUE); 12252708Swollman} 12262708Swollman 122771579Sdeischenstatic void 1228177824Sdavidxutzsetwall_basic(int rdlocked) 12292708Swollman{ 1230177824Sdavidxu if (!rdlocked) 1231177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1232177824Sdavidxu if (lcl_is_set < 0) { 1233177824Sdavidxu if (!rdlocked) 1234177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 12359936Swollman return; 1236177824Sdavidxu } 1237177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1238177824Sdavidxu 1239177824Sdavidxu _RWLOCK_WRLOCK(&lcl_rwlock); 12409936Swollman lcl_is_set = -1; 12419936Swollman 12422708Swollman#ifdef ALL_STATE 12432708Swollman if (lclptr == NULL) { 1244214411Sedwin lclptr = (struct state *) calloc(1, sizeof *lclptr); 12452708Swollman if (lclptr == NULL) { 12462708Swollman settzname(); /* all we can do */ 1247177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1248177824Sdavidxu if (rdlocked) 1249177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12502708Swollman return; 12512708Swollman } 12522708Swollman } 12532708Swollman#endif /* defined ALL_STATE */ 1254192625Sedwin if (tzload((char *) NULL, lclptr, TRUE) != 0) 12552708Swollman gmtload(lclptr); 12562708Swollman settzname(); 1257177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1258177824Sdavidxu 1259177824Sdavidxu if (rdlocked) 1260177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 12612708Swollman} 12622708Swollman 12632708Swollmanvoid 126497423Salfredtzsetwall(void) 126513545Sjulian{ 1266177824Sdavidxu tzsetwall_basic(0); 126713545Sjulian} 126813545Sjulian 126913545Sjulianstatic void 1270177824Sdavidxutzset_basic(int rdlocked) 12712708Swollman{ 127292889Sobrien const char * name; 12732708Swollman 12742708Swollman name = getenv("TZ"); 12752708Swollman if (name == NULL) { 1276177824Sdavidxu tzsetwall_basic(rdlocked); 12772708Swollman return; 12782708Swollman } 12799936Swollman 1280177824Sdavidxu if (!rdlocked) 1281177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1282177824Sdavidxu if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { 1283177824Sdavidxu if (!rdlocked) 1284177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 12859936Swollman return; 1286177824Sdavidxu } 1287177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1288177824Sdavidxu 1289177824Sdavidxu _RWLOCK_WRLOCK(&lcl_rwlock); 1290130461Sstefanf lcl_is_set = strlen(name) < sizeof lcl_TZname; 12919936Swollman if (lcl_is_set) 12929936Swollman (void) strcpy(lcl_TZname, name); 12939936Swollman 12942708Swollman#ifdef ALL_STATE 12952708Swollman if (lclptr == NULL) { 1296214411Sedwin lclptr = (struct state *) calloc(1, sizeof *lclptr); 12972708Swollman if (lclptr == NULL) { 12982708Swollman settzname(); /* all we can do */ 1299177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1300177824Sdavidxu if (rdlocked) 1301177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 13022708Swollman return; 13032708Swollman } 13042708Swollman } 13052708Swollman#endif /* defined ALL_STATE */ 13062708Swollman if (*name == '\0') { 13072708Swollman /* 13082708Swollman ** User wants it fast rather than right. 13092708Swollman */ 13102708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 13112708Swollman lclptr->timecnt = 0; 1312130461Sstefanf lclptr->typecnt = 0; 1313130461Sstefanf lclptr->ttis[0].tt_isdst = 0; 13142708Swollman lclptr->ttis[0].tt_gmtoff = 0; 13152708Swollman lclptr->ttis[0].tt_abbrind = 0; 13169936Swollman (void) strcpy(lclptr->chars, gmt); 1317192625Sedwin } else if (tzload(name, lclptr, TRUE) != 0) 13182708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 13192708Swollman (void) gmtload(lclptr); 13202708Swollman settzname(); 1321177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1322177824Sdavidxu 1323177824Sdavidxu if (rdlocked) 1324177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 13252708Swollman} 13262708Swollman 132713545Sjulianvoid 132897423Salfredtzset(void) 132913545Sjulian{ 1330177824Sdavidxu tzset_basic(0); 133113545Sjulian} 133213545Sjulian 13332708Swollman/* 13342708Swollman** The easy way to behave "as if no library function calls" localtime 13352708Swollman** is to not call it--so we drop its guts into "localsub", which can be 1336192625Sedwin** freely called. (And no, the PANS doesn't require the above behavior-- 13372708Swollman** but it *is* desirable.) 13382708Swollman** 13392708Swollman** The unused offset argument is for the benefit of mktime variants. 13402708Swollman*/ 13412708Swollman 13422708Swollman/*ARGSUSED*/ 1343192625Sedwinstatic struct tm * 13442708Swollmanlocalsub(timep, offset, tmp) 13452708Swollmanconst time_t * const timep; 13462708Swollmanconst long offset; 13472708Swollmanstruct tm * const tmp; 13482708Swollman{ 134992889Sobrien struct state * sp; 135092889Sobrien const struct ttinfo * ttisp; 135192889Sobrien int i; 1352192625Sedwin struct tm * result; 1353192625Sedwin const time_t t = *timep; 13542708Swollman 13552708Swollman sp = lclptr; 13562708Swollman#ifdef ALL_STATE 1357192625Sedwin if (sp == NULL) 1358192625Sedwin return gmtsub(timep, offset, tmp); 1359192625Sedwin#endif /* defined ALL_STATE */ 1360192625Sedwin if ((sp->goback && t < sp->ats[0]) || 1361192625Sedwin (sp->goahead && t > sp->ats[sp->timecnt - 1])) { 1362192625Sedwin time_t newt = t; 1363192625Sedwin register time_t seconds; 1364192625Sedwin register time_t tcycles; 1365192625Sedwin register int_fast64_t icycles; 1366192625Sedwin 1367192625Sedwin if (t < sp->ats[0]) 1368192625Sedwin seconds = sp->ats[0] - t; 1369192625Sedwin else seconds = t - sp->ats[sp->timecnt - 1]; 1370192625Sedwin --seconds; 1371192625Sedwin tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR; 1372192625Sedwin ++tcycles; 1373192625Sedwin icycles = tcycles; 1374192625Sedwin if (tcycles - icycles >= 1 || icycles - tcycles >= 1) 1375192625Sedwin return NULL; 1376192625Sedwin seconds = icycles; 1377192625Sedwin seconds *= YEARSPERREPEAT; 1378192625Sedwin seconds *= AVGSECSPERYEAR; 1379192625Sedwin if (t < sp->ats[0]) 1380192625Sedwin newt += seconds; 1381192625Sedwin else newt -= seconds; 1382192625Sedwin if (newt < sp->ats[0] || 1383192625Sedwin newt > sp->ats[sp->timecnt - 1]) 1384192625Sedwin return NULL; /* "cannot happen" */ 1385192625Sedwin result = localsub(&newt, offset, tmp); 1386192625Sedwin if (result == tmp) { 1387192625Sedwin register time_t newy; 1388192625Sedwin 1389192625Sedwin newy = tmp->tm_year; 1390192625Sedwin if (t < sp->ats[0]) 1391192625Sedwin newy -= icycles * YEARSPERREPEAT; 1392192625Sedwin else newy += icycles * YEARSPERREPEAT; 1393192625Sedwin tmp->tm_year = newy; 1394192625Sedwin if (tmp->tm_year != newy) 1395192625Sedwin return NULL; 1396192625Sedwin } 1397192625Sedwin return result; 13982708Swollman } 13992708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 14002708Swollman i = 0; 14012708Swollman while (sp->ttis[i].tt_isdst) 14022708Swollman if (++i >= sp->typecnt) { 14032708Swollman i = 0; 14042708Swollman break; 14052708Swollman } 14062708Swollman } else { 1407192625Sedwin register int lo = 1; 1408192625Sedwin register int hi = sp->timecnt; 1409192625Sedwin 1410192625Sedwin while (lo < hi) { 1411192625Sedwin register int mid = (lo + hi) >> 1; 1412192625Sedwin 1413192625Sedwin if (t < sp->ats[mid]) 1414192625Sedwin hi = mid; 1415192625Sedwin else lo = mid + 1; 1416192625Sedwin } 1417192625Sedwin i = (int) sp->types[lo - 1]; 14182708Swollman } 14192708Swollman ttisp = &sp->ttis[i]; 14202708Swollman /* 14212708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 14222708Swollman ** you'd replace the statement below with 14232708Swollman ** t += ttisp->tt_gmtoff; 14242708Swollman ** timesub(&t, 0L, sp, tmp); 14252708Swollman */ 1426192625Sedwin result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); 14272708Swollman tmp->tm_isdst = ttisp->tt_isdst; 14289936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 14292708Swollman#ifdef TM_ZONE 14309936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 14312708Swollman#endif /* defined TM_ZONE */ 1432192625Sedwin return result; 14332708Swollman} 14342708Swollman 1435200797Sjhbstatic void 1436200797Sjhblocaltime_key_init(void) 1437200797Sjhb{ 1438200797Sjhb 1439200797Sjhb localtime_key_error = _pthread_key_create(&localtime_key, free); 1440200797Sjhb} 1441200797Sjhb 144219636Shsustruct tm * 14432708Swollmanlocaltime(timep) 14442708Swollmanconst time_t * const timep; 14452708Swollman{ 144613545Sjulian struct tm *p_tm; 144713545Sjulian 144871579Sdeischen if (__isthreaded != 0) { 1449201669Sjhb _pthread_once(&localtime_once, localtime_key_init); 1450200797Sjhb if (localtime_key_error != 0) { 1451200797Sjhb errno = localtime_key_error; 1452200797Sjhb return(NULL); 145313545Sjulian } 145471579Sdeischen p_tm = _pthread_getspecific(localtime_key); 145571579Sdeischen if (p_tm == NULL) { 145671579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 145771579Sdeischen == NULL) 145871579Sdeischen return(NULL); 145971579Sdeischen _pthread_setspecific(localtime_key, p_tm); 146071579Sdeischen } 1461177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1462177824Sdavidxu tzset_basic(1); 146371579Sdeischen localsub(timep, 0L, p_tm); 1464177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 146571579Sdeischen return(p_tm); 146671579Sdeischen } else { 1467177824Sdavidxu tzset_basic(0); 146871579Sdeischen localsub(timep, 0L, &tm); 146971579Sdeischen return(&tm); 147013545Sjulian } 14712708Swollman} 14722708Swollman 14732708Swollman/* 1474130461Sstefanf** Re-entrant version of localtime. 1475130461Sstefanf*/ 1476130461Sstefanf 1477130461Sstefanfstruct tm * 1478192625Sedwinlocaltime_r(timep, tmp) 1479130461Sstefanfconst time_t * const timep; 1480192625Sedwinstruct tm * tmp; 1481130461Sstefanf{ 1482177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 1483177824Sdavidxu tzset_basic(1); 1484192625Sedwin localsub(timep, 0L, tmp); 1485177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 1486192625Sedwin return tmp; 1487130461Sstefanf} 1488130461Sstefanf 1489199607Sjhbstatic void 1490199607Sjhbgmt_init(void) 1491199607Sjhb{ 1492199607Sjhb 1493199607Sjhb#ifdef ALL_STATE 1494214411Sedwin gmtptr = (struct state *) calloc(1, sizeof *gmtptr); 1495199607Sjhb if (gmtptr != NULL) 1496199607Sjhb#endif /* defined ALL_STATE */ 1497199607Sjhb gmtload(gmtptr); 1498199607Sjhb} 1499199607Sjhb 1500130461Sstefanf/* 15012708Swollman** gmtsub is to gmtime as localsub is to localtime. 15022708Swollman*/ 15032708Swollman 1504192625Sedwinstatic struct tm * 15052708Swollmangmtsub(timep, offset, tmp) 15062708Swollmanconst time_t * const timep; 15072708Swollmanconst long offset; 15082708Swollmanstruct tm * const tmp; 15092708Swollman{ 1510192625Sedwin register struct tm * result; 1511192625Sedwin 1512199607Sjhb _once(&gmt_once, gmt_init); 1513192625Sedwin result = timesub(timep, offset, gmtptr, tmp); 15142708Swollman#ifdef TM_ZONE 15152708Swollman /* 15162708Swollman ** Could get fancy here and deliver something such as 1517130461Sstefanf ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, 15182708Swollman ** but this is no time for a treasure hunt. 15192708Swollman */ 15202708Swollman if (offset != 0) 15219936Swollman tmp->TM_ZONE = wildabbr; 15222708Swollman else { 15232708Swollman#ifdef ALL_STATE 15242708Swollman if (gmtptr == NULL) 15259936Swollman tmp->TM_ZONE = gmt; 15262708Swollman else tmp->TM_ZONE = gmtptr->chars; 15272708Swollman#endif /* defined ALL_STATE */ 15282708Swollman#ifndef ALL_STATE 15292708Swollman tmp->TM_ZONE = gmtptr->chars; 15302708Swollman#endif /* State Farm */ 15312708Swollman } 15322708Swollman#endif /* defined TM_ZONE */ 1533192625Sedwin return result; 15342708Swollman} 15352708Swollman 1536201270Sjhbstatic void 1537201270Sjhbgmtime_key_init(void) 1538201270Sjhb{ 1539201270Sjhb 1540201270Sjhb gmtime_key_error = _pthread_key_create(&gmtime_key, free); 1541201270Sjhb} 1542201270Sjhb 15432708Swollmanstruct tm * 15442708Swollmangmtime(timep) 15452708Swollmanconst time_t * const timep; 15462708Swollman{ 154713545Sjulian struct tm *p_tm; 154813545Sjulian 154971579Sdeischen if (__isthreaded != 0) { 1550201669Sjhb _pthread_once(&gmtime_once, gmtime_key_init); 1551201270Sjhb if (gmtime_key_error != 0) { 1552201270Sjhb errno = gmtime_key_error; 1553201270Sjhb return(NULL); 155413545Sjulian } 155571579Sdeischen /* 155671579Sdeischen * Changed to follow POSIX.1 threads standard, which 155771579Sdeischen * is what BSD currently has. 155871579Sdeischen */ 155971579Sdeischen if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { 156071579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 156171579Sdeischen == NULL) { 156271579Sdeischen return(NULL); 156371579Sdeischen } 156471579Sdeischen _pthread_setspecific(gmtime_key, p_tm); 156513545Sjulian } 156671579Sdeischen gmtsub(timep, 0L, p_tm); 156771579Sdeischen return(p_tm); 156813545Sjulian } 156971579Sdeischen else { 157071579Sdeischen gmtsub(timep, 0L, &tm); 157171579Sdeischen return(&tm); 157271579Sdeischen } 15732708Swollman} 15742708Swollman 1575130461Sstefanf/* 1576130461Sstefanf* Re-entrant version of gmtime. 1577130461Sstefanf*/ 1578130461Sstefanf 157919636Shsustruct tm * 1580192625Sedwingmtime_r(timep, tmp) 1581130461Sstefanfconst time_t * const timep; 1582192625Sedwinstruct tm * tmp; 158313545Sjulian{ 1584192625Sedwin return gmtsub(timep, 0L, tmp); 158513545Sjulian} 158613545Sjulian 15872708Swollman#ifdef STD_INSPIRED 15882708Swollman 15892708Swollmanstruct tm * 15902708Swollmanofftime(timep, offset) 15912708Swollmanconst time_t * const timep; 15922708Swollmanconst long offset; 15932708Swollman{ 1594192625Sedwin return gmtsub(timep, offset, &tm); 15952708Swollman} 15962708Swollman 15972708Swollman#endif /* defined STD_INSPIRED */ 15982708Swollman 1599192625Sedwin/* 1600192625Sedwin** Return the number of leap years through the end of the given year 1601192625Sedwin** where, to make the math easy, the answer for year zero is defined as zero. 1602192625Sedwin*/ 1603192625Sedwin 1604192625Sedwinstatic int 1605192625Sedwinleaps_thru_end_of(y) 1606192625Sedwinregister const int y; 1607192625Sedwin{ 1608192625Sedwin return (y >= 0) ? (y / 4 - y / 100 + y / 400) : 1609192625Sedwin -(leaps_thru_end_of(-(y + 1)) + 1); 1610192625Sedwin} 1611192625Sedwin 1612192625Sedwinstatic struct tm * 16132708Swollmantimesub(timep, offset, sp, tmp) 16142708Swollmanconst time_t * const timep; 16152708Swollmanconst long offset; 161692889Sobrienconst struct state * const sp; 161792889Sobrienstruct tm * const tmp; 16182708Swollman{ 161992889Sobrien const struct lsinfo * lp; 1620192625Sedwin time_t tdays; 1621192625Sedwin int idays; /* unsigned would be so 2003 */ 162292889Sobrien long rem; 1623192625Sedwin int y; 162492889Sobrien const int * ip; 162592889Sobrien long corr; 162692889Sobrien int hit; 162792889Sobrien int i; 16282708Swollman 16292708Swollman corr = 0; 16302708Swollman hit = 0; 16312708Swollman#ifdef ALL_STATE 16322708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 16332708Swollman#endif /* defined ALL_STATE */ 16342708Swollman#ifndef ALL_STATE 16352708Swollman i = sp->leapcnt; 16362708Swollman#endif /* State Farm */ 16372708Swollman while (--i >= 0) { 16382708Swollman lp = &sp->lsis[i]; 16392708Swollman if (*timep >= lp->ls_trans) { 16402708Swollman if (*timep == lp->ls_trans) { 16412708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 16422708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 16432708Swollman if (hit) 16442708Swollman while (i > 0 && 16452708Swollman sp->lsis[i].ls_trans == 16462708Swollman sp->lsis[i - 1].ls_trans + 1 && 16472708Swollman sp->lsis[i].ls_corr == 16482708Swollman sp->lsis[i - 1].ls_corr + 1) { 16492708Swollman ++hit; 16502708Swollman --i; 16512708Swollman } 16522708Swollman } 16532708Swollman corr = lp->ls_corr; 16542708Swollman break; 16552708Swollman } 16562708Swollman } 1657192625Sedwin y = EPOCH_YEAR; 1658192625Sedwin tdays = *timep / SECSPERDAY; 1659192625Sedwin rem = *timep - tdays * SECSPERDAY; 1660192625Sedwin while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { 1661192625Sedwin int newy; 1662192625Sedwin register time_t tdelta; 1663192625Sedwin register int idelta; 1664192625Sedwin register int leapdays; 1665192625Sedwin 1666192625Sedwin tdelta = tdays / DAYSPERLYEAR; 1667192625Sedwin idelta = tdelta; 1668192625Sedwin if (tdelta - idelta >= 1 || idelta - tdelta >= 1) 1669192625Sedwin return NULL; 1670192625Sedwin if (idelta == 0) 1671192625Sedwin idelta = (tdays < 0) ? -1 : 1; 1672192625Sedwin newy = y; 1673192625Sedwin if (increment_overflow(&newy, idelta)) 1674192625Sedwin return NULL; 1675192625Sedwin leapdays = leaps_thru_end_of(newy - 1) - 1676192625Sedwin leaps_thru_end_of(y - 1); 1677192625Sedwin tdays -= ((time_t) newy - y) * DAYSPERNYEAR; 1678192625Sedwin tdays -= leapdays; 1679192625Sedwin y = newy; 16802708Swollman } 1681192625Sedwin { 1682192625Sedwin register long seconds; 1683192625Sedwin 1684192625Sedwin seconds = tdays * SECSPERDAY + 0.5; 1685192625Sedwin tdays = seconds / SECSPERDAY; 1686192625Sedwin rem += seconds - tdays * SECSPERDAY; 1687192625Sedwin } 1688192625Sedwin /* 1689192625Sedwin ** Given the range, we can now fearlessly cast... 1690192625Sedwin */ 1691192625Sedwin idays = tdays; 1692192625Sedwin rem += offset - corr; 16932708Swollman while (rem < 0) { 16942708Swollman rem += SECSPERDAY; 1695192625Sedwin --idays; 16962708Swollman } 16972708Swollman while (rem >= SECSPERDAY) { 16982708Swollman rem -= SECSPERDAY; 1699192625Sedwin ++idays; 17002708Swollman } 1701192625Sedwin while (idays < 0) { 1702192625Sedwin if (increment_overflow(&y, -1)) 1703192625Sedwin return NULL; 1704192625Sedwin idays += year_lengths[isleap(y)]; 1705192625Sedwin } 1706192625Sedwin while (idays >= year_lengths[isleap(y)]) { 1707192625Sedwin idays -= year_lengths[isleap(y)]; 1708192625Sedwin if (increment_overflow(&y, 1)) 1709192625Sedwin return NULL; 1710192625Sedwin } 1711192625Sedwin tmp->tm_year = y; 1712192625Sedwin if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) 1713192625Sedwin return NULL; 1714192625Sedwin tmp->tm_yday = idays; 1715192625Sedwin /* 1716192625Sedwin ** The "extra" mods below avoid overflow problems. 1717192625Sedwin */ 1718192625Sedwin tmp->tm_wday = EPOCH_WDAY + 1719192625Sedwin ((y - EPOCH_YEAR) % DAYSPERWEEK) * 1720192625Sedwin (DAYSPERNYEAR % DAYSPERWEEK) + 1721192625Sedwin leaps_thru_end_of(y - 1) - 1722192625Sedwin leaps_thru_end_of(EPOCH_YEAR - 1) + 1723192625Sedwin idays; 1724192625Sedwin tmp->tm_wday %= DAYSPERWEEK; 1725192625Sedwin if (tmp->tm_wday < 0) 1726192625Sedwin tmp->tm_wday += DAYSPERWEEK; 17272708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 1728192625Sedwin rem %= SECSPERHOUR; 17292708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 173017209Swollman /* 173117209Swollman ** A positive leap second requires a special 1732192625Sedwin ** representation. This uses "... ??:59:60" et seq. 173317209Swollman */ 173417209Swollman tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 1735192625Sedwin ip = mon_lengths[isleap(y)]; 1736192625Sedwin for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1737192625Sedwin idays -= ip[tmp->tm_mon]; 1738192625Sedwin tmp->tm_mday = (int) (idays + 1); 17392708Swollman tmp->tm_isdst = 0; 17402708Swollman#ifdef TM_GMTOFF 17412708Swollman tmp->TM_GMTOFF = offset; 17422708Swollman#endif /* defined TM_GMTOFF */ 1743192625Sedwin return tmp; 17442708Swollman} 17452708Swollman 17462708Swollmanchar * 17472708Swollmanctime(timep) 17482708Swollmanconst time_t * const timep; 17492708Swollman{ 17509936Swollman/* 17519936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 1752130461Sstefanf** The ctime function converts the calendar time pointed to by timer 1753192625Sedwin** to local time in the form of a string. It is equivalent to 17549936Swollman** asctime(localtime(timer)) 17559936Swollman*/ 17562708Swollman return asctime(localtime(timep)); 17572708Swollman} 17582708Swollman 175935285Sphkchar * 176035285Sphkctime_r(timep, buf) 176135285Sphkconst time_t * const timep; 1762130461Sstefanfchar * buf; 176335285Sphk{ 1764192625Sedwin struct tm mytm; 1765130461Sstefanf 1766192625Sedwin return asctime_r(localtime_r(timep, &mytm), buf); 176735285Sphk} 176835285Sphk 17692708Swollman/* 17702708Swollman** Adapted from code provided by Robert Elz, who writes: 17712708Swollman** The "best" way to do mktime I think is based on an idea of Bob 177217209Swollman** Kridle's (so its said...) from a long time ago. 1773192625Sedwin** It does a binary search of the time_t space. Since time_t's are 17742708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 17752708Swollman** would still be very reasonable). 17762708Swollman*/ 17772708Swollman 17782708Swollman#ifndef WRONG 17792708Swollman#define WRONG (-1) 17802708Swollman#endif /* !defined WRONG */ 17812708Swollman 17822708Swollman/* 1783192625Sedwin** Simplified normalize logic courtesy Paul Eggert. 17842708Swollman*/ 17852708Swollman 17862708Swollmanstatic int 17872708Swollmanincrement_overflow(number, delta) 17882708Swollmanint * number; 17892708Swollmanint delta; 17902708Swollman{ 17919936Swollman int number0; 17928870Srgrimes 17932708Swollman number0 = *number; 17942708Swollman *number += delta; 17952708Swollman return (*number < number0) != (delta < 0); 17962708Swollman} 17972708Swollman 17982708Swollmanstatic int 1799192625Sedwinlong_increment_overflow(number, delta) 1800192625Sedwinlong * number; 1801192625Sedwinint delta; 1802192625Sedwin{ 1803192625Sedwin long number0; 1804192625Sedwin 1805192625Sedwin number0 = *number; 1806192625Sedwin *number += delta; 1807192625Sedwin return (*number < number0) != (delta < 0); 1808192625Sedwin} 1809192625Sedwin 1810192625Sedwinstatic int 18112708Swollmannormalize_overflow(tensptr, unitsptr, base) 18122708Swollmanint * const tensptr; 18132708Swollmanint * const unitsptr; 18142708Swollmanconst int base; 18152708Swollman{ 181692889Sobrien int tensdelta; 18172708Swollman 18182708Swollman tensdelta = (*unitsptr >= 0) ? 18192708Swollman (*unitsptr / base) : 18202708Swollman (-1 - (-1 - *unitsptr) / base); 18212708Swollman *unitsptr -= tensdelta * base; 18222708Swollman return increment_overflow(tensptr, tensdelta); 18232708Swollman} 18242708Swollman 18252708Swollmanstatic int 1826192625Sedwinlong_normalize_overflow(tensptr, unitsptr, base) 1827192625Sedwinlong * const tensptr; 1828192625Sedwinint * const unitsptr; 1829192625Sedwinconst int base; 1830192625Sedwin{ 1831192625Sedwin register int tensdelta; 1832192625Sedwin 1833192625Sedwin tensdelta = (*unitsptr >= 0) ? 1834192625Sedwin (*unitsptr / base) : 1835192625Sedwin (-1 - (-1 - *unitsptr) / base); 1836192625Sedwin *unitsptr -= tensdelta * base; 1837192625Sedwin return long_increment_overflow(tensptr, tensdelta); 1838192625Sedwin} 1839192625Sedwin 1840192625Sedwinstatic int 18412708Swollmantmcomp(atmp, btmp) 184292889Sobrienconst struct tm * const atmp; 184392889Sobrienconst struct tm * const btmp; 18442708Swollman{ 184592889Sobrien int result; 18462708Swollman 18472708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 18482708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 18492708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 18502708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 18512708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 18522708Swollman result = atmp->tm_sec - btmp->tm_sec; 18532708Swollman return result; 18542708Swollman} 18552708Swollman 18562708Swollmanstatic time_t 1857130461Sstefanftime2sub(tmp, funcp, offset, okayp, do_norm_secs) 18582708Swollmanstruct tm * const tmp; 1859192625Sedwinstruct tm * (* const funcp)(const time_t*, long, struct tm*); 18602708Swollmanconst long offset; 18612708Swollmanint * const okayp; 1862130461Sstefanfconst int do_norm_secs; 18632708Swollman{ 186492889Sobrien const struct state * sp; 186592889Sobrien int dir; 1866192625Sedwin int i, j; 186792889Sobrien int saved_seconds; 1868192625Sedwin long li; 1869192625Sedwin time_t lo; 1870192625Sedwin time_t hi; 1871192625Sedwin long y; 1872192625Sedwin time_t newt; 1873192625Sedwin time_t t; 1874192625Sedwin struct tm yourtm, mytm; 18752708Swollman 18762708Swollman *okayp = FALSE; 18772708Swollman yourtm = *tmp; 1878130461Sstefanf if (do_norm_secs) { 1879130461Sstefanf if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, 1880130461Sstefanf SECSPERMIN)) 1881130461Sstefanf return WRONG; 1882130461Sstefanf } 18832708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 18842708Swollman return WRONG; 18852708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 18862708Swollman return WRONG; 1887192625Sedwin y = yourtm.tm_year; 1888192625Sedwin if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) 18892708Swollman return WRONG; 18902708Swollman /* 1891192625Sedwin ** Turn y into an actual year number for now. 18922708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 18932708Swollman */ 1894192625Sedwin if (long_increment_overflow(&y, TM_YEAR_BASE)) 18952708Swollman return WRONG; 18962708Swollman while (yourtm.tm_mday <= 0) { 1897192625Sedwin if (long_increment_overflow(&y, -1)) 18982708Swollman return WRONG; 1899192625Sedwin li = y + (1 < yourtm.tm_mon); 1900192625Sedwin yourtm.tm_mday += year_lengths[isleap(li)]; 19012708Swollman } 19022708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 1903192625Sedwin li = y + (1 < yourtm.tm_mon); 1904192625Sedwin yourtm.tm_mday -= year_lengths[isleap(li)]; 1905192625Sedwin if (long_increment_overflow(&y, 1)) 19062708Swollman return WRONG; 19072708Swollman } 19082708Swollman for ( ; ; ) { 1909192625Sedwin i = mon_lengths[isleap(y)][yourtm.tm_mon]; 19102708Swollman if (yourtm.tm_mday <= i) 19112708Swollman break; 19122708Swollman yourtm.tm_mday -= i; 19132708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 19142708Swollman yourtm.tm_mon = 0; 1915192625Sedwin if (long_increment_overflow(&y, 1)) 19162708Swollman return WRONG; 19172708Swollman } 19182708Swollman } 1919192625Sedwin if (long_increment_overflow(&y, -TM_YEAR_BASE)) 19202708Swollman return WRONG; 1921192625Sedwin yourtm.tm_year = y; 1922192625Sedwin if (yourtm.tm_year != y) 1923192625Sedwin return WRONG; 1924134231Speter /* Don't go below 1900 for POLA */ 1925134231Speter if (yourtm.tm_year < 0) 1926134231Speter return WRONG; 192777785Swollman if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) 192877785Swollman saved_seconds = 0; 1929192625Sedwin else if (y + TM_YEAR_BASE < EPOCH_YEAR) { 19302708Swollman /* 19312708Swollman ** We can't set tm_sec to 0, because that might push the 19322708Swollman ** time below the minimum representable time. 19332708Swollman ** Set tm_sec to 59 instead. 19342708Swollman ** This assumes that the minimum representable time is 19352708Swollman ** not in the same minute that a leap second was deleted from, 19362708Swollman ** which is a safer assumption than using 58 would be. 19372708Swollman */ 19382708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 19392708Swollman return WRONG; 19402708Swollman saved_seconds = yourtm.tm_sec; 19412708Swollman yourtm.tm_sec = SECSPERMIN - 1; 19422708Swollman } else { 19432708Swollman saved_seconds = yourtm.tm_sec; 19442708Swollman yourtm.tm_sec = 0; 19452708Swollman } 19462708Swollman /* 1947192625Sedwin ** Do a binary search (this works whatever time_t's type is). 19482708Swollman */ 1949192625Sedwin if (!TYPE_SIGNED(time_t)) { 1950192625Sedwin lo = 0; 1951192625Sedwin hi = lo - 1; 1952192625Sedwin } else if (!TYPE_INTEGRAL(time_t)) { 1953192625Sedwin if (sizeof(time_t) > sizeof(float)) 1954192625Sedwin hi = (time_t) DBL_MAX; 1955192625Sedwin else hi = (time_t) FLT_MAX; 1956192625Sedwin lo = -hi; 1957192625Sedwin } else { 1958192625Sedwin lo = 1; 1959192625Sedwin for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i) 1960192625Sedwin lo *= 2; 1961192625Sedwin hi = -(lo + 1); 1962192625Sedwin } 19632708Swollman for ( ; ; ) { 1964192625Sedwin t = lo / 2 + hi / 2; 1965192625Sedwin if (t < lo) 1966192625Sedwin t = lo; 1967192625Sedwin else if (t > hi) 1968192625Sedwin t = hi; 1969192625Sedwin if ((*funcp)(&t, offset, &mytm) == NULL) { 1970192625Sedwin /* 1971192625Sedwin ** Assume that t is too extreme to be represented in 1972192625Sedwin ** a struct tm; arrange things so that it is less 1973192625Sedwin ** extreme on the next pass. 1974192625Sedwin */ 1975192625Sedwin dir = (t > 0) ? 1 : -1; 1976192625Sedwin } else dir = tmcomp(&mytm, &yourtm); 19772708Swollman if (dir != 0) { 1978192625Sedwin if (t == lo) { 1979192625Sedwin ++t; 1980192625Sedwin if (t <= lo) 1981192625Sedwin return WRONG; 1982192625Sedwin ++lo; 1983192625Sedwin } else if (t == hi) { 1984192625Sedwin --t; 1985192625Sedwin if (t >= hi) 1986192625Sedwin return WRONG; 1987192625Sedwin --hi; 1988192625Sedwin } 1989192625Sedwin if (lo > hi) 19902708Swollman return WRONG; 1991192625Sedwin if (dir > 0) 1992192625Sedwin hi = t; 1993192625Sedwin else lo = t; 19942708Swollman continue; 19952708Swollman } 19962708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 19972708Swollman break; 19982708Swollman /* 19992708Swollman ** Right time, wrong type. 20002708Swollman ** Hunt for right time, right type. 20012708Swollman ** It's okay to guess wrong since the guess 20022708Swollman ** gets checked. 20032708Swollman */ 2004192625Sedwin sp = (const struct state *) 2005192625Sedwin ((funcp == localsub) ? lclptr : gmtptr); 20062708Swollman#ifdef ALL_STATE 20072708Swollman if (sp == NULL) 20082708Swollman return WRONG; 20092708Swollman#endif /* defined ALL_STATE */ 201017209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 20112708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 20122708Swollman continue; 201317209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 20142708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 20152708Swollman continue; 20162708Swollman newt = t + sp->ttis[j].tt_gmtoff - 20172708Swollman sp->ttis[i].tt_gmtoff; 2018192625Sedwin if ((*funcp)(&newt, offset, &mytm) == NULL) 2019192625Sedwin continue; 20202708Swollman if (tmcomp(&mytm, &yourtm) != 0) 20212708Swollman continue; 20222708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 20232708Swollman continue; 20242708Swollman /* 20252708Swollman ** We have a match. 20262708Swollman */ 20272708Swollman t = newt; 20282708Swollman goto label; 20292708Swollman } 20302708Swollman } 20312708Swollman return WRONG; 20322708Swollman } 20332708Swollmanlabel: 20342708Swollman newt = t + saved_seconds; 20352708Swollman if ((newt < t) != (saved_seconds < 0)) 20362708Swollman return WRONG; 20372708Swollman t = newt; 2038192625Sedwin if ((*funcp)(&t, offset, tmp)) 2039192625Sedwin *okayp = TRUE; 20402708Swollman return t; 20412708Swollman} 20422708Swollman 20432708Swollmanstatic time_t 2044130461Sstefanftime2(tmp, funcp, offset, okayp) 2045130461Sstefanfstruct tm * const tmp; 2046192625Sedwinstruct tm * (* const funcp)(const time_t*, long, struct tm*); 2047130461Sstefanfconst long offset; 2048130461Sstefanfint * const okayp; 2049130461Sstefanf{ 2050130461Sstefanf time_t t; 2051130461Sstefanf 2052130461Sstefanf /* 2053130461Sstefanf ** First try without normalization of seconds 2054130461Sstefanf ** (in case tm_sec contains a value associated with a leap second). 2055130461Sstefanf ** If that fails, try with normalization of seconds. 2056130461Sstefanf */ 2057130461Sstefanf t = time2sub(tmp, funcp, offset, okayp, FALSE); 2058130461Sstefanf return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); 2059130461Sstefanf} 2060130461Sstefanf 2061130461Sstefanfstatic time_t 20622708Swollmantime1(tmp, funcp, offset) 20632708Swollmanstruct tm * const tmp; 2064192625Sedwinstruct tm * (* const funcp)(const time_t *, long, struct tm *); 20652708Swollmanconst long offset; 20662708Swollman{ 206792889Sobrien time_t t; 206892889Sobrien const struct state * sp; 206992889Sobrien int samei, otheri; 2070130461Sstefanf int sameind, otherind; 2071130461Sstefanf int i; 2072130461Sstefanf int nseen; 2073130461Sstefanf int seen[TZ_MAX_TYPES]; 2074130461Sstefanf int types[TZ_MAX_TYPES]; 20752708Swollman int okay; 20762708Swollman 2077214411Sedwin if (tmp == NULL) { 2078214411Sedwin errno = EINVAL; 2079214411Sedwin return WRONG; 2080214411Sedwin } 2081214411Sedwin 20822708Swollman if (tmp->tm_isdst > 1) 20832708Swollman tmp->tm_isdst = 1; 20842708Swollman t = time2(tmp, funcp, offset, &okay); 20852708Swollman#ifdef PCTS 20862708Swollman /* 2087192625Sedwin ** PCTS code courtesy Grant Sullivan. 20882708Swollman */ 20892708Swollman if (okay) 20902708Swollman return t; 20912708Swollman if (tmp->tm_isdst < 0) 20922708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 20932708Swollman#endif /* defined PCTS */ 20942708Swollman#ifndef PCTS 20952708Swollman if (okay || tmp->tm_isdst < 0) 20962708Swollman return t; 20972708Swollman#endif /* !defined PCTS */ 20982708Swollman /* 20992708Swollman ** We're supposed to assume that somebody took a time of one type 21002708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 21012708Swollman ** We try to divine the type they started from and adjust to the 21022708Swollman ** type they need. 21032708Swollman */ 2104192625Sedwin sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 21052708Swollman#ifdef ALL_STATE 21062708Swollman if (sp == NULL) 21072708Swollman return WRONG; 21082708Swollman#endif /* defined ALL_STATE */ 2109130461Sstefanf for (i = 0; i < sp->typecnt; ++i) 2110130461Sstefanf seen[i] = FALSE; 2111130461Sstefanf nseen = 0; 2112130461Sstefanf for (i = sp->timecnt - 1; i >= 0; --i) 2113130461Sstefanf if (!seen[sp->types[i]]) { 2114130461Sstefanf seen[sp->types[i]] = TRUE; 2115130461Sstefanf types[nseen++] = sp->types[i]; 2116130461Sstefanf } 2117130461Sstefanf for (sameind = 0; sameind < nseen; ++sameind) { 2118130461Sstefanf samei = types[sameind]; 21192708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 21202708Swollman continue; 2121130461Sstefanf for (otherind = 0; otherind < nseen; ++otherind) { 2122130461Sstefanf otheri = types[otherind]; 21232708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 21242708Swollman continue; 21252708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 21262708Swollman sp->ttis[samei].tt_gmtoff; 21272708Swollman tmp->tm_isdst = !tmp->tm_isdst; 21282708Swollman t = time2(tmp, funcp, offset, &okay); 21292708Swollman if (okay) 21302708Swollman return t; 21312708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 21322708Swollman sp->ttis[samei].tt_gmtoff; 21332708Swollman tmp->tm_isdst = !tmp->tm_isdst; 21342708Swollman } 21352708Swollman } 21362708Swollman return WRONG; 21372708Swollman} 21382708Swollman 21392708Swollmantime_t 21402708Swollmanmktime(tmp) 21412708Swollmanstruct tm * const tmp; 21422708Swollman{ 214313545Sjulian time_t mktime_return_value; 2144177824Sdavidxu _RWLOCK_RDLOCK(&lcl_rwlock); 2145177824Sdavidxu tzset_basic(1); 214613545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 2147177824Sdavidxu _RWLOCK_UNLOCK(&lcl_rwlock); 214813545Sjulian return(mktime_return_value); 21492708Swollman} 21502708Swollman 21512708Swollman#ifdef STD_INSPIRED 21522708Swollman 21532708Swollmantime_t 21542708Swollmantimelocal(tmp) 21552708Swollmanstruct tm * const tmp; 21562708Swollman{ 2157214411Sedwin if (tmp != NULL) 2158214411Sedwin tmp->tm_isdst = -1; /* in case it wasn't initialized */ 21592708Swollman return mktime(tmp); 21602708Swollman} 21612708Swollman 21622708Swollmantime_t 21632708Swollmantimegm(tmp) 21642708Swollmanstruct tm * const tmp; 21652708Swollman{ 2166214411Sedwin if (tmp != NULL) 2167214411Sedwin tmp->tm_isdst = 0; 21682708Swollman return time1(tmp, gmtsub, 0L); 21692708Swollman} 21702708Swollman 21712708Swollmantime_t 21722708Swollmantimeoff(tmp, offset) 21732708Swollmanstruct tm * const tmp; 21742708Swollmanconst long offset; 21752708Swollman{ 2176214411Sedwin if (tmp != NULL) 2177214411Sedwin tmp->tm_isdst = 0; 21782708Swollman return time1(tmp, gmtsub, offset); 21792708Swollman} 21802708Swollman 21812708Swollman#endif /* defined STD_INSPIRED */ 21822708Swollman 21832708Swollman#ifdef CMUCS 21842708Swollman 21852708Swollman/* 21862708Swollman** The following is supplied for compatibility with 21872708Swollman** previous versions of the CMUCS runtime library. 21882708Swollman*/ 21892708Swollman 21902708Swollmanlong 21912708Swollmangtime(tmp) 21922708Swollmanstruct tm * const tmp; 21932708Swollman{ 21942708Swollman const time_t t = mktime(tmp); 21952708Swollman 21962708Swollman if (t == WRONG) 21972708Swollman return -1; 21982708Swollman return t; 21992708Swollman} 22002708Swollman 22012708Swollman#endif /* defined CMUCS */ 22022708Swollman 22032708Swollman/* 22042708Swollman** XXX--is the below the right way to conditionalize?? 22052708Swollman*/ 22062708Swollman 22072708Swollman#ifdef STD_INSPIRED 22082708Swollman 22092708Swollman/* 22102708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 2211130461Sstefanf** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which 22122708Swollman** is not the case if we are accounting for leap seconds. 22132708Swollman** So, we provide the following conversion routines for use 22142708Swollman** when exchanging timestamps with POSIX conforming systems. 22152708Swollman*/ 22162708Swollman 22172708Swollmanstatic long 22182708Swollmanleapcorr(timep) 22192708Swollmantime_t * timep; 22202708Swollman{ 222192889Sobrien struct state * sp; 222292889Sobrien struct lsinfo * lp; 222392889Sobrien int i; 22242708Swollman 22252708Swollman sp = lclptr; 22262708Swollman i = sp->leapcnt; 22272708Swollman while (--i >= 0) { 22282708Swollman lp = &sp->lsis[i]; 22292708Swollman if (*timep >= lp->ls_trans) 22302708Swollman return lp->ls_corr; 22312708Swollman } 22322708Swollman return 0; 22332708Swollman} 22342708Swollman 22352708Swollmantime_t 22362708Swollmantime2posix(t) 22372708Swollmantime_t t; 22382708Swollman{ 22399936Swollman tzset(); 22402708Swollman return t - leapcorr(&t); 22412708Swollman} 22422708Swollman 22432708Swollmantime_t 22442708Swollmanposix2time(t) 22452708Swollmantime_t t; 22462708Swollman{ 22472708Swollman time_t x; 22482708Swollman time_t y; 22492708Swollman 22509936Swollman tzset(); 22512708Swollman /* 22522708Swollman ** For a positive leap second hit, the result 2253192625Sedwin ** is not unique. For a negative leap second 22542708Swollman ** hit, the corresponding time doesn't exist, 22552708Swollman ** so we return an adjacent second. 22562708Swollman */ 22572708Swollman x = t + leapcorr(&t); 22582708Swollman y = x - leapcorr(&x); 22592708Swollman if (y < t) { 22602708Swollman do { 22612708Swollman x++; 22622708Swollman y = x - leapcorr(&x); 22632708Swollman } while (y < t); 22642708Swollman if (t != y) 22652708Swollman return x - 1; 22662708Swollman } else if (y > t) { 22672708Swollman do { 22682708Swollman --x; 22692708Swollman y = x - leapcorr(&x); 22702708Swollman } while (y > t); 22712708Swollman if (t != y) 22722708Swollman return x + 1; 22732708Swollman } 22742708Swollman return x; 22752708Swollman} 22762708Swollman 22772708Swollman#endif /* defined STD_INSPIRED */ 2278