localtime.c revision 21659
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 2018834Swollman#include <sys/types.h> 2118834Swollman#include <sys/stat.h> 2218834Swollman 232708Swollman#include "private.h" 242708Swollman#include "tzfile.h" 252708Swollman#include "fcntl.h" 2613545Sjulian#ifdef _THREAD_SAFE 2713545Sjulian#include <pthread.h> 2813545Sjulian#include "pthread_private.h" 2913545Sjulian#endif 302708Swollman 319936Swollman/* 329936Swollman** SunOS 4.1.1 headers lack O_BINARY. 339936Swollman*/ 342708Swollman 352708Swollman#ifdef O_BINARY 362708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 372708Swollman#endif /* defined O_BINARY */ 382708Swollman#ifndef O_BINARY 392708Swollman#define OPEN_MODE O_RDONLY 402708Swollman#endif /* !defined O_BINARY */ 412708Swollman 422708Swollman#ifndef WILDABBR 432708Swollman/* 442708Swollman** Someone might make incorrect use of a time zone abbreviation: 452708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 469936Swollman** or implicitly). 472708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 489936Swollman** or implicitly). 492708Swollman** 3. They might reference tzname[1] after setting to a time zone 502708Swollman** in which Daylight Saving Time is never observed. 512708Swollman** 4. They might reference tzname[0] after setting to a time zone 522708Swollman** in which Standard Time is never observed. 532708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 542708Swollman** What's best to do in the above cases is open to debate; 552708Swollman** for now, we just set things up so that in any of the five cases 562708Swollman** WILDABBR is used. Another possibility: initialize tzname[0] to the 572708Swollman** string "tzname[0] used before set", and similarly for the other cases. 582708Swollman** And another: initialize tzname[0] to "ERA", with an explanation in the 592708Swollman** manual page of what this "time zone abbreviation" means (doing this so 602708Swollman** that tzname[0] has the "normal" length of three characters). 612708Swollman*/ 622708Swollman#define WILDABBR " " 632708Swollman#endif /* !defined WILDABBR */ 642708Swollman 659936Swollmanstatic char wildabbr[] = "WILDABBR"; 662708Swollman 679936Swollmanstatic const char gmt[] = "GMT"; 689936Swollman 692708Swollmanstruct ttinfo { /* time type information */ 702708Swollman long tt_gmtoff; /* GMT offset in seconds */ 712708Swollman int tt_isdst; /* used to set tm_isdst */ 722708Swollman int tt_abbrind; /* abbreviation list index */ 732708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 749936Swollman int tt_ttisgmt; /* TRUE if transition is GMT */ 752708Swollman}; 762708Swollman 772708Swollmanstruct lsinfo { /* leap second information */ 782708Swollman time_t ls_trans; /* transition time */ 792708Swollman long ls_corr; /* correction to apply */ 802708Swollman}; 812708Swollman 822708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 832708Swollman 842708Swollman#ifdef TZNAME_MAX 852708Swollman#define MY_TZNAME_MAX TZNAME_MAX 862708Swollman#endif /* defined TZNAME_MAX */ 872708Swollman#ifndef TZNAME_MAX 882708Swollman#define MY_TZNAME_MAX 255 892708Swollman#endif /* !defined TZNAME_MAX */ 902708Swollman 912708Swollmanstruct state { 922708Swollman int leapcnt; 932708Swollman int timecnt; 942708Swollman int typecnt; 952708Swollman int charcnt; 962708Swollman time_t ats[TZ_MAX_TIMES]; 972708Swollman unsigned char types[TZ_MAX_TIMES]; 982708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 999936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 1002708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 1012708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 1022708Swollman}; 1032708Swollman 1042708Swollmanstruct rule { 1052708Swollman int r_type; /* type of rule--see below */ 1062708Swollman int r_day; /* day number of rule */ 1072708Swollman int r_week; /* week number of rule */ 1082708Swollman int r_mon; /* month number of rule */ 1092708Swollman long r_time; /* transition time of rule */ 1102708Swollman}; 1112708Swollman 1122708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1132708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1142708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1152708Swollman 1162708Swollman/* 1172708Swollman** Prototypes for static functions. 1182708Swollman*/ 1192708Swollman 1202708Swollmanstatic long detzcode P((const char * codep)); 1212708Swollmanstatic const char * getzname P((const char * strp)); 1222708Swollmanstatic const char * getnum P((const char * strp, int * nump, int min, 1232708Swollman int max)); 1242708Swollmanstatic const char * getsecs P((const char * strp, long * secsp)); 1252708Swollmanstatic const char * getoffset P((const char * strp, long * offsetp)); 1262708Swollmanstatic const char * getrule P((const char * strp, struct rule * rulep)); 1272708Swollmanstatic void gmtload P((struct state * sp)); 1282708Swollmanstatic void gmtsub P((const time_t * timep, long offset, 1292708Swollman struct tm * tmp)); 1302708Swollmanstatic void localsub P((const time_t * timep, long offset, 1312708Swollman struct tm * tmp)); 1322708Swollmanstatic int increment_overflow P((int * number, int delta)); 1332708Swollmanstatic int normalize_overflow P((int * tensptr, int * unitsptr, 1342708Swollman int base)); 1352708Swollmanstatic void settzname P((void)); 1369936Swollmanstatic time_t time1 P((struct tm * tmp, 1379936Swollman void(*funcp) P((const time_t *, 1389936Swollman long, struct tm *)), 1392708Swollman long offset)); 1409936Swollmanstatic time_t time2 P((struct tm *tmp, 1419936Swollman void(*funcp) P((const time_t *, 1429936Swollman long, struct tm*)), 1432708Swollman long offset, int * okayp)); 1442708Swollmanstatic void timesub P((const time_t * timep, long offset, 1452708Swollman const struct state * sp, struct tm * tmp)); 1462708Swollmanstatic int tmcomp P((const struct tm * atmp, 1472708Swollman const struct tm * btmp)); 1482708Swollmanstatic time_t transtime P((time_t janfirst, int year, 1492708Swollman const struct rule * rulep, long offset)); 1502708Swollmanstatic int tzload P((const char * name, struct state * sp)); 1512708Swollmanstatic int tzparse P((const char * name, struct state * sp, 1522708Swollman int lastditch)); 1532708Swollman 1542708Swollman#ifdef ALL_STATE 1552708Swollmanstatic struct state * lclptr; 1562708Swollmanstatic struct state * gmtptr; 1572708Swollman#endif /* defined ALL_STATE */ 1582708Swollman 1592708Swollman#ifndef ALL_STATE 1602708Swollmanstatic struct state lclmem; 1612708Swollmanstatic struct state gmtmem; 1622708Swollman#define lclptr (&lclmem) 1632708Swollman#define gmtptr (&gmtmem) 1642708Swollman#endif /* State Farm */ 1652708Swollman 1669936Swollman#ifndef TZ_STRLEN_MAX 1679936Swollman#define TZ_STRLEN_MAX 255 1689936Swollman#endif /* !defined TZ_STRLEN_MAX */ 1699936Swollman 1709936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 1712708Swollmanstatic int lcl_is_set; 1722708Swollmanstatic int gmt_is_set; 17313545Sjulian#ifdef _THREAD_SAFE 17417706Sjulianstatic struct pthread_mutex _lcl_mutexd = PTHREAD_MUTEX_INITIALIZER; 17517706Sjulianstatic struct pthread_mutex _gmt_mutexd = PTHREAD_MUTEX_INITIALIZER; 17617706Sjulianstatic pthread_mutex_t lcl_mutex = &_lcl_mutexd; 17717706Sjulianstatic pthread_mutex_t gmt_mutex = &_gmt_mutexd; 17813545Sjulian#endif 1792708Swollman 1802708Swollmanchar * tzname[2] = { 1819936Swollman wildabbr, 1829936Swollman wildabbr 1832708Swollman}; 1842708Swollman 1859936Swollman/* 1869936Swollman** Section 4.12.3 of X3.159-1989 requires that 1879936Swollman** Except for the strftime function, these functions [asctime, 1889936Swollman** ctime, gmtime, localtime] return values in one of two static 1899936Swollman** objects: a broken-down time structure and an array of char. 1909936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 1919936Swollman*/ 1929936Swollman 1939936Swollmanstatic struct tm tm; 1949936Swollman 1952708Swollman#ifdef USG_COMPAT 1962708Swollmantime_t timezone = 0; 1972708Swollmanint daylight = 0; 1982708Swollman#endif /* defined USG_COMPAT */ 1992708Swollman 2002708Swollman#ifdef ALTZONE 2012708Swollmantime_t altzone = 0; 2022708Swollman#endif /* defined ALTZONE */ 2032708Swollman 2042708Swollmanstatic long 2052708Swollmandetzcode(codep) 2062708Swollmanconst char * const codep; 2072708Swollman{ 2082708Swollman register long result; 2092708Swollman register int i; 2102708Swollman 21117209Swollman result = (codep[0] & 0x80) ? ~0L : 0L; 2122708Swollman for (i = 0; i < 4; ++i) 2132708Swollman result = (result << 8) | (codep[i] & 0xff); 2142708Swollman return result; 2152708Swollman} 2162708Swollman 2172708Swollmanstatic void 2189936Swollmansettzname P((void)) 2192708Swollman{ 22017209Swollman register struct state * const sp = lclptr; 22117209Swollman register int i; 2222708Swollman 2239936Swollman tzname[0] = wildabbr; 2249936Swollman tzname[1] = wildabbr; 2252708Swollman#ifdef USG_COMPAT 2262708Swollman daylight = 0; 2272708Swollman timezone = 0; 2282708Swollman#endif /* defined USG_COMPAT */ 2292708Swollman#ifdef ALTZONE 2302708Swollman altzone = 0; 2312708Swollman#endif /* defined ALTZONE */ 2322708Swollman#ifdef ALL_STATE 2332708Swollman if (sp == NULL) { 2349936Swollman tzname[0] = tzname[1] = gmt; 2352708Swollman return; 2362708Swollman } 2372708Swollman#endif /* defined ALL_STATE */ 2382708Swollman for (i = 0; i < sp->typecnt; ++i) { 2392708Swollman register const struct ttinfo * const ttisp = &sp->ttis[i]; 2402708Swollman 2412708Swollman tzname[ttisp->tt_isdst] = 2429936Swollman &sp->chars[ttisp->tt_abbrind]; 2432708Swollman#ifdef USG_COMPAT 2442708Swollman if (ttisp->tt_isdst) 2452708Swollman daylight = 1; 2462708Swollman if (i == 0 || !ttisp->tt_isdst) 2472708Swollman timezone = -(ttisp->tt_gmtoff); 2482708Swollman#endif /* defined USG_COMPAT */ 2492708Swollman#ifdef ALTZONE 2502708Swollman if (i == 0 || ttisp->tt_isdst) 2512708Swollman altzone = -(ttisp->tt_gmtoff); 2522708Swollman#endif /* defined ALTZONE */ 2532708Swollman } 2542708Swollman /* 2552708Swollman ** And to get the latest zone names into tzname. . . 2562708Swollman */ 2572708Swollman for (i = 0; i < sp->timecnt; ++i) { 2582708Swollman register const struct ttinfo * const ttisp = 2592708Swollman &sp->ttis[ 2602708Swollman sp->types[i]]; 2612708Swollman 2622708Swollman tzname[ttisp->tt_isdst] = 2639936Swollman &sp->chars[ttisp->tt_abbrind]; 2642708Swollman } 2652708Swollman} 2662708Swollman 2672708Swollmanstatic int 2682708Swollmantzload(name, sp) 2692708Swollmanregister const char * name; 2702708Swollmanregister struct state * const sp; 2712708Swollman{ 2722708Swollman register const char * p; 2732708Swollman register int i; 2742708Swollman register int fid; 2752708Swollman 2762708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 2772708Swollman return -1; 2782708Swollman { 2799936Swollman register int doaccess; 28018834Swollman struct stat stab; 2819936Swollman /* 2829936Swollman ** Section 4.9.1 of the C standard says that 2839936Swollman ** "FILENAME_MAX expands to an integral constant expression 28418834Swollman ** that is the size needed for an array of char large enough 2859936Swollman ** to hold the longest file name string that the implementation 2869936Swollman ** guarantees can be opened." 2879936Swollman */ 2882708Swollman char fullname[FILENAME_MAX + 1]; 2892708Swollman 2902708Swollman if (name[0] == ':') 2912708Swollman ++name; 2922708Swollman doaccess = name[0] == '/'; 2932708Swollman if (!doaccess) { 2942708Swollman if ((p = TZDIR) == NULL) 2952708Swollman return -1; 2962708Swollman if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 2972708Swollman return -1; 2982708Swollman (void) strcpy(fullname, p); 2992708Swollman (void) strcat(fullname, "/"); 3002708Swollman (void) strcat(fullname, name); 3012708Swollman /* 3022708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 3032708Swollman */ 3042708Swollman if (strchr(name, '.') != NULL) 3052708Swollman doaccess = TRUE; 3062708Swollman name = fullname; 3072708Swollman } 3089936Swollman if (doaccess && access(name, R_OK) != 0) 3092708Swollman return -1; 3102708Swollman if ((fid = open(name, OPEN_MODE)) == -1) 3112708Swollman return -1; 31218834Swollman if ((fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) 31318834Swollman return -1; 3142708Swollman } 3152708Swollman { 3169936Swollman struct tzhead * tzhp; 3179936Swollman char buf[sizeof *sp + sizeof *tzhp]; 3189936Swollman int ttisstdcnt; 3199936Swollman int ttisgmtcnt; 3202708Swollman 3212708Swollman i = read(fid, buf, sizeof buf); 3229936Swollman if (close(fid) != 0) 3232708Swollman return -1; 3249936Swollman p = buf; 3259936Swollman p += sizeof tzhp->tzh_reserved; 3269936Swollman ttisstdcnt = (int) detzcode(p); 3279936Swollman p += 4; 3289936Swollman ttisgmtcnt = (int) detzcode(p); 3299936Swollman p += 4; 3309936Swollman sp->leapcnt = (int) detzcode(p); 3319936Swollman p += 4; 3329936Swollman sp->timecnt = (int) detzcode(p); 3339936Swollman p += 4; 3349936Swollman sp->typecnt = (int) detzcode(p); 3359936Swollman p += 4; 3369936Swollman sp->charcnt = (int) detzcode(p); 3379936Swollman p += 4; 3382708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 3392708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 3402708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 3412708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 3429936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 3439936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 3442708Swollman return -1; 3459936Swollman if (i - (p - buf) < sp->timecnt * 4 + /* ats */ 3469936Swollman sp->timecnt + /* types */ 3479936Swollman sp->typecnt * (4 + 2) + /* ttinfos */ 3489936Swollman sp->charcnt + /* chars */ 3499936Swollman sp->leapcnt * (4 + 4) + /* lsinfos */ 3509936Swollman ttisstdcnt + /* ttisstds */ 3519936Swollman ttisgmtcnt) /* ttisgmts */ 3522708Swollman return -1; 3532708Swollman for (i = 0; i < sp->timecnt; ++i) { 3542708Swollman sp->ats[i] = detzcode(p); 3552708Swollman p += 4; 3562708Swollman } 3572708Swollman for (i = 0; i < sp->timecnt; ++i) { 3582708Swollman sp->types[i] = (unsigned char) *p++; 3592708Swollman if (sp->types[i] >= sp->typecnt) 3602708Swollman return -1; 3612708Swollman } 3622708Swollman for (i = 0; i < sp->typecnt; ++i) { 3632708Swollman register struct ttinfo * ttisp; 3642708Swollman 3652708Swollman ttisp = &sp->ttis[i]; 3662708Swollman ttisp->tt_gmtoff = detzcode(p); 3672708Swollman p += 4; 3682708Swollman ttisp->tt_isdst = (unsigned char) *p++; 3692708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 3702708Swollman return -1; 3712708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 3722708Swollman if (ttisp->tt_abbrind < 0 || 3732708Swollman ttisp->tt_abbrind > sp->charcnt) 3742708Swollman return -1; 3752708Swollman } 3762708Swollman for (i = 0; i < sp->charcnt; ++i) 3772708Swollman sp->chars[i] = *p++; 3782708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 3792708Swollman for (i = 0; i < sp->leapcnt; ++i) { 3802708Swollman register struct lsinfo * lsisp; 3812708Swollman 3822708Swollman lsisp = &sp->lsis[i]; 3832708Swollman lsisp->ls_trans = detzcode(p); 3842708Swollman p += 4; 3852708Swollman lsisp->ls_corr = detzcode(p); 3862708Swollman p += 4; 3872708Swollman } 3882708Swollman for (i = 0; i < sp->typecnt; ++i) { 3892708Swollman register struct ttinfo * ttisp; 3902708Swollman 3912708Swollman ttisp = &sp->ttis[i]; 3922708Swollman if (ttisstdcnt == 0) 3932708Swollman ttisp->tt_ttisstd = FALSE; 3942708Swollman else { 3952708Swollman ttisp->tt_ttisstd = *p++; 3962708Swollman if (ttisp->tt_ttisstd != TRUE && 3972708Swollman ttisp->tt_ttisstd != FALSE) 3982708Swollman return -1; 3992708Swollman } 4002708Swollman } 4019936Swollman for (i = 0; i < sp->typecnt; ++i) { 4029936Swollman register struct ttinfo * ttisp; 4039936Swollman 4049936Swollman ttisp = &sp->ttis[i]; 4059936Swollman if (ttisgmtcnt == 0) 4069936Swollman ttisp->tt_ttisgmt = FALSE; 4079936Swollman else { 4089936Swollman ttisp->tt_ttisgmt = *p++; 4099936Swollman if (ttisp->tt_ttisgmt != TRUE && 4109936Swollman ttisp->tt_ttisgmt != FALSE) 4119936Swollman return -1; 4129936Swollman } 4139936Swollman } 4142708Swollman } 4152708Swollman return 0; 4162708Swollman} 4172708Swollman 4182708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 4192708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 4202708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 4212708Swollman}; 4222708Swollman 4232708Swollmanstatic const int year_lengths[2] = { 4242708Swollman DAYSPERNYEAR, DAYSPERLYEAR 4252708Swollman}; 4262708Swollman 4272708Swollman/* 4282708Swollman** Given a pointer into a time zone string, scan until a character that is not 4292708Swollman** a valid character in a zone name is found. Return a pointer to that 4302708Swollman** character. 4312708Swollman*/ 4322708Swollman 4332708Swollmanstatic const char * 4342708Swollmangetzname(strp) 4352708Swollmanregister const char * strp; 4362708Swollman{ 4372708Swollman register char c; 4382708Swollman 43917209Swollman while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 4402708Swollman c != '+') 4412708Swollman ++strp; 4422708Swollman return strp; 4432708Swollman} 4442708Swollman 4452708Swollman/* 4462708Swollman** Given a pointer into a time zone string, extract a number from that string. 4472708Swollman** Check that the number is within a specified range; if it is not, return 4482708Swollman** NULL. 4492708Swollman** Otherwise, return a pointer to the first character not part of the number. 4502708Swollman*/ 4512708Swollman 4522708Swollmanstatic const char * 4532708Swollmangetnum(strp, nump, min, max) 4542708Swollmanregister const char * strp; 4552708Swollmanint * const nump; 4562708Swollmanconst int min; 4572708Swollmanconst int max; 4582708Swollman{ 4592708Swollman register char c; 4602708Swollman register int num; 4612708Swollman 46217209Swollman if (strp == NULL || !is_digit(c = *strp)) 4632708Swollman return NULL; 4642708Swollman num = 0; 46517209Swollman do { 4662708Swollman num = num * 10 + (c - '0'); 4672708Swollman if (num > max) 4682708Swollman return NULL; /* illegal value */ 46917209Swollman c = *++strp; 47017209Swollman } while (is_digit(c)); 4712708Swollman if (num < min) 4722708Swollman return NULL; /* illegal value */ 4732708Swollman *nump = num; 4742708Swollman return strp; 4752708Swollman} 4762708Swollman 4772708Swollman/* 4782708Swollman** Given a pointer into a time zone string, extract a number of seconds, 4792708Swollman** in hh[:mm[:ss]] form, from the string. 4802708Swollman** If any error occurs, return NULL. 4812708Swollman** Otherwise, return a pointer to the first character not part of the number 4822708Swollman** of seconds. 4832708Swollman*/ 4842708Swollman 4852708Swollmanstatic const char * 4862708Swollmangetsecs(strp, secsp) 4872708Swollmanregister const char * strp; 4882708Swollmanlong * const secsp; 4892708Swollman{ 4902708Swollman int num; 4912708Swollman 4929936Swollman /* 4939936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 4949936Swollman ** "M10.4.6/26", which does not conform to Posix, 4959936Swollman ** but which specifies the equivalent of 4969936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 4979936Swollman */ 4989936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 4992708Swollman if (strp == NULL) 5002708Swollman return NULL; 5019936Swollman *secsp = num * (long) SECSPERHOUR; 5022708Swollman if (*strp == ':') { 5032708Swollman ++strp; 5042708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 5052708Swollman if (strp == NULL) 5062708Swollman return NULL; 5072708Swollman *secsp += num * SECSPERMIN; 5082708Swollman if (*strp == ':') { 5092708Swollman ++strp; 5109936Swollman /* `SECSPERMIN' allows for leap seconds. */ 5119936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 5122708Swollman if (strp == NULL) 5132708Swollman return NULL; 5142708Swollman *secsp += num; 5152708Swollman } 5162708Swollman } 5172708Swollman return strp; 5182708Swollman} 5192708Swollman 5202708Swollman/* 5212708Swollman** Given a pointer into a time zone string, extract an offset, in 5222708Swollman** [+-]hh[:mm[:ss]] form, from the string. 5232708Swollman** If any error occurs, return NULL. 5242708Swollman** Otherwise, return a pointer to the first character not part of the time. 5252708Swollman*/ 5262708Swollman 5272708Swollmanstatic const char * 5282708Swollmangetoffset(strp, offsetp) 5292708Swollmanregister const char * strp; 5302708Swollmanlong * const offsetp; 5312708Swollman{ 53217209Swollman register int neg = 0; 5332708Swollman 5342708Swollman if (*strp == '-') { 5352708Swollman neg = 1; 5362708Swollman ++strp; 53717209Swollman } else if (*strp == '+') 53817209Swollman ++strp; 5392708Swollman strp = getsecs(strp, offsetp); 5402708Swollman if (strp == NULL) 5412708Swollman return NULL; /* illegal time */ 5422708Swollman if (neg) 5432708Swollman *offsetp = -*offsetp; 5442708Swollman return strp; 5452708Swollman} 5462708Swollman 5472708Swollman/* 5482708Swollman** Given a pointer into a time zone string, extract a rule in the form 5492708Swollman** date[/time]. See POSIX section 8 for the format of "date" and "time". 5502708Swollman** If a valid rule is not found, return NULL. 5512708Swollman** Otherwise, return a pointer to the first character not part of the rule. 5522708Swollman*/ 5532708Swollman 5542708Swollmanstatic const char * 5552708Swollmangetrule(strp, rulep) 5562708Swollmanconst char * strp; 5572708Swollmanregister struct rule * const rulep; 5582708Swollman{ 5592708Swollman if (*strp == 'J') { 5602708Swollman /* 5612708Swollman ** Julian day. 5622708Swollman */ 5632708Swollman rulep->r_type = JULIAN_DAY; 5642708Swollman ++strp; 5652708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 5662708Swollman } else if (*strp == 'M') { 5672708Swollman /* 5682708Swollman ** Month, week, day. 5692708Swollman */ 5702708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 5712708Swollman ++strp; 5722708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 5732708Swollman if (strp == NULL) 5742708Swollman return NULL; 5752708Swollman if (*strp++ != '.') 5762708Swollman return NULL; 5772708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 5782708Swollman if (strp == NULL) 5792708Swollman return NULL; 5802708Swollman if (*strp++ != '.') 5812708Swollman return NULL; 5822708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 58317209Swollman } else if (is_digit(*strp)) { 5842708Swollman /* 5852708Swollman ** Day of year. 5862708Swollman */ 5872708Swollman rulep->r_type = DAY_OF_YEAR; 5882708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 5892708Swollman } else return NULL; /* invalid format */ 5902708Swollman if (strp == NULL) 5912708Swollman return NULL; 5922708Swollman if (*strp == '/') { 5932708Swollman /* 5942708Swollman ** Time specified. 5952708Swollman */ 5962708Swollman ++strp; 5972708Swollman strp = getsecs(strp, &rulep->r_time); 5982708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 5992708Swollman return strp; 6002708Swollman} 6012708Swollman 6022708Swollman/* 6032708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 6042708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect, 6052708Swollman** calculate the Epoch-relative time that rule takes effect. 6062708Swollman*/ 6072708Swollman 6082708Swollmanstatic time_t 6092708Swollmantranstime(janfirst, year, rulep, offset) 6102708Swollmanconst time_t janfirst; 6112708Swollmanconst int year; 6122708Swollmanregister const struct rule * const rulep; 6132708Swollmanconst long offset; 6142708Swollman{ 6152708Swollman register int leapyear; 6162708Swollman register time_t value; 6172708Swollman register int i; 6182708Swollman int d, m1, yy0, yy1, yy2, dow; 6192708Swollman 6209936Swollman INITIALIZE(value); 6212708Swollman leapyear = isleap(year); 6222708Swollman switch (rulep->r_type) { 6232708Swollman 6242708Swollman case JULIAN_DAY: 6252708Swollman /* 6262708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 6272708Swollman ** years. 6282708Swollman ** In non-leap years, or if the day number is 59 or less, just 6292708Swollman ** add SECSPERDAY times the day number-1 to the time of 6302708Swollman ** January 1, midnight, to get the day. 6312708Swollman */ 6322708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 6332708Swollman if (leapyear && rulep->r_day >= 60) 6342708Swollman value += SECSPERDAY; 6352708Swollman break; 6362708Swollman 6372708Swollman case DAY_OF_YEAR: 6382708Swollman /* 6392708Swollman ** n - day of year. 6402708Swollman ** Just add SECSPERDAY times the day number to the time of 6412708Swollman ** January 1, midnight, to get the day. 6422708Swollman */ 6432708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 6442708Swollman break; 6452708Swollman 6462708Swollman case MONTH_NTH_DAY_OF_WEEK: 6472708Swollman /* 6482708Swollman ** Mm.n.d - nth "dth day" of month m. 6492708Swollman */ 6502708Swollman value = janfirst; 6512708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 6522708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 6532708Swollman 6542708Swollman /* 6552708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 6562708Swollman ** month. 6572708Swollman */ 6582708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 6592708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 6602708Swollman yy1 = yy0 / 100; 6612708Swollman yy2 = yy0 % 100; 6622708Swollman dow = ((26 * m1 - 2) / 10 + 6632708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 6642708Swollman if (dow < 0) 6652708Swollman dow += DAYSPERWEEK; 6662708Swollman 6672708Swollman /* 6682708Swollman ** "dow" is the day-of-week of the first day of the month. Get 6692708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 6702708Swollman ** month. 6712708Swollman */ 6722708Swollman d = rulep->r_day - dow; 6732708Swollman if (d < 0) 6742708Swollman d += DAYSPERWEEK; 6752708Swollman for (i = 1; i < rulep->r_week; ++i) { 6762708Swollman if (d + DAYSPERWEEK >= 6772708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 6782708Swollman break; 6792708Swollman d += DAYSPERWEEK; 6802708Swollman } 6812708Swollman 6822708Swollman /* 6832708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 6842708Swollman */ 6852708Swollman value += d * SECSPERDAY; 6862708Swollman break; 6872708Swollman } 6882708Swollman 6892708Swollman /* 6902708Swollman ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 6912708Swollman ** question. To get the Epoch-relative time of the specified local 6922708Swollman ** time on that day, add the transition time and the current offset 6932708Swollman ** from GMT. 6942708Swollman */ 6952708Swollman return value + rulep->r_time + offset; 6962708Swollman} 6972708Swollman 6982708Swollman/* 6992708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 7002708Swollman** appropriate. 7012708Swollman*/ 7022708Swollman 7032708Swollmanstatic int 7042708Swollmantzparse(name, sp, lastditch) 7052708Swollmanconst char * name; 7062708Swollmanregister struct state * const sp; 7072708Swollmanconst int lastditch; 7082708Swollman{ 7092708Swollman const char * stdname; 7102708Swollman const char * dstname; 7119936Swollman size_t stdlen; 7129936Swollman size_t dstlen; 7132708Swollman long stdoffset; 7142708Swollman long dstoffset; 7152708Swollman register time_t * atp; 7162708Swollman register unsigned char * typep; 7172708Swollman register char * cp; 7182708Swollman register int load_result; 7192708Swollman 7209936Swollman INITIALIZE(dstname); 7212708Swollman stdname = name; 7222708Swollman if (lastditch) { 7232708Swollman stdlen = strlen(name); /* length of standard zone name */ 7242708Swollman name += stdlen; 7252708Swollman if (stdlen >= sizeof sp->chars) 7262708Swollman stdlen = (sizeof sp->chars) - 1; 72721659Swollman stdoffset = 0; 7282708Swollman } else { 7292708Swollman name = getzname(name); 7302708Swollman stdlen = name - stdname; 7312708Swollman if (stdlen < 3) 7322708Swollman return -1; 73321659Swollman if (*name == '\0') 73421659Swollman return -1; /* was "stdoffset = 0;" */ 73521659Swollman else { 73621659Swollman name = getoffset(name, &stdoffset); 73721659Swollman if (name == NULL) 73821659Swollman return -1; 73921659Swollman } 7402708Swollman } 7412708Swollman load_result = tzload(TZDEFRULES, sp); 7422708Swollman if (load_result != 0) 7432708Swollman sp->leapcnt = 0; /* so, we're off a little */ 7442708Swollman if (*name != '\0') { 7452708Swollman dstname = name; 7462708Swollman name = getzname(name); 7472708Swollman dstlen = name - dstname; /* length of DST zone name */ 7482708Swollman if (dstlen < 3) 7492708Swollman return -1; 7502708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 7512708Swollman name = getoffset(name, &dstoffset); 7522708Swollman if (name == NULL) 7532708Swollman return -1; 7542708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 7552708Swollman if (*name == ',' || *name == ';') { 7562708Swollman struct rule start; 7572708Swollman struct rule end; 7582708Swollman register int year; 7592708Swollman register time_t janfirst; 7602708Swollman time_t starttime; 7612708Swollman time_t endtime; 7622708Swollman 7632708Swollman ++name; 7642708Swollman if ((name = getrule(name, &start)) == NULL) 7652708Swollman return -1; 7662708Swollman if (*name++ != ',') 7672708Swollman return -1; 7682708Swollman if ((name = getrule(name, &end)) == NULL) 7692708Swollman return -1; 7702708Swollman if (*name != '\0') 7712708Swollman return -1; 7722708Swollman sp->typecnt = 2; /* standard time and DST */ 7732708Swollman /* 7742708Swollman ** Two transitions per year, from EPOCH_YEAR to 2037. 7752708Swollman */ 7762708Swollman sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 7772708Swollman if (sp->timecnt > TZ_MAX_TIMES) 7782708Swollman return -1; 7792708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 7802708Swollman sp->ttis[0].tt_isdst = 1; 7812708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 7822708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 7832708Swollman sp->ttis[1].tt_isdst = 0; 7842708Swollman sp->ttis[1].tt_abbrind = 0; 7852708Swollman atp = sp->ats; 7862708Swollman typep = sp->types; 7872708Swollman janfirst = 0; 7882708Swollman for (year = EPOCH_YEAR; year <= 2037; ++year) { 7892708Swollman starttime = transtime(janfirst, year, &start, 7902708Swollman stdoffset); 7912708Swollman endtime = transtime(janfirst, year, &end, 7922708Swollman dstoffset); 7932708Swollman if (starttime > endtime) { 7942708Swollman *atp++ = endtime; 7952708Swollman *typep++ = 1; /* DST ends */ 7962708Swollman *atp++ = starttime; 7972708Swollman *typep++ = 0; /* DST begins */ 7982708Swollman } else { 7992708Swollman *atp++ = starttime; 8002708Swollman *typep++ = 0; /* DST begins */ 8012708Swollman *atp++ = endtime; 8022708Swollman *typep++ = 1; /* DST ends */ 8032708Swollman } 8042708Swollman janfirst += year_lengths[isleap(year)] * 8052708Swollman SECSPERDAY; 8062708Swollman } 8072708Swollman } else { 8089936Swollman register long theirstdoffset; 8099936Swollman register long theirdstoffset; 8109936Swollman register long theiroffset; 8119936Swollman register int isdst; 8122708Swollman register int i; 8139936Swollman register int j; 8142708Swollman 8152708Swollman if (*name != '\0') 8162708Swollman return -1; 8172708Swollman if (load_result != 0) 8182708Swollman return -1; 8192708Swollman /* 8209936Swollman ** Initial values of theirstdoffset and theirdstoffset. 8212708Swollman */ 8229936Swollman theirstdoffset = 0; 8239936Swollman for (i = 0; i < sp->timecnt; ++i) { 8249936Swollman j = sp->types[i]; 8259936Swollman if (!sp->ttis[j].tt_isdst) { 82617209Swollman theirstdoffset = 82717209Swollman -sp->ttis[j].tt_gmtoff; 8289936Swollman break; 8292708Swollman } 8302708Swollman } 8319936Swollman theirdstoffset = 0; 8329936Swollman for (i = 0; i < sp->timecnt; ++i) { 8339936Swollman j = sp->types[i]; 8349936Swollman if (sp->ttis[j].tt_isdst) { 83517209Swollman theirdstoffset = 83617209Swollman -sp->ttis[j].tt_gmtoff; 8379936Swollman break; 8389936Swollman } 8399936Swollman } 8402708Swollman /* 8419936Swollman ** Initially we're assumed to be in standard time. 8422708Swollman */ 8439936Swollman isdst = FALSE; 8449936Swollman theiroffset = theirstdoffset; 8452708Swollman /* 8469936Swollman ** Now juggle transition times and types 8479936Swollman ** tracking offsets as you do. 8482708Swollman */ 8492708Swollman for (i = 0; i < sp->timecnt; ++i) { 8509936Swollman j = sp->types[i]; 8519936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 8529936Swollman if (sp->ttis[j].tt_ttisgmt) { 8539936Swollman /* No adjustment to transition time */ 8549936Swollman } else { 8559936Swollman /* 8569936Swollman ** If summer time is in effect, and the 8579936Swollman ** transition time was not specified as 8589936Swollman ** standard time, add the summer time 8599936Swollman ** offset to the transition time; 8609936Swollman ** otherwise, add the standard time 8619936Swollman ** offset to the transition time. 8629936Swollman */ 8639936Swollman /* 8649936Swollman ** Transitions from DST to DDST 8659936Swollman ** will effectively disappear since 8669936Swollman ** POSIX provides for only one DST 8679936Swollman ** offset. 8689936Swollman */ 8699936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 8709936Swollman sp->ats[i] += dstoffset - 8719936Swollman theirdstoffset; 8729936Swollman } else { 8739936Swollman sp->ats[i] += stdoffset - 8749936Swollman theirstdoffset; 8759936Swollman } 8769936Swollman } 8779936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 8789936Swollman if (sp->ttis[j].tt_isdst) 8799936Swollman theirdstoffset = theiroffset; 8809936Swollman else theirstdoffset = theiroffset; 8812708Swollman } 8829936Swollman /* 8839936Swollman ** Finally, fill in ttis. 8849936Swollman ** ttisstd and ttisgmt need not be handled. 8859936Swollman */ 8869936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8879936Swollman sp->ttis[0].tt_isdst = FALSE; 8889936Swollman sp->ttis[0].tt_abbrind = 0; 8899936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 8909936Swollman sp->ttis[1].tt_isdst = TRUE; 8919936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 8922708Swollman } 8932708Swollman } else { 8942708Swollman dstlen = 0; 8952708Swollman sp->typecnt = 1; /* only standard time */ 8962708Swollman sp->timecnt = 0; 8972708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8982708Swollman sp->ttis[0].tt_isdst = 0; 8992708Swollman sp->ttis[0].tt_abbrind = 0; 9002708Swollman } 9012708Swollman sp->charcnt = stdlen + 1; 9022708Swollman if (dstlen != 0) 9032708Swollman sp->charcnt += dstlen + 1; 9042708Swollman if (sp->charcnt > sizeof sp->chars) 9052708Swollman return -1; 9062708Swollman cp = sp->chars; 9072708Swollman (void) strncpy(cp, stdname, stdlen); 9082708Swollman cp += stdlen; 9092708Swollman *cp++ = '\0'; 9102708Swollman if (dstlen != 0) { 9112708Swollman (void) strncpy(cp, dstname, dstlen); 9122708Swollman *(cp + dstlen) = '\0'; 9132708Swollman } 9142708Swollman return 0; 9152708Swollman} 9162708Swollman 9172708Swollmanstatic void 9182708Swollmangmtload(sp) 9192708Swollmanstruct state * const sp; 9202708Swollman{ 9219936Swollman if (tzload(gmt, sp) != 0) 9229936Swollman (void) tzparse(gmt, sp, TRUE); 9232708Swollman} 9242708Swollman 9252708Swollman#ifndef STD_INSPIRED 9269936Swollman/* 9279936Swollman** A non-static declaration of tzsetwall in a system header file 9289936Swollman** may cause a warning about this upcoming static declaration... 9299936Swollman*/ 9302708Swollmanstatic 9312708Swollman#endif /* !defined STD_INSPIRED */ 93213545Sjulian#ifdef _THREAD_SAFE 9332708Swollmanvoid 93413545Sjuliantzsetwall_basic P((void)) 93513545Sjulian#else 93613545Sjulianvoid 9379936Swollmantzsetwall P((void)) 93813545Sjulian#endif 9392708Swollman{ 9409936Swollman if (lcl_is_set < 0) 9419936Swollman return; 9429936Swollman lcl_is_set = -1; 9439936Swollman 9442708Swollman#ifdef ALL_STATE 9452708Swollman if (lclptr == NULL) { 9462708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9472708Swollman if (lclptr == NULL) { 9482708Swollman settzname(); /* all we can do */ 9492708Swollman return; 9502708Swollman } 9512708Swollman } 9522708Swollman#endif /* defined ALL_STATE */ 9532708Swollman if (tzload((char *) NULL, lclptr) != 0) 9542708Swollman gmtload(lclptr); 9552708Swollman settzname(); 9562708Swollman} 9572708Swollman 95813545Sjulian#ifdef _THREAD_SAFE 9592708Swollmanvoid 96013545Sjuliantzsetwall P((void)) 96113545Sjulian{ 96213545Sjulian pthread_mutex_lock(&lcl_mutex); 96313545Sjulian tzsetwall_basic(); 96413545Sjulian pthread_mutex_unlock(&lcl_mutex); 96513545Sjulian} 96613545Sjulian#endif 96713545Sjulian 96813545Sjulian#ifdef _THREAD_SAFE 96913545Sjulianstatic void 97013545Sjuliantzset_basic P((void)) 97113545Sjulian#else 97213545Sjulianvoid 9739936Swollmantzset P((void)) 97413545Sjulian#endif 9752708Swollman{ 9762708Swollman register const char * name; 9772708Swollman 9782708Swollman name = getenv("TZ"); 9792708Swollman if (name == NULL) { 9802708Swollman tzsetwall(); 9812708Swollman return; 9822708Swollman } 9839936Swollman 9849936Swollman if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) 9859936Swollman return; 9869936Swollman lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); 9879936Swollman if (lcl_is_set) 9889936Swollman (void) strcpy(lcl_TZname, name); 9899936Swollman 9902708Swollman#ifdef ALL_STATE 9912708Swollman if (lclptr == NULL) { 9922708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9932708Swollman if (lclptr == NULL) { 9942708Swollman settzname(); /* all we can do */ 9952708Swollman return; 9962708Swollman } 9972708Swollman } 9982708Swollman#endif /* defined ALL_STATE */ 9992708Swollman if (*name == '\0') { 10002708Swollman /* 10012708Swollman ** User wants it fast rather than right. 10022708Swollman */ 10032708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 10042708Swollman lclptr->timecnt = 0; 10052708Swollman lclptr->ttis[0].tt_gmtoff = 0; 10062708Swollman lclptr->ttis[0].tt_abbrind = 0; 10079936Swollman (void) strcpy(lclptr->chars, gmt); 10082708Swollman } else if (tzload(name, lclptr) != 0) 10092708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 10102708Swollman (void) gmtload(lclptr); 10112708Swollman settzname(); 10122708Swollman} 10132708Swollman 101413545Sjulian#ifdef _THREAD_SAFE 101513545Sjulianvoid 101613545Sjuliantzset P((void)) 101713545Sjulian{ 101813545Sjulian pthread_mutex_lock(&lcl_mutex); 101913545Sjulian tzset_basic(); 102013545Sjulian pthread_mutex_unlock(&lcl_mutex); 102113545Sjulian} 102213545Sjulian#endif 102313545Sjulian 10242708Swollman/* 10252708Swollman** The easy way to behave "as if no library function calls" localtime 10262708Swollman** is to not call it--so we drop its guts into "localsub", which can be 10272708Swollman** freely called. (And no, the PANS doesn't require the above behavior-- 10282708Swollman** but it *is* desirable.) 10292708Swollman** 10302708Swollman** The unused offset argument is for the benefit of mktime variants. 10312708Swollman*/ 10322708Swollman 10332708Swollman/*ARGSUSED*/ 10342708Swollmanstatic void 10352708Swollmanlocalsub(timep, offset, tmp) 10362708Swollmanconst time_t * const timep; 10372708Swollmanconst long offset; 10382708Swollmanstruct tm * const tmp; 10392708Swollman{ 10409936Swollman register struct state * sp; 10412708Swollman register const struct ttinfo * ttisp; 10422708Swollman register int i; 10432708Swollman const time_t t = *timep; 10442708Swollman 10452708Swollman sp = lclptr; 10462708Swollman#ifdef ALL_STATE 10472708Swollman if (sp == NULL) { 10482708Swollman gmtsub(timep, offset, tmp); 10492708Swollman return; 10502708Swollman } 10512708Swollman#endif /* defined ALL_STATE */ 10522708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 10532708Swollman i = 0; 10542708Swollman while (sp->ttis[i].tt_isdst) 10552708Swollman if (++i >= sp->typecnt) { 10562708Swollman i = 0; 10572708Swollman break; 10582708Swollman } 10592708Swollman } else { 10602708Swollman for (i = 1; i < sp->timecnt; ++i) 10612708Swollman if (t < sp->ats[i]) 10622708Swollman break; 10632708Swollman i = sp->types[i - 1]; 10642708Swollman } 10652708Swollman ttisp = &sp->ttis[i]; 10662708Swollman /* 10672708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 10682708Swollman ** you'd replace the statement below with 10692708Swollman ** t += ttisp->tt_gmtoff; 10702708Swollman ** timesub(&t, 0L, sp, tmp); 10712708Swollman */ 10722708Swollman timesub(&t, ttisp->tt_gmtoff, sp, tmp); 10732708Swollman tmp->tm_isdst = ttisp->tt_isdst; 10749936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 10752708Swollman#ifdef TM_ZONE 10769936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 10772708Swollman#endif /* defined TM_ZONE */ 10782708Swollman} 10792708Swollman 108013545Sjulian#ifdef _THREAD_SAFE 108119636Shsustruct tm * 108213545Sjulianlocaltime_r(timep, p_tm) 108313545Sjulianconst time_t * const timep; 108413545Sjulianstruct tm *p_tm; 108513545Sjulian{ 108613545Sjulian pthread_mutex_lock(&lcl_mutex); 108713545Sjulian tzset(); 108813545Sjulian localsub(timep, 0L, p_tm); 108913545Sjulian pthread_mutex_unlock(&lcl_mutex); 109019636Shsu return(p_tm); 109113545Sjulian} 109213545Sjulian#endif 109313545Sjulian 10942708Swollmanstruct tm * 10952708Swollmanlocaltime(timep) 10962708Swollmanconst time_t * const timep; 10972708Swollman{ 109813545Sjulian#ifdef _THREAD_SAFE 109917706Sjulian static struct pthread_mutex _localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 110017706Sjulian static pthread_mutex_t localtime_mutex = &_localtime_mutex; 110113545Sjulian static pthread_key_t localtime_key = -1; 110213545Sjulian struct tm *p_tm; 110313545Sjulian 110413545Sjulian pthread_mutex_lock(&localtime_mutex); 110513545Sjulian if (localtime_key < 0) { 110619636Shsu if (pthread_key_create(&localtime_key, free) < 0) { 110713545Sjulian pthread_mutex_unlock(&localtime_mutex); 110813545Sjulian return(NULL); 110913545Sjulian } 111013545Sjulian } 111113545Sjulian pthread_mutex_unlock(&localtime_mutex); 111219636Shsu if ((p_tm = pthread_getspecific(localtime_key)) != 0) { 111313545Sjulian return(NULL); 111413545Sjulian } else if (p_tm == NULL) { 111513545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 111613545Sjulian return(NULL); 111713545Sjulian } 111813545Sjulian pthread_setspecific(localtime_key, p_tm); 111913545Sjulian } 112013545Sjulian pthread_mutex_lock(&lcl_mutex); 11219936Swollman tzset(); 112213545Sjulian localsub(timep, 0L, p_tm); 112313545Sjulian pthread_mutex_unlock(&lcl_mutex); 112413545Sjulian return p_tm; 112513545Sjulian#else 112613545Sjulian tzset(); 11272708Swollman localsub(timep, 0L, &tm); 11282708Swollman return &tm; 112913545Sjulian#endif 11302708Swollman} 11312708Swollman 11322708Swollman/* 11332708Swollman** gmtsub is to gmtime as localsub is to localtime. 11342708Swollman*/ 11352708Swollman 11362708Swollmanstatic void 11372708Swollmangmtsub(timep, offset, tmp) 11382708Swollmanconst time_t * const timep; 11392708Swollmanconst long offset; 11402708Swollmanstruct tm * const tmp; 11412708Swollman{ 114213545Sjulian#ifdef _THREAD_SAFE 114313545Sjulian pthread_mutex_lock(&gmt_mutex); 114413545Sjulian#endif 11452708Swollman if (!gmt_is_set) { 11462708Swollman gmt_is_set = TRUE; 11472708Swollman#ifdef ALL_STATE 11482708Swollman gmtptr = (struct state *) malloc(sizeof *gmtptr); 11492708Swollman if (gmtptr != NULL) 11502708Swollman#endif /* defined ALL_STATE */ 11512708Swollman gmtload(gmtptr); 11522708Swollman } 115313545Sjulian#ifdef _THREAD_SAFE 115413545Sjulian pthread_mutex_unlock(&gmt_mutex); 115513545Sjulian#endif 11562708Swollman timesub(timep, offset, gmtptr, tmp); 11572708Swollman#ifdef TM_ZONE 11582708Swollman /* 11592708Swollman ** Could get fancy here and deliver something such as 11602708Swollman ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 11612708Swollman ** but this is no time for a treasure hunt. 11622708Swollman */ 11632708Swollman if (offset != 0) 11649936Swollman tmp->TM_ZONE = wildabbr; 11652708Swollman else { 11662708Swollman#ifdef ALL_STATE 11672708Swollman if (gmtptr == NULL) 11689936Swollman tmp->TM_ZONE = gmt; 11692708Swollman else tmp->TM_ZONE = gmtptr->chars; 11702708Swollman#endif /* defined ALL_STATE */ 11712708Swollman#ifndef ALL_STATE 11722708Swollman tmp->TM_ZONE = gmtptr->chars; 11732708Swollman#endif /* State Farm */ 11742708Swollman } 11752708Swollman#endif /* defined TM_ZONE */ 11762708Swollman} 11772708Swollman 11782708Swollmanstruct tm * 11792708Swollmangmtime(timep) 11802708Swollmanconst time_t * const timep; 11812708Swollman{ 118213545Sjulian#ifdef _THREAD_SAFE 118317706Sjulian static struct pthread_mutex _gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 118417706Sjulian static pthread_mutex_t gmtime_mutex = &_gmtime_mutex; 118513545Sjulian static pthread_key_t gmtime_key = -1; 118613545Sjulian struct tm *p_tm; 118713545Sjulian 118813545Sjulian pthread_mutex_lock(&gmtime_mutex); 118913545Sjulian if (gmtime_key < 0) { 119019636Shsu if (pthread_key_create(&gmtime_key, free) < 0) { 119113545Sjulian pthread_mutex_unlock(&gmtime_mutex); 119213545Sjulian return(NULL); 119313545Sjulian } 119413545Sjulian } 119513545Sjulian pthread_mutex_unlock(&gmtime_mutex); 119619636Shsu if ((p_tm = pthread_getspecific(gmtime_key)) != 0) { 119713545Sjulian return(NULL); 119813545Sjulian } else if (p_tm == NULL) { 119913545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 120013545Sjulian return(NULL); 120113545Sjulian } 120213545Sjulian pthread_setspecific(gmtime_key, p_tm); 120313545Sjulian } 120413545Sjulian gmtsub(timep, 0L, p_tm); 120513545Sjulian return(p_tm); 120613545Sjulian#else 12072708Swollman gmtsub(timep, 0L, &tm); 12082708Swollman return &tm; 120913545Sjulian#endif 12102708Swollman} 12112708Swollman 121213545Sjulian#ifdef _THREAD_SAFE 121319636Shsustruct tm * 121413545Sjuliangmtime_r(const time_t * timep, struct tm * tm) 121513545Sjulian{ 121613545Sjulian gmtsub(timep, 0L, tm); 121719636Shsu return(tm); 121813545Sjulian} 121913545Sjulian#endif 122013545Sjulian 12212708Swollman#ifdef STD_INSPIRED 12222708Swollman 12232708Swollmanstruct tm * 12242708Swollmanofftime(timep, offset) 12252708Swollmanconst time_t * const timep; 12262708Swollmanconst long offset; 12272708Swollman{ 12282708Swollman gmtsub(timep, offset, &tm); 12292708Swollman return &tm; 12302708Swollman} 12312708Swollman 12322708Swollman#endif /* defined STD_INSPIRED */ 12332708Swollman 12342708Swollmanstatic void 12352708Swollmantimesub(timep, offset, sp, tmp) 12362708Swollmanconst time_t * const timep; 12372708Swollmanconst long offset; 12382708Swollmanregister const struct state * const sp; 12392708Swollmanregister struct tm * const tmp; 12402708Swollman{ 12412708Swollman register const struct lsinfo * lp; 12422708Swollman register long days; 12432708Swollman register long rem; 12442708Swollman register int y; 12452708Swollman register int yleap; 12462708Swollman register const int * ip; 12472708Swollman register long corr; 12482708Swollman register int hit; 12492708Swollman register int i; 12502708Swollman 12512708Swollman corr = 0; 12522708Swollman hit = 0; 12532708Swollman#ifdef ALL_STATE 12542708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 12552708Swollman#endif /* defined ALL_STATE */ 12562708Swollman#ifndef ALL_STATE 12572708Swollman i = sp->leapcnt; 12582708Swollman#endif /* State Farm */ 12592708Swollman while (--i >= 0) { 12602708Swollman lp = &sp->lsis[i]; 12612708Swollman if (*timep >= lp->ls_trans) { 12622708Swollman if (*timep == lp->ls_trans) { 12632708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 12642708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 12652708Swollman if (hit) 12662708Swollman while (i > 0 && 12672708Swollman sp->lsis[i].ls_trans == 12682708Swollman sp->lsis[i - 1].ls_trans + 1 && 12692708Swollman sp->lsis[i].ls_corr == 12702708Swollman sp->lsis[i - 1].ls_corr + 1) { 12712708Swollman ++hit; 12722708Swollman --i; 12732708Swollman } 12742708Swollman } 12752708Swollman corr = lp->ls_corr; 12762708Swollman break; 12772708Swollman } 12782708Swollman } 12792708Swollman days = *timep / SECSPERDAY; 12802708Swollman rem = *timep % SECSPERDAY; 12812708Swollman#ifdef mc68k 12822708Swollman if (*timep == 0x80000000) { 12832708Swollman /* 12842708Swollman ** A 3B1 muffs the division on the most negative number. 12852708Swollman */ 12862708Swollman days = -24855; 12872708Swollman rem = -11648; 12882708Swollman } 12899936Swollman#endif /* defined mc68k */ 12902708Swollman rem += (offset - corr); 12912708Swollman while (rem < 0) { 12922708Swollman rem += SECSPERDAY; 12932708Swollman --days; 12942708Swollman } 12952708Swollman while (rem >= SECSPERDAY) { 12962708Swollman rem -= SECSPERDAY; 12972708Swollman ++days; 12982708Swollman } 12992708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 13002708Swollman rem = rem % SECSPERHOUR; 13012708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 130217209Swollman /* 130317209Swollman ** A positive leap second requires a special 130417209Swollman ** representation. This uses "... ??:59:60" et seq. 130517209Swollman */ 130617209Swollman tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; 13072708Swollman tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 13082708Swollman if (tmp->tm_wday < 0) 13092708Swollman tmp->tm_wday += DAYSPERWEEK; 13102708Swollman y = EPOCH_YEAR; 131117209Swollman#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) 131217209Swollman while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { 131317209Swollman register int newy; 131417209Swollman 131517209Swollman newy = y + days / DAYSPERNYEAR; 131617209Swollman if (days < 0) 131717209Swollman --newy; 131817209Swollman days -= (newy - y) * DAYSPERNYEAR + 131917209Swollman LEAPS_THRU_END_OF(newy - 1) - 132017209Swollman LEAPS_THRU_END_OF(y - 1); 132117209Swollman y = newy; 132217209Swollman } 13232708Swollman tmp->tm_year = y - TM_YEAR_BASE; 13242708Swollman tmp->tm_yday = (int) days; 13252708Swollman ip = mon_lengths[yleap]; 13262708Swollman for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 13272708Swollman days = days - (long) ip[tmp->tm_mon]; 13282708Swollman tmp->tm_mday = (int) (days + 1); 13292708Swollman tmp->tm_isdst = 0; 13302708Swollman#ifdef TM_GMTOFF 13312708Swollman tmp->TM_GMTOFF = offset; 13322708Swollman#endif /* defined TM_GMTOFF */ 13332708Swollman} 13342708Swollman 13352708Swollmanchar * 13362708Swollmanctime(timep) 13372708Swollmanconst time_t * const timep; 13382708Swollman{ 13399936Swollman/* 13409936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 13419936Swollman** The ctime funciton converts the calendar time pointed to by timer 13429936Swollman** to local time in the form of a string. It is equivalent to 13439936Swollman** asctime(localtime(timer)) 13449936Swollman*/ 13452708Swollman return asctime(localtime(timep)); 13462708Swollman} 13472708Swollman 13482708Swollman/* 13492708Swollman** Adapted from code provided by Robert Elz, who writes: 13502708Swollman** The "best" way to do mktime I think is based on an idea of Bob 135117209Swollman** Kridle's (so its said...) from a long time ago. 135217209Swollman** [kridle@xinet.com as of 1996-01-16.] 13532708Swollman** It does a binary search of the time_t space. Since time_t's are 13542708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 13552708Swollman** would still be very reasonable). 13562708Swollman*/ 13572708Swollman 13582708Swollman#ifndef WRONG 13592708Swollman#define WRONG (-1) 13602708Swollman#endif /* !defined WRONG */ 13612708Swollman 13622708Swollman/* 13632708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 13642708Swollman*/ 13652708Swollman 13662708Swollmanstatic int 13672708Swollmanincrement_overflow(number, delta) 13682708Swollmanint * number; 13692708Swollmanint delta; 13702708Swollman{ 13719936Swollman int number0; 13728870Srgrimes 13732708Swollman number0 = *number; 13742708Swollman *number += delta; 13752708Swollman return (*number < number0) != (delta < 0); 13762708Swollman} 13772708Swollman 13782708Swollmanstatic int 13792708Swollmannormalize_overflow(tensptr, unitsptr, base) 13802708Swollmanint * const tensptr; 13812708Swollmanint * const unitsptr; 13822708Swollmanconst int base; 13832708Swollman{ 13842708Swollman register int tensdelta; 13852708Swollman 13862708Swollman tensdelta = (*unitsptr >= 0) ? 13872708Swollman (*unitsptr / base) : 13882708Swollman (-1 - (-1 - *unitsptr) / base); 13892708Swollman *unitsptr -= tensdelta * base; 13902708Swollman return increment_overflow(tensptr, tensdelta); 13912708Swollman} 13922708Swollman 13932708Swollmanstatic int 13942708Swollmantmcomp(atmp, btmp) 13952708Swollmanregister const struct tm * const atmp; 13962708Swollmanregister const struct tm * const btmp; 13972708Swollman{ 13982708Swollman register int result; 13992708Swollman 14002708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 14012708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 14022708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 14032708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 14042708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 14052708Swollman result = atmp->tm_sec - btmp->tm_sec; 14062708Swollman return result; 14072708Swollman} 14082708Swollman 14092708Swollmanstatic time_t 14102708Swollmantime2(tmp, funcp, offset, okayp) 14112708Swollmanstruct tm * const tmp; 14129936Swollmanvoid (* const funcp) P((const time_t*, long, struct tm*)); 14132708Swollmanconst long offset; 14142708Swollmanint * const okayp; 14152708Swollman{ 14162708Swollman register const struct state * sp; 14172708Swollman register int dir; 14182708Swollman register int bits; 14192708Swollman register int i, j ; 14202708Swollman register int saved_seconds; 14212708Swollman time_t newt; 14222708Swollman time_t t; 14232708Swollman struct tm yourtm, mytm; 14242708Swollman 14252708Swollman *okayp = FALSE; 14262708Swollman yourtm = *tmp; 14272708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 14282708Swollman return WRONG; 14292708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 14302708Swollman return WRONG; 14312708Swollman if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 14322708Swollman return WRONG; 14332708Swollman /* 14342708Swollman ** Turn yourtm.tm_year into an actual year number for now. 14352708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 14362708Swollman */ 14372708Swollman if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 14382708Swollman return WRONG; 14392708Swollman while (yourtm.tm_mday <= 0) { 14402708Swollman if (increment_overflow(&yourtm.tm_year, -1)) 14412708Swollman return WRONG; 144217209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 144317209Swollman yourtm.tm_mday += year_lengths[isleap(i)]; 14442708Swollman } 14452708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 144617209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 144717209Swollman yourtm.tm_mday -= year_lengths[isleap(i)]; 14482708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14492708Swollman return WRONG; 14502708Swollman } 14512708Swollman for ( ; ; ) { 14522708Swollman i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 14532708Swollman if (yourtm.tm_mday <= i) 14542708Swollman break; 14552708Swollman yourtm.tm_mday -= i; 14562708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 14572708Swollman yourtm.tm_mon = 0; 14582708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14592708Swollman return WRONG; 14602708Swollman } 14612708Swollman } 14622708Swollman if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 14632708Swollman return WRONG; 14642708Swollman if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 14652708Swollman /* 14662708Swollman ** We can't set tm_sec to 0, because that might push the 14672708Swollman ** time below the minimum representable time. 14682708Swollman ** Set tm_sec to 59 instead. 14692708Swollman ** This assumes that the minimum representable time is 14702708Swollman ** not in the same minute that a leap second was deleted from, 14712708Swollman ** which is a safer assumption than using 58 would be. 14722708Swollman */ 14732708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 14742708Swollman return WRONG; 14752708Swollman saved_seconds = yourtm.tm_sec; 14762708Swollman yourtm.tm_sec = SECSPERMIN - 1; 14772708Swollman } else { 14782708Swollman saved_seconds = yourtm.tm_sec; 14792708Swollman yourtm.tm_sec = 0; 14802708Swollman } 14812708Swollman /* 148217209Swollman ** Divide the search space in half 148317209Swollman ** (this works whether time_t is signed or unsigned). 14842708Swollman */ 148517209Swollman bits = TYPE_BIT(time_t) - 1; 14862708Swollman /* 148717209Swollman ** If time_t is signed, then 0 is just above the median, 148817209Swollman ** assuming two's complement arithmetic. 148917209Swollman ** If time_t is unsigned, then (1 << bits) is just above the median. 14902708Swollman */ 149117209Swollman t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); 14922708Swollman for ( ; ; ) { 14932708Swollman (*funcp)(&t, offset, &mytm); 14942708Swollman dir = tmcomp(&mytm, &yourtm); 14952708Swollman if (dir != 0) { 14962708Swollman if (bits-- < 0) 14972708Swollman return WRONG; 14982708Swollman if (bits < 0) 149917209Swollman --t; /* may be needed if new t is minimal */ 15002708Swollman else if (dir > 0) 150117209Swollman t -= ((time_t) 1) << bits; 150217209Swollman else t += ((time_t) 1) << bits; 15032708Swollman continue; 15042708Swollman } 15052708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 15062708Swollman break; 15072708Swollman /* 15082708Swollman ** Right time, wrong type. 15092708Swollman ** Hunt for right time, right type. 15102708Swollman ** It's okay to guess wrong since the guess 15112708Swollman ** gets checked. 15122708Swollman */ 15132708Swollman /* 15142708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15152708Swollman */ 15162708Swollman sp = (const struct state *) 15172708Swollman (((void *) funcp == (void *) localsub) ? 15182708Swollman lclptr : gmtptr); 15192708Swollman#ifdef ALL_STATE 15202708Swollman if (sp == NULL) 15212708Swollman return WRONG; 15222708Swollman#endif /* defined ALL_STATE */ 152317209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 15242708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 15252708Swollman continue; 152617209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 15272708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 15282708Swollman continue; 15292708Swollman newt = t + sp->ttis[j].tt_gmtoff - 15302708Swollman sp->ttis[i].tt_gmtoff; 15312708Swollman (*funcp)(&newt, offset, &mytm); 15322708Swollman if (tmcomp(&mytm, &yourtm) != 0) 15332708Swollman continue; 15342708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 15352708Swollman continue; 15362708Swollman /* 15372708Swollman ** We have a match. 15382708Swollman */ 15392708Swollman t = newt; 15402708Swollman goto label; 15412708Swollman } 15422708Swollman } 15432708Swollman return WRONG; 15442708Swollman } 15452708Swollmanlabel: 15462708Swollman newt = t + saved_seconds; 15472708Swollman if ((newt < t) != (saved_seconds < 0)) 15482708Swollman return WRONG; 15492708Swollman t = newt; 15502708Swollman (*funcp)(&t, offset, tmp); 15512708Swollman *okayp = TRUE; 15522708Swollman return t; 15532708Swollman} 15542708Swollman 15552708Swollmanstatic time_t 15562708Swollmantime1(tmp, funcp, offset) 15572708Swollmanstruct tm * const tmp; 155817209Swollmanvoid (* const funcp) P((const time_t *, long, struct tm *)); 15592708Swollmanconst long offset; 15602708Swollman{ 15612708Swollman register time_t t; 15622708Swollman register const struct state * sp; 15632708Swollman register int samei, otheri; 15642708Swollman int okay; 15652708Swollman 15662708Swollman if (tmp->tm_isdst > 1) 15672708Swollman tmp->tm_isdst = 1; 15682708Swollman t = time2(tmp, funcp, offset, &okay); 15692708Swollman#ifdef PCTS 15702708Swollman /* 15712708Swollman ** PCTS code courtesy Grant Sullivan (grant@osf.org). 15722708Swollman */ 15732708Swollman if (okay) 15742708Swollman return t; 15752708Swollman if (tmp->tm_isdst < 0) 15762708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 15772708Swollman#endif /* defined PCTS */ 15782708Swollman#ifndef PCTS 15792708Swollman if (okay || tmp->tm_isdst < 0) 15802708Swollman return t; 15812708Swollman#endif /* !defined PCTS */ 15822708Swollman /* 15832708Swollman ** We're supposed to assume that somebody took a time of one type 15842708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 15852708Swollman ** We try to divine the type they started from and adjust to the 15862708Swollman ** type they need. 15872708Swollman */ 15882708Swollman /* 15892708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15902708Swollman */ 15912708Swollman sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 15922708Swollman lclptr : gmtptr); 15932708Swollman#ifdef ALL_STATE 15942708Swollman if (sp == NULL) 15952708Swollman return WRONG; 15962708Swollman#endif /* defined ALL_STATE */ 159717209Swollman for (samei = sp->typecnt - 1; samei >= 0; --samei) { 15982708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 15992708Swollman continue; 160017209Swollman for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { 16012708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 16022708Swollman continue; 16032708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 16042708Swollman sp->ttis[samei].tt_gmtoff; 16052708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16062708Swollman t = time2(tmp, funcp, offset, &okay); 16072708Swollman if (okay) 16082708Swollman return t; 16092708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 16102708Swollman sp->ttis[samei].tt_gmtoff; 16112708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16122708Swollman } 16132708Swollman } 16142708Swollman return WRONG; 16152708Swollman} 16162708Swollman 16172708Swollmantime_t 16182708Swollmanmktime(tmp) 16192708Swollmanstruct tm * const tmp; 16202708Swollman{ 162113545Sjulian time_t mktime_return_value; 162213545Sjulian#ifdef _THREAD_SAFE 162313545Sjulian pthread_mutex_lock(&lcl_mutex); 162413545Sjulian#endif 16259936Swollman tzset(); 162613545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 162713545Sjulian#ifdef _THREAD_SAFE 162813545Sjulian pthread_mutex_unlock(&lcl_mutex); 162913545Sjulian#endif 163013545Sjulian return(mktime_return_value); 16312708Swollman} 16322708Swollman 16332708Swollman#ifdef STD_INSPIRED 16342708Swollman 16352708Swollmantime_t 16362708Swollmantimelocal(tmp) 16372708Swollmanstruct tm * const tmp; 16382708Swollman{ 16392708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 16402708Swollman return mktime(tmp); 16412708Swollman} 16422708Swollman 16432708Swollmantime_t 16442708Swollmantimegm(tmp) 16452708Swollmanstruct tm * const tmp; 16462708Swollman{ 16472708Swollman tmp->tm_isdst = 0; 16482708Swollman return time1(tmp, gmtsub, 0L); 16492708Swollman} 16502708Swollman 16512708Swollmantime_t 16522708Swollmantimeoff(tmp, offset) 16532708Swollmanstruct tm * const tmp; 16542708Swollmanconst long offset; 16552708Swollman{ 16562708Swollman tmp->tm_isdst = 0; 16572708Swollman return time1(tmp, gmtsub, offset); 16582708Swollman} 16592708Swollman 16602708Swollman#endif /* defined STD_INSPIRED */ 16612708Swollman 16622708Swollman#ifdef CMUCS 16632708Swollman 16642708Swollman/* 16652708Swollman** The following is supplied for compatibility with 16662708Swollman** previous versions of the CMUCS runtime library. 16672708Swollman*/ 16682708Swollman 16692708Swollmanlong 16702708Swollmangtime(tmp) 16712708Swollmanstruct tm * const tmp; 16722708Swollman{ 16732708Swollman const time_t t = mktime(tmp); 16742708Swollman 16752708Swollman if (t == WRONG) 16762708Swollman return -1; 16772708Swollman return t; 16782708Swollman} 16792708Swollman 16802708Swollman#endif /* defined CMUCS */ 16812708Swollman 16822708Swollman/* 16832708Swollman** XXX--is the below the right way to conditionalize?? 16842708Swollman*/ 16852708Swollman 16862708Swollman#ifdef STD_INSPIRED 16872708Swollman 16882708Swollman/* 16892708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 16902708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 16912708Swollman** is not the case if we are accounting for leap seconds. 16922708Swollman** So, we provide the following conversion routines for use 16932708Swollman** when exchanging timestamps with POSIX conforming systems. 16942708Swollman*/ 16952708Swollman 16962708Swollmanstatic long 16972708Swollmanleapcorr(timep) 16982708Swollmantime_t * timep; 16992708Swollman{ 17002708Swollman register struct state * sp; 17012708Swollman register struct lsinfo * lp; 17022708Swollman register int i; 17032708Swollman 17042708Swollman sp = lclptr; 17052708Swollman i = sp->leapcnt; 17062708Swollman while (--i >= 0) { 17072708Swollman lp = &sp->lsis[i]; 17082708Swollman if (*timep >= lp->ls_trans) 17092708Swollman return lp->ls_corr; 17102708Swollman } 17112708Swollman return 0; 17122708Swollman} 17132708Swollman 17142708Swollmantime_t 17152708Swollmantime2posix(t) 17162708Swollmantime_t t; 17172708Swollman{ 17189936Swollman tzset(); 17192708Swollman return t - leapcorr(&t); 17202708Swollman} 17212708Swollman 17222708Swollmantime_t 17232708Swollmanposix2time(t) 17242708Swollmantime_t t; 17252708Swollman{ 17262708Swollman time_t x; 17272708Swollman time_t y; 17282708Swollman 17299936Swollman tzset(); 17302708Swollman /* 17312708Swollman ** For a positive leap second hit, the result 17322708Swollman ** is not unique. For a negative leap second 17332708Swollman ** hit, the corresponding time doesn't exist, 17342708Swollman ** so we return an adjacent second. 17352708Swollman */ 17362708Swollman x = t + leapcorr(&t); 17372708Swollman y = x - leapcorr(&x); 17382708Swollman if (y < t) { 17392708Swollman do { 17402708Swollman x++; 17412708Swollman y = x - leapcorr(&x); 17422708Swollman } while (y < t); 17432708Swollman if (t != y) 17442708Swollman return x - 1; 17452708Swollman } else if (y > t) { 17462708Swollman do { 17472708Swollman --x; 17482708Swollman y = x - leapcorr(&x); 17492708Swollman } while (y > t); 17502708Swollman if (t != y) 17512708Swollman return x + 1; 17522708Swollman } 17532708Swollman return x; 17542708Swollman} 17552708Swollman 17562708Swollman#endif /* defined STD_INSPIRED */ 1757