localtime.c revision 35285
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 17435026Sjbstatic struct pthread_mutex _lcl_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER; 17535026Sjbstatic struct pthread_mutex _gmt_mutexd = PTHREAD_MUTEX_STATIC_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 } 30824253Simp if (doaccess && access(name, R_OK) != 0) 30924253Simp 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 109935026Sjb static struct pthread_mutex _localtime_mutex = PTHREAD_MUTEX_STATIC_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); 111222315Sjulian p_tm = pthread_getspecific(localtime_key); 111322315Sjulian if (p_tm == NULL) { 111422315Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) 111513545Sjulian return(NULL); 111613545Sjulian pthread_setspecific(localtime_key, p_tm); 111713545Sjulian } 111813545Sjulian pthread_mutex_lock(&lcl_mutex); 11199936Swollman tzset(); 112013545Sjulian localsub(timep, 0L, p_tm); 112113545Sjulian pthread_mutex_unlock(&lcl_mutex); 112213545Sjulian return p_tm; 112313545Sjulian#else 112413545Sjulian tzset(); 11252708Swollman localsub(timep, 0L, &tm); 11262708Swollman return &tm; 112713545Sjulian#endif 11282708Swollman} 11292708Swollman 11302708Swollman/* 11312708Swollman** gmtsub is to gmtime as localsub is to localtime. 11322708Swollman*/ 11332708Swollman 11342708Swollmanstatic void 11352708Swollmangmtsub(timep, offset, tmp) 11362708Swollmanconst time_t * const timep; 11372708Swollmanconst long offset; 11382708Swollmanstruct tm * const tmp; 11392708Swollman{ 114013545Sjulian#ifdef _THREAD_SAFE 114113545Sjulian pthread_mutex_lock(&gmt_mutex); 114213545Sjulian#endif 11432708Swollman if (!gmt_is_set) { 11442708Swollman gmt_is_set = TRUE; 11452708Swollman#ifdef ALL_STATE 11462708Swollman gmtptr = (struct state *) malloc(sizeof *gmtptr); 11472708Swollman if (gmtptr != NULL) 11482708Swollman#endif /* defined ALL_STATE */ 11492708Swollman gmtload(gmtptr); 11502708Swollman } 115113545Sjulian#ifdef _THREAD_SAFE 115213545Sjulian pthread_mutex_unlock(&gmt_mutex); 115313545Sjulian#endif 11542708Swollman timesub(timep, offset, gmtptr, tmp); 11552708Swollman#ifdef TM_ZONE 11562708Swollman /* 11572708Swollman ** Could get fancy here and deliver something such as 11582708Swollman ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 11592708Swollman ** but this is no time for a treasure hunt. 11602708Swollman */ 11612708Swollman if (offset != 0) 11629936Swollman tmp->TM_ZONE = wildabbr; 11632708Swollman else { 11642708Swollman#ifdef ALL_STATE 11652708Swollman if (gmtptr == NULL) 11669936Swollman tmp->TM_ZONE = gmt; 11672708Swollman else tmp->TM_ZONE = gmtptr->chars; 11682708Swollman#endif /* defined ALL_STATE */ 11692708Swollman#ifndef ALL_STATE 11702708Swollman tmp->TM_ZONE = gmtptr->chars; 11712708Swollman#endif /* State Farm */ 11722708Swollman } 11732708Swollman#endif /* defined TM_ZONE */ 11742708Swollman} 11752708Swollman 11762708Swollmanstruct tm * 11772708Swollmangmtime(timep) 11782708Swollmanconst time_t * const timep; 11792708Swollman{ 118013545Sjulian#ifdef _THREAD_SAFE 118135026Sjb static struct pthread_mutex _gmtime_mutex = PTHREAD_MUTEX_STATIC_INITIALIZER; 118217706Sjulian static pthread_mutex_t gmtime_mutex = &_gmtime_mutex; 118313545Sjulian static pthread_key_t gmtime_key = -1; 118413545Sjulian struct tm *p_tm; 118513545Sjulian 118613545Sjulian pthread_mutex_lock(&gmtime_mutex); 118713545Sjulian if (gmtime_key < 0) { 118819636Shsu if (pthread_key_create(&gmtime_key, free) < 0) { 118913545Sjulian pthread_mutex_unlock(&gmtime_mutex); 119013545Sjulian return(NULL); 119113545Sjulian } 119213545Sjulian } 119313545Sjulian pthread_mutex_unlock(&gmtime_mutex); 119433527Sjulian /* 119533527Sjulian * Changed to follow draft 4 pthreads standard, which 119633527Sjulian * is what BSD currently has. 119733527Sjulian */ 119833527Sjulian if ((p_tm = pthread_getspecific(gmtime_key)) == 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 134835285Sphkchar * 134935285Sphkctime_r(timep, buf) 135035285Sphkconst time_t * const timep; 135135285Sphkchar *buf; 135235285Sphk{ 135335285Sphk struct tm tm; 135435285Sphk return asctime_r(localtime_r(timep, &tm), buf); 135535285Sphk} 135635285Sphk 13572708Swollman/* 13582708Swollman** Adapted from code provided by Robert Elz, who writes: 13592708Swollman** The "best" way to do mktime I think is based on an idea of Bob 136017209Swollman** Kridle's (so its said...) from a long time ago. 136117209Swollman** [kridle@xinet.com as of 1996-01-16.] 13622708Swollman** It does a binary search of the time_t space. Since time_t's are 13632708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 13642708Swollman** would still be very reasonable). 13652708Swollman*/ 13662708Swollman 13672708Swollman#ifndef WRONG 13682708Swollman#define WRONG (-1) 13692708Swollman#endif /* !defined WRONG */ 13702708Swollman 13712708Swollman/* 13722708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 13732708Swollman*/ 13742708Swollman 13752708Swollmanstatic int 13762708Swollmanincrement_overflow(number, delta) 13772708Swollmanint * number; 13782708Swollmanint delta; 13792708Swollman{ 13809936Swollman int number0; 13818870Srgrimes 13822708Swollman number0 = *number; 13832708Swollman *number += delta; 13842708Swollman return (*number < number0) != (delta < 0); 13852708Swollman} 13862708Swollman 13872708Swollmanstatic int 13882708Swollmannormalize_overflow(tensptr, unitsptr, base) 13892708Swollmanint * const tensptr; 13902708Swollmanint * const unitsptr; 13912708Swollmanconst int base; 13922708Swollman{ 13932708Swollman register int tensdelta; 13942708Swollman 13952708Swollman tensdelta = (*unitsptr >= 0) ? 13962708Swollman (*unitsptr / base) : 13972708Swollman (-1 - (-1 - *unitsptr) / base); 13982708Swollman *unitsptr -= tensdelta * base; 13992708Swollman return increment_overflow(tensptr, tensdelta); 14002708Swollman} 14012708Swollman 14022708Swollmanstatic int 14032708Swollmantmcomp(atmp, btmp) 14042708Swollmanregister const struct tm * const atmp; 14052708Swollmanregister const struct tm * const btmp; 14062708Swollman{ 14072708Swollman register int result; 14082708Swollman 14092708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 14102708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 14112708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 14122708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 14132708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 14142708Swollman result = atmp->tm_sec - btmp->tm_sec; 14152708Swollman return result; 14162708Swollman} 14172708Swollman 14182708Swollmanstatic time_t 14192708Swollmantime2(tmp, funcp, offset, okayp) 14202708Swollmanstruct tm * const tmp; 14219936Swollmanvoid (* const funcp) P((const time_t*, long, struct tm*)); 14222708Swollmanconst long offset; 14232708Swollmanint * const okayp; 14242708Swollman{ 14252708Swollman register const struct state * sp; 14262708Swollman register int dir; 14272708Swollman register int bits; 14282708Swollman register int i, j ; 14292708Swollman register int saved_seconds; 14302708Swollman time_t newt; 14312708Swollman time_t t; 14322708Swollman struct tm yourtm, mytm; 14332708Swollman 14342708Swollman *okayp = FALSE; 14352708Swollman yourtm = *tmp; 14362708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 14372708Swollman return WRONG; 14382708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 14392708Swollman return WRONG; 14402708Swollman if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 14412708Swollman return WRONG; 14422708Swollman /* 14432708Swollman ** Turn yourtm.tm_year into an actual year number for now. 14442708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 14452708Swollman */ 14462708Swollman if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 14472708Swollman return WRONG; 14482708Swollman while (yourtm.tm_mday <= 0) { 14492708Swollman if (increment_overflow(&yourtm.tm_year, -1)) 14502708Swollman return WRONG; 145117209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 145217209Swollman yourtm.tm_mday += year_lengths[isleap(i)]; 14532708Swollman } 14542708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 145517209Swollman i = yourtm.tm_year + (1 < yourtm.tm_mon); 145617209Swollman yourtm.tm_mday -= year_lengths[isleap(i)]; 14572708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14582708Swollman return WRONG; 14592708Swollman } 14602708Swollman for ( ; ; ) { 14612708Swollman i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 14622708Swollman if (yourtm.tm_mday <= i) 14632708Swollman break; 14642708Swollman yourtm.tm_mday -= i; 14652708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 14662708Swollman yourtm.tm_mon = 0; 14672708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14682708Swollman return WRONG; 14692708Swollman } 14702708Swollman } 14712708Swollman if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 14722708Swollman return WRONG; 14732708Swollman if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 14742708Swollman /* 14752708Swollman ** We can't set tm_sec to 0, because that might push the 14762708Swollman ** time below the minimum representable time. 14772708Swollman ** Set tm_sec to 59 instead. 14782708Swollman ** This assumes that the minimum representable time is 14792708Swollman ** not in the same minute that a leap second was deleted from, 14802708Swollman ** which is a safer assumption than using 58 would be. 14812708Swollman */ 14822708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 14832708Swollman return WRONG; 14842708Swollman saved_seconds = yourtm.tm_sec; 14852708Swollman yourtm.tm_sec = SECSPERMIN - 1; 14862708Swollman } else { 14872708Swollman saved_seconds = yourtm.tm_sec; 14882708Swollman yourtm.tm_sec = 0; 14892708Swollman } 14902708Swollman /* 149117209Swollman ** Divide the search space in half 149217209Swollman ** (this works whether time_t is signed or unsigned). 14932708Swollman */ 149417209Swollman bits = TYPE_BIT(time_t) - 1; 14952708Swollman /* 149617209Swollman ** If time_t is signed, then 0 is just above the median, 149717209Swollman ** assuming two's complement arithmetic. 149817209Swollman ** If time_t is unsigned, then (1 << bits) is just above the median. 14992708Swollman */ 150017209Swollman t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); 15012708Swollman for ( ; ; ) { 15022708Swollman (*funcp)(&t, offset, &mytm); 15032708Swollman dir = tmcomp(&mytm, &yourtm); 15042708Swollman if (dir != 0) { 15052708Swollman if (bits-- < 0) 15062708Swollman return WRONG; 15072708Swollman if (bits < 0) 150817209Swollman --t; /* may be needed if new t is minimal */ 15092708Swollman else if (dir > 0) 151017209Swollman t -= ((time_t) 1) << bits; 151117209Swollman else t += ((time_t) 1) << bits; 15122708Swollman continue; 15132708Swollman } 15142708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 15152708Swollman break; 15162708Swollman /* 15172708Swollman ** Right time, wrong type. 15182708Swollman ** Hunt for right time, right type. 15192708Swollman ** It's okay to guess wrong since the guess 15202708Swollman ** gets checked. 15212708Swollman */ 15222708Swollman /* 15232708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15242708Swollman */ 15252708Swollman sp = (const struct state *) 15262708Swollman (((void *) funcp == (void *) localsub) ? 15272708Swollman lclptr : gmtptr); 15282708Swollman#ifdef ALL_STATE 15292708Swollman if (sp == NULL) 15302708Swollman return WRONG; 15312708Swollman#endif /* defined ALL_STATE */ 153217209Swollman for (i = sp->typecnt - 1; i >= 0; --i) { 15332708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 15342708Swollman continue; 153517209Swollman for (j = sp->typecnt - 1; j >= 0; --j) { 15362708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 15372708Swollman continue; 15382708Swollman newt = t + sp->ttis[j].tt_gmtoff - 15392708Swollman sp->ttis[i].tt_gmtoff; 15402708Swollman (*funcp)(&newt, offset, &mytm); 15412708Swollman if (tmcomp(&mytm, &yourtm) != 0) 15422708Swollman continue; 15432708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 15442708Swollman continue; 15452708Swollman /* 15462708Swollman ** We have a match. 15472708Swollman */ 15482708Swollman t = newt; 15492708Swollman goto label; 15502708Swollman } 15512708Swollman } 15522708Swollman return WRONG; 15532708Swollman } 15542708Swollmanlabel: 15552708Swollman newt = t + saved_seconds; 15562708Swollman if ((newt < t) != (saved_seconds < 0)) 15572708Swollman return WRONG; 15582708Swollman t = newt; 15592708Swollman (*funcp)(&t, offset, tmp); 15602708Swollman *okayp = TRUE; 15612708Swollman return t; 15622708Swollman} 15632708Swollman 15642708Swollmanstatic time_t 15652708Swollmantime1(tmp, funcp, offset) 15662708Swollmanstruct tm * const tmp; 156717209Swollmanvoid (* const funcp) P((const time_t *, long, struct tm *)); 15682708Swollmanconst long offset; 15692708Swollman{ 15702708Swollman register time_t t; 15712708Swollman register const struct state * sp; 15722708Swollman register int samei, otheri; 15732708Swollman int okay; 15742708Swollman 15752708Swollman if (tmp->tm_isdst > 1) 15762708Swollman tmp->tm_isdst = 1; 15772708Swollman t = time2(tmp, funcp, offset, &okay); 15782708Swollman#ifdef PCTS 15792708Swollman /* 15802708Swollman ** PCTS code courtesy Grant Sullivan (grant@osf.org). 15812708Swollman */ 15822708Swollman if (okay) 15832708Swollman return t; 15842708Swollman if (tmp->tm_isdst < 0) 15852708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 15862708Swollman#endif /* defined PCTS */ 15872708Swollman#ifndef PCTS 15882708Swollman if (okay || tmp->tm_isdst < 0) 15892708Swollman return t; 15902708Swollman#endif /* !defined PCTS */ 15912708Swollman /* 15922708Swollman ** We're supposed to assume that somebody took a time of one type 15932708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 15942708Swollman ** We try to divine the type they started from and adjust to the 15952708Swollman ** type they need. 15962708Swollman */ 15972708Swollman /* 15982708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15992708Swollman */ 16002708Swollman sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 16012708Swollman lclptr : gmtptr); 16022708Swollman#ifdef ALL_STATE 16032708Swollman if (sp == NULL) 16042708Swollman return WRONG; 16052708Swollman#endif /* defined ALL_STATE */ 160617209Swollman for (samei = sp->typecnt - 1; samei >= 0; --samei) { 16072708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 16082708Swollman continue; 160917209Swollman for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { 16102708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 16112708Swollman continue; 16122708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 16132708Swollman sp->ttis[samei].tt_gmtoff; 16142708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16152708Swollman t = time2(tmp, funcp, offset, &okay); 16162708Swollman if (okay) 16172708Swollman return t; 16182708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 16192708Swollman sp->ttis[samei].tt_gmtoff; 16202708Swollman tmp->tm_isdst = !tmp->tm_isdst; 16212708Swollman } 16222708Swollman } 16232708Swollman return WRONG; 16242708Swollman} 16252708Swollman 16262708Swollmantime_t 16272708Swollmanmktime(tmp) 16282708Swollmanstruct tm * const tmp; 16292708Swollman{ 163013545Sjulian time_t mktime_return_value; 163113545Sjulian#ifdef _THREAD_SAFE 163213545Sjulian pthread_mutex_lock(&lcl_mutex); 163313545Sjulian#endif 16349936Swollman tzset(); 163513545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 163613545Sjulian#ifdef _THREAD_SAFE 163713545Sjulian pthread_mutex_unlock(&lcl_mutex); 163813545Sjulian#endif 163913545Sjulian return(mktime_return_value); 16402708Swollman} 16412708Swollman 16422708Swollman#ifdef STD_INSPIRED 16432708Swollman 16442708Swollmantime_t 16452708Swollmantimelocal(tmp) 16462708Swollmanstruct tm * const tmp; 16472708Swollman{ 16482708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 16492708Swollman return mktime(tmp); 16502708Swollman} 16512708Swollman 16522708Swollmantime_t 16532708Swollmantimegm(tmp) 16542708Swollmanstruct tm * const tmp; 16552708Swollman{ 16562708Swollman tmp->tm_isdst = 0; 16572708Swollman return time1(tmp, gmtsub, 0L); 16582708Swollman} 16592708Swollman 16602708Swollmantime_t 16612708Swollmantimeoff(tmp, offset) 16622708Swollmanstruct tm * const tmp; 16632708Swollmanconst long offset; 16642708Swollman{ 16652708Swollman tmp->tm_isdst = 0; 16662708Swollman return time1(tmp, gmtsub, offset); 16672708Swollman} 16682708Swollman 16692708Swollman#endif /* defined STD_INSPIRED */ 16702708Swollman 16712708Swollman#ifdef CMUCS 16722708Swollman 16732708Swollman/* 16742708Swollman** The following is supplied for compatibility with 16752708Swollman** previous versions of the CMUCS runtime library. 16762708Swollman*/ 16772708Swollman 16782708Swollmanlong 16792708Swollmangtime(tmp) 16802708Swollmanstruct tm * const tmp; 16812708Swollman{ 16822708Swollman const time_t t = mktime(tmp); 16832708Swollman 16842708Swollman if (t == WRONG) 16852708Swollman return -1; 16862708Swollman return t; 16872708Swollman} 16882708Swollman 16892708Swollman#endif /* defined CMUCS */ 16902708Swollman 16912708Swollman/* 16922708Swollman** XXX--is the below the right way to conditionalize?? 16932708Swollman*/ 16942708Swollman 16952708Swollman#ifdef STD_INSPIRED 16962708Swollman 16972708Swollman/* 16982708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 16992708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 17002708Swollman** is not the case if we are accounting for leap seconds. 17012708Swollman** So, we provide the following conversion routines for use 17022708Swollman** when exchanging timestamps with POSIX conforming systems. 17032708Swollman*/ 17042708Swollman 17052708Swollmanstatic long 17062708Swollmanleapcorr(timep) 17072708Swollmantime_t * timep; 17082708Swollman{ 17092708Swollman register struct state * sp; 17102708Swollman register struct lsinfo * lp; 17112708Swollman register int i; 17122708Swollman 17132708Swollman sp = lclptr; 17142708Swollman i = sp->leapcnt; 17152708Swollman while (--i >= 0) { 17162708Swollman lp = &sp->lsis[i]; 17172708Swollman if (*timep >= lp->ls_trans) 17182708Swollman return lp->ls_corr; 17192708Swollman } 17202708Swollman return 0; 17212708Swollman} 17222708Swollman 17232708Swollmantime_t 17242708Swollmantime2posix(t) 17252708Swollmantime_t t; 17262708Swollman{ 17279936Swollman tzset(); 17282708Swollman return t - leapcorr(&t); 17292708Swollman} 17302708Swollman 17312708Swollmantime_t 17322708Swollmanposix2time(t) 17332708Swollmantime_t t; 17342708Swollman{ 17352708Swollman time_t x; 17362708Swollman time_t y; 17372708Swollman 17389936Swollman tzset(); 17392708Swollman /* 17402708Swollman ** For a positive leap second hit, the result 17412708Swollman ** is not unique. For a negative leap second 17422708Swollman ** hit, the corresponding time doesn't exist, 17432708Swollman ** so we return an adjacent second. 17442708Swollman */ 17452708Swollman x = t + leapcorr(&t); 17462708Swollman y = x - leapcorr(&x); 17472708Swollman if (y < t) { 17482708Swollman do { 17492708Swollman x++; 17502708Swollman y = x - leapcorr(&x); 17512708Swollman } while (y < t); 17522708Swollman if (t != y) 17532708Swollman return x - 1; 17542708Swollman } else if (y > t) { 17552708Swollman do { 17562708Swollman --x; 17572708Swollman y = x - leapcorr(&x); 17582708Swollman } while (y > t); 17592708Swollman if (t != y) 17602708Swollman return x + 1; 17612708Swollman } 17622708Swollman return x; 17632708Swollman} 17642708Swollman 17652708Swollman#endif /* defined STD_INSPIRED */ 1766