localtime.c revision 97423
117209Swollman/* 217209Swollman** This file is in the public domain, so clarified as of 317209Swollman** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). 417209Swollman*/ 515923Sscrappy 62708Swollman#ifndef lint 72708Swollman#ifndef NOID 817209Swollmanstatic char elsieid[] = "@(#)localtime.c 7.57"; 92708Swollman#endif /* !defined NOID */ 102708Swollman#endif /* !defined lint */ 1192986Sobrien#include <sys/cdefs.h> 1292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdtime/localtime.c 97423 2002-05-28 20:12:42Z alfred $"); 132708Swollman 142708Swollman/* 152708Swollman** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 162708Swollman** POSIX-style TZ environment variable handling from Guy Harris 172708Swollman** (guy@auspex.com). 182708Swollman*/ 192708Swollman 202708Swollman/*LINTLIBRARY*/ 212708Swollman 2271579Sdeischen#include "namespace.h" 2318834Swollman#include <sys/types.h> 2418834Swollman#include <sys/stat.h> 2571579Sdeischen#include <fcntl.h> 2671579Sdeischen#include <pthread.h> 2771579Sdeischen#include "private.h" 2871579Sdeischen#include "un-namespace.h" 2918834Swollman 302708Swollman#include "tzfile.h" 312708Swollman 3271579Sdeischen#include "libc_private.h" 3371579Sdeischen 3471579Sdeischen#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 3571579Sdeischen#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 3671579Sdeischen 379936Swollman/* 389936Swollman** SunOS 4.1.1 headers lack O_BINARY. 399936Swollman*/ 402708Swollman 412708Swollman#ifdef O_BINARY 422708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 432708Swollman#endif /* defined O_BINARY */ 442708Swollman#ifndef O_BINARY 452708Swollman#define OPEN_MODE O_RDONLY 462708Swollman#endif /* !defined O_BINARY */ 472708Swollman 482708Swollman#ifndef WILDABBR 492708Swollman/* 502708Swollman** Someone might make incorrect use of a time zone abbreviation: 512708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 529936Swollman** or implicitly). 532708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 549936Swollman** or implicitly). 552708Swollman** 3. They might reference tzname[1] after setting to a time zone 562708Swollman** in which Daylight Saving Time is never observed. 572708Swollman** 4. They might reference tzname[0] after setting to a time zone 582708Swollman** in which Standard Time is never observed. 592708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 602708Swollman** What's best to do in the above cases is open to debate; 612708Swollman** for now, we just set things up so that in any of the five cases 622708Swollman** WILDABBR is used. Another possibility: initialize tzname[0] to the 632708Swollman** string "tzname[0] used before set", and similarly for the other cases. 642708Swollman** And another: initialize tzname[0] to "ERA", with an explanation in the 652708Swollman** manual page of what this "time zone abbreviation" means (doing this so 662708Swollman** that tzname[0] has the "normal" length of three characters). 672708Swollman*/ 682708Swollman#define WILDABBR " " 692708Swollman#endif /* !defined WILDABBR */ 702708Swollman 719936Swollmanstatic char wildabbr[] = "WILDABBR"; 722708Swollman 739936Swollmanstatic const char gmt[] = "GMT"; 749936Swollman 752708Swollmanstruct ttinfo { /* time type information */ 762708Swollman long tt_gmtoff; /* GMT offset in seconds */ 772708Swollman int tt_isdst; /* used to set tm_isdst */ 782708Swollman int tt_abbrind; /* abbreviation list index */ 792708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 809936Swollman int tt_ttisgmt; /* TRUE if transition is GMT */ 812708Swollman}; 822708Swollman 832708Swollmanstruct lsinfo { /* leap second information */ 842708Swollman time_t ls_trans; /* transition time */ 852708Swollman long ls_corr; /* correction to apply */ 862708Swollman}; 872708Swollman 882708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 892708Swollman 902708Swollman#ifdef TZNAME_MAX 912708Swollman#define MY_TZNAME_MAX TZNAME_MAX 922708Swollman#endif /* defined TZNAME_MAX */ 932708Swollman#ifndef TZNAME_MAX 942708Swollman#define MY_TZNAME_MAX 255 952708Swollman#endif /* !defined TZNAME_MAX */ 962708Swollman 972708Swollmanstruct state { 982708Swollman int leapcnt; 992708Swollman int timecnt; 1002708Swollman int typecnt; 1012708Swollman int charcnt; 1022708Swollman time_t ats[TZ_MAX_TIMES]; 1032708Swollman unsigned char types[TZ_MAX_TIMES]; 1042708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 1059936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 1062708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 1072708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 1082708Swollman}; 1092708Swollman 1102708Swollmanstruct rule { 1112708Swollman int r_type; /* type of rule--see below */ 1122708Swollman int r_day; /* day number of rule */ 1132708Swollman int r_week; /* week number of rule */ 1142708Swollman int r_mon; /* month number of rule */ 1152708Swollman long r_time; /* transition time of rule */ 1162708Swollman}; 1172708Swollman 1182708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1192708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1202708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1212708Swollman 1222708Swollman/* 1232708Swollman** Prototypes for static functions. 1242708Swollman*/ 1252708Swollman 12697423Salfredstatic long detzcode(const char * codep); 12797423Salfredstatic const char * getzname(const char * strp); 12897423Salfredstatic const char * getnum(const char * strp, int * nump, int min, 12997423Salfred int max); 13097423Salfredstatic const char * getsecs(const char * strp, long * secsp); 13197423Salfredstatic const char * getoffset(const char * strp, long * offsetp); 13297423Salfredstatic const char * getrule(const char * strp, struct rule * rulep); 13397423Salfredstatic void gmtload(struct state * sp); 13497423Salfredstatic void gmtsub(const time_t * timep, long offset, 13597423Salfred struct tm * tmp); 13697423Salfredstatic void localsub(const time_t * timep, long offset, 13797423Salfred struct tm * tmp); 13897423Salfredstatic int increment_overflow(int * number, int delta); 13997423Salfredstatic int normalize_overflow(int * tensptr, int * unitsptr, 14097423Salfred int base); 14197423Salfredstatic void settzname(void); 14297423Salfredstatic time_t time1(struct tm * tmp, 14397423Salfred void(*funcp) (const time_t *, 14497423Salfred long, struct tm *), 14597423Salfred long offset); 14697423Salfredstatic time_t time2(struct tm *tmp, 14797423Salfred void(*funcp) (const time_t *, 14897423Salfred long, struct tm*), 14997423Salfred long offset, int * okayp); 15097423Salfredstatic void timesub(const time_t * timep, long offset, 15197423Salfred const struct state * sp, struct tm * tmp); 15297423Salfredstatic int tmcomp(const struct tm * atmp, 15397423Salfred const struct tm * btmp); 15497423Salfredstatic time_t transtime(time_t janfirst, int year, 15597423Salfred const struct rule * rulep, long offset); 15697423Salfredstatic int tzload(const char * name, struct state * sp); 15797423Salfredstatic int tzparse(const char * name, struct state * sp, 15897423Salfred int lastditch); 1592708Swollman 1602708Swollman#ifdef ALL_STATE 1612708Swollmanstatic struct state * lclptr; 1622708Swollmanstatic struct state * gmtptr; 1632708Swollman#endif /* defined ALL_STATE */ 1642708Swollman 1652708Swollman#ifndef ALL_STATE 1662708Swollmanstatic struct state lclmem; 1672708Swollmanstatic struct state gmtmem; 1682708Swollman#define lclptr (&lclmem) 1692708Swollman#define gmtptr (&gmtmem) 1702708Swollman#endif /* State Farm */ 1712708Swollman 1729936Swollman#ifndef TZ_STRLEN_MAX 1739936Swollman#define TZ_STRLEN_MAX 255 1749936Swollman#endif /* !defined TZ_STRLEN_MAX */ 1759936Swollman 1769936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 1772708Swollmanstatic int lcl_is_set; 1782708Swollmanstatic int gmt_is_set; 17971579Sdeischenstatic pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER; 18071579Sdeischenstatic pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; 1812708Swollman 1822708Swollmanchar * tzname[2] = { 1839936Swollman wildabbr, 1849936Swollman wildabbr 1852708Swollman}; 1862708Swollman 1879936Swollman/* 1889936Swollman** Section 4.12.3 of X3.159-1989 requires that 1899936Swollman** Except for the strftime function, these functions [asctime, 1909936Swollman** ctime, gmtime, localtime] return values in one of two static 1919936Swollman** objects: a broken-down time structure and an array of char. 1929936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 1939936Swollman*/ 1949936Swollman 1959936Swollmanstatic struct tm tm; 1969936Swollman 1972708Swollman#ifdef USG_COMPAT 1982708Swollmantime_t timezone = 0; 1992708Swollmanint daylight = 0; 2002708Swollman#endif /* defined USG_COMPAT */ 2012708Swollman 2022708Swollman#ifdef ALTZONE 2032708Swollmantime_t altzone = 0; 2042708Swollman#endif /* defined ALTZONE */ 2052708Swollman 2062708Swollmanstatic long 2072708Swollmandetzcode(codep) 2082708Swollmanconst char * const codep; 2092708Swollman{ 21092889Sobrien long result; 21192889Sobrien int i; 2122708Swollman 21317209Swollman result = (codep[0] & 0x80) ? ~0L : 0L; 2142708Swollman for (i = 0; i < 4; ++i) 2152708Swollman result = (result << 8) | (codep[i] & 0xff); 2162708Swollman return result; 2172708Swollman} 2182708Swollman 2192708Swollmanstatic void 22097423Salfredsettzname(void) 2212708Swollman{ 22292889Sobrien struct state * sp = lclptr; 22392889Sobrien int i; 2242708Swollman 2259936Swollman tzname[0] = wildabbr; 2269936Swollman tzname[1] = wildabbr; 2272708Swollman#ifdef USG_COMPAT 2282708Swollman daylight = 0; 2292708Swollman timezone = 0; 2302708Swollman#endif /* defined USG_COMPAT */ 2312708Swollman#ifdef ALTZONE 2322708Swollman altzone = 0; 2332708Swollman#endif /* defined ALTZONE */ 2342708Swollman#ifdef ALL_STATE 2352708Swollman if (sp == NULL) { 2369936Swollman tzname[0] = tzname[1] = gmt; 2372708Swollman return; 2382708Swollman } 2392708Swollman#endif /* defined ALL_STATE */ 2402708Swollman for (i = 0; i < sp->typecnt; ++i) { 24192889Sobrien const struct ttinfo * const ttisp = &sp->ttis[i]; 2422708Swollman 2432708Swollman tzname[ttisp->tt_isdst] = 2449936Swollman &sp->chars[ttisp->tt_abbrind]; 2452708Swollman#ifdef USG_COMPAT 2462708Swollman if (ttisp->tt_isdst) 2472708Swollman daylight = 1; 2482708Swollman if (i == 0 || !ttisp->tt_isdst) 2492708Swollman timezone = -(ttisp->tt_gmtoff); 2502708Swollman#endif /* defined USG_COMPAT */ 2512708Swollman#ifdef ALTZONE 2522708Swollman if (i == 0 || ttisp->tt_isdst) 2532708Swollman altzone = -(ttisp->tt_gmtoff); 2542708Swollman#endif /* defined ALTZONE */ 2552708Swollman } 2562708Swollman /* 2572708Swollman ** And to get the latest zone names into tzname. . . 2582708Swollman */ 2592708Swollman for (i = 0; i < sp->timecnt; ++i) { 26092889Sobrien const struct ttinfo * const ttisp = 2612708Swollman &sp->ttis[ 2622708Swollman sp->types[i]]; 2632708Swollman 2642708Swollman tzname[ttisp->tt_isdst] = 2659936Swollman &sp->chars[ttisp->tt_abbrind]; 2662708Swollman } 2672708Swollman} 2682708Swollman 2692708Swollmanstatic int 2702708Swollmantzload(name, sp) 27192889Sobrienconst char * name; 27292889Sobrienstruct state * const sp; 2732708Swollman{ 27492889Sobrien const char * p; 27592889Sobrien int i; 27692889Sobrien int fid; 2772708Swollman 27839327Simp /* XXX The following is from OpenBSD, and I'm not sure it is correct */ 27939327Simp if (name != NULL && issetugid() != 0) 28039327Simp if ((name[0] == ':' && name[1] == '/') || 28139327Simp name[0] == '/' || strchr(name, '.')) 28239327Simp name = NULL; 2832708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 2842708Swollman return -1; 2852708Swollman { 28692889Sobrien int doaccess; 28718834Swollman struct stat stab; 2889936Swollman /* 2899936Swollman ** Section 4.9.1 of the C standard says that 2909936Swollman ** "FILENAME_MAX expands to an integral constant expression 29118834Swollman ** that is the size needed for an array of char large enough 2929936Swollman ** to hold the longest file name string that the implementation 2939936Swollman ** guarantees can be opened." 2949936Swollman */ 2952708Swollman char fullname[FILENAME_MAX + 1]; 2962708Swollman 2972708Swollman if (name[0] == ':') 2982708Swollman ++name; 2992708Swollman doaccess = name[0] == '/'; 3002708Swollman if (!doaccess) { 3012708Swollman if ((p = TZDIR) == NULL) 3022708Swollman return -1; 30339327Simp if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname) 3042708Swollman return -1; 3052708Swollman (void) strcpy(fullname, p); 3062708Swollman (void) strcat(fullname, "/"); 3072708Swollman (void) strcat(fullname, name); 3082708Swollman /* 3092708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 3102708Swollman */ 3112708Swollman if (strchr(name, '.') != NULL) 3122708Swollman doaccess = TRUE; 3132708Swollman name = fullname; 3142708Swollman } 31524253Simp if (doaccess && access(name, R_OK) != 0) 31639327Simp return -1; 31756698Sjasone if ((fid = _open(name, OPEN_MODE)) == -1) 3182708Swollman return -1; 31995989Swollman if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) { 32095989Swollman _close(fid); 32118834Swollman return -1; 32295989Swollman } 3232708Swollman } 3242708Swollman { 3259936Swollman struct tzhead * tzhp; 3269936Swollman char buf[sizeof *sp + sizeof *tzhp]; 3279936Swollman int ttisstdcnt; 3289936Swollman int ttisgmtcnt; 3292708Swollman 33056698Sjasone i = _read(fid, buf, sizeof buf); 33156698Sjasone if (_close(fid) != 0) 3322708Swollman return -1; 3339936Swollman p = buf; 33442989Swollman p += (sizeof tzhp->tzh_magic) + (sizeof tzhp->tzh_reserved); 3359936Swollman ttisstdcnt = (int) detzcode(p); 3369936Swollman p += 4; 3379936Swollman ttisgmtcnt = (int) detzcode(p); 3389936Swollman p += 4; 3399936Swollman sp->leapcnt = (int) detzcode(p); 3409936Swollman p += 4; 3419936Swollman sp->timecnt = (int) detzcode(p); 3429936Swollman p += 4; 3439936Swollman sp->typecnt = (int) detzcode(p); 3449936Swollman p += 4; 3459936Swollman sp->charcnt = (int) detzcode(p); 3469936Swollman p += 4; 3472708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 3482708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 3492708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 3502708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 3519936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 3529936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 3532708Swollman return -1; 3549936Swollman if (i - (p - buf) < sp->timecnt * 4 + /* ats */ 3559936Swollman sp->timecnt + /* types */ 3569936Swollman sp->typecnt * (4 + 2) + /* ttinfos */ 3579936Swollman sp->charcnt + /* chars */ 3589936Swollman sp->leapcnt * (4 + 4) + /* lsinfos */ 3599936Swollman ttisstdcnt + /* ttisstds */ 3609936Swollman ttisgmtcnt) /* ttisgmts */ 3612708Swollman return -1; 3622708Swollman for (i = 0; i < sp->timecnt; ++i) { 3632708Swollman sp->ats[i] = detzcode(p); 3642708Swollman p += 4; 3652708Swollman } 3662708Swollman for (i = 0; i < sp->timecnt; ++i) { 3672708Swollman sp->types[i] = (unsigned char) *p++; 3682708Swollman if (sp->types[i] >= sp->typecnt) 3692708Swollman return -1; 3702708Swollman } 3712708Swollman for (i = 0; i < sp->typecnt; ++i) { 37292889Sobrien struct ttinfo * ttisp; 3732708Swollman 3742708Swollman ttisp = &sp->ttis[i]; 3752708Swollman ttisp->tt_gmtoff = detzcode(p); 3762708Swollman p += 4; 3772708Swollman ttisp->tt_isdst = (unsigned char) *p++; 3782708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 3792708Swollman return -1; 3802708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 3812708Swollman if (ttisp->tt_abbrind < 0 || 3822708Swollman ttisp->tt_abbrind > sp->charcnt) 3832708Swollman return -1; 3842708Swollman } 3852708Swollman for (i = 0; i < sp->charcnt; ++i) 3862708Swollman sp->chars[i] = *p++; 3872708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 3882708Swollman for (i = 0; i < sp->leapcnt; ++i) { 38992889Sobrien struct lsinfo * lsisp; 3902708Swollman 3912708Swollman lsisp = &sp->lsis[i]; 3922708Swollman lsisp->ls_trans = detzcode(p); 3932708Swollman p += 4; 3942708Swollman lsisp->ls_corr = detzcode(p); 3952708Swollman p += 4; 3962708Swollman } 3972708Swollman for (i = 0; i < sp->typecnt; ++i) { 39892889Sobrien struct ttinfo * ttisp; 3992708Swollman 4002708Swollman ttisp = &sp->ttis[i]; 4012708Swollman if (ttisstdcnt == 0) 4022708Swollman ttisp->tt_ttisstd = FALSE; 4032708Swollman else { 4042708Swollman ttisp->tt_ttisstd = *p++; 4052708Swollman if (ttisp->tt_ttisstd != TRUE && 4062708Swollman ttisp->tt_ttisstd != FALSE) 4072708Swollman return -1; 4082708Swollman } 4092708Swollman } 4109936Swollman for (i = 0; i < sp->typecnt; ++i) { 41192889Sobrien struct ttinfo * ttisp; 4129936Swollman 4139936Swollman ttisp = &sp->ttis[i]; 4149936Swollman if (ttisgmtcnt == 0) 4159936Swollman ttisp->tt_ttisgmt = FALSE; 4169936Swollman else { 4179936Swollman ttisp->tt_ttisgmt = *p++; 4189936Swollman if (ttisp->tt_ttisgmt != TRUE && 4199936Swollman ttisp->tt_ttisgmt != FALSE) 4209936Swollman return -1; 4219936Swollman } 4229936Swollman } 4232708Swollman } 4242708Swollman return 0; 4252708Swollman} 4262708Swollman 4272708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 4282708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 4292708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 4302708Swollman}; 4312708Swollman 4322708Swollmanstatic const int year_lengths[2] = { 4332708Swollman DAYSPERNYEAR, DAYSPERLYEAR 4342708Swollman}; 4352708Swollman 4362708Swollman/* 4372708Swollman** Given a pointer into a time zone string, scan until a character that is not 4382708Swollman** a valid character in a zone name is found. Return a pointer to that 4392708Swollman** character. 4402708Swollman*/ 4412708Swollman 4422708Swollmanstatic const char * 4432708Swollmangetzname(strp) 44492889Sobrienconst char * strp; 4452708Swollman{ 44692889Sobrien char c; 4472708Swollman 44817209Swollman while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 4492708Swollman c != '+') 4502708Swollman ++strp; 4512708Swollman return strp; 4522708Swollman} 4532708Swollman 4542708Swollman/* 4552708Swollman** Given a pointer into a time zone string, extract a number from that string. 4562708Swollman** Check that the number is within a specified range; if it is not, return 4572708Swollman** NULL. 4582708Swollman** Otherwise, return a pointer to the first character not part of the number. 4592708Swollman*/ 4602708Swollman 4612708Swollmanstatic const char * 4622708Swollmangetnum(strp, nump, min, max) 46392889Sobrienconst char * strp; 4642708Swollmanint * const nump; 4652708Swollmanconst int min; 4662708Swollmanconst int max; 4672708Swollman{ 46892889Sobrien char c; 46992889Sobrien int num; 4702708Swollman 47117209Swollman if (strp == NULL || !is_digit(c = *strp)) 4722708Swollman return NULL; 4732708Swollman num = 0; 47417209Swollman do { 4752708Swollman num = num * 10 + (c - '0'); 4762708Swollman if (num > max) 4772708Swollman return NULL; /* illegal value */ 47817209Swollman c = *++strp; 47917209Swollman } while (is_digit(c)); 4802708Swollman if (num < min) 4812708Swollman return NULL; /* illegal value */ 4822708Swollman *nump = num; 4832708Swollman return strp; 4842708Swollman} 4852708Swollman 4862708Swollman/* 4872708Swollman** Given a pointer into a time zone string, extract a number of seconds, 4882708Swollman** in hh[:mm[:ss]] form, from the string. 4892708Swollman** If any error occurs, return NULL. 4902708Swollman** Otherwise, return a pointer to the first character not part of the number 4912708Swollman** of seconds. 4922708Swollman*/ 4932708Swollman 4942708Swollmanstatic const char * 4952708Swollmangetsecs(strp, secsp) 49692889Sobrienconst char * strp; 4972708Swollmanlong * const secsp; 4982708Swollman{ 4992708Swollman int num; 5002708Swollman 5019936Swollman /* 5029936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 5039936Swollman ** "M10.4.6/26", which does not conform to Posix, 5049936Swollman ** but which specifies the equivalent of 5059936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 5069936Swollman */ 5079936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 5082708Swollman if (strp == NULL) 5092708Swollman return NULL; 5109936Swollman *secsp = num * (long) SECSPERHOUR; 5112708Swollman if (*strp == ':') { 5122708Swollman ++strp; 5132708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 5142708Swollman if (strp == NULL) 5152708Swollman return NULL; 5162708Swollman *secsp += num * SECSPERMIN; 5172708Swollman if (*strp == ':') { 5182708Swollman ++strp; 5199936Swollman /* `SECSPERMIN' allows for leap seconds. */ 5209936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 5212708Swollman if (strp == NULL) 5222708Swollman return NULL; 5232708Swollman *secsp += num; 5242708Swollman } 5252708Swollman } 5262708Swollman return strp; 5272708Swollman} 5282708Swollman 5292708Swollman/* 5302708Swollman** Given a pointer into a time zone string, extract an offset, in 5312708Swollman** [+-]hh[:mm[:ss]] form, from the string. 5322708Swollman** If any error occurs, return NULL. 5332708Swollman** Otherwise, return a pointer to the first character not part of the time. 5342708Swollman*/ 5352708Swollman 5362708Swollmanstatic const char * 5372708Swollmangetoffset(strp, offsetp) 53892889Sobrienconst char * strp; 5392708Swollmanlong * const offsetp; 5402708Swollman{ 54192889Sobrien int neg = 0; 5422708Swollman 5432708Swollman if (*strp == '-') { 5442708Swollman neg = 1; 5452708Swollman ++strp; 54617209Swollman } else if (*strp == '+') 54717209Swollman ++strp; 5482708Swollman strp = getsecs(strp, offsetp); 5492708Swollman if (strp == NULL) 5502708Swollman return NULL; /* illegal time */ 5512708Swollman if (neg) 5522708Swollman *offsetp = -*offsetp; 5532708Swollman return strp; 5542708Swollman} 5552708Swollman 5562708Swollman/* 5572708Swollman** Given a pointer into a time zone string, extract a rule in the form 5582708Swollman** date[/time]. See POSIX section 8 for the format of "date" and "time". 5592708Swollman** If a valid rule is not found, return NULL. 5602708Swollman** Otherwise, return a pointer to the first character not part of the rule. 5612708Swollman*/ 5622708Swollman 5632708Swollmanstatic const char * 5642708Swollmangetrule(strp, rulep) 5652708Swollmanconst char * strp; 56692889Sobrienstruct rule * const rulep; 5672708Swollman{ 5682708Swollman if (*strp == 'J') { 5692708Swollman /* 5702708Swollman ** Julian day. 5712708Swollman */ 5722708Swollman rulep->r_type = JULIAN_DAY; 5732708Swollman ++strp; 5742708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 5752708Swollman } else if (*strp == 'M') { 5762708Swollman /* 5772708Swollman ** Month, week, day. 5782708Swollman */ 5792708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 5802708Swollman ++strp; 5812708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 5822708Swollman if (strp == NULL) 5832708Swollman return NULL; 5842708Swollman if (*strp++ != '.') 5852708Swollman return NULL; 5862708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 5872708Swollman if (strp == NULL) 5882708Swollman return NULL; 5892708Swollman if (*strp++ != '.') 5902708Swollman return NULL; 5912708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 59217209Swollman } else if (is_digit(*strp)) { 5932708Swollman /* 5942708Swollman ** Day of year. 5952708Swollman */ 5962708Swollman rulep->r_type = DAY_OF_YEAR; 5972708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 5982708Swollman } else return NULL; /* invalid format */ 5992708Swollman if (strp == NULL) 6002708Swollman return NULL; 6012708Swollman if (*strp == '/') { 6022708Swollman /* 6032708Swollman ** Time specified. 6042708Swollman */ 6052708Swollman ++strp; 6062708Swollman strp = getsecs(strp, &rulep->r_time); 6072708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 6082708Swollman return strp; 6092708Swollman} 6102708Swollman 6112708Swollman/* 6122708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 6132708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect, 6142708Swollman** calculate the Epoch-relative time that rule takes effect. 6152708Swollman*/ 6162708Swollman 6172708Swollmanstatic time_t 6182708Swollmantranstime(janfirst, year, rulep, offset) 6192708Swollmanconst time_t janfirst; 6202708Swollmanconst int year; 62192889Sobrienconst struct rule * const rulep; 6222708Swollmanconst long offset; 6232708Swollman{ 62492889Sobrien int leapyear; 62592889Sobrien time_t value; 62692889Sobrien int i; 6272708Swollman int d, m1, yy0, yy1, yy2, dow; 6282708Swollman 6299936Swollman INITIALIZE(value); 6302708Swollman leapyear = isleap(year); 6312708Swollman switch (rulep->r_type) { 6322708Swollman 6332708Swollman case JULIAN_DAY: 6342708Swollman /* 6352708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 6362708Swollman ** years. 6372708Swollman ** In non-leap years, or if the day number is 59 or less, just 6382708Swollman ** add SECSPERDAY times the day number-1 to the time of 6392708Swollman ** January 1, midnight, to get the day. 6402708Swollman */ 6412708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 6422708Swollman if (leapyear && rulep->r_day >= 60) 6432708Swollman value += SECSPERDAY; 6442708Swollman break; 6452708Swollman 6462708Swollman case DAY_OF_YEAR: 6472708Swollman /* 6482708Swollman ** n - day of year. 6492708Swollman ** Just add SECSPERDAY times the day number to the time of 6502708Swollman ** January 1, midnight, to get the day. 6512708Swollman */ 6522708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 6532708Swollman break; 6542708Swollman 6552708Swollman case MONTH_NTH_DAY_OF_WEEK: 6562708Swollman /* 6572708Swollman ** Mm.n.d - nth "dth day" of month m. 6582708Swollman */ 6592708Swollman value = janfirst; 6602708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 6612708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 6622708Swollman 6632708Swollman /* 6642708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 6652708Swollman ** month. 6662708Swollman */ 6672708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 6682708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 6692708Swollman yy1 = yy0 / 100; 6702708Swollman yy2 = yy0 % 100; 6712708Swollman dow = ((26 * m1 - 2) / 10 + 6722708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 6732708Swollman if (dow < 0) 6742708Swollman dow += DAYSPERWEEK; 6752708Swollman 6762708Swollman /* 6772708Swollman ** "dow" is the day-of-week of the first day of the month. Get 6782708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 6792708Swollman ** month. 6802708Swollman */ 6812708Swollman d = rulep->r_day - dow; 6822708Swollman if (d < 0) 6832708Swollman d += DAYSPERWEEK; 6842708Swollman for (i = 1; i < rulep->r_week; ++i) { 6852708Swollman if (d + DAYSPERWEEK >= 6862708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 6872708Swollman break; 6882708Swollman d += DAYSPERWEEK; 6892708Swollman } 6902708Swollman 6912708Swollman /* 6922708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 6932708Swollman */ 6942708Swollman value += d * SECSPERDAY; 6952708Swollman break; 6962708Swollman } 6972708Swollman 6982708Swollman /* 6992708Swollman ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 7002708Swollman ** question. To get the Epoch-relative time of the specified local 7012708Swollman ** time on that day, add the transition time and the current offset 7022708Swollman ** from GMT. 7032708Swollman */ 7042708Swollman return value + rulep->r_time + offset; 7052708Swollman} 7062708Swollman 7072708Swollman/* 7082708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 7092708Swollman** appropriate. 7102708Swollman*/ 7112708Swollman 7122708Swollmanstatic int 7132708Swollmantzparse(name, sp, lastditch) 7142708Swollmanconst char * name; 71592889Sobrienstruct state * const sp; 7162708Swollmanconst int lastditch; 7172708Swollman{ 7182708Swollman const char * stdname; 7192708Swollman const char * dstname; 7209936Swollman size_t stdlen; 7219936Swollman size_t dstlen; 7222708Swollman long stdoffset; 7232708Swollman long dstoffset; 72492889Sobrien time_t * atp; 72592889Sobrien unsigned char * typep; 72692889Sobrien char * cp; 72792889Sobrien int load_result; 7282708Swollman 7299936Swollman INITIALIZE(dstname); 7302708Swollman stdname = name; 7312708Swollman if (lastditch) { 7322708Swollman stdlen = strlen(name); /* length of standard zone name */ 7332708Swollman name += stdlen; 7342708Swollman if (stdlen >= sizeof sp->chars) 7352708Swollman stdlen = (sizeof sp->chars) - 1; 73621659Swollman stdoffset = 0; 7372708Swollman } else { 7382708Swollman name = getzname(name); 7392708Swollman stdlen = name - stdname; 7402708Swollman if (stdlen < 3) 7412708Swollman return -1; 74221659Swollman if (*name == '\0') 74321659Swollman return -1; /* was "stdoffset = 0;" */ 74421659Swollman else { 74521659Swollman name = getoffset(name, &stdoffset); 74621659Swollman if (name == NULL) 74721659Swollman return -1; 74821659Swollman } 7492708Swollman } 7502708Swollman load_result = tzload(TZDEFRULES, sp); 7512708Swollman if (load_result != 0) 7522708Swollman sp->leapcnt = 0; /* so, we're off a little */ 7532708Swollman if (*name != '\0') { 7542708Swollman dstname = name; 7552708Swollman name = getzname(name); 7562708Swollman dstlen = name - dstname; /* length of DST zone name */ 7572708Swollman if (dstlen < 3) 7582708Swollman return -1; 7592708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 7602708Swollman name = getoffset(name, &dstoffset); 7612708Swollman if (name == NULL) 7622708Swollman return -1; 7632708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 7642708Swollman if (*name == ',' || *name == ';') { 7652708Swollman struct rule start; 7662708Swollman struct rule end; 76792889Sobrien int year; 76892889Sobrien time_t janfirst; 7692708Swollman time_t starttime; 7702708Swollman time_t endtime; 7712708Swollman 7722708Swollman ++name; 7732708Swollman if ((name = getrule(name, &start)) == NULL) 7742708Swollman return -1; 7752708Swollman if (*name++ != ',') 7762708Swollman return -1; 7772708Swollman if ((name = getrule(name, &end)) == NULL) 7782708Swollman return -1; 7792708Swollman if (*name != '\0') 7802708Swollman return -1; 7812708Swollman sp->typecnt = 2; /* standard time and DST */ 7822708Swollman /* 7832708Swollman ** Two transitions per year, from EPOCH_YEAR to 2037. 7842708Swollman */ 7852708Swollman sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 7862708Swollman if (sp->timecnt > TZ_MAX_TIMES) 7872708Swollman return -1; 7882708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 7892708Swollman sp->ttis[0].tt_isdst = 1; 7902708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 7912708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 7922708Swollman sp->ttis[1].tt_isdst = 0; 7932708Swollman sp->ttis[1].tt_abbrind = 0; 7942708Swollman atp = sp->ats; 7952708Swollman typep = sp->types; 7962708Swollman janfirst = 0; 7972708Swollman for (year = EPOCH_YEAR; year <= 2037; ++year) { 7982708Swollman starttime = transtime(janfirst, year, &start, 7992708Swollman stdoffset); 8002708Swollman endtime = transtime(janfirst, year, &end, 8012708Swollman dstoffset); 8022708Swollman if (starttime > endtime) { 8032708Swollman *atp++ = endtime; 8042708Swollman *typep++ = 1; /* DST ends */ 8052708Swollman *atp++ = starttime; 8062708Swollman *typep++ = 0; /* DST begins */ 8072708Swollman } else { 8082708Swollman *atp++ = starttime; 8092708Swollman *typep++ = 0; /* DST begins */ 8102708Swollman *atp++ = endtime; 8112708Swollman *typep++ = 1; /* DST ends */ 8122708Swollman } 8132708Swollman janfirst += year_lengths[isleap(year)] * 8142708Swollman SECSPERDAY; 8152708Swollman } 8162708Swollman } else { 81792889Sobrien long theirstdoffset; 81892889Sobrien long theirdstoffset; 81992889Sobrien long theiroffset; 82092889Sobrien int isdst; 82192889Sobrien int i; 82292889Sobrien int j; 8232708Swollman 8242708Swollman if (*name != '\0') 8252708Swollman return -1; 8262708Swollman if (load_result != 0) 8272708Swollman return -1; 8282708Swollman /* 8299936Swollman ** Initial values of theirstdoffset and theirdstoffset. 8302708Swollman */ 8319936Swollman theirstdoffset = 0; 8329936Swollman for (i = 0; i < sp->timecnt; ++i) { 8339936Swollman j = sp->types[i]; 8349936Swollman if (!sp->ttis[j].tt_isdst) { 83517209Swollman theirstdoffset = 83617209Swollman -sp->ttis[j].tt_gmtoff; 8379936Swollman break; 8382708Swollman } 8392708Swollman } 8409936Swollman theirdstoffset = 0; 8419936Swollman for (i = 0; i < sp->timecnt; ++i) { 8429936Swollman j = sp->types[i]; 8439936Swollman if (sp->ttis[j].tt_isdst) { 84417209Swollman theirdstoffset = 84517209Swollman -sp->ttis[j].tt_gmtoff; 8469936Swollman break; 8479936Swollman } 8489936Swollman } 8492708Swollman /* 8509936Swollman ** Initially we're assumed to be in standard time. 8512708Swollman */ 8529936Swollman isdst = FALSE; 8539936Swollman theiroffset = theirstdoffset; 8542708Swollman /* 8559936Swollman ** Now juggle transition times and types 8569936Swollman ** tracking offsets as you do. 8572708Swollman */ 8582708Swollman for (i = 0; i < sp->timecnt; ++i) { 8599936Swollman j = sp->types[i]; 8609936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 8619936Swollman if (sp->ttis[j].tt_ttisgmt) { 8629936Swollman /* No adjustment to transition time */ 8639936Swollman } else { 8649936Swollman /* 8659936Swollman ** If summer time is in effect, and the 8669936Swollman ** transition time was not specified as 8679936Swollman ** standard time, add the summer time 8689936Swollman ** offset to the transition time; 8699936Swollman ** otherwise, add the standard time 8709936Swollman ** offset to the transition time. 8719936Swollman */ 8729936Swollman /* 8739936Swollman ** Transitions from DST to DDST 8749936Swollman ** will effectively disappear since 8759936Swollman ** POSIX provides for only one DST 8769936Swollman ** offset. 8779936Swollman */ 8789936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 8799936Swollman sp->ats[i] += dstoffset - 8809936Swollman theirdstoffset; 8819936Swollman } else { 8829936Swollman sp->ats[i] += stdoffset - 8839936Swollman theirstdoffset; 8849936Swollman } 8859936Swollman } 8869936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 8879936Swollman if (sp->ttis[j].tt_isdst) 8889936Swollman theirdstoffset = theiroffset; 8899936Swollman else theirstdoffset = theiroffset; 8902708Swollman } 8919936Swollman /* 8929936Swollman ** Finally, fill in ttis. 8939936Swollman ** ttisstd and ttisgmt need not be handled. 8949936Swollman */ 8959936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8969936Swollman sp->ttis[0].tt_isdst = FALSE; 8979936Swollman sp->ttis[0].tt_abbrind = 0; 8989936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 8999936Swollman sp->ttis[1].tt_isdst = TRUE; 9009936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 9012708Swollman } 9022708Swollman } else { 9032708Swollman dstlen = 0; 9042708Swollman sp->typecnt = 1; /* only standard time */ 9052708Swollman sp->timecnt = 0; 9062708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 9072708Swollman sp->ttis[0].tt_isdst = 0; 9082708Swollman sp->ttis[0].tt_abbrind = 0; 9092708Swollman } 9102708Swollman sp->charcnt = stdlen + 1; 9112708Swollman if (dstlen != 0) 9122708Swollman sp->charcnt += dstlen + 1; 9132708Swollman if (sp->charcnt > sizeof sp->chars) 9142708Swollman return -1; 9152708Swollman cp = sp->chars; 9162708Swollman (void) strncpy(cp, stdname, stdlen); 9172708Swollman cp += stdlen; 9182708Swollman *cp++ = '\0'; 9192708Swollman if (dstlen != 0) { 9202708Swollman (void) strncpy(cp, dstname, dstlen); 9212708Swollman *(cp + dstlen) = '\0'; 9222708Swollman } 9232708Swollman return 0; 9242708Swollman} 9252708Swollman 9262708Swollmanstatic void 9272708Swollmangmtload(sp) 9282708Swollmanstruct state * const sp; 9292708Swollman{ 9309936Swollman if (tzload(gmt, sp) != 0) 9319936Swollman (void) tzparse(gmt, sp, TRUE); 9322708Swollman} 9332708Swollman 93471579Sdeischenstatic void 93571579Sdeischentzsetwall_basic(void) 9362708Swollman{ 9379936Swollman if (lcl_is_set < 0) 9389936Swollman return; 9399936Swollman lcl_is_set = -1; 9409936Swollman 9412708Swollman#ifdef ALL_STATE 9422708Swollman if (lclptr == NULL) { 9432708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9442708Swollman if (lclptr == NULL) { 9452708Swollman settzname(); /* all we can do */ 9462708Swollman return; 9472708Swollman } 9482708Swollman } 9492708Swollman#endif /* defined ALL_STATE */ 9502708Swollman if (tzload((char *) NULL, lclptr) != 0) 9512708Swollman gmtload(lclptr); 9522708Swollman settzname(); 9532708Swollman} 9542708Swollman 9552708Swollmanvoid 95697423Salfredtzsetwall(void) 95713545Sjulian{ 95871579Sdeischen _MUTEX_LOCK(&lcl_mutex); 95913545Sjulian tzsetwall_basic(); 96071579Sdeischen _MUTEX_UNLOCK(&lcl_mutex); 96113545Sjulian} 96213545Sjulian 96313545Sjulianstatic void 96471579Sdeischentzset_basic(void) 9652708Swollman{ 96692889Sobrien const char * name; 9672708Swollman 9682708Swollman name = getenv("TZ"); 9692708Swollman if (name == NULL) { 97072524Stegge tzsetwall_basic(); 9712708Swollman return; 9722708Swollman } 9739936Swollman 9749936Swollman if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) 9759936Swollman return; 9769936Swollman lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); 9779936Swollman if (lcl_is_set) 9789936Swollman (void) strcpy(lcl_TZname, name); 9799936Swollman 9802708Swollman#ifdef ALL_STATE 9812708Swollman if (lclptr == NULL) { 9822708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9832708Swollman if (lclptr == NULL) { 9842708Swollman settzname(); /* all we can do */ 9852708Swollman return; 9862708Swollman } 9872708Swollman } 9882708Swollman#endif /* defined ALL_STATE */ 9892708Swollman if (*name == '\0') { 9902708Swollman /* 9912708Swollman ** User wants it fast rather than right. 9922708Swollman */ 9932708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 9942708Swollman lclptr->timecnt = 0; 9952708Swollman lclptr->ttis[0].tt_gmtoff = 0; 9962708Swollman lclptr->ttis[0].tt_abbrind = 0; 9979936Swollman (void) strcpy(lclptr->chars, gmt); 9982708Swollman } else if (tzload(name, lclptr) != 0) 9992708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 10002708Swollman (void) gmtload(lclptr); 10012708Swollman settzname(); 10022708Swollman} 10032708Swollman 100413545Sjulianvoid 100597423Salfredtzset(void) 100613545Sjulian{ 100771579Sdeischen _MUTEX_LOCK(&lcl_mutex); 100813545Sjulian tzset_basic(); 100971579Sdeischen _MUTEX_UNLOCK(&lcl_mutex); 101013545Sjulian} 101113545Sjulian 10122708Swollman/* 10132708Swollman** The easy way to behave "as if no library function calls" localtime 10142708Swollman** is to not call it--so we drop its guts into "localsub", which can be 10152708Swollman** freely called. (And no, the PANS doesn't require the above behavior-- 10162708Swollman** but it *is* desirable.) 10172708Swollman** 10182708Swollman** The unused offset argument is for the benefit of mktime variants. 10192708Swollman*/ 10202708Swollman 10212708Swollman/*ARGSUSED*/ 10222708Swollmanstatic void 10232708Swollmanlocalsub(timep, offset, tmp) 10242708Swollmanconst time_t * const timep; 10252708Swollmanconst long offset; 10262708Swollmanstruct tm * const tmp; 10272708Swollman{ 102892889Sobrien struct state * sp; 102992889Sobrien const struct ttinfo * ttisp; 103092889Sobrien int i; 10312708Swollman const time_t t = *timep; 10322708Swollman 10332708Swollman sp = lclptr; 10342708Swollman#ifdef ALL_STATE 10352708Swollman if (sp == NULL) { 10362708Swollman gmtsub(timep, offset, tmp); 10372708Swollman return; 10382708Swollman } 10392708Swollman#endif /* defined ALL_STATE */ 10402708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 10412708Swollman i = 0; 10422708Swollman while (sp->ttis[i].tt_isdst) 10432708Swollman if (++i >= sp->typecnt) { 10442708Swollman i = 0; 10452708Swollman break; 10462708Swollman } 10472708Swollman } else { 10482708Swollman for (i = 1; i < sp->timecnt; ++i) 10492708Swollman if (t < sp->ats[i]) 10502708Swollman break; 10512708Swollman i = sp->types[i - 1]; 10522708Swollman } 10532708Swollman ttisp = &sp->ttis[i]; 10542708Swollman /* 10552708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 10562708Swollman ** you'd replace the statement below with 10572708Swollman ** t += ttisp->tt_gmtoff; 10582708Swollman ** timesub(&t, 0L, sp, tmp); 10592708Swollman */ 10602708Swollman timesub(&t, ttisp->tt_gmtoff, sp, tmp); 10612708Swollman tmp->tm_isdst = ttisp->tt_isdst; 10629936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 10632708Swollman#ifdef TM_ZONE 10649936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 10652708Swollman#endif /* defined TM_ZONE */ 10662708Swollman} 10672708Swollman 106819636Shsustruct tm * 106913545Sjulianlocaltime_r(timep, p_tm) 107013545Sjulianconst time_t * const timep; 107113545Sjulianstruct tm *p_tm; 107213545Sjulian{ 107371579Sdeischen _MUTEX_LOCK(&lcl_mutex); 107472524Stegge tzset_basic(); 107513545Sjulian localsub(timep, 0L, p_tm); 107671579Sdeischen _MUTEX_UNLOCK(&lcl_mutex); 107719636Shsu return(p_tm); 107813545Sjulian} 107913545Sjulian 10802708Swollmanstruct tm * 10812708Swollmanlocaltime(timep) 10822708Swollmanconst time_t * const timep; 10832708Swollman{ 108471579Sdeischen static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 108513545Sjulian static pthread_key_t localtime_key = -1; 108613545Sjulian struct tm *p_tm; 108713545Sjulian 108871579Sdeischen if (__isthreaded != 0) { 108971579Sdeischen _pthread_mutex_lock(&localtime_mutex); 109071579Sdeischen if (localtime_key < 0) { 109171579Sdeischen if (_pthread_key_create(&localtime_key, free) < 0) { 109271579Sdeischen _pthread_mutex_unlock(&localtime_mutex); 109371579Sdeischen return(NULL); 109471579Sdeischen } 109513545Sjulian } 109671579Sdeischen _pthread_mutex_unlock(&localtime_mutex); 109771579Sdeischen p_tm = _pthread_getspecific(localtime_key); 109871579Sdeischen if (p_tm == NULL) { 109971579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 110071579Sdeischen == NULL) 110171579Sdeischen return(NULL); 110271579Sdeischen _pthread_setspecific(localtime_key, p_tm); 110371579Sdeischen } 110471579Sdeischen _pthread_mutex_lock(&lcl_mutex); 110572524Stegge tzset_basic(); 110671579Sdeischen localsub(timep, 0L, p_tm); 110771579Sdeischen _pthread_mutex_unlock(&lcl_mutex); 110871579Sdeischen return(p_tm); 110971579Sdeischen } else { 111072524Stegge tzset_basic(); 111171579Sdeischen localsub(timep, 0L, &tm); 111271579Sdeischen return(&tm); 111313545Sjulian } 11142708Swollman} 11152708Swollman 11162708Swollman/* 11172708Swollman** gmtsub is to gmtime as localsub is to localtime. 11182708Swollman*/ 11192708Swollman 11202708Swollmanstatic void 11212708Swollmangmtsub(timep, offset, tmp) 11222708Swollmanconst time_t * const timep; 11232708Swollmanconst long offset; 11242708Swollmanstruct tm * const tmp; 11252708Swollman{ 112671579Sdeischen _MUTEX_LOCK(&gmt_mutex); 11272708Swollman if (!gmt_is_set) { 11282708Swollman gmt_is_set = TRUE; 11292708Swollman#ifdef ALL_STATE 11302708Swollman gmtptr = (struct state *) malloc(sizeof *gmtptr); 11312708Swollman if (gmtptr != NULL) 11322708Swollman#endif /* defined ALL_STATE */ 11332708Swollman gmtload(gmtptr); 11342708Swollman } 113571579Sdeischen _MUTEX_UNLOCK(&gmt_mutex); 11362708Swollman timesub(timep, offset, gmtptr, tmp); 11372708Swollman#ifdef TM_ZONE 11382708Swollman /* 11392708Swollman ** Could get fancy here and deliver something such as 11402708Swollman ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 11412708Swollman ** but this is no time for a treasure hunt. 11422708Swollman */ 11432708Swollman if (offset != 0) 11449936Swollman tmp->TM_ZONE = wildabbr; 11452708Swollman else { 11462708Swollman#ifdef ALL_STATE 11472708Swollman if (gmtptr == NULL) 11489936Swollman tmp->TM_ZONE = gmt; 11492708Swollman else tmp->TM_ZONE = gmtptr->chars; 11502708Swollman#endif /* defined ALL_STATE */ 11512708Swollman#ifndef ALL_STATE 11522708Swollman tmp->TM_ZONE = gmtptr->chars; 11532708Swollman#endif /* State Farm */ 11542708Swollman } 11552708Swollman#endif /* defined TM_ZONE */ 11562708Swollman} 11572708Swollman 11582708Swollmanstruct tm * 11592708Swollmangmtime(timep) 11602708Swollmanconst time_t * const timep; 11612708Swollman{ 116271579Sdeischen static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 116313545Sjulian static pthread_key_t gmtime_key = -1; 116413545Sjulian struct tm *p_tm; 116513545Sjulian 116671579Sdeischen if (__isthreaded != 0) { 116771579Sdeischen _pthread_mutex_lock(&gmtime_mutex); 116871579Sdeischen if (gmtime_key < 0) { 116971579Sdeischen if (_pthread_key_create(&gmtime_key, free) < 0) { 117071579Sdeischen _pthread_mutex_unlock(&gmtime_mutex); 117171579Sdeischen return(NULL); 117271579Sdeischen } 117313545Sjulian } 117471579Sdeischen _pthread_mutex_unlock(&gmtime_mutex); 117571579Sdeischen /* 117671579Sdeischen * Changed to follow POSIX.1 threads standard, which 117771579Sdeischen * is what BSD currently has. 117871579Sdeischen */ 117971579Sdeischen if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { 118071579Sdeischen if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) 118171579Sdeischen == NULL) { 118271579Sdeischen return(NULL); 118371579Sdeischen } 118471579Sdeischen _pthread_setspecific(gmtime_key, p_tm); 118513545Sjulian } 118671579Sdeischen gmtsub(timep, 0L, p_tm); 118771579Sdeischen return(p_tm); 118813545Sjulian } 118971579Sdeischen else { 119071579Sdeischen gmtsub(timep, 0L, &tm); 119171579Sdeischen return(&tm); 119271579Sdeischen } 11932708Swollman} 11942708Swollman 119519636Shsustruct tm * 119613545Sjuliangmtime_r(const time_t * timep, struct tm * tm) 119713545Sjulian{ 119813545Sjulian gmtsub(timep, 0L, tm); 119919636Shsu return(tm); 120013545Sjulian} 120113545Sjulian 12022708Swollman#ifdef STD_INSPIRED 12032708Swollman 12042708Swollmanstruct tm * 12052708Swollmanofftime(timep, offset) 12062708Swollmanconst time_t * const timep; 12072708Swollmanconst long offset; 12082708Swollman{ 12092708Swollman gmtsub(timep, offset, &tm); 12102708Swollman return &tm; 12112708Swollman} 12122708Swollman 12132708Swollman#endif /* defined STD_INSPIRED */ 12142708Swollman 12152708Swollmanstatic void 12162708Swollmantimesub(timep, offset, sp, tmp) 12172708Swollmanconst time_t * const timep; 12182708Swollmanconst long offset; 121992889Sobrienconst struct state * const sp; 122092889Sobrienstruct tm * const tmp; 12212708Swollman{ 122292889Sobrien const struct lsinfo * lp; 122392889Sobrien long days; 122492889Sobrien long rem; 122592889Sobrien int y; 122692889Sobrien int yleap; 122792889Sobrien const int * ip; 122892889Sobrien long corr; 122992889Sobrien int hit; 123092889Sobrien int i; 12312708Swollman 12322708Swollman corr = 0; 12332708Swollman hit = 0; 12342708Swollman#ifdef ALL_STATE 12352708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 12362708Swollman#endif /* defined ALL_STATE */ 12372708Swollman#ifndef ALL_STATE 12382708Swollman i = sp->leapcnt; 12392708Swollman#endif /* State Farm */ 12402708Swollman while (--i >= 0) { 12412708Swollman lp = &sp->lsis[i]; 12422708Swollman if (*timep >= lp->ls_trans) { 12432708Swollman if (*timep == lp->ls_trans) { 12442708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 12452708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 12462708Swollman if (hit) 12472708Swollman while (i > 0 && 12482708Swollman sp->lsis[i].ls_trans == 12492708Swollman sp->lsis[i - 1].ls_trans + 1 && 12502708Swollman sp->lsis[i].ls_corr == 12512708Swollman sp->lsis[i - 1].ls_corr + 1) { 12522708Swollman ++hit; 12532708Swollman --i; 12542708Swollman } 12552708Swollman } 12562708Swollman corr = lp->ls_corr; 12572708Swollman break; 12582708Swollman } 12592708Swollman } 12602708Swollman days = *timep / SECSPERDAY; 12612708Swollman rem = *timep % SECSPERDAY; 12622708Swollman#ifdef mc68k 12632708Swollman if (*timep == 0x80000000) { 12642708Swollman /* 12652708Swollman ** A 3B1 muffs the division on the most negative number. 12662708Swollman */ 12672708Swollman days = -24855; 12682708Swollman rem = -11648; 12692708Swollman } 12709936Swollman#endif /* defined mc68k */ 12712708Swollman rem += (offset - corr); 12722708Swollman while (rem < 0) { 12732708Swollman rem += SECSPERDAY; 12742708Swollman --days; 12752708Swollman } 12762708Swollman while (rem >= SECSPERDAY) { 12772708Swollman rem -= SECSPERDAY; 12782708Swollman ++days; 12792708Swollman } 12802708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 12812708Swollman rem = rem % SECSPERHOUR; 12822708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 128317209Swollman /* 128417209Swollman ** A positive leap second requires a special 128517209Swollman ** representation. This uses "... ??:59:60" et seq. 128617209Swollman */ 128717209Swollman tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 12882708Swollman tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 12892708Swollman if (tmp->tm_wday < 0) 12902708Swollman tmp->tm_wday += DAYSPERWEEK; 12912708Swollman y = EPOCH_YEAR; 129217209Swollman#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) 129317209Swollman while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { 129492889Sobrien int newy; 129517209Swollman 129617209Swollman newy = y + days / DAYSPERNYEAR; 129717209Swollman if (days < 0) 129817209Swollman --newy; 129917209Swollman days -= (newy - y) * DAYSPERNYEAR + 130017209Swollman LEAPS_THRU_END_OF(newy - 1) - 130117209Swollman LEAPS_THRU_END_OF(y - 1); 130217209Swollman y = newy; 130317209Swollman } 13042708Swollman tmp->tm_year = y - TM_YEAR_BASE; 13052708Swollman tmp->tm_yday = (int) days; 13062708Swollman ip = mon_lengths[yleap]; 13072708Swollman for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 13082708Swollman days = days - (long) ip[tmp->tm_mon]; 13092708Swollman tmp->tm_mday = (int) (days + 1); 13102708Swollman tmp->tm_isdst = 0; 13112708Swollman#ifdef TM_GMTOFF 13122708Swollman tmp->TM_GMTOFF = offset; 13132708Swollman#endif /* defined TM_GMTOFF */ 13142708Swollman} 13152708Swollman 13162708Swollmanchar * 13172708Swollmanctime(timep) 13182708Swollmanconst time_t * const timep; 13192708Swollman{ 13209936Swollman/* 13219936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 13229936Swollman** The ctime funciton converts the calendar time pointed to by timer 13239936Swollman** to local time in the form of a string. It is equivalent to 13249936Swollman** asctime(localtime(timer)) 13259936Swollman*/ 13262708Swollman return asctime(localtime(timep)); 13272708Swollman} 13282708Swollman 132935285Sphkchar * 133035285Sphkctime_r(timep, buf) 133135285Sphkconst time_t * const timep; 133235285Sphkchar *buf; 133335285Sphk{ 133435285Sphk struct tm tm; 133535285Sphk return asctime_r(localtime_r(timep, &tm), buf); 133635285Sphk} 133735285Sphk 13382708Swollman/* 13392708Swollman** Adapted from code provided by Robert Elz, who writes: 13402708Swollman** The "best" way to do mktime I think is based on an idea of Bob 134117209Swollman** Kridle's (so its said...) from a long time ago. 134217209Swollman** [kridle@xinet.com as of 1996-01-16.] 13432708Swollman** It does a binary search of the time_t space. Since time_t's are 13442708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 13452708Swollman** would still be very reasonable). 13462708Swollman*/ 13472708Swollman 13482708Swollman#ifndef WRONG 13492708Swollman#define WRONG (-1) 13502708Swollman#endif /* !defined WRONG */ 13512708Swollman 13522708Swollman/* 13532708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 13542708Swollman*/ 13552708Swollman 13562708Swollmanstatic int 13572708Swollmanincrement_overflow(number, delta) 13582708Swollmanint * number; 13592708Swollmanint delta; 13602708Swollman{ 13619936Swollman int number0; 13628870Srgrimes 13632708Swollman number0 = *number; 13642708Swollman *number += delta; 13652708Swollman return (*number < number0) != (delta < 0); 13662708Swollman} 13672708Swollman 13682708Swollmanstatic int 13692708Swollmannormalize_overflow(tensptr, unitsptr, base) 13702708Swollmanint * const tensptr; 13712708Swollmanint * const unitsptr; 13722708Swollmanconst int base; 13732708Swollman{ 137492889Sobrien int tensdelta; 13752708Swollman 13762708Swollman tensdelta = (*unitsptr >= 0) ? 13772708Swollman (*unitsptr / base) : 13782708Swollman (-1 - (-1 - *unitsptr) / base); 13792708Swollman *unitsptr -= tensdelta * base; 13802708Swollman return increment_overflow(tensptr, tensdelta); 13812708Swollman} 13822708Swollman 13832708Swollmanstatic int 13842708Swollmantmcomp(atmp, btmp) 138592889Sobrienconst struct tm * const atmp; 138692889Sobrienconst struct tm * const btmp; 13872708Swollman{ 138892889Sobrien int result; 13892708Swollman 13902708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 13912708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 13922708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 13932708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 13942708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 13952708Swollman result = atmp->tm_sec - btmp->tm_sec; 13962708Swollman return result; 13972708Swollman} 13982708Swollman 13992708Swollmanstatic time_t 14002708Swollmantime2(tmp, funcp, offset, okayp) 14012708Swollmanstruct tm * const tmp; 140297423Salfredvoid (* const funcp)(const time_t*, long, struct tm*); 14032708Swollmanconst long offset; 14042708Swollmanint * const okayp; 14052708Swollman{ 140692889Sobrien const struct state * sp; 140792889Sobrien int dir; 140892889Sobrien int bits; 140992889Sobrien int i, j ; 141092889Sobrien int saved_seconds; 14112708Swollman time_t newt; 14122708Swollman time_t t; 14132708Swollman struct tm yourtm, mytm; 14142708Swollman 14152708Swollman *okayp = FALSE; 14162708Swollman yourtm = *tmp; 14172708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 14182708Swollman return WRONG; 14192708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 14202708Swollman return WRONG; 14212708Swollman if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 14222708Swollman return WRONG; 14232708Swollman /* 14242708Swollman ** Turn yourtm.tm_year into an actual year number for now. 14252708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 14262708Swollman */ 14272708Swollman if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 14282708Swollman return WRONG; 14292708Swollman while (yourtm.tm_mday <= 0) { 14302708Swollman if (increment_overflow(&yourtm.tm_year, -1)) 14312708Swollman return WRONG; 143217209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 143317209Swollman yourtm.tm_mday += year_lengths[isleap(i)]; 14342708Swollman } 14352708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 143617209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 143717209Swollman yourtm.tm_mday -= year_lengths[isleap(i)]; 14382708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14392708Swollman return WRONG; 14402708Swollman } 14412708Swollman for ( ; ; ) { 14422708Swollman i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 14432708Swollman if (yourtm.tm_mday <= i) 14442708Swollman break; 14452708Swollman yourtm.tm_mday -= i; 14462708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 14472708Swollman yourtm.tm_mon = 0; 14482708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14492708Swollman return WRONG; 14502708Swollman } 14512708Swollman } 14522708Swollman if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 14532708Swollman return WRONG; 145477785Swollman if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) 145577785Swollman saved_seconds = 0; 145677785Swollman else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 14572708Swollman /* 14582708Swollman ** We can't set tm_sec to 0, because that might push the 14592708Swollman ** time below the minimum representable time. 14602708Swollman ** Set tm_sec to 59 instead. 14612708Swollman ** This assumes that the minimum representable time is 14622708Swollman ** not in the same minute that a leap second was deleted from, 14632708Swollman ** which is a safer assumption than using 58 would be. 14642708Swollman */ 14652708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 14662708Swollman return WRONG; 14672708Swollman saved_seconds = yourtm.tm_sec; 14682708Swollman yourtm.tm_sec = SECSPERMIN - 1; 14692708Swollman } else { 14702708Swollman saved_seconds = yourtm.tm_sec; 14712708Swollman yourtm.tm_sec = 0; 14722708Swollman } 14732708Swollman /* 147417209Swollman ** Divide the search space in half 147517209Swollman ** (this works whether time_t is signed or unsigned). 14762708Swollman */ 147717209Swollman bits = TYPE_BIT(time_t) - 1; 14782708Swollman /* 147917209Swollman ** If time_t is signed, then 0 is just above the median, 148017209Swollman ** assuming two's complement arithmetic. 148117209Swollman ** If time_t is unsigned, then (1 << bits) is just above the median. 14822708Swollman */ 148317209Swollman t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); 14842708Swollman for ( ; ; ) { 14852708Swollman (*funcp)(&t, offset, &mytm); 14862708Swollman dir = tmcomp(&mytm, &yourtm); 14872708Swollman if (dir != 0) { 14882708Swollman if (bits-- < 0) 14892708Swollman return WRONG; 14902708Swollman if (bits < 0) 149117209Swollman --t; /* may be needed if new t is minimal */ 14922708Swollman else if (dir > 0) 149317209Swollman t -= ((time_t) 1) << bits; 149417209Swollman else t += ((time_t) 1) << bits; 14952708Swollman continue; 14962708Swollman } 14972708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 14982708Swollman break; 14992708Swollman /* 15002708Swollman ** Right time, wrong type. 15012708Swollman ** Hunt for right time, right type. 15022708Swollman ** It's okay to guess wrong since the guess 15032708Swollman ** gets checked. 15042708Swollman */ 15052708Swollman /* 15062708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15072708Swollman */ 15082708Swollman sp = (const struct state *) 15092708Swollman (((void *) funcp == (void *) localsub) ? 15102708Swollman lclptr : gmtptr); 15112708Swollman#ifdef ALL_STATE 15122708Swollman if (sp == NULL) 15132708Swollman return WRONG; 15142708Swollman#endif /* defined ALL_STATE */ 151517209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 15162708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 15172708Swollman continue; 151817209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 15192708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 15202708Swollman continue; 15212708Swollman newt = t + sp->ttis[j].tt_gmtoff - 15222708Swollman sp->ttis[i].tt_gmtoff; 15232708Swollman (*funcp)(&newt, offset, &mytm); 15242708Swollman if (tmcomp(&mytm, &yourtm) != 0) 15252708Swollman continue; 15262708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 15272708Swollman continue; 15282708Swollman /* 15292708Swollman ** We have a match. 15302708Swollman */ 15312708Swollman t = newt; 15322708Swollman goto label; 15332708Swollman } 15342708Swollman } 15352708Swollman return WRONG; 15362708Swollman } 15372708Swollmanlabel: 15382708Swollman newt = t + saved_seconds; 15392708Swollman if ((newt < t) != (saved_seconds < 0)) 15402708Swollman return WRONG; 15412708Swollman t = newt; 15422708Swollman (*funcp)(&t, offset, tmp); 15432708Swollman *okayp = TRUE; 15442708Swollman return t; 15452708Swollman} 15462708Swollman 15472708Swollmanstatic time_t 15482708Swollmantime1(tmp, funcp, offset) 15492708Swollmanstruct tm * const tmp; 155097423Salfredvoid (* const funcp)(const time_t *, long, struct tm *); 15512708Swollmanconst long offset; 15522708Swollman{ 155392889Sobrien time_t t; 155492889Sobrien const struct state * sp; 155592889Sobrien int samei, otheri; 15562708Swollman int okay; 15572708Swollman 15582708Swollman if (tmp->tm_isdst > 1) 15592708Swollman tmp->tm_isdst = 1; 15602708Swollman t = time2(tmp, funcp, offset, &okay); 15612708Swollman#ifdef PCTS 15622708Swollman /* 15632708Swollman ** PCTS code courtesy Grant Sullivan (grant@osf.org). 15642708Swollman */ 15652708Swollman if (okay) 15662708Swollman return t; 15672708Swollman if (tmp->tm_isdst < 0) 15682708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 15692708Swollman#endif /* defined PCTS */ 15702708Swollman#ifndef PCTS 15712708Swollman if (okay || tmp->tm_isdst < 0) 15722708Swollman return t; 15732708Swollman#endif /* !defined PCTS */ 15742708Swollman /* 15752708Swollman ** We're supposed to assume that somebody took a time of one type 15762708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 15772708Swollman ** We try to divine the type they started from and adjust to the 15782708Swollman ** type they need. 15792708Swollman */ 15802708Swollman /* 15812708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15822708Swollman */ 15832708Swollman sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 15842708Swollman lclptr : gmtptr); 15852708Swollman#ifdef ALL_STATE 15862708Swollman if (sp == NULL) 15872708Swollman return WRONG; 15882708Swollman#endif /* defined ALL_STATE */ 158917209Swollman for (samei = sp->typecnt - 1; samei >= 0; --samei) { 15902708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 15912708Swollman continue; 159217209Swollman for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { 15932708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 15942708Swollman continue; 15952708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 15962708Swollman sp->ttis[samei].tt_gmtoff; 15972708Swollman tmp->tm_isdst = !tmp->tm_isdst; 15982708Swollman t = time2(tmp, funcp, offset, &okay); 15992708Swollman if (okay) 16002708Swollman return t; 16012708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 16022708Swollman sp->ttis[samei].tt_gmtoff; 16032708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16042708Swollman } 16052708Swollman } 16062708Swollman return WRONG; 16072708Swollman} 16082708Swollman 16092708Swollmantime_t 16102708Swollmanmktime(tmp) 16112708Swollmanstruct tm * const tmp; 16122708Swollman{ 161313545Sjulian time_t mktime_return_value; 161471579Sdeischen _MUTEX_LOCK(&lcl_mutex); 161572524Stegge tzset_basic(); 161613545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 161771579Sdeischen _MUTEX_UNLOCK(&lcl_mutex); 161813545Sjulian return(mktime_return_value); 16192708Swollman} 16202708Swollman 16212708Swollman#ifdef STD_INSPIRED 16222708Swollman 16232708Swollmantime_t 16242708Swollmantimelocal(tmp) 16252708Swollmanstruct tm * const tmp; 16262708Swollman{ 16272708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 16282708Swollman return mktime(tmp); 16292708Swollman} 16302708Swollman 16312708Swollmantime_t 16322708Swollmantimegm(tmp) 16332708Swollmanstruct tm * const tmp; 16342708Swollman{ 16352708Swollman tmp->tm_isdst = 0; 16362708Swollman return time1(tmp, gmtsub, 0L); 16372708Swollman} 16382708Swollman 16392708Swollmantime_t 16402708Swollmantimeoff(tmp, offset) 16412708Swollmanstruct tm * const tmp; 16422708Swollmanconst long offset; 16432708Swollman{ 16442708Swollman tmp->tm_isdst = 0; 16452708Swollman return time1(tmp, gmtsub, offset); 16462708Swollman} 16472708Swollman 16482708Swollman#endif /* defined STD_INSPIRED */ 16492708Swollman 16502708Swollman#ifdef CMUCS 16512708Swollman 16522708Swollman/* 16532708Swollman** The following is supplied for compatibility with 16542708Swollman** previous versions of the CMUCS runtime library. 16552708Swollman*/ 16562708Swollman 16572708Swollmanlong 16582708Swollmangtime(tmp) 16592708Swollmanstruct tm * const tmp; 16602708Swollman{ 16612708Swollman const time_t t = mktime(tmp); 16622708Swollman 16632708Swollman if (t == WRONG) 16642708Swollman return -1; 16652708Swollman return t; 16662708Swollman} 16672708Swollman 16682708Swollman#endif /* defined CMUCS */ 16692708Swollman 16702708Swollman/* 16712708Swollman** XXX--is the below the right way to conditionalize?? 16722708Swollman*/ 16732708Swollman 16742708Swollman#ifdef STD_INSPIRED 16752708Swollman 16762708Swollman/* 16772708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 16782708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 16792708Swollman** is not the case if we are accounting for leap seconds. 16802708Swollman** So, we provide the following conversion routines for use 16812708Swollman** when exchanging timestamps with POSIX conforming systems. 16822708Swollman*/ 16832708Swollman 16842708Swollmanstatic long 16852708Swollmanleapcorr(timep) 16862708Swollmantime_t * timep; 16872708Swollman{ 168892889Sobrien struct state * sp; 168992889Sobrien struct lsinfo * lp; 169092889Sobrien int i; 16912708Swollman 16922708Swollman sp = lclptr; 16932708Swollman i = sp->leapcnt; 16942708Swollman while (--i >= 0) { 16952708Swollman lp = &sp->lsis[i]; 16962708Swollman if (*timep >= lp->ls_trans) 16972708Swollman return lp->ls_corr; 16982708Swollman } 16992708Swollman return 0; 17002708Swollman} 17012708Swollman 17022708Swollmantime_t 17032708Swollmantime2posix(t) 17042708Swollmantime_t t; 17052708Swollman{ 17069936Swollman tzset(); 17072708Swollman return t - leapcorr(&t); 17082708Swollman} 17092708Swollman 17102708Swollmantime_t 17112708Swollmanposix2time(t) 17122708Swollmantime_t t; 17132708Swollman{ 17142708Swollman time_t x; 17152708Swollman time_t y; 17162708Swollman 17179936Swollman tzset(); 17182708Swollman /* 17192708Swollman ** For a positive leap second hit, the result 17202708Swollman ** is not unique. For a negative leap second 17212708Swollman ** hit, the corresponding time doesn't exist, 17222708Swollman ** so we return an adjacent second. 17232708Swollman */ 17242708Swollman x = t + leapcorr(&t); 17252708Swollman y = x - leapcorr(&x); 17262708Swollman if (y < t) { 17272708Swollman do { 17282708Swollman x++; 17292708Swollman y = x - leapcorr(&x); 17302708Swollman } while (y < t); 17312708Swollman if (t != y) 17322708Swollman return x - 1; 17332708Swollman } else if (y > t) { 17342708Swollman do { 17352708Swollman --x; 17362708Swollman y = x - leapcorr(&x); 17372708Swollman } while (y > t); 17382708Swollman if (t != y) 17392708Swollman return x + 1; 17402708Swollman } 17412708Swollman return x; 17422708Swollman} 17432708Swollman 17442708Swollman#endif /* defined STD_INSPIRED */ 1745