localtime.c revision 17209
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 */ 112708Swollman 122708Swollman/* 132708Swollman** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 142708Swollman** POSIX-style TZ environment variable handling from Guy Harris 152708Swollman** (guy@auspex.com). 162708Swollman*/ 172708Swollman 182708Swollman/*LINTLIBRARY*/ 192708Swollman 202708Swollman#include "private.h" 212708Swollman#include "tzfile.h" 222708Swollman#include "fcntl.h" 2313545Sjulian#ifdef _THREAD_SAFE 2413545Sjulian#include <pthread.h> 2513545Sjulian#include "pthread_private.h" 2613545Sjulian#endif 272708Swollman 289936Swollman/* 299936Swollman** SunOS 4.1.1 headers lack O_BINARY. 309936Swollman*/ 312708Swollman 322708Swollman#ifdef O_BINARY 332708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 342708Swollman#endif /* defined O_BINARY */ 352708Swollman#ifndef O_BINARY 362708Swollman#define OPEN_MODE O_RDONLY 372708Swollman#endif /* !defined O_BINARY */ 382708Swollman 392708Swollman#ifndef WILDABBR 402708Swollman/* 412708Swollman** Someone might make incorrect use of a time zone abbreviation: 422708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 439936Swollman** or implicitly). 442708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 459936Swollman** or implicitly). 462708Swollman** 3. They might reference tzname[1] after setting to a time zone 472708Swollman** in which Daylight Saving Time is never observed. 482708Swollman** 4. They might reference tzname[0] after setting to a time zone 492708Swollman** in which Standard Time is never observed. 502708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 512708Swollman** What's best to do in the above cases is open to debate; 522708Swollman** for now, we just set things up so that in any of the five cases 532708Swollman** WILDABBR is used. Another possibility: initialize tzname[0] to the 542708Swollman** string "tzname[0] used before set", and similarly for the other cases. 552708Swollman** And another: initialize tzname[0] to "ERA", with an explanation in the 562708Swollman** manual page of what this "time zone abbreviation" means (doing this so 572708Swollman** that tzname[0] has the "normal" length of three characters). 582708Swollman*/ 592708Swollman#define WILDABBR " " 602708Swollman#endif /* !defined WILDABBR */ 612708Swollman 629936Swollmanstatic char wildabbr[] = "WILDABBR"; 632708Swollman 649936Swollmanstatic const char gmt[] = "GMT"; 659936Swollman 662708Swollmanstruct ttinfo { /* time type information */ 672708Swollman long tt_gmtoff; /* GMT offset in seconds */ 682708Swollman int tt_isdst; /* used to set tm_isdst */ 692708Swollman int tt_abbrind; /* abbreviation list index */ 702708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 719936Swollman int tt_ttisgmt; /* TRUE if transition is GMT */ 722708Swollman}; 732708Swollman 742708Swollmanstruct lsinfo { /* leap second information */ 752708Swollman time_t ls_trans; /* transition time */ 762708Swollman long ls_corr; /* correction to apply */ 772708Swollman}; 782708Swollman 792708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 802708Swollman 812708Swollman#ifdef TZNAME_MAX 822708Swollman#define MY_TZNAME_MAX TZNAME_MAX 832708Swollman#endif /* defined TZNAME_MAX */ 842708Swollman#ifndef TZNAME_MAX 852708Swollman#define MY_TZNAME_MAX 255 862708Swollman#endif /* !defined TZNAME_MAX */ 872708Swollman 882708Swollmanstruct state { 892708Swollman int leapcnt; 902708Swollman int timecnt; 912708Swollman int typecnt; 922708Swollman int charcnt; 932708Swollman time_t ats[TZ_MAX_TIMES]; 942708Swollman unsigned char types[TZ_MAX_TIMES]; 952708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 969936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 972708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 982708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 992708Swollman}; 1002708Swollman 1012708Swollmanstruct rule { 1022708Swollman int r_type; /* type of rule--see below */ 1032708Swollman int r_day; /* day number of rule */ 1042708Swollman int r_week; /* week number of rule */ 1052708Swollman int r_mon; /* month number of rule */ 1062708Swollman long r_time; /* transition time of rule */ 1072708Swollman}; 1082708Swollman 1092708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1102708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1112708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1122708Swollman 1132708Swollman/* 1142708Swollman** Prototypes for static functions. 1152708Swollman*/ 1162708Swollman 1172708Swollmanstatic long detzcode P((const char * codep)); 1182708Swollmanstatic const char * getzname P((const char * strp)); 1192708Swollmanstatic const char * getnum P((const char * strp, int * nump, int min, 1202708Swollman int max)); 1212708Swollmanstatic const char * getsecs P((const char * strp, long * secsp)); 1222708Swollmanstatic const char * getoffset P((const char * strp, long * offsetp)); 1232708Swollmanstatic const char * getrule P((const char * strp, struct rule * rulep)); 1242708Swollmanstatic void gmtload P((struct state * sp)); 1252708Swollmanstatic void gmtsub P((const time_t * timep, long offset, 1262708Swollman struct tm * tmp)); 1272708Swollmanstatic void localsub P((const time_t * timep, long offset, 1282708Swollman struct tm * tmp)); 1292708Swollmanstatic int increment_overflow P((int * number, int delta)); 1302708Swollmanstatic int normalize_overflow P((int * tensptr, int * unitsptr, 1312708Swollman int base)); 1322708Swollmanstatic void settzname P((void)); 1339936Swollmanstatic time_t time1 P((struct tm * tmp, 1349936Swollman void(*funcp) P((const time_t *, 1359936Swollman long, struct tm *)), 1362708Swollman long offset)); 1379936Swollmanstatic time_t time2 P((struct tm *tmp, 1389936Swollman void(*funcp) P((const time_t *, 1399936Swollman long, struct tm*)), 1402708Swollman long offset, int * okayp)); 1412708Swollmanstatic void timesub P((const time_t * timep, long offset, 1422708Swollman const struct state * sp, struct tm * tmp)); 1432708Swollmanstatic int tmcomp P((const struct tm * atmp, 1442708Swollman const struct tm * btmp)); 1452708Swollmanstatic time_t transtime P((time_t janfirst, int year, 1462708Swollman const struct rule * rulep, long offset)); 1472708Swollmanstatic int tzload P((const char * name, struct state * sp)); 1482708Swollmanstatic int tzparse P((const char * name, struct state * sp, 1492708Swollman int lastditch)); 1502708Swollman 1512708Swollman#ifdef ALL_STATE 1522708Swollmanstatic struct state * lclptr; 1532708Swollmanstatic struct state * gmtptr; 1542708Swollman#endif /* defined ALL_STATE */ 1552708Swollman 1562708Swollman#ifndef ALL_STATE 1572708Swollmanstatic struct state lclmem; 1582708Swollmanstatic struct state gmtmem; 1592708Swollman#define lclptr (&lclmem) 1602708Swollman#define gmtptr (&gmtmem) 1612708Swollman#endif /* State Farm */ 1622708Swollman 1639936Swollman#ifndef TZ_STRLEN_MAX 1649936Swollman#define TZ_STRLEN_MAX 255 1659936Swollman#endif /* !defined TZ_STRLEN_MAX */ 1669936Swollman 1679936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 1682708Swollmanstatic int lcl_is_set; 1692708Swollmanstatic int gmt_is_set; 17013545Sjulian#ifdef _THREAD_SAFE 17113545Sjulianstatic pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER; 17213545Sjulianstatic pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; 17313545Sjulian#endif 1742708Swollman 1752708Swollmanchar * tzname[2] = { 1769936Swollman wildabbr, 1779936Swollman wildabbr 1782708Swollman}; 1792708Swollman 1809936Swollman/* 1819936Swollman** Section 4.12.3 of X3.159-1989 requires that 1829936Swollman** Except for the strftime function, these functions [asctime, 1839936Swollman** ctime, gmtime, localtime] return values in one of two static 1849936Swollman** objects: a broken-down time structure and an array of char. 1859936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 1869936Swollman*/ 1879936Swollman 1889936Swollmanstatic struct tm tm; 1899936Swollman 1902708Swollman#ifdef USG_COMPAT 1912708Swollmantime_t timezone = 0; 1922708Swollmanint daylight = 0; 1932708Swollman#endif /* defined USG_COMPAT */ 1942708Swollman 1952708Swollman#ifdef ALTZONE 1962708Swollmantime_t altzone = 0; 1972708Swollman#endif /* defined ALTZONE */ 1982708Swollman 1992708Swollmanstatic long 2002708Swollmandetzcode(codep) 2012708Swollmanconst char * const codep; 2022708Swollman{ 2032708Swollman register long result; 2042708Swollman register int i; 2052708Swollman 20617209Swollman result = (codep[0] & 0x80) ? ~0L : 0L; 2072708Swollman for (i = 0; i < 4; ++i) 2082708Swollman result = (result << 8) | (codep[i] & 0xff); 2092708Swollman return result; 2102708Swollman} 2112708Swollman 2122708Swollmanstatic void 2139936Swollmansettzname P((void)) 2142708Swollman{ 21517209Swollman register struct state * const sp = lclptr; 21617209Swollman register int i; 2172708Swollman 2189936Swollman tzname[0] = wildabbr; 2199936Swollman tzname[1] = wildabbr; 2202708Swollman#ifdef USG_COMPAT 2212708Swollman daylight = 0; 2222708Swollman timezone = 0; 2232708Swollman#endif /* defined USG_COMPAT */ 2242708Swollman#ifdef ALTZONE 2252708Swollman altzone = 0; 2262708Swollman#endif /* defined ALTZONE */ 2272708Swollman#ifdef ALL_STATE 2282708Swollman if (sp == NULL) { 2299936Swollman tzname[0] = tzname[1] = gmt; 2302708Swollman return; 2312708Swollman } 2322708Swollman#endif /* defined ALL_STATE */ 2332708Swollman for (i = 0; i < sp->typecnt; ++i) { 2342708Swollman register const struct ttinfo * const ttisp = &sp->ttis[i]; 2352708Swollman 2362708Swollman tzname[ttisp->tt_isdst] = 2379936Swollman &sp->chars[ttisp->tt_abbrind]; 2382708Swollman#ifdef USG_COMPAT 2392708Swollman if (ttisp->tt_isdst) 2402708Swollman daylight = 1; 2412708Swollman if (i == 0 || !ttisp->tt_isdst) 2422708Swollman timezone = -(ttisp->tt_gmtoff); 2432708Swollman#endif /* defined USG_COMPAT */ 2442708Swollman#ifdef ALTZONE 2452708Swollman if (i == 0 || ttisp->tt_isdst) 2462708Swollman altzone = -(ttisp->tt_gmtoff); 2472708Swollman#endif /* defined ALTZONE */ 2482708Swollman } 2492708Swollman /* 2502708Swollman ** And to get the latest zone names into tzname. . . 2512708Swollman */ 2522708Swollman for (i = 0; i < sp->timecnt; ++i) { 2532708Swollman register const struct ttinfo * const ttisp = 2542708Swollman &sp->ttis[ 2552708Swollman sp->types[i]]; 2562708Swollman 2572708Swollman tzname[ttisp->tt_isdst] = 2589936Swollman &sp->chars[ttisp->tt_abbrind]; 2592708Swollman } 2602708Swollman} 2612708Swollman 2622708Swollmanstatic int 2632708Swollmantzload(name, sp) 2642708Swollmanregister const char * name; 2652708Swollmanregister struct state * const sp; 2662708Swollman{ 2672708Swollman register const char * p; 2682708Swollman register int i; 2692708Swollman register int fid; 2702708Swollman 2712708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 2722708Swollman return -1; 2732708Swollman { 2749936Swollman register int doaccess; 2759936Swollman /* 2769936Swollman ** Section 4.9.1 of the C standard says that 2779936Swollman ** "FILENAME_MAX expands to an integral constant expression 2789936Swollman ** that is the sie needed for an array of char large enough 2799936Swollman ** to hold the longest file name string that the implementation 2809936Swollman ** guarantees can be opened." 2819936Swollman */ 2822708Swollman char fullname[FILENAME_MAX + 1]; 2832708Swollman 2842708Swollman if (name[0] == ':') 2852708Swollman ++name; 2862708Swollman doaccess = name[0] == '/'; 2872708Swollman if (!doaccess) { 2882708Swollman if ((p = TZDIR) == NULL) 2892708Swollman return -1; 2902708Swollman if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 2912708Swollman return -1; 2922708Swollman (void) strcpy(fullname, p); 2932708Swollman (void) strcat(fullname, "/"); 2942708Swollman (void) strcat(fullname, name); 2952708Swollman /* 2962708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 2972708Swollman */ 2982708Swollman if (strchr(name, '.') != NULL) 2992708Swollman doaccess = TRUE; 3002708Swollman name = fullname; 3012708Swollman } 3029936Swollman if (doaccess && access(name, R_OK) != 0) 3032708Swollman return -1; 3042708Swollman if ((fid = open(name, OPEN_MODE)) == -1) 3052708Swollman return -1; 3062708Swollman } 3072708Swollman { 3089936Swollman struct tzhead * tzhp; 3099936Swollman char buf[sizeof *sp + sizeof *tzhp]; 3109936Swollman int ttisstdcnt; 3119936Swollman int ttisgmtcnt; 3122708Swollman 3132708Swollman i = read(fid, buf, sizeof buf); 3149936Swollman if (close(fid) != 0) 3152708Swollman return -1; 3169936Swollman p = buf; 3179936Swollman p += sizeof tzhp->tzh_reserved; 3189936Swollman ttisstdcnt = (int) detzcode(p); 3199936Swollman p += 4; 3209936Swollman ttisgmtcnt = (int) detzcode(p); 3219936Swollman p += 4; 3229936Swollman sp->leapcnt = (int) detzcode(p); 3239936Swollman p += 4; 3249936Swollman sp->timecnt = (int) detzcode(p); 3259936Swollman p += 4; 3269936Swollman sp->typecnt = (int) detzcode(p); 3279936Swollman p += 4; 3289936Swollman sp->charcnt = (int) detzcode(p); 3299936Swollman p += 4; 3302708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 3312708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 3322708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 3332708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 3349936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 3359936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 3362708Swollman return -1; 3379936Swollman if (i - (p - buf) < sp->timecnt * 4 + /* ats */ 3389936Swollman sp->timecnt + /* types */ 3399936Swollman sp->typecnt * (4 + 2) + /* ttinfos */ 3409936Swollman sp->charcnt + /* chars */ 3419936Swollman sp->leapcnt * (4 + 4) + /* lsinfos */ 3429936Swollman ttisstdcnt + /* ttisstds */ 3439936Swollman ttisgmtcnt) /* ttisgmts */ 3442708Swollman return -1; 3452708Swollman for (i = 0; i < sp->timecnt; ++i) { 3462708Swollman sp->ats[i] = detzcode(p); 3472708Swollman p += 4; 3482708Swollman } 3492708Swollman for (i = 0; i < sp->timecnt; ++i) { 3502708Swollman sp->types[i] = (unsigned char) *p++; 3512708Swollman if (sp->types[i] >= sp->typecnt) 3522708Swollman return -1; 3532708Swollman } 3542708Swollman for (i = 0; i < sp->typecnt; ++i) { 3552708Swollman register struct ttinfo * ttisp; 3562708Swollman 3572708Swollman ttisp = &sp->ttis[i]; 3582708Swollman ttisp->tt_gmtoff = detzcode(p); 3592708Swollman p += 4; 3602708Swollman ttisp->tt_isdst = (unsigned char) *p++; 3612708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 3622708Swollman return -1; 3632708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 3642708Swollman if (ttisp->tt_abbrind < 0 || 3652708Swollman ttisp->tt_abbrind > sp->charcnt) 3662708Swollman return -1; 3672708Swollman } 3682708Swollman for (i = 0; i < sp->charcnt; ++i) 3692708Swollman sp->chars[i] = *p++; 3702708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 3712708Swollman for (i = 0; i < sp->leapcnt; ++i) { 3722708Swollman register struct lsinfo * lsisp; 3732708Swollman 3742708Swollman lsisp = &sp->lsis[i]; 3752708Swollman lsisp->ls_trans = detzcode(p); 3762708Swollman p += 4; 3772708Swollman lsisp->ls_corr = detzcode(p); 3782708Swollman p += 4; 3792708Swollman } 3802708Swollman for (i = 0; i < sp->typecnt; ++i) { 3812708Swollman register struct ttinfo * ttisp; 3822708Swollman 3832708Swollman ttisp = &sp->ttis[i]; 3842708Swollman if (ttisstdcnt == 0) 3852708Swollman ttisp->tt_ttisstd = FALSE; 3862708Swollman else { 3872708Swollman ttisp->tt_ttisstd = *p++; 3882708Swollman if (ttisp->tt_ttisstd != TRUE && 3892708Swollman ttisp->tt_ttisstd != FALSE) 3902708Swollman return -1; 3912708Swollman } 3922708Swollman } 3939936Swollman for (i = 0; i < sp->typecnt; ++i) { 3949936Swollman register struct ttinfo * ttisp; 3959936Swollman 3969936Swollman ttisp = &sp->ttis[i]; 3979936Swollman if (ttisgmtcnt == 0) 3989936Swollman ttisp->tt_ttisgmt = FALSE; 3999936Swollman else { 4009936Swollman ttisp->tt_ttisgmt = *p++; 4019936Swollman if (ttisp->tt_ttisgmt != TRUE && 4029936Swollman ttisp->tt_ttisgmt != FALSE) 4039936Swollman return -1; 4049936Swollman } 4059936Swollman } 4062708Swollman } 4072708Swollman return 0; 4082708Swollman} 4092708Swollman 4102708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 4112708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 4122708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 4132708Swollman}; 4142708Swollman 4152708Swollmanstatic const int year_lengths[2] = { 4162708Swollman DAYSPERNYEAR, DAYSPERLYEAR 4172708Swollman}; 4182708Swollman 4192708Swollman/* 4202708Swollman** Given a pointer into a time zone string, scan until a character that is not 4212708Swollman** a valid character in a zone name is found. Return a pointer to that 4222708Swollman** character. 4232708Swollman*/ 4242708Swollman 4252708Swollmanstatic const char * 4262708Swollmangetzname(strp) 4272708Swollmanregister const char * strp; 4282708Swollman{ 4292708Swollman register char c; 4302708Swollman 43117209Swollman while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 4322708Swollman c != '+') 4332708Swollman ++strp; 4342708Swollman return strp; 4352708Swollman} 4362708Swollman 4372708Swollman/* 4382708Swollman** Given a pointer into a time zone string, extract a number from that string. 4392708Swollman** Check that the number is within a specified range; if it is not, return 4402708Swollman** NULL. 4412708Swollman** Otherwise, return a pointer to the first character not part of the number. 4422708Swollman*/ 4432708Swollman 4442708Swollmanstatic const char * 4452708Swollmangetnum(strp, nump, min, max) 4462708Swollmanregister const char * strp; 4472708Swollmanint * const nump; 4482708Swollmanconst int min; 4492708Swollmanconst int max; 4502708Swollman{ 4512708Swollman register char c; 4522708Swollman register int num; 4532708Swollman 45417209Swollman if (strp == NULL || !is_digit(c = *strp)) 4552708Swollman return NULL; 4562708Swollman num = 0; 45717209Swollman do { 4582708Swollman num = num * 10 + (c - '0'); 4592708Swollman if (num > max) 4602708Swollman return NULL; /* illegal value */ 46117209Swollman c = *++strp; 46217209Swollman } while (is_digit(c)); 4632708Swollman if (num < min) 4642708Swollman return NULL; /* illegal value */ 4652708Swollman *nump = num; 4662708Swollman return strp; 4672708Swollman} 4682708Swollman 4692708Swollman/* 4702708Swollman** Given a pointer into a time zone string, extract a number of seconds, 4712708Swollman** in hh[:mm[:ss]] form, from the string. 4722708Swollman** If any error occurs, return NULL. 4732708Swollman** Otherwise, return a pointer to the first character not part of the number 4742708Swollman** of seconds. 4752708Swollman*/ 4762708Swollman 4772708Swollmanstatic const char * 4782708Swollmangetsecs(strp, secsp) 4792708Swollmanregister const char * strp; 4802708Swollmanlong * const secsp; 4812708Swollman{ 4822708Swollman int num; 4832708Swollman 4849936Swollman /* 4859936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 4869936Swollman ** "M10.4.6/26", which does not conform to Posix, 4879936Swollman ** but which specifies the equivalent of 4889936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 4899936Swollman */ 4909936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 4912708Swollman if (strp == NULL) 4922708Swollman return NULL; 4939936Swollman *secsp = num * (long) SECSPERHOUR; 4942708Swollman if (*strp == ':') { 4952708Swollman ++strp; 4962708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 4972708Swollman if (strp == NULL) 4982708Swollman return NULL; 4992708Swollman *secsp += num * SECSPERMIN; 5002708Swollman if (*strp == ':') { 5012708Swollman ++strp; 5029936Swollman /* `SECSPERMIN' allows for leap seconds. */ 5039936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 5042708Swollman if (strp == NULL) 5052708Swollman return NULL; 5062708Swollman *secsp += num; 5072708Swollman } 5082708Swollman } 5092708Swollman return strp; 5102708Swollman} 5112708Swollman 5122708Swollman/* 5132708Swollman** Given a pointer into a time zone string, extract an offset, in 5142708Swollman** [+-]hh[:mm[:ss]] form, from the string. 5152708Swollman** If any error occurs, return NULL. 5162708Swollman** Otherwise, return a pointer to the first character not part of the time. 5172708Swollman*/ 5182708Swollman 5192708Swollmanstatic const char * 5202708Swollmangetoffset(strp, offsetp) 5212708Swollmanregister const char * strp; 5222708Swollmanlong * const offsetp; 5232708Swollman{ 52417209Swollman register int neg = 0; 5252708Swollman 5262708Swollman if (*strp == '-') { 5272708Swollman neg = 1; 5282708Swollman ++strp; 52917209Swollman } else if (*strp == '+') 53017209Swollman ++strp; 5312708Swollman strp = getsecs(strp, offsetp); 5322708Swollman if (strp == NULL) 5332708Swollman return NULL; /* illegal time */ 5342708Swollman if (neg) 5352708Swollman *offsetp = -*offsetp; 5362708Swollman return strp; 5372708Swollman} 5382708Swollman 5392708Swollman/* 5402708Swollman** Given a pointer into a time zone string, extract a rule in the form 5412708Swollman** date[/time]. See POSIX section 8 for the format of "date" and "time". 5422708Swollman** If a valid rule is not found, return NULL. 5432708Swollman** Otherwise, return a pointer to the first character not part of the rule. 5442708Swollman*/ 5452708Swollman 5462708Swollmanstatic const char * 5472708Swollmangetrule(strp, rulep) 5482708Swollmanconst char * strp; 5492708Swollmanregister struct rule * const rulep; 5502708Swollman{ 5512708Swollman if (*strp == 'J') { 5522708Swollman /* 5532708Swollman ** Julian day. 5542708Swollman */ 5552708Swollman rulep->r_type = JULIAN_DAY; 5562708Swollman ++strp; 5572708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 5582708Swollman } else if (*strp == 'M') { 5592708Swollman /* 5602708Swollman ** Month, week, day. 5612708Swollman */ 5622708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 5632708Swollman ++strp; 5642708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 5652708Swollman if (strp == NULL) 5662708Swollman return NULL; 5672708Swollman if (*strp++ != '.') 5682708Swollman return NULL; 5692708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 5702708Swollman if (strp == NULL) 5712708Swollman return NULL; 5722708Swollman if (*strp++ != '.') 5732708Swollman return NULL; 5742708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 57517209Swollman } else if (is_digit(*strp)) { 5762708Swollman /* 5772708Swollman ** Day of year. 5782708Swollman */ 5792708Swollman rulep->r_type = DAY_OF_YEAR; 5802708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 5812708Swollman } else return NULL; /* invalid format */ 5822708Swollman if (strp == NULL) 5832708Swollman return NULL; 5842708Swollman if (*strp == '/') { 5852708Swollman /* 5862708Swollman ** Time specified. 5872708Swollman */ 5882708Swollman ++strp; 5892708Swollman strp = getsecs(strp, &rulep->r_time); 5902708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 5912708Swollman return strp; 5922708Swollman} 5932708Swollman 5942708Swollman/* 5952708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 5962708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect, 5972708Swollman** calculate the Epoch-relative time that rule takes effect. 5982708Swollman*/ 5992708Swollman 6002708Swollmanstatic time_t 6012708Swollmantranstime(janfirst, year, rulep, offset) 6022708Swollmanconst time_t janfirst; 6032708Swollmanconst int year; 6042708Swollmanregister const struct rule * const rulep; 6052708Swollmanconst long offset; 6062708Swollman{ 6072708Swollman register int leapyear; 6082708Swollman register time_t value; 6092708Swollman register int i; 6102708Swollman int d, m1, yy0, yy1, yy2, dow; 6112708Swollman 6129936Swollman INITIALIZE(value); 6132708Swollman leapyear = isleap(year); 6142708Swollman switch (rulep->r_type) { 6152708Swollman 6162708Swollman case JULIAN_DAY: 6172708Swollman /* 6182708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 6192708Swollman ** years. 6202708Swollman ** In non-leap years, or if the day number is 59 or less, just 6212708Swollman ** add SECSPERDAY times the day number-1 to the time of 6222708Swollman ** January 1, midnight, to get the day. 6232708Swollman */ 6242708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 6252708Swollman if (leapyear && rulep->r_day >= 60) 6262708Swollman value += SECSPERDAY; 6272708Swollman break; 6282708Swollman 6292708Swollman case DAY_OF_YEAR: 6302708Swollman /* 6312708Swollman ** n - day of year. 6322708Swollman ** Just add SECSPERDAY times the day number to the time of 6332708Swollman ** January 1, midnight, to get the day. 6342708Swollman */ 6352708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 6362708Swollman break; 6372708Swollman 6382708Swollman case MONTH_NTH_DAY_OF_WEEK: 6392708Swollman /* 6402708Swollman ** Mm.n.d - nth "dth day" of month m. 6412708Swollman */ 6422708Swollman value = janfirst; 6432708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 6442708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 6452708Swollman 6462708Swollman /* 6472708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 6482708Swollman ** month. 6492708Swollman */ 6502708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 6512708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 6522708Swollman yy1 = yy0 / 100; 6532708Swollman yy2 = yy0 % 100; 6542708Swollman dow = ((26 * m1 - 2) / 10 + 6552708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 6562708Swollman if (dow < 0) 6572708Swollman dow += DAYSPERWEEK; 6582708Swollman 6592708Swollman /* 6602708Swollman ** "dow" is the day-of-week of the first day of the month. Get 6612708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 6622708Swollman ** month. 6632708Swollman */ 6642708Swollman d = rulep->r_day - dow; 6652708Swollman if (d < 0) 6662708Swollman d += DAYSPERWEEK; 6672708Swollman for (i = 1; i < rulep->r_week; ++i) { 6682708Swollman if (d + DAYSPERWEEK >= 6692708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 6702708Swollman break; 6712708Swollman d += DAYSPERWEEK; 6722708Swollman } 6732708Swollman 6742708Swollman /* 6752708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 6762708Swollman */ 6772708Swollman value += d * SECSPERDAY; 6782708Swollman break; 6792708Swollman } 6802708Swollman 6812708Swollman /* 6822708Swollman ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 6832708Swollman ** question. To get the Epoch-relative time of the specified local 6842708Swollman ** time on that day, add the transition time and the current offset 6852708Swollman ** from GMT. 6862708Swollman */ 6872708Swollman return value + rulep->r_time + offset; 6882708Swollman} 6892708Swollman 6902708Swollman/* 6912708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 6922708Swollman** appropriate. 6932708Swollman*/ 6942708Swollman 6952708Swollmanstatic int 6962708Swollmantzparse(name, sp, lastditch) 6972708Swollmanconst char * name; 6982708Swollmanregister struct state * const sp; 6992708Swollmanconst int lastditch; 7002708Swollman{ 7012708Swollman const char * stdname; 7022708Swollman const char * dstname; 7039936Swollman size_t stdlen; 7049936Swollman size_t dstlen; 7052708Swollman long stdoffset; 7062708Swollman long dstoffset; 7072708Swollman register time_t * atp; 7082708Swollman register unsigned char * typep; 7092708Swollman register char * cp; 7102708Swollman register int load_result; 7112708Swollman 7129936Swollman INITIALIZE(dstname); 7132708Swollman stdname = name; 7142708Swollman if (lastditch) { 7152708Swollman stdlen = strlen(name); /* length of standard zone name */ 7162708Swollman name += stdlen; 7172708Swollman if (stdlen >= sizeof sp->chars) 7182708Swollman stdlen = (sizeof sp->chars) - 1; 7192708Swollman } else { 7202708Swollman name = getzname(name); 7212708Swollman stdlen = name - stdname; 7222708Swollman if (stdlen < 3) 7232708Swollman return -1; 7242708Swollman } 7252708Swollman if (*name == '\0') 7262708Swollman return -1; /* was "stdoffset = 0;" */ 7272708Swollman else { 7282708Swollman name = getoffset(name, &stdoffset); 7292708Swollman if (name == NULL) 7302708Swollman return -1; 7312708Swollman } 7322708Swollman load_result = tzload(TZDEFRULES, sp); 7332708Swollman if (load_result != 0) 7342708Swollman sp->leapcnt = 0; /* so, we're off a little */ 7352708Swollman if (*name != '\0') { 7362708Swollman dstname = name; 7372708Swollman name = getzname(name); 7382708Swollman dstlen = name - dstname; /* length of DST zone name */ 7392708Swollman if (dstlen < 3) 7402708Swollman return -1; 7412708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 7422708Swollman name = getoffset(name, &dstoffset); 7432708Swollman if (name == NULL) 7442708Swollman return -1; 7452708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 7462708Swollman if (*name == ',' || *name == ';') { 7472708Swollman struct rule start; 7482708Swollman struct rule end; 7492708Swollman register int year; 7502708Swollman register time_t janfirst; 7512708Swollman time_t starttime; 7522708Swollman time_t endtime; 7532708Swollman 7542708Swollman ++name; 7552708Swollman if ((name = getrule(name, &start)) == NULL) 7562708Swollman return -1; 7572708Swollman if (*name++ != ',') 7582708Swollman return -1; 7592708Swollman if ((name = getrule(name, &end)) == NULL) 7602708Swollman return -1; 7612708Swollman if (*name != '\0') 7622708Swollman return -1; 7632708Swollman sp->typecnt = 2; /* standard time and DST */ 7642708Swollman /* 7652708Swollman ** Two transitions per year, from EPOCH_YEAR to 2037. 7662708Swollman */ 7672708Swollman sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 7682708Swollman if (sp->timecnt > TZ_MAX_TIMES) 7692708Swollman return -1; 7702708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 7712708Swollman sp->ttis[0].tt_isdst = 1; 7722708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 7732708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 7742708Swollman sp->ttis[1].tt_isdst = 0; 7752708Swollman sp->ttis[1].tt_abbrind = 0; 7762708Swollman atp = sp->ats; 7772708Swollman typep = sp->types; 7782708Swollman janfirst = 0; 7792708Swollman for (year = EPOCH_YEAR; year <= 2037; ++year) { 7802708Swollman starttime = transtime(janfirst, year, &start, 7812708Swollman stdoffset); 7822708Swollman endtime = transtime(janfirst, year, &end, 7832708Swollman dstoffset); 7842708Swollman if (starttime > endtime) { 7852708Swollman *atp++ = endtime; 7862708Swollman *typep++ = 1; /* DST ends */ 7872708Swollman *atp++ = starttime; 7882708Swollman *typep++ = 0; /* DST begins */ 7892708Swollman } else { 7902708Swollman *atp++ = starttime; 7912708Swollman *typep++ = 0; /* DST begins */ 7922708Swollman *atp++ = endtime; 7932708Swollman *typep++ = 1; /* DST ends */ 7942708Swollman } 7952708Swollman janfirst += year_lengths[isleap(year)] * 7962708Swollman SECSPERDAY; 7972708Swollman } 7982708Swollman } else { 7999936Swollman register long theirstdoffset; 8009936Swollman register long theirdstoffset; 8019936Swollman register long theiroffset; 8029936Swollman register int isdst; 8032708Swollman register int i; 8049936Swollman register int j; 8052708Swollman 8062708Swollman if (*name != '\0') 8072708Swollman return -1; 8082708Swollman if (load_result != 0) 8092708Swollman return -1; 8102708Swollman /* 8119936Swollman ** Initial values of theirstdoffset and theirdstoffset. 8122708Swollman */ 8139936Swollman theirstdoffset = 0; 8149936Swollman for (i = 0; i < sp->timecnt; ++i) { 8159936Swollman j = sp->types[i]; 8169936Swollman if (!sp->ttis[j].tt_isdst) { 81717209Swollman theirstdoffset = 81817209Swollman -sp->ttis[j].tt_gmtoff; 8199936Swollman break; 8202708Swollman } 8212708Swollman } 8229936Swollman theirdstoffset = 0; 8239936Swollman for (i = 0; i < sp->timecnt; ++i) { 8249936Swollman j = sp->types[i]; 8259936Swollman if (sp->ttis[j].tt_isdst) { 82617209Swollman theirdstoffset = 82717209Swollman -sp->ttis[j].tt_gmtoff; 8289936Swollman break; 8299936Swollman } 8309936Swollman } 8312708Swollman /* 8329936Swollman ** Initially we're assumed to be in standard time. 8332708Swollman */ 8349936Swollman isdst = FALSE; 8359936Swollman theiroffset = theirstdoffset; 8362708Swollman /* 8379936Swollman ** Now juggle transition times and types 8389936Swollman ** tracking offsets as you do. 8392708Swollman */ 8402708Swollman for (i = 0; i < sp->timecnt; ++i) { 8419936Swollman j = sp->types[i]; 8429936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 8439936Swollman if (sp->ttis[j].tt_ttisgmt) { 8449936Swollman /* No adjustment to transition time */ 8459936Swollman } else { 8469936Swollman /* 8479936Swollman ** If summer time is in effect, and the 8489936Swollman ** transition time was not specified as 8499936Swollman ** standard time, add the summer time 8509936Swollman ** offset to the transition time; 8519936Swollman ** otherwise, add the standard time 8529936Swollman ** offset to the transition time. 8539936Swollman */ 8549936Swollman /* 8559936Swollman ** Transitions from DST to DDST 8569936Swollman ** will effectively disappear since 8579936Swollman ** POSIX provides for only one DST 8589936Swollman ** offset. 8599936Swollman */ 8609936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 8619936Swollman sp->ats[i] += dstoffset - 8629936Swollman theirdstoffset; 8639936Swollman } else { 8649936Swollman sp->ats[i] += stdoffset - 8659936Swollman theirstdoffset; 8669936Swollman } 8679936Swollman } 8689936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 8699936Swollman if (sp->ttis[j].tt_isdst) 8709936Swollman theirdstoffset = theiroffset; 8719936Swollman else theirstdoffset = theiroffset; 8722708Swollman } 8739936Swollman /* 8749936Swollman ** Finally, fill in ttis. 8759936Swollman ** ttisstd and ttisgmt need not be handled. 8769936Swollman */ 8779936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8789936Swollman sp->ttis[0].tt_isdst = FALSE; 8799936Swollman sp->ttis[0].tt_abbrind = 0; 8809936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 8819936Swollman sp->ttis[1].tt_isdst = TRUE; 8829936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 8832708Swollman } 8842708Swollman } else { 8852708Swollman dstlen = 0; 8862708Swollman sp->typecnt = 1; /* only standard time */ 8872708Swollman sp->timecnt = 0; 8882708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8892708Swollman sp->ttis[0].tt_isdst = 0; 8902708Swollman sp->ttis[0].tt_abbrind = 0; 8912708Swollman } 8922708Swollman sp->charcnt = stdlen + 1; 8932708Swollman if (dstlen != 0) 8942708Swollman sp->charcnt += dstlen + 1; 8952708Swollman if (sp->charcnt > sizeof sp->chars) 8962708Swollman return -1; 8972708Swollman cp = sp->chars; 8982708Swollman (void) strncpy(cp, stdname, stdlen); 8992708Swollman cp += stdlen; 9002708Swollman *cp++ = '\0'; 9012708Swollman if (dstlen != 0) { 9022708Swollman (void) strncpy(cp, dstname, dstlen); 9032708Swollman *(cp + dstlen) = '\0'; 9042708Swollman } 9052708Swollman return 0; 9062708Swollman} 9072708Swollman 9082708Swollmanstatic void 9092708Swollmangmtload(sp) 9102708Swollmanstruct state * const sp; 9112708Swollman{ 9129936Swollman if (tzload(gmt, sp) != 0) 9139936Swollman (void) tzparse(gmt, sp, TRUE); 9142708Swollman} 9152708Swollman 9162708Swollman#ifndef STD_INSPIRED 9179936Swollman/* 9189936Swollman** A non-static declaration of tzsetwall in a system header file 9199936Swollman** may cause a warning about this upcoming static declaration... 9209936Swollman*/ 9212708Swollmanstatic 9222708Swollman#endif /* !defined STD_INSPIRED */ 92313545Sjulian#ifdef _THREAD_SAFE 9242708Swollmanvoid 92513545Sjuliantzsetwall_basic P((void)) 92613545Sjulian#else 92713545Sjulianvoid 9289936Swollmantzsetwall P((void)) 92913545Sjulian#endif 9302708Swollman{ 9319936Swollman if (lcl_is_set < 0) 9329936Swollman return; 9339936Swollman lcl_is_set = -1; 9349936Swollman 9352708Swollman#ifdef ALL_STATE 9362708Swollman if (lclptr == NULL) { 9372708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9382708Swollman if (lclptr == NULL) { 9392708Swollman settzname(); /* all we can do */ 9402708Swollman return; 9412708Swollman } 9422708Swollman } 9432708Swollman#endif /* defined ALL_STATE */ 9442708Swollman if (tzload((char *) NULL, lclptr) != 0) 9452708Swollman gmtload(lclptr); 9462708Swollman settzname(); 9472708Swollman} 9482708Swollman 94913545Sjulian#ifdef _THREAD_SAFE 9502708Swollmanvoid 95113545Sjuliantzsetwall P((void)) 95213545Sjulian{ 95313545Sjulian pthread_mutex_lock(&lcl_mutex); 95413545Sjulian tzsetwall_basic(); 95513545Sjulian pthread_mutex_unlock(&lcl_mutex); 95613545Sjulian} 95713545Sjulian#endif 95813545Sjulian 95913545Sjulian#ifdef _THREAD_SAFE 96013545Sjulianstatic void 96113545Sjuliantzset_basic P((void)) 96213545Sjulian#else 96313545Sjulianvoid 9649936Swollmantzset P((void)) 96513545Sjulian#endif 9662708Swollman{ 9672708Swollman register const char * name; 9682708Swollman 9692708Swollman name = getenv("TZ"); 9702708Swollman if (name == NULL) { 9712708Swollman tzsetwall(); 9722708Swollman return; 9732708Swollman } 9749936Swollman 9759936Swollman if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) 9769936Swollman return; 9779936Swollman lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); 9789936Swollman if (lcl_is_set) 9799936Swollman (void) strcpy(lcl_TZname, name); 9809936Swollman 9812708Swollman#ifdef ALL_STATE 9822708Swollman if (lclptr == NULL) { 9832708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9842708Swollman if (lclptr == NULL) { 9852708Swollman settzname(); /* all we can do */ 9862708Swollman return; 9872708Swollman } 9882708Swollman } 9892708Swollman#endif /* defined ALL_STATE */ 9902708Swollman if (*name == '\0') { 9912708Swollman /* 9922708Swollman ** User wants it fast rather than right. 9932708Swollman */ 9942708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 9952708Swollman lclptr->timecnt = 0; 9962708Swollman lclptr->ttis[0].tt_gmtoff = 0; 9972708Swollman lclptr->ttis[0].tt_abbrind = 0; 9989936Swollman (void) strcpy(lclptr->chars, gmt); 9992708Swollman } else if (tzload(name, lclptr) != 0) 10002708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 10012708Swollman (void) gmtload(lclptr); 10022708Swollman settzname(); 10032708Swollman} 10042708Swollman 100513545Sjulian#ifdef _THREAD_SAFE 100613545Sjulianvoid 100713545Sjuliantzset P((void)) 100813545Sjulian{ 100913545Sjulian pthread_mutex_lock(&lcl_mutex); 101013545Sjulian tzset_basic(); 101113545Sjulian pthread_mutex_unlock(&lcl_mutex); 101213545Sjulian} 101313545Sjulian#endif 101413545Sjulian 10152708Swollman/* 10162708Swollman** The easy way to behave "as if no library function calls" localtime 10172708Swollman** is to not call it--so we drop its guts into "localsub", which can be 10182708Swollman** freely called. (And no, the PANS doesn't require the above behavior-- 10192708Swollman** but it *is* desirable.) 10202708Swollman** 10212708Swollman** The unused offset argument is for the benefit of mktime variants. 10222708Swollman*/ 10232708Swollman 10242708Swollman/*ARGSUSED*/ 10252708Swollmanstatic void 10262708Swollmanlocalsub(timep, offset, tmp) 10272708Swollmanconst time_t * const timep; 10282708Swollmanconst long offset; 10292708Swollmanstruct tm * const tmp; 10302708Swollman{ 10319936Swollman register struct state * sp; 10322708Swollman register const struct ttinfo * ttisp; 10332708Swollman register int i; 10342708Swollman const time_t t = *timep; 10352708Swollman 10362708Swollman sp = lclptr; 10372708Swollman#ifdef ALL_STATE 10382708Swollman if (sp == NULL) { 10392708Swollman gmtsub(timep, offset, tmp); 10402708Swollman return; 10412708Swollman } 10422708Swollman#endif /* defined ALL_STATE */ 10432708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 10442708Swollman i = 0; 10452708Swollman while (sp->ttis[i].tt_isdst) 10462708Swollman if (++i >= sp->typecnt) { 10472708Swollman i = 0; 10482708Swollman break; 10492708Swollman } 10502708Swollman } else { 10512708Swollman for (i = 1; i < sp->timecnt; ++i) 10522708Swollman if (t < sp->ats[i]) 10532708Swollman break; 10542708Swollman i = sp->types[i - 1]; 10552708Swollman } 10562708Swollman ttisp = &sp->ttis[i]; 10572708Swollman /* 10582708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 10592708Swollman ** you'd replace the statement below with 10602708Swollman ** t += ttisp->tt_gmtoff; 10612708Swollman ** timesub(&t, 0L, sp, tmp); 10622708Swollman */ 10632708Swollman timesub(&t, ttisp->tt_gmtoff, sp, tmp); 10642708Swollman tmp->tm_isdst = ttisp->tt_isdst; 10659936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 10662708Swollman#ifdef TM_ZONE 10679936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 10682708Swollman#endif /* defined TM_ZONE */ 10692708Swollman} 10702708Swollman 107113545Sjulian#ifdef _THREAD_SAFE 107213545Sjulianint 107313545Sjulianlocaltime_r(timep, p_tm) 107413545Sjulianconst time_t * const timep; 107513545Sjulianstruct tm *p_tm; 107613545Sjulian{ 107713545Sjulian pthread_mutex_lock(&lcl_mutex); 107813545Sjulian tzset(); 107913545Sjulian localsub(timep, 0L, p_tm); 108013545Sjulian pthread_mutex_unlock(&lcl_mutex); 108113545Sjulian return(0); 108213545Sjulian} 108313545Sjulian#endif 108413545Sjulian 10852708Swollmanstruct tm * 10862708Swollmanlocaltime(timep) 10872708Swollmanconst time_t * const timep; 10882708Swollman{ 108913545Sjulian#ifdef _THREAD_SAFE 109013545Sjulian static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 109113545Sjulian static pthread_key_t localtime_key = -1; 109213545Sjulian struct tm *p_tm; 109313545Sjulian 109413545Sjulian pthread_mutex_lock(&localtime_mutex); 109513545Sjulian if (localtime_key < 0) { 109613545Sjulian if (pthread_keycreate(&localtime_key, free) < 0) { 109713545Sjulian pthread_mutex_unlock(&localtime_mutex); 109813545Sjulian return(NULL); 109913545Sjulian } 110013545Sjulian } 110113545Sjulian pthread_mutex_unlock(&localtime_mutex); 110213545Sjulian if (pthread_getspecific(localtime_key,(void **) &p_tm) != 0) { 110313545Sjulian return(NULL); 110413545Sjulian } else if (p_tm == NULL) { 110513545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 110613545Sjulian return(NULL); 110713545Sjulian } 110813545Sjulian pthread_setspecific(localtime_key, p_tm); 110913545Sjulian } 111013545Sjulian pthread_mutex_lock(&lcl_mutex); 11119936Swollman tzset(); 111213545Sjulian localsub(timep, 0L, p_tm); 111313545Sjulian pthread_mutex_unlock(&lcl_mutex); 111413545Sjulian return p_tm; 111513545Sjulian#else 111613545Sjulian tzset(); 11172708Swollman localsub(timep, 0L, &tm); 11182708Swollman return &tm; 111913545Sjulian#endif 11202708Swollman} 11212708Swollman 11222708Swollman/* 11232708Swollman** gmtsub is to gmtime as localsub is to localtime. 11242708Swollman*/ 11252708Swollman 11262708Swollmanstatic void 11272708Swollmangmtsub(timep, offset, tmp) 11282708Swollmanconst time_t * const timep; 11292708Swollmanconst long offset; 11302708Swollmanstruct tm * const tmp; 11312708Swollman{ 113213545Sjulian#ifdef _THREAD_SAFE 113313545Sjulian pthread_mutex_lock(&gmt_mutex); 113413545Sjulian#endif 11352708Swollman if (!gmt_is_set) { 11362708Swollman gmt_is_set = TRUE; 11372708Swollman#ifdef ALL_STATE 11382708Swollman gmtptr = (struct state *) malloc(sizeof *gmtptr); 11392708Swollman if (gmtptr != NULL) 11402708Swollman#endif /* defined ALL_STATE */ 11412708Swollman gmtload(gmtptr); 11422708Swollman } 114313545Sjulian#ifdef _THREAD_SAFE 114413545Sjulian pthread_mutex_unlock(&gmt_mutex); 114513545Sjulian#endif 11462708Swollman timesub(timep, offset, gmtptr, tmp); 11472708Swollman#ifdef TM_ZONE 11482708Swollman /* 11492708Swollman ** Could get fancy here and deliver something such as 11502708Swollman ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 11512708Swollman ** but this is no time for a treasure hunt. 11522708Swollman */ 11532708Swollman if (offset != 0) 11549936Swollman tmp->TM_ZONE = wildabbr; 11552708Swollman else { 11562708Swollman#ifdef ALL_STATE 11572708Swollman if (gmtptr == NULL) 11589936Swollman tmp->TM_ZONE = gmt; 11592708Swollman else tmp->TM_ZONE = gmtptr->chars; 11602708Swollman#endif /* defined ALL_STATE */ 11612708Swollman#ifndef ALL_STATE 11622708Swollman tmp->TM_ZONE = gmtptr->chars; 11632708Swollman#endif /* State Farm */ 11642708Swollman } 11652708Swollman#endif /* defined TM_ZONE */ 11662708Swollman} 11672708Swollman 11682708Swollmanstruct tm * 11692708Swollmangmtime(timep) 11702708Swollmanconst time_t * const timep; 11712708Swollman{ 117213545Sjulian#ifdef _THREAD_SAFE 117313545Sjulian static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 117413545Sjulian static pthread_key_t gmtime_key = -1; 117513545Sjulian struct tm *p_tm; 117613545Sjulian 117713545Sjulian pthread_mutex_lock(&gmtime_mutex); 117813545Sjulian if (gmtime_key < 0) { 117913545Sjulian if (pthread_keycreate(&gmtime_key, free) < 0) { 118013545Sjulian pthread_mutex_unlock(&gmtime_mutex); 118113545Sjulian return(NULL); 118213545Sjulian } 118313545Sjulian } 118413545Sjulian pthread_mutex_unlock(&gmtime_mutex); 118513545Sjulian if (pthread_getspecific(gmtime_key,(void **) &p_tm) != 0) { 118613545Sjulian return(NULL); 118713545Sjulian } else if (p_tm == NULL) { 118813545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 118913545Sjulian return(NULL); 119013545Sjulian } 119113545Sjulian pthread_setspecific(gmtime_key, p_tm); 119213545Sjulian } 119313545Sjulian gmtsub(timep, 0L, p_tm); 119413545Sjulian return(p_tm); 119513545Sjulian#else 11962708Swollman gmtsub(timep, 0L, &tm); 11972708Swollman return &tm; 119813545Sjulian#endif 11992708Swollman} 12002708Swollman 120113545Sjulian#ifdef _THREAD_SAFE 120213545Sjulianint 120313545Sjuliangmtime_r(const time_t * timep, struct tm * tm) 120413545Sjulian{ 120513545Sjulian gmtsub(timep, 0L, tm); 120613545Sjulian return(0); 120713545Sjulian} 120813545Sjulian#endif 120913545Sjulian 12102708Swollman#ifdef STD_INSPIRED 12112708Swollman 12122708Swollmanstruct tm * 12132708Swollmanofftime(timep, offset) 12142708Swollmanconst time_t * const timep; 12152708Swollmanconst long offset; 12162708Swollman{ 12172708Swollman gmtsub(timep, offset, &tm); 12182708Swollman return &tm; 12192708Swollman} 12202708Swollman 12212708Swollman#endif /* defined STD_INSPIRED */ 12222708Swollman 12232708Swollmanstatic void 12242708Swollmantimesub(timep, offset, sp, tmp) 12252708Swollmanconst time_t * const timep; 12262708Swollmanconst long offset; 12272708Swollmanregister const struct state * const sp; 12282708Swollmanregister struct tm * const tmp; 12292708Swollman{ 12302708Swollman register const struct lsinfo * lp; 12312708Swollman register long days; 12322708Swollman register long rem; 12332708Swollman register int y; 12342708Swollman register int yleap; 12352708Swollman register const int * ip; 12362708Swollman register long corr; 12372708Swollman register int hit; 12382708Swollman register int i; 12392708Swollman 12402708Swollman corr = 0; 12412708Swollman hit = 0; 12422708Swollman#ifdef ALL_STATE 12432708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 12442708Swollman#endif /* defined ALL_STATE */ 12452708Swollman#ifndef ALL_STATE 12462708Swollman i = sp->leapcnt; 12472708Swollman#endif /* State Farm */ 12482708Swollman while (--i >= 0) { 12492708Swollman lp = &sp->lsis[i]; 12502708Swollman if (*timep >= lp->ls_trans) { 12512708Swollman if (*timep == lp->ls_trans) { 12522708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 12532708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 12542708Swollman if (hit) 12552708Swollman while (i > 0 && 12562708Swollman sp->lsis[i].ls_trans == 12572708Swollman sp->lsis[i - 1].ls_trans + 1 && 12582708Swollman sp->lsis[i].ls_corr == 12592708Swollman sp->lsis[i - 1].ls_corr + 1) { 12602708Swollman ++hit; 12612708Swollman --i; 12622708Swollman } 12632708Swollman } 12642708Swollman corr = lp->ls_corr; 12652708Swollman break; 12662708Swollman } 12672708Swollman } 12682708Swollman days = *timep / SECSPERDAY; 12692708Swollman rem = *timep % SECSPERDAY; 12702708Swollman#ifdef mc68k 12712708Swollman if (*timep == 0x80000000) { 12722708Swollman /* 12732708Swollman ** A 3B1 muffs the division on the most negative number. 12742708Swollman */ 12752708Swollman days = -24855; 12762708Swollman rem = -11648; 12772708Swollman } 12789936Swollman#endif /* defined mc68k */ 12792708Swollman rem += (offset - corr); 12802708Swollman while (rem < 0) { 12812708Swollman rem += SECSPERDAY; 12822708Swollman --days; 12832708Swollman } 12842708Swollman while (rem >= SECSPERDAY) { 12852708Swollman rem -= SECSPERDAY; 12862708Swollman ++days; 12872708Swollman } 12882708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 12892708Swollman rem = rem % SECSPERHOUR; 12902708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 129117209Swollman /* 129217209Swollman ** A positive leap second requires a special 129317209Swollman ** representation. This uses "... ??:59:60" et seq. 129417209Swollman */ 129517209Swollman tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 12962708Swollman tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 12972708Swollman if (tmp->tm_wday < 0) 12982708Swollman tmp->tm_wday += DAYSPERWEEK; 12992708Swollman y = EPOCH_YEAR; 130017209Swollman#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) 130117209Swollman while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { 130217209Swollman register int newy; 130317209Swollman 130417209Swollman newy = y + days / DAYSPERNYEAR; 130517209Swollman if (days < 0) 130617209Swollman --newy; 130717209Swollman days -= (newy - y) * DAYSPERNYEAR + 130817209Swollman LEAPS_THRU_END_OF(newy - 1) - 130917209Swollman LEAPS_THRU_END_OF(y - 1); 131017209Swollman y = newy; 131117209Swollman } 13122708Swollman tmp->tm_year = y - TM_YEAR_BASE; 13132708Swollman tmp->tm_yday = (int) days; 13142708Swollman ip = mon_lengths[yleap]; 13152708Swollman for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 13162708Swollman days = days - (long) ip[tmp->tm_mon]; 13172708Swollman tmp->tm_mday = (int) (days + 1); 13182708Swollman tmp->tm_isdst = 0; 13192708Swollman#ifdef TM_GMTOFF 13202708Swollman tmp->TM_GMTOFF = offset; 13212708Swollman#endif /* defined TM_GMTOFF */ 13222708Swollman} 13232708Swollman 13242708Swollmanchar * 13252708Swollmanctime(timep) 13262708Swollmanconst time_t * const timep; 13272708Swollman{ 13289936Swollman/* 13299936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 13309936Swollman** The ctime funciton converts the calendar time pointed to by timer 13319936Swollman** to local time in the form of a string. It is equivalent to 13329936Swollman** asctime(localtime(timer)) 13339936Swollman*/ 13342708Swollman return asctime(localtime(timep)); 13352708Swollman} 13362708Swollman 13372708Swollman/* 13382708Swollman** Adapted from code provided by Robert Elz, who writes: 13392708Swollman** The "best" way to do mktime I think is based on an idea of Bob 134017209Swollman** Kridle's (so its said...) from a long time ago. 134117209Swollman** [kridle@xinet.com as of 1996-01-16.] 13422708Swollman** It does a binary search of the time_t space. Since time_t's are 13432708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 13442708Swollman** would still be very reasonable). 13452708Swollman*/ 13462708Swollman 13472708Swollman#ifndef WRONG 13482708Swollman#define WRONG (-1) 13492708Swollman#endif /* !defined WRONG */ 13502708Swollman 13512708Swollman/* 13522708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 13532708Swollman*/ 13542708Swollman 13552708Swollmanstatic int 13562708Swollmanincrement_overflow(number, delta) 13572708Swollmanint * number; 13582708Swollmanint delta; 13592708Swollman{ 13609936Swollman int number0; 13618870Srgrimes 13622708Swollman number0 = *number; 13632708Swollman *number += delta; 13642708Swollman return (*number < number0) != (delta < 0); 13652708Swollman} 13662708Swollman 13672708Swollmanstatic int 13682708Swollmannormalize_overflow(tensptr, unitsptr, base) 13692708Swollmanint * const tensptr; 13702708Swollmanint * const unitsptr; 13712708Swollmanconst int base; 13722708Swollman{ 13732708Swollman register int tensdelta; 13742708Swollman 13752708Swollman tensdelta = (*unitsptr >= 0) ? 13762708Swollman (*unitsptr / base) : 13772708Swollman (-1 - (-1 - *unitsptr) / base); 13782708Swollman *unitsptr -= tensdelta * base; 13792708Swollman return increment_overflow(tensptr, tensdelta); 13802708Swollman} 13812708Swollman 13822708Swollmanstatic int 13832708Swollmantmcomp(atmp, btmp) 13842708Swollmanregister const struct tm * const atmp; 13852708Swollmanregister const struct tm * const btmp; 13862708Swollman{ 13872708Swollman register int result; 13882708Swollman 13892708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 13902708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 13912708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 13922708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 13932708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 13942708Swollman result = atmp->tm_sec - btmp->tm_sec; 13952708Swollman return result; 13962708Swollman} 13972708Swollman 13982708Swollmanstatic time_t 13992708Swollmantime2(tmp, funcp, offset, okayp) 14002708Swollmanstruct tm * const tmp; 14019936Swollmanvoid (* const funcp) P((const time_t*, long, struct tm*)); 14022708Swollmanconst long offset; 14032708Swollmanint * const okayp; 14042708Swollman{ 14052708Swollman register const struct state * sp; 14062708Swollman register int dir; 14072708Swollman register int bits; 14082708Swollman register int i, j ; 14092708Swollman register int saved_seconds; 14102708Swollman time_t newt; 14112708Swollman time_t t; 14122708Swollman struct tm yourtm, mytm; 14132708Swollman 14142708Swollman *okayp = FALSE; 14152708Swollman yourtm = *tmp; 14162708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 14172708Swollman return WRONG; 14182708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 14192708Swollman return WRONG; 14202708Swollman if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 14212708Swollman return WRONG; 14222708Swollman /* 14232708Swollman ** Turn yourtm.tm_year into an actual year number for now. 14242708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 14252708Swollman */ 14262708Swollman if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 14272708Swollman return WRONG; 14282708Swollman while (yourtm.tm_mday <= 0) { 14292708Swollman if (increment_overflow(&yourtm.tm_year, -1)) 14302708Swollman return WRONG; 143117209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 143217209Swollman yourtm.tm_mday += year_lengths[isleap(i)]; 14332708Swollman } 14342708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 143517209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 143617209Swollman yourtm.tm_mday -= year_lengths[isleap(i)]; 14372708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14382708Swollman return WRONG; 14392708Swollman } 14402708Swollman for ( ; ; ) { 14412708Swollman i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 14422708Swollman if (yourtm.tm_mday <= i) 14432708Swollman break; 14442708Swollman yourtm.tm_mday -= i; 14452708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 14462708Swollman yourtm.tm_mon = 0; 14472708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14482708Swollman return WRONG; 14492708Swollman } 14502708Swollman } 14512708Swollman if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 14522708Swollman return WRONG; 14532708Swollman if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 14542708Swollman /* 14552708Swollman ** We can't set tm_sec to 0, because that might push the 14562708Swollman ** time below the minimum representable time. 14572708Swollman ** Set tm_sec to 59 instead. 14582708Swollman ** This assumes that the minimum representable time is 14592708Swollman ** not in the same minute that a leap second was deleted from, 14602708Swollman ** which is a safer assumption than using 58 would be. 14612708Swollman */ 14622708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 14632708Swollman return WRONG; 14642708Swollman saved_seconds = yourtm.tm_sec; 14652708Swollman yourtm.tm_sec = SECSPERMIN - 1; 14662708Swollman } else { 14672708Swollman saved_seconds = yourtm.tm_sec; 14682708Swollman yourtm.tm_sec = 0; 14692708Swollman } 14702708Swollman /* 147117209Swollman ** Divide the search space in half 147217209Swollman ** (this works whether time_t is signed or unsigned). 14732708Swollman */ 147417209Swollman bits = TYPE_BIT(time_t) - 1; 14752708Swollman /* 147617209Swollman ** If time_t is signed, then 0 is just above the median, 147717209Swollman ** assuming two's complement arithmetic. 147817209Swollman ** If time_t is unsigned, then (1 << bits) is just above the median. 14792708Swollman */ 148017209Swollman t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); 14812708Swollman for ( ; ; ) { 14822708Swollman (*funcp)(&t, offset, &mytm); 14832708Swollman dir = tmcomp(&mytm, &yourtm); 14842708Swollman if (dir != 0) { 14852708Swollman if (bits-- < 0) 14862708Swollman return WRONG; 14872708Swollman if (bits < 0) 148817209Swollman --t; /* may be needed if new t is minimal */ 14892708Swollman else if (dir > 0) 149017209Swollman t -= ((time_t) 1) << bits; 149117209Swollman else t += ((time_t) 1) << bits; 14922708Swollman continue; 14932708Swollman } 14942708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 14952708Swollman break; 14962708Swollman /* 14972708Swollman ** Right time, wrong type. 14982708Swollman ** Hunt for right time, right type. 14992708Swollman ** It's okay to guess wrong since the guess 15002708Swollman ** gets checked. 15012708Swollman */ 15022708Swollman /* 15032708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15042708Swollman */ 15052708Swollman sp = (const struct state *) 15062708Swollman (((void *) funcp == (void *) localsub) ? 15072708Swollman lclptr : gmtptr); 15082708Swollman#ifdef ALL_STATE 15092708Swollman if (sp == NULL) 15102708Swollman return WRONG; 15112708Swollman#endif /* defined ALL_STATE */ 151217209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 15132708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 15142708Swollman continue; 151517209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 15162708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 15172708Swollman continue; 15182708Swollman newt = t + sp->ttis[j].tt_gmtoff - 15192708Swollman sp->ttis[i].tt_gmtoff; 15202708Swollman (*funcp)(&newt, offset, &mytm); 15212708Swollman if (tmcomp(&mytm, &yourtm) != 0) 15222708Swollman continue; 15232708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 15242708Swollman continue; 15252708Swollman /* 15262708Swollman ** We have a match. 15272708Swollman */ 15282708Swollman t = newt; 15292708Swollman goto label; 15302708Swollman } 15312708Swollman } 15322708Swollman return WRONG; 15332708Swollman } 15342708Swollmanlabel: 15352708Swollman newt = t + saved_seconds; 15362708Swollman if ((newt < t) != (saved_seconds < 0)) 15372708Swollman return WRONG; 15382708Swollman t = newt; 15392708Swollman (*funcp)(&t, offset, tmp); 15402708Swollman *okayp = TRUE; 15412708Swollman return t; 15422708Swollman} 15432708Swollman 15442708Swollmanstatic time_t 15452708Swollmantime1(tmp, funcp, offset) 15462708Swollmanstruct tm * const tmp; 154717209Swollmanvoid (* const funcp) P((const time_t *, long, struct tm *)); 15482708Swollmanconst long offset; 15492708Swollman{ 15502708Swollman register time_t t; 15512708Swollman register const struct state * sp; 15522708Swollman register int samei, otheri; 15532708Swollman int okay; 15542708Swollman 15552708Swollman if (tmp->tm_isdst > 1) 15562708Swollman tmp->tm_isdst = 1; 15572708Swollman t = time2(tmp, funcp, offset, &okay); 15582708Swollman#ifdef PCTS 15592708Swollman /* 15602708Swollman ** PCTS code courtesy Grant Sullivan (grant@osf.org). 15612708Swollman */ 15622708Swollman if (okay) 15632708Swollman return t; 15642708Swollman if (tmp->tm_isdst < 0) 15652708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 15662708Swollman#endif /* defined PCTS */ 15672708Swollman#ifndef PCTS 15682708Swollman if (okay || tmp->tm_isdst < 0) 15692708Swollman return t; 15702708Swollman#endif /* !defined PCTS */ 15712708Swollman /* 15722708Swollman ** We're supposed to assume that somebody took a time of one type 15732708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 15742708Swollman ** We try to divine the type they started from and adjust to the 15752708Swollman ** type they need. 15762708Swollman */ 15772708Swollman /* 15782708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15792708Swollman */ 15802708Swollman sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 15812708Swollman lclptr : gmtptr); 15822708Swollman#ifdef ALL_STATE 15832708Swollman if (sp == NULL) 15842708Swollman return WRONG; 15852708Swollman#endif /* defined ALL_STATE */ 158617209Swollman for (samei = sp->typecnt - 1; samei >= 0; --samei) { 15872708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 15882708Swollman continue; 158917209Swollman for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { 15902708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 15912708Swollman continue; 15922708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 15932708Swollman sp->ttis[samei].tt_gmtoff; 15942708Swollman tmp->tm_isdst = !tmp->tm_isdst; 15952708Swollman t = time2(tmp, funcp, offset, &okay); 15962708Swollman if (okay) 15972708Swollman return t; 15982708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 15992708Swollman sp->ttis[samei].tt_gmtoff; 16002708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16012708Swollman } 16022708Swollman } 16032708Swollman return WRONG; 16042708Swollman} 16052708Swollman 16062708Swollmantime_t 16072708Swollmanmktime(tmp) 16082708Swollmanstruct tm * const tmp; 16092708Swollman{ 161013545Sjulian time_t mktime_return_value; 161113545Sjulian#ifdef _THREAD_SAFE 161213545Sjulian pthread_mutex_lock(&lcl_mutex); 161313545Sjulian#endif 16149936Swollman tzset(); 161513545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 161613545Sjulian#ifdef _THREAD_SAFE 161713545Sjulian pthread_mutex_unlock(&lcl_mutex); 161813545Sjulian#endif 161913545Sjulian return(mktime_return_value); 16202708Swollman} 16212708Swollman 16222708Swollman#ifdef STD_INSPIRED 16232708Swollman 16242708Swollmantime_t 16252708Swollmantimelocal(tmp) 16262708Swollmanstruct tm * const tmp; 16272708Swollman{ 16282708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 16292708Swollman return mktime(tmp); 16302708Swollman} 16312708Swollman 16322708Swollmantime_t 16332708Swollmantimegm(tmp) 16342708Swollmanstruct tm * const tmp; 16352708Swollman{ 16362708Swollman tmp->tm_isdst = 0; 16372708Swollman return time1(tmp, gmtsub, 0L); 16382708Swollman} 16392708Swollman 16402708Swollmantime_t 16412708Swollmantimeoff(tmp, offset) 16422708Swollmanstruct tm * const tmp; 16432708Swollmanconst long offset; 16442708Swollman{ 16452708Swollman tmp->tm_isdst = 0; 16462708Swollman return time1(tmp, gmtsub, offset); 16472708Swollman} 16482708Swollman 16492708Swollman#endif /* defined STD_INSPIRED */ 16502708Swollman 16512708Swollman#ifdef CMUCS 16522708Swollman 16532708Swollman/* 16542708Swollman** The following is supplied for compatibility with 16552708Swollman** previous versions of the CMUCS runtime library. 16562708Swollman*/ 16572708Swollman 16582708Swollmanlong 16592708Swollmangtime(tmp) 16602708Swollmanstruct tm * const tmp; 16612708Swollman{ 16622708Swollman const time_t t = mktime(tmp); 16632708Swollman 16642708Swollman if (t == WRONG) 16652708Swollman return -1; 16662708Swollman return t; 16672708Swollman} 16682708Swollman 16692708Swollman#endif /* defined CMUCS */ 16702708Swollman 16712708Swollman/* 16722708Swollman** XXX--is the below the right way to conditionalize?? 16732708Swollman*/ 16742708Swollman 16752708Swollman#ifdef STD_INSPIRED 16762708Swollman 16772708Swollman/* 16782708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 16792708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 16802708Swollman** is not the case if we are accounting for leap seconds. 16812708Swollman** So, we provide the following conversion routines for use 16822708Swollman** when exchanging timestamps with POSIX conforming systems. 16832708Swollman*/ 16842708Swollman 16852708Swollmanstatic long 16862708Swollmanleapcorr(timep) 16872708Swollmantime_t * timep; 16882708Swollman{ 16892708Swollman register struct state * sp; 16902708Swollman register struct lsinfo * lp; 16912708Swollman register int i; 16922708Swollman 16932708Swollman sp = lclptr; 16942708Swollman i = sp->leapcnt; 16952708Swollman while (--i >= 0) { 16962708Swollman lp = &sp->lsis[i]; 16972708Swollman if (*timep >= lp->ls_trans) 16982708Swollman return lp->ls_corr; 16992708Swollman } 17002708Swollman return 0; 17012708Swollman} 17022708Swollman 17032708Swollmantime_t 17042708Swollmantime2posix(t) 17052708Swollmantime_t t; 17062708Swollman{ 17079936Swollman tzset(); 17082708Swollman return t - leapcorr(&t); 17092708Swollman} 17102708Swollman 17112708Swollmantime_t 17122708Swollmanposix2time(t) 17132708Swollmantime_t t; 17142708Swollman{ 17152708Swollman time_t x; 17162708Swollman time_t y; 17172708Swollman 17189936Swollman tzset(); 17192708Swollman /* 17202708Swollman ** For a positive leap second hit, the result 17212708Swollman ** is not unique. For a negative leap second 17222708Swollman ** hit, the corresponding time doesn't exist, 17232708Swollman ** so we return an adjacent second. 17242708Swollman */ 17252708Swollman x = t + leapcorr(&t); 17262708Swollman y = x - leapcorr(&x); 17272708Swollman if (y < t) { 17282708Swollman do { 17292708Swollman x++; 17302708Swollman y = x - leapcorr(&x); 17312708Swollman } while (y < t); 17322708Swollman if (t != y) 17332708Swollman return x - 1; 17342708Swollman } else if (y > t) { 17352708Swollman do { 17362708Swollman --x; 17372708Swollman y = x - leapcorr(&x); 17382708Swollman } while (y > t); 17392708Swollman if (t != y) 17402708Swollman return x + 1; 17412708Swollman } 17422708Swollman return x; 17432708Swollman} 17442708Swollman 17452708Swollman#endif /* defined STD_INSPIRED */ 1746