localtime.c revision 13545
12708Swollman#ifndef lint 22708Swollman#ifndef NOID 39936Swollmanstatic char elsieid[] = "@(#)localtime.c 7.44"; 42708Swollman#endif /* !defined NOID */ 52708Swollman#endif /* !defined lint */ 62708Swollman 72708Swollman/* 82708Swollman** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). 92708Swollman** POSIX-style TZ environment variable handling from Guy Harris 102708Swollman** (guy@auspex.com). 112708Swollman*/ 122708Swollman 132708Swollman/*LINTLIBRARY*/ 142708Swollman 152708Swollman#include "private.h" 162708Swollman#include "tzfile.h" 172708Swollman#include "fcntl.h" 1813545Sjulian#ifdef _THREAD_SAFE 1913545Sjulian#include <pthread.h> 2013545Sjulian#include "pthread_private.h" 2113545Sjulian#endif 222708Swollman 239936Swollman/* 249936Swollman** SunOS 4.1.1 headers lack O_BINARY. 259936Swollman*/ 262708Swollman 272708Swollman#ifdef O_BINARY 282708Swollman#define OPEN_MODE (O_RDONLY | O_BINARY) 292708Swollman#endif /* defined O_BINARY */ 302708Swollman#ifndef O_BINARY 312708Swollman#define OPEN_MODE O_RDONLY 322708Swollman#endif /* !defined O_BINARY */ 332708Swollman 342708Swollman#ifndef WILDABBR 352708Swollman/* 362708Swollman** Someone might make incorrect use of a time zone abbreviation: 372708Swollman** 1. They might reference tzname[0] before calling tzset (explicitly 389936Swollman** or implicitly). 392708Swollman** 2. They might reference tzname[1] before calling tzset (explicitly 409936Swollman** or implicitly). 412708Swollman** 3. They might reference tzname[1] after setting to a time zone 422708Swollman** in which Daylight Saving Time is never observed. 432708Swollman** 4. They might reference tzname[0] after setting to a time zone 442708Swollman** in which Standard Time is never observed. 452708Swollman** 5. They might reference tm.TM_ZONE after calling offtime. 462708Swollman** What's best to do in the above cases is open to debate; 472708Swollman** for now, we just set things up so that in any of the five cases 482708Swollman** WILDABBR is used. Another possibility: initialize tzname[0] to the 492708Swollman** string "tzname[0] used before set", and similarly for the other cases. 502708Swollman** And another: initialize tzname[0] to "ERA", with an explanation in the 512708Swollman** manual page of what this "time zone abbreviation" means (doing this so 522708Swollman** that tzname[0] has the "normal" length of three characters). 532708Swollman*/ 542708Swollman#define WILDABBR " " 552708Swollman#endif /* !defined WILDABBR */ 562708Swollman 579936Swollmanstatic char wildabbr[] = "WILDABBR"; 582708Swollman 599936Swollmanstatic const char gmt[] = "GMT"; 609936Swollman 612708Swollmanstruct ttinfo { /* time type information */ 622708Swollman long tt_gmtoff; /* GMT offset in seconds */ 632708Swollman int tt_isdst; /* used to set tm_isdst */ 642708Swollman int tt_abbrind; /* abbreviation list index */ 652708Swollman int tt_ttisstd; /* TRUE if transition is std time */ 669936Swollman int tt_ttisgmt; /* TRUE if transition is GMT */ 672708Swollman}; 682708Swollman 692708Swollmanstruct lsinfo { /* leap second information */ 702708Swollman time_t ls_trans; /* transition time */ 712708Swollman long ls_corr; /* correction to apply */ 722708Swollman}; 732708Swollman 742708Swollman#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) 752708Swollman 762708Swollman#ifdef TZNAME_MAX 772708Swollman#define MY_TZNAME_MAX TZNAME_MAX 782708Swollman#endif /* defined TZNAME_MAX */ 792708Swollman#ifndef TZNAME_MAX 802708Swollman#define MY_TZNAME_MAX 255 812708Swollman#endif /* !defined TZNAME_MAX */ 822708Swollman 832708Swollmanstruct state { 842708Swollman int leapcnt; 852708Swollman int timecnt; 862708Swollman int typecnt; 872708Swollman int charcnt; 882708Swollman time_t ats[TZ_MAX_TIMES]; 892708Swollman unsigned char types[TZ_MAX_TIMES]; 902708Swollman struct ttinfo ttis[TZ_MAX_TYPES]; 919936Swollman char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), 922708Swollman (2 * (MY_TZNAME_MAX + 1)))]; 932708Swollman struct lsinfo lsis[TZ_MAX_LEAPS]; 942708Swollman}; 952708Swollman 962708Swollmanstruct rule { 972708Swollman int r_type; /* type of rule--see below */ 982708Swollman int r_day; /* day number of rule */ 992708Swollman int r_week; /* week number of rule */ 1002708Swollman int r_mon; /* month number of rule */ 1012708Swollman long r_time; /* transition time of rule */ 1022708Swollman}; 1032708Swollman 1042708Swollman#define JULIAN_DAY 0 /* Jn - Julian day */ 1052708Swollman#define DAY_OF_YEAR 1 /* n - day of year */ 1062708Swollman#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 1072708Swollman 1082708Swollman/* 1092708Swollman** Prototypes for static functions. 1102708Swollman*/ 1112708Swollman 1122708Swollmanstatic long detzcode P((const char * codep)); 1132708Swollmanstatic const char * getzname P((const char * strp)); 1142708Swollmanstatic const char * getnum P((const char * strp, int * nump, int min, 1152708Swollman int max)); 1162708Swollmanstatic const char * getsecs P((const char * strp, long * secsp)); 1172708Swollmanstatic const char * getoffset P((const char * strp, long * offsetp)); 1182708Swollmanstatic const char * getrule P((const char * strp, struct rule * rulep)); 1192708Swollmanstatic void gmtload P((struct state * sp)); 1202708Swollmanstatic void gmtsub P((const time_t * timep, long offset, 1212708Swollman struct tm * tmp)); 1222708Swollmanstatic void localsub P((const time_t * timep, long offset, 1232708Swollman struct tm * tmp)); 1242708Swollmanstatic int increment_overflow P((int * number, int delta)); 1252708Swollmanstatic int normalize_overflow P((int * tensptr, int * unitsptr, 1262708Swollman int base)); 1272708Swollmanstatic void settzname P((void)); 1289936Swollmanstatic time_t time1 P((struct tm * tmp, 1299936Swollman void(*funcp) P((const time_t *, 1309936Swollman long, struct tm *)), 1312708Swollman long offset)); 1329936Swollmanstatic time_t time2 P((struct tm *tmp, 1339936Swollman void(*funcp) P((const time_t *, 1349936Swollman long, struct tm*)), 1352708Swollman long offset, int * okayp)); 1362708Swollmanstatic void timesub P((const time_t * timep, long offset, 1372708Swollman const struct state * sp, struct tm * tmp)); 1382708Swollmanstatic int tmcomp P((const struct tm * atmp, 1392708Swollman const struct tm * btmp)); 1402708Swollmanstatic time_t transtime P((time_t janfirst, int year, 1412708Swollman const struct rule * rulep, long offset)); 1422708Swollmanstatic int tzload P((const char * name, struct state * sp)); 1432708Swollmanstatic int tzparse P((const char * name, struct state * sp, 1442708Swollman int lastditch)); 1452708Swollman 1462708Swollman#ifdef ALL_STATE 1472708Swollmanstatic struct state * lclptr; 1482708Swollmanstatic struct state * gmtptr; 1492708Swollman#endif /* defined ALL_STATE */ 1502708Swollman 1512708Swollman#ifndef ALL_STATE 1522708Swollmanstatic struct state lclmem; 1532708Swollmanstatic struct state gmtmem; 1542708Swollman#define lclptr (&lclmem) 1552708Swollman#define gmtptr (&gmtmem) 1562708Swollman#endif /* State Farm */ 1572708Swollman 1589936Swollman#ifndef TZ_STRLEN_MAX 1599936Swollman#define TZ_STRLEN_MAX 255 1609936Swollman#endif /* !defined TZ_STRLEN_MAX */ 1619936Swollman 1629936Swollmanstatic char lcl_TZname[TZ_STRLEN_MAX + 1]; 1632708Swollmanstatic int lcl_is_set; 1642708Swollmanstatic int gmt_is_set; 16513545Sjulian#ifdef _THREAD_SAFE 16613545Sjulianstatic pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER; 16713545Sjulianstatic pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; 16813545Sjulian#endif 1692708Swollman 1702708Swollmanchar * tzname[2] = { 1719936Swollman wildabbr, 1729936Swollman wildabbr 1732708Swollman}; 1742708Swollman 1759936Swollman/* 1769936Swollman** Section 4.12.3 of X3.159-1989 requires that 1779936Swollman** Except for the strftime function, these functions [asctime, 1789936Swollman** ctime, gmtime, localtime] return values in one of two static 1799936Swollman** objects: a broken-down time structure and an array of char. 1809936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. 1819936Swollman*/ 1829936Swollman 1839936Swollmanstatic struct tm tm; 1849936Swollman 1852708Swollman#ifdef USG_COMPAT 1862708Swollmantime_t timezone = 0; 1872708Swollmanint daylight = 0; 1882708Swollman#endif /* defined USG_COMPAT */ 1892708Swollman 1902708Swollman#ifdef ALTZONE 1912708Swollmantime_t altzone = 0; 1922708Swollman#endif /* defined ALTZONE */ 1932708Swollman 1942708Swollmanstatic long 1952708Swollmandetzcode(codep) 1962708Swollmanconst char * const codep; 1972708Swollman{ 1982708Swollman register long result; 1992708Swollman register int i; 2002708Swollman 2019936Swollman result = (codep[0] & 0x80) ? ~0L : 0L; 2022708Swollman for (i = 0; i < 4; ++i) 2032708Swollman result = (result << 8) | (codep[i] & 0xff); 2042708Swollman return result; 2052708Swollman} 2062708Swollman 2072708Swollmanstatic void 2089936Swollmansettzname P((void)) 2092708Swollman{ 2109936Swollman register struct state * const sp = lclptr; 2112708Swollman register int i; 2122708Swollman 2139936Swollman tzname[0] = wildabbr; 2149936Swollman tzname[1] = wildabbr; 2152708Swollman#ifdef USG_COMPAT 2162708Swollman daylight = 0; 2172708Swollman timezone = 0; 2182708Swollman#endif /* defined USG_COMPAT */ 2192708Swollman#ifdef ALTZONE 2202708Swollman altzone = 0; 2212708Swollman#endif /* defined ALTZONE */ 2222708Swollman#ifdef ALL_STATE 2232708Swollman if (sp == NULL) { 2249936Swollman tzname[0] = tzname[1] = gmt; 2252708Swollman return; 2262708Swollman } 2272708Swollman#endif /* defined ALL_STATE */ 2282708Swollman for (i = 0; i < sp->typecnt; ++i) { 2292708Swollman register const struct ttinfo * const ttisp = &sp->ttis[i]; 2302708Swollman 2312708Swollman tzname[ttisp->tt_isdst] = 2329936Swollman &sp->chars[ttisp->tt_abbrind]; 2332708Swollman#ifdef USG_COMPAT 2342708Swollman if (ttisp->tt_isdst) 2352708Swollman daylight = 1; 2362708Swollman if (i == 0 || !ttisp->tt_isdst) 2372708Swollman timezone = -(ttisp->tt_gmtoff); 2382708Swollman#endif /* defined USG_COMPAT */ 2392708Swollman#ifdef ALTZONE 2402708Swollman if (i == 0 || ttisp->tt_isdst) 2412708Swollman altzone = -(ttisp->tt_gmtoff); 2422708Swollman#endif /* defined ALTZONE */ 2432708Swollman } 2442708Swollman /* 2452708Swollman ** And to get the latest zone names into tzname. . . 2462708Swollman */ 2472708Swollman for (i = 0; i < sp->timecnt; ++i) { 2482708Swollman register const struct ttinfo * const ttisp = 2492708Swollman &sp->ttis[ 2502708Swollman sp->types[i]]; 2512708Swollman 2522708Swollman tzname[ttisp->tt_isdst] = 2539936Swollman &sp->chars[ttisp->tt_abbrind]; 2542708Swollman } 2552708Swollman} 2562708Swollman 2572708Swollmanstatic int 2582708Swollmantzload(name, sp) 2592708Swollmanregister const char * name; 2602708Swollmanregister struct state * const sp; 2612708Swollman{ 2622708Swollman register const char * p; 2632708Swollman register int i; 2642708Swollman register int fid; 2652708Swollman 2662708Swollman if (name == NULL && (name = TZDEFAULT) == NULL) 2672708Swollman return -1; 2682708Swollman { 2699936Swollman register int doaccess; 2709936Swollman /* 2719936Swollman ** Section 4.9.1 of the C standard says that 2729936Swollman ** "FILENAME_MAX expands to an integral constant expression 2739936Swollman ** that is the sie needed for an array of char large enough 2749936Swollman ** to hold the longest file name string that the implementation 2759936Swollman ** guarantees can be opened." 2769936Swollman */ 2772708Swollman char fullname[FILENAME_MAX + 1]; 2782708Swollman 2792708Swollman if (name[0] == ':') 2802708Swollman ++name; 2812708Swollman doaccess = name[0] == '/'; 2822708Swollman if (!doaccess) { 2832708Swollman if ((p = TZDIR) == NULL) 2842708Swollman return -1; 2852708Swollman if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 2862708Swollman return -1; 2872708Swollman (void) strcpy(fullname, p); 2882708Swollman (void) strcat(fullname, "/"); 2892708Swollman (void) strcat(fullname, name); 2902708Swollman /* 2912708Swollman ** Set doaccess if '.' (as in "../") shows up in name. 2922708Swollman */ 2932708Swollman if (strchr(name, '.') != NULL) 2942708Swollman doaccess = TRUE; 2952708Swollman name = fullname; 2962708Swollman } 2979936Swollman if (doaccess && access(name, R_OK) != 0) 2982708Swollman return -1; 2992708Swollman if ((fid = open(name, OPEN_MODE)) == -1) 3002708Swollman return -1; 3012708Swollman } 3022708Swollman { 3039936Swollman struct tzhead * tzhp; 3049936Swollman char buf[sizeof *sp + sizeof *tzhp]; 3059936Swollman int ttisstdcnt; 3069936Swollman int ttisgmtcnt; 3072708Swollman 3082708Swollman i = read(fid, buf, sizeof buf); 3099936Swollman if (close(fid) != 0) 3102708Swollman return -1; 3119936Swollman p = buf; 3129936Swollman p += sizeof tzhp->tzh_reserved; 3139936Swollman ttisstdcnt = (int) detzcode(p); 3149936Swollman p += 4; 3159936Swollman ttisgmtcnt = (int) detzcode(p); 3169936Swollman p += 4; 3179936Swollman sp->leapcnt = (int) detzcode(p); 3189936Swollman p += 4; 3199936Swollman sp->timecnt = (int) detzcode(p); 3209936Swollman p += 4; 3219936Swollman sp->typecnt = (int) detzcode(p); 3229936Swollman p += 4; 3239936Swollman sp->charcnt = (int) detzcode(p); 3249936Swollman p += 4; 3252708Swollman if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || 3262708Swollman sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 3272708Swollman sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 3282708Swollman sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 3299936Swollman (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || 3309936Swollman (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) 3312708Swollman return -1; 3329936Swollman if (i - (p - buf) < sp->timecnt * 4 + /* ats */ 3339936Swollman sp->timecnt + /* types */ 3349936Swollman sp->typecnt * (4 + 2) + /* ttinfos */ 3359936Swollman sp->charcnt + /* chars */ 3369936Swollman sp->leapcnt * (4 + 4) + /* lsinfos */ 3379936Swollman ttisstdcnt + /* ttisstds */ 3389936Swollman ttisgmtcnt) /* ttisgmts */ 3392708Swollman return -1; 3402708Swollman for (i = 0; i < sp->timecnt; ++i) { 3412708Swollman sp->ats[i] = detzcode(p); 3422708Swollman p += 4; 3432708Swollman } 3442708Swollman for (i = 0; i < sp->timecnt; ++i) { 3452708Swollman sp->types[i] = (unsigned char) *p++; 3462708Swollman if (sp->types[i] >= sp->typecnt) 3472708Swollman return -1; 3482708Swollman } 3492708Swollman for (i = 0; i < sp->typecnt; ++i) { 3502708Swollman register struct ttinfo * ttisp; 3512708Swollman 3522708Swollman ttisp = &sp->ttis[i]; 3532708Swollman ttisp->tt_gmtoff = detzcode(p); 3542708Swollman p += 4; 3552708Swollman ttisp->tt_isdst = (unsigned char) *p++; 3562708Swollman if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 3572708Swollman return -1; 3582708Swollman ttisp->tt_abbrind = (unsigned char) *p++; 3592708Swollman if (ttisp->tt_abbrind < 0 || 3602708Swollman ttisp->tt_abbrind > sp->charcnt) 3612708Swollman return -1; 3622708Swollman } 3632708Swollman for (i = 0; i < sp->charcnt; ++i) 3642708Swollman sp->chars[i] = *p++; 3652708Swollman sp->chars[i] = '\0'; /* ensure '\0' at end */ 3662708Swollman for (i = 0; i < sp->leapcnt; ++i) { 3672708Swollman register struct lsinfo * lsisp; 3682708Swollman 3692708Swollman lsisp = &sp->lsis[i]; 3702708Swollman lsisp->ls_trans = detzcode(p); 3712708Swollman p += 4; 3722708Swollman lsisp->ls_corr = detzcode(p); 3732708Swollman p += 4; 3742708Swollman } 3752708Swollman for (i = 0; i < sp->typecnt; ++i) { 3762708Swollman register struct ttinfo * ttisp; 3772708Swollman 3782708Swollman ttisp = &sp->ttis[i]; 3792708Swollman if (ttisstdcnt == 0) 3802708Swollman ttisp->tt_ttisstd = FALSE; 3812708Swollman else { 3822708Swollman ttisp->tt_ttisstd = *p++; 3832708Swollman if (ttisp->tt_ttisstd != TRUE && 3842708Swollman ttisp->tt_ttisstd != FALSE) 3852708Swollman return -1; 3862708Swollman } 3872708Swollman } 3889936Swollman for (i = 0; i < sp->typecnt; ++i) { 3899936Swollman register struct ttinfo * ttisp; 3909936Swollman 3919936Swollman ttisp = &sp->ttis[i]; 3929936Swollman if (ttisgmtcnt == 0) 3939936Swollman ttisp->tt_ttisgmt = FALSE; 3949936Swollman else { 3959936Swollman ttisp->tt_ttisgmt = *p++; 3969936Swollman if (ttisp->tt_ttisgmt != TRUE && 3979936Swollman ttisp->tt_ttisgmt != FALSE) 3989936Swollman return -1; 3999936Swollman } 4009936Swollman } 4012708Swollman } 4022708Swollman return 0; 4032708Swollman} 4042708Swollman 4052708Swollmanstatic const int mon_lengths[2][MONSPERYEAR] = { 4062708Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 4072708Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 4082708Swollman}; 4092708Swollman 4102708Swollmanstatic const int year_lengths[2] = { 4112708Swollman DAYSPERNYEAR, DAYSPERLYEAR 4122708Swollman}; 4132708Swollman 4142708Swollman/* 4152708Swollman** Given a pointer into a time zone string, scan until a character that is not 4162708Swollman** a valid character in a zone name is found. Return a pointer to that 4172708Swollman** character. 4182708Swollman*/ 4192708Swollman 4202708Swollmanstatic const char * 4212708Swollmangetzname(strp) 4222708Swollmanregister const char * strp; 4232708Swollman{ 4242708Swollman register char c; 4252708Swollman 4262708Swollman while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && 4272708Swollman c != '+') 4282708Swollman ++strp; 4292708Swollman return strp; 4302708Swollman} 4312708Swollman 4322708Swollman/* 4332708Swollman** Given a pointer into a time zone string, extract a number from that string. 4342708Swollman** Check that the number is within a specified range; if it is not, return 4352708Swollman** NULL. 4362708Swollman** Otherwise, return a pointer to the first character not part of the number. 4372708Swollman*/ 4382708Swollman 4392708Swollmanstatic const char * 4402708Swollmangetnum(strp, nump, min, max) 4412708Swollmanregister const char * strp; 4422708Swollmanint * const nump; 4432708Swollmanconst int min; 4442708Swollmanconst int max; 4452708Swollman{ 4462708Swollman register char c; 4472708Swollman register int num; 4482708Swollman 4492708Swollman if (strp == NULL || !isdigit(*strp)) 4502708Swollman return NULL; 4512708Swollman num = 0; 4522708Swollman while ((c = *strp) != '\0' && isdigit(c)) { 4532708Swollman num = num * 10 + (c - '0'); 4542708Swollman if (num > max) 4552708Swollman return NULL; /* illegal value */ 4562708Swollman ++strp; 4572708Swollman } 4582708Swollman if (num < min) 4592708Swollman return NULL; /* illegal value */ 4602708Swollman *nump = num; 4612708Swollman return strp; 4622708Swollman} 4632708Swollman 4642708Swollman/* 4652708Swollman** Given a pointer into a time zone string, extract a number of seconds, 4662708Swollman** in hh[:mm[:ss]] form, from the string. 4672708Swollman** If any error occurs, return NULL. 4682708Swollman** Otherwise, return a pointer to the first character not part of the number 4692708Swollman** of seconds. 4702708Swollman*/ 4712708Swollman 4722708Swollmanstatic const char * 4732708Swollmangetsecs(strp, secsp) 4742708Swollmanregister const char * strp; 4752708Swollmanlong * const secsp; 4762708Swollman{ 4772708Swollman int num; 4782708Swollman 4799936Swollman /* 4809936Swollman ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like 4819936Swollman ** "M10.4.6/26", which does not conform to Posix, 4829936Swollman ** but which specifies the equivalent of 4839936Swollman ** ``02:00 on the first Sunday on or after 23 Oct''. 4849936Swollman */ 4859936Swollman strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 4862708Swollman if (strp == NULL) 4872708Swollman return NULL; 4889936Swollman *secsp = num * (long) SECSPERHOUR; 4892708Swollman if (*strp == ':') { 4902708Swollman ++strp; 4912708Swollman strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 4922708Swollman if (strp == NULL) 4932708Swollman return NULL; 4942708Swollman *secsp += num * SECSPERMIN; 4952708Swollman if (*strp == ':') { 4962708Swollman ++strp; 4979936Swollman /* `SECSPERMIN' allows for leap seconds. */ 4989936Swollman strp = getnum(strp, &num, 0, SECSPERMIN); 4992708Swollman if (strp == NULL) 5002708Swollman return NULL; 5012708Swollman *secsp += num; 5022708Swollman } 5032708Swollman } 5042708Swollman return strp; 5052708Swollman} 5062708Swollman 5072708Swollman/* 5082708Swollman** Given a pointer into a time zone string, extract an offset, in 5092708Swollman** [+-]hh[:mm[:ss]] form, from the string. 5102708Swollman** If any error occurs, return NULL. 5112708Swollman** Otherwise, return a pointer to the first character not part of the time. 5122708Swollman*/ 5132708Swollman 5142708Swollmanstatic const char * 5152708Swollmangetoffset(strp, offsetp) 5162708Swollmanregister const char * strp; 5172708Swollmanlong * const offsetp; 5182708Swollman{ 5192708Swollman register int neg; 5202708Swollman 5212708Swollman if (*strp == '-') { 5222708Swollman neg = 1; 5232708Swollman ++strp; 5242708Swollman } else if (isdigit(*strp) || *strp++ == '+') 5252708Swollman neg = 0; 5262708Swollman else return NULL; /* illegal offset */ 5272708Swollman strp = getsecs(strp, offsetp); 5282708Swollman if (strp == NULL) 5292708Swollman return NULL; /* illegal time */ 5302708Swollman if (neg) 5312708Swollman *offsetp = -*offsetp; 5322708Swollman return strp; 5332708Swollman} 5342708Swollman 5352708Swollman/* 5362708Swollman** Given a pointer into a time zone string, extract a rule in the form 5372708Swollman** date[/time]. See POSIX section 8 for the format of "date" and "time". 5382708Swollman** If a valid rule is not found, return NULL. 5392708Swollman** Otherwise, return a pointer to the first character not part of the rule. 5402708Swollman*/ 5412708Swollman 5422708Swollmanstatic const char * 5432708Swollmangetrule(strp, rulep) 5442708Swollmanconst char * strp; 5452708Swollmanregister struct rule * const rulep; 5462708Swollman{ 5472708Swollman if (*strp == 'J') { 5482708Swollman /* 5492708Swollman ** Julian day. 5502708Swollman */ 5512708Swollman rulep->r_type = JULIAN_DAY; 5522708Swollman ++strp; 5532708Swollman strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 5542708Swollman } else if (*strp == 'M') { 5552708Swollman /* 5562708Swollman ** Month, week, day. 5572708Swollman */ 5582708Swollman rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 5592708Swollman ++strp; 5602708Swollman strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 5612708Swollman if (strp == NULL) 5622708Swollman return NULL; 5632708Swollman if (*strp++ != '.') 5642708Swollman return NULL; 5652708Swollman strp = getnum(strp, &rulep->r_week, 1, 5); 5662708Swollman if (strp == NULL) 5672708Swollman return NULL; 5682708Swollman if (*strp++ != '.') 5692708Swollman return NULL; 5702708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 5712708Swollman } else if (isdigit(*strp)) { 5722708Swollman /* 5732708Swollman ** Day of year. 5742708Swollman */ 5752708Swollman rulep->r_type = DAY_OF_YEAR; 5762708Swollman strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 5772708Swollman } else return NULL; /* invalid format */ 5782708Swollman if (strp == NULL) 5792708Swollman return NULL; 5802708Swollman if (*strp == '/') { 5812708Swollman /* 5822708Swollman ** Time specified. 5832708Swollman */ 5842708Swollman ++strp; 5852708Swollman strp = getsecs(strp, &rulep->r_time); 5862708Swollman } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 5872708Swollman return strp; 5882708Swollman} 5892708Swollman 5902708Swollman/* 5912708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 5922708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect, 5932708Swollman** calculate the Epoch-relative time that rule takes effect. 5942708Swollman*/ 5952708Swollman 5962708Swollmanstatic time_t 5972708Swollmantranstime(janfirst, year, rulep, offset) 5982708Swollmanconst time_t janfirst; 5992708Swollmanconst int year; 6002708Swollmanregister const struct rule * const rulep; 6012708Swollmanconst long offset; 6022708Swollman{ 6032708Swollman register int leapyear; 6042708Swollman register time_t value; 6052708Swollman register int i; 6062708Swollman int d, m1, yy0, yy1, yy2, dow; 6072708Swollman 6089936Swollman INITIALIZE(value); 6092708Swollman leapyear = isleap(year); 6102708Swollman switch (rulep->r_type) { 6112708Swollman 6122708Swollman case JULIAN_DAY: 6132708Swollman /* 6142708Swollman ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 6152708Swollman ** years. 6162708Swollman ** In non-leap years, or if the day number is 59 or less, just 6172708Swollman ** add SECSPERDAY times the day number-1 to the time of 6182708Swollman ** January 1, midnight, to get the day. 6192708Swollman */ 6202708Swollman value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 6212708Swollman if (leapyear && rulep->r_day >= 60) 6222708Swollman value += SECSPERDAY; 6232708Swollman break; 6242708Swollman 6252708Swollman case DAY_OF_YEAR: 6262708Swollman /* 6272708Swollman ** n - day of year. 6282708Swollman ** Just add SECSPERDAY times the day number to the time of 6292708Swollman ** January 1, midnight, to get the day. 6302708Swollman */ 6312708Swollman value = janfirst + rulep->r_day * SECSPERDAY; 6322708Swollman break; 6332708Swollman 6342708Swollman case MONTH_NTH_DAY_OF_WEEK: 6352708Swollman /* 6362708Swollman ** Mm.n.d - nth "dth day" of month m. 6372708Swollman */ 6382708Swollman value = janfirst; 6392708Swollman for (i = 0; i < rulep->r_mon - 1; ++i) 6402708Swollman value += mon_lengths[leapyear][i] * SECSPERDAY; 6412708Swollman 6422708Swollman /* 6432708Swollman ** Use Zeller's Congruence to get day-of-week of first day of 6442708Swollman ** month. 6452708Swollman */ 6462708Swollman m1 = (rulep->r_mon + 9) % 12 + 1; 6472708Swollman yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 6482708Swollman yy1 = yy0 / 100; 6492708Swollman yy2 = yy0 % 100; 6502708Swollman dow = ((26 * m1 - 2) / 10 + 6512708Swollman 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 6522708Swollman if (dow < 0) 6532708Swollman dow += DAYSPERWEEK; 6542708Swollman 6552708Swollman /* 6562708Swollman ** "dow" is the day-of-week of the first day of the month. Get 6572708Swollman ** the day-of-month (zero-origin) of the first "dow" day of the 6582708Swollman ** month. 6592708Swollman */ 6602708Swollman d = rulep->r_day - dow; 6612708Swollman if (d < 0) 6622708Swollman d += DAYSPERWEEK; 6632708Swollman for (i = 1; i < rulep->r_week; ++i) { 6642708Swollman if (d + DAYSPERWEEK >= 6652708Swollman mon_lengths[leapyear][rulep->r_mon - 1]) 6662708Swollman break; 6672708Swollman d += DAYSPERWEEK; 6682708Swollman } 6692708Swollman 6702708Swollman /* 6712708Swollman ** "d" is the day-of-month (zero-origin) of the day we want. 6722708Swollman */ 6732708Swollman value += d * SECSPERDAY; 6742708Swollman break; 6752708Swollman } 6762708Swollman 6772708Swollman /* 6782708Swollman ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 6792708Swollman ** question. To get the Epoch-relative time of the specified local 6802708Swollman ** time on that day, add the transition time and the current offset 6812708Swollman ** from GMT. 6822708Swollman */ 6832708Swollman return value + rulep->r_time + offset; 6842708Swollman} 6852708Swollman 6862708Swollman/* 6872708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as 6882708Swollman** appropriate. 6892708Swollman*/ 6902708Swollman 6912708Swollmanstatic int 6922708Swollmantzparse(name, sp, lastditch) 6932708Swollmanconst char * name; 6942708Swollmanregister struct state * const sp; 6952708Swollmanconst int lastditch; 6962708Swollman{ 6972708Swollman const char * stdname; 6982708Swollman const char * dstname; 6999936Swollman size_t stdlen; 7009936Swollman size_t dstlen; 7012708Swollman long stdoffset; 7022708Swollman long dstoffset; 7032708Swollman register time_t * atp; 7042708Swollman register unsigned char * typep; 7052708Swollman register char * cp; 7062708Swollman register int load_result; 7072708Swollman 7089936Swollman INITIALIZE(dstname); 7092708Swollman stdname = name; 7102708Swollman if (lastditch) { 7112708Swollman stdlen = strlen(name); /* length of standard zone name */ 7122708Swollman name += stdlen; 7132708Swollman if (stdlen >= sizeof sp->chars) 7142708Swollman stdlen = (sizeof sp->chars) - 1; 7152708Swollman } else { 7162708Swollman name = getzname(name); 7172708Swollman stdlen = name - stdname; 7182708Swollman if (stdlen < 3) 7192708Swollman return -1; 7202708Swollman } 7212708Swollman if (*name == '\0') 7222708Swollman return -1; /* was "stdoffset = 0;" */ 7232708Swollman else { 7242708Swollman name = getoffset(name, &stdoffset); 7252708Swollman if (name == NULL) 7262708Swollman return -1; 7272708Swollman } 7282708Swollman load_result = tzload(TZDEFRULES, sp); 7292708Swollman if (load_result != 0) 7302708Swollman sp->leapcnt = 0; /* so, we're off a little */ 7312708Swollman if (*name != '\0') { 7322708Swollman dstname = name; 7332708Swollman name = getzname(name); 7342708Swollman dstlen = name - dstname; /* length of DST zone name */ 7352708Swollman if (dstlen < 3) 7362708Swollman return -1; 7372708Swollman if (*name != '\0' && *name != ',' && *name != ';') { 7382708Swollman name = getoffset(name, &dstoffset); 7392708Swollman if (name == NULL) 7402708Swollman return -1; 7412708Swollman } else dstoffset = stdoffset - SECSPERHOUR; 7422708Swollman if (*name == ',' || *name == ';') { 7432708Swollman struct rule start; 7442708Swollman struct rule end; 7452708Swollman register int year; 7462708Swollman register time_t janfirst; 7472708Swollman time_t starttime; 7482708Swollman time_t endtime; 7492708Swollman 7502708Swollman ++name; 7512708Swollman if ((name = getrule(name, &start)) == NULL) 7522708Swollman return -1; 7532708Swollman if (*name++ != ',') 7542708Swollman return -1; 7552708Swollman if ((name = getrule(name, &end)) == NULL) 7562708Swollman return -1; 7572708Swollman if (*name != '\0') 7582708Swollman return -1; 7592708Swollman sp->typecnt = 2; /* standard time and DST */ 7602708Swollman /* 7612708Swollman ** Two transitions per year, from EPOCH_YEAR to 2037. 7622708Swollman */ 7632708Swollman sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 7642708Swollman if (sp->timecnt > TZ_MAX_TIMES) 7652708Swollman return -1; 7662708Swollman sp->ttis[0].tt_gmtoff = -dstoffset; 7672708Swollman sp->ttis[0].tt_isdst = 1; 7682708Swollman sp->ttis[0].tt_abbrind = stdlen + 1; 7692708Swollman sp->ttis[1].tt_gmtoff = -stdoffset; 7702708Swollman sp->ttis[1].tt_isdst = 0; 7712708Swollman sp->ttis[1].tt_abbrind = 0; 7722708Swollman atp = sp->ats; 7732708Swollman typep = sp->types; 7742708Swollman janfirst = 0; 7752708Swollman for (year = EPOCH_YEAR; year <= 2037; ++year) { 7762708Swollman starttime = transtime(janfirst, year, &start, 7772708Swollman stdoffset); 7782708Swollman endtime = transtime(janfirst, year, &end, 7792708Swollman dstoffset); 7802708Swollman if (starttime > endtime) { 7812708Swollman *atp++ = endtime; 7822708Swollman *typep++ = 1; /* DST ends */ 7832708Swollman *atp++ = starttime; 7842708Swollman *typep++ = 0; /* DST begins */ 7852708Swollman } else { 7862708Swollman *atp++ = starttime; 7872708Swollman *typep++ = 0; /* DST begins */ 7882708Swollman *atp++ = endtime; 7892708Swollman *typep++ = 1; /* DST ends */ 7902708Swollman } 7912708Swollman janfirst += year_lengths[isleap(year)] * 7922708Swollman SECSPERDAY; 7932708Swollman } 7942708Swollman } else { 7959936Swollman register long theirstdoffset; 7969936Swollman register long theirdstoffset; 7979936Swollman register long theiroffset; 7989936Swollman register int isdst; 7992708Swollman register int i; 8009936Swollman register int j; 8012708Swollman 8022708Swollman if (*name != '\0') 8032708Swollman return -1; 8042708Swollman if (load_result != 0) 8052708Swollman return -1; 8062708Swollman /* 8079936Swollman ** Initial values of theirstdoffset and theirdstoffset. 8082708Swollman */ 8099936Swollman theirstdoffset = 0; 8109936Swollman for (i = 0; i < sp->timecnt; ++i) { 8119936Swollman j = sp->types[i]; 8129936Swollman if (!sp->ttis[j].tt_isdst) { 8139936Swollman theirstdoffset = -sp->ttis[j].tt_gmtoff; 8149936Swollman break; 8152708Swollman } 8162708Swollman } 8179936Swollman theirdstoffset = 0; 8189936Swollman for (i = 0; i < sp->timecnt; ++i) { 8199936Swollman j = sp->types[i]; 8209936Swollman if (sp->ttis[j].tt_isdst) { 8219936Swollman theirdstoffset = -sp->ttis[j].tt_gmtoff; 8229936Swollman break; 8239936Swollman } 8249936Swollman } 8252708Swollman /* 8269936Swollman ** Initially we're assumed to be in standard time. 8272708Swollman */ 8289936Swollman isdst = FALSE; 8299936Swollman theiroffset = theirstdoffset; 8302708Swollman /* 8319936Swollman ** Now juggle transition times and types 8329936Swollman ** tracking offsets as you do. 8332708Swollman */ 8342708Swollman for (i = 0; i < sp->timecnt; ++i) { 8359936Swollman j = sp->types[i]; 8369936Swollman sp->types[i] = sp->ttis[j].tt_isdst; 8379936Swollman if (sp->ttis[j].tt_ttisgmt) { 8389936Swollman /* No adjustment to transition time */ 8399936Swollman } else { 8409936Swollman /* 8419936Swollman ** If summer time is in effect, and the 8429936Swollman ** transition time was not specified as 8439936Swollman ** standard time, add the summer time 8449936Swollman ** offset to the transition time; 8459936Swollman ** otherwise, add the standard time 8469936Swollman ** offset to the transition time. 8479936Swollman */ 8489936Swollman /* 8499936Swollman ** Transitions from DST to DDST 8509936Swollman ** will effectively disappear since 8519936Swollman ** POSIX provides for only one DST 8529936Swollman ** offset. 8539936Swollman */ 8549936Swollman if (isdst && !sp->ttis[j].tt_ttisstd) { 8559936Swollman sp->ats[i] += dstoffset - 8569936Swollman theirdstoffset; 8579936Swollman } else { 8589936Swollman sp->ats[i] += stdoffset - 8599936Swollman theirstdoffset; 8609936Swollman } 8619936Swollman } 8629936Swollman theiroffset = -sp->ttis[j].tt_gmtoff; 8639936Swollman if (sp->ttis[j].tt_isdst) 8649936Swollman theirdstoffset = theiroffset; 8659936Swollman else theirstdoffset = theiroffset; 8662708Swollman } 8679936Swollman /* 8689936Swollman ** Finally, fill in ttis. 8699936Swollman ** ttisstd and ttisgmt need not be handled. 8709936Swollman */ 8719936Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8729936Swollman sp->ttis[0].tt_isdst = FALSE; 8739936Swollman sp->ttis[0].tt_abbrind = 0; 8749936Swollman sp->ttis[1].tt_gmtoff = -dstoffset; 8759936Swollman sp->ttis[1].tt_isdst = TRUE; 8769936Swollman sp->ttis[1].tt_abbrind = stdlen + 1; 8772708Swollman } 8782708Swollman } else { 8792708Swollman dstlen = 0; 8802708Swollman sp->typecnt = 1; /* only standard time */ 8812708Swollman sp->timecnt = 0; 8822708Swollman sp->ttis[0].tt_gmtoff = -stdoffset; 8832708Swollman sp->ttis[0].tt_isdst = 0; 8842708Swollman sp->ttis[0].tt_abbrind = 0; 8852708Swollman } 8862708Swollman sp->charcnt = stdlen + 1; 8872708Swollman if (dstlen != 0) 8882708Swollman sp->charcnt += dstlen + 1; 8892708Swollman if (sp->charcnt > sizeof sp->chars) 8902708Swollman return -1; 8912708Swollman cp = sp->chars; 8922708Swollman (void) strncpy(cp, stdname, stdlen); 8932708Swollman cp += stdlen; 8942708Swollman *cp++ = '\0'; 8952708Swollman if (dstlen != 0) { 8962708Swollman (void) strncpy(cp, dstname, dstlen); 8972708Swollman *(cp + dstlen) = '\0'; 8982708Swollman } 8992708Swollman return 0; 9002708Swollman} 9012708Swollman 9022708Swollmanstatic void 9032708Swollmangmtload(sp) 9042708Swollmanstruct state * const sp; 9052708Swollman{ 9069936Swollman if (tzload(gmt, sp) != 0) 9079936Swollman (void) tzparse(gmt, sp, TRUE); 9082708Swollman} 9092708Swollman 9102708Swollman#ifndef STD_INSPIRED 9119936Swollman/* 9129936Swollman** A non-static declaration of tzsetwall in a system header file 9139936Swollman** may cause a warning about this upcoming static declaration... 9149936Swollman*/ 9152708Swollmanstatic 9162708Swollman#endif /* !defined STD_INSPIRED */ 91713545Sjulian#ifdef _THREAD_SAFE 9182708Swollmanvoid 91913545Sjuliantzsetwall_basic P((void)) 92013545Sjulian#else 92113545Sjulianvoid 9229936Swollmantzsetwall P((void)) 92313545Sjulian#endif 9242708Swollman{ 9259936Swollman if (lcl_is_set < 0) 9269936Swollman return; 9279936Swollman lcl_is_set = -1; 9289936Swollman 9292708Swollman#ifdef ALL_STATE 9302708Swollman if (lclptr == NULL) { 9312708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9322708Swollman if (lclptr == NULL) { 9332708Swollman settzname(); /* all we can do */ 9342708Swollman return; 9352708Swollman } 9362708Swollman } 9372708Swollman#endif /* defined ALL_STATE */ 9382708Swollman if (tzload((char *) NULL, lclptr) != 0) 9392708Swollman gmtload(lclptr); 9402708Swollman settzname(); 9412708Swollman} 9422708Swollman 94313545Sjulian#ifdef _THREAD_SAFE 9442708Swollmanvoid 94513545Sjuliantzsetwall P((void)) 94613545Sjulian{ 94713545Sjulian pthread_mutex_lock(&lcl_mutex); 94813545Sjulian tzsetwall_basic(); 94913545Sjulian pthread_mutex_unlock(&lcl_mutex); 95013545Sjulian} 95113545Sjulian#endif 95213545Sjulian 95313545Sjulian#ifdef _THREAD_SAFE 95413545Sjulianstatic void 95513545Sjuliantzset_basic P((void)) 95613545Sjulian#else 95713545Sjulianvoid 9589936Swollmantzset P((void)) 95913545Sjulian#endif 9602708Swollman{ 9612708Swollman register const char * name; 9622708Swollman 9632708Swollman name = getenv("TZ"); 9642708Swollman if (name == NULL) { 9652708Swollman tzsetwall(); 9662708Swollman return; 9672708Swollman } 9689936Swollman 9699936Swollman if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) 9709936Swollman return; 9719936Swollman lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); 9729936Swollman if (lcl_is_set) 9739936Swollman (void) strcpy(lcl_TZname, name); 9749936Swollman 9752708Swollman#ifdef ALL_STATE 9762708Swollman if (lclptr == NULL) { 9772708Swollman lclptr = (struct state *) malloc(sizeof *lclptr); 9782708Swollman if (lclptr == NULL) { 9792708Swollman settzname(); /* all we can do */ 9802708Swollman return; 9812708Swollman } 9822708Swollman } 9832708Swollman#endif /* defined ALL_STATE */ 9842708Swollman if (*name == '\0') { 9852708Swollman /* 9862708Swollman ** User wants it fast rather than right. 9872708Swollman */ 9882708Swollman lclptr->leapcnt = 0; /* so, we're off a little */ 9892708Swollman lclptr->timecnt = 0; 9902708Swollman lclptr->ttis[0].tt_gmtoff = 0; 9912708Swollman lclptr->ttis[0].tt_abbrind = 0; 9929936Swollman (void) strcpy(lclptr->chars, gmt); 9932708Swollman } else if (tzload(name, lclptr) != 0) 9942708Swollman if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 9952708Swollman (void) gmtload(lclptr); 9962708Swollman settzname(); 9972708Swollman} 9982708Swollman 99913545Sjulian#ifdef _THREAD_SAFE 100013545Sjulianvoid 100113545Sjuliantzset P((void)) 100213545Sjulian{ 100313545Sjulian pthread_mutex_lock(&lcl_mutex); 100413545Sjulian tzset_basic(); 100513545Sjulian pthread_mutex_unlock(&lcl_mutex); 100613545Sjulian} 100713545Sjulian#endif 100813545Sjulian 10092708Swollman/* 10102708Swollman** The easy way to behave "as if no library function calls" localtime 10112708Swollman** is to not call it--so we drop its guts into "localsub", which can be 10122708Swollman** freely called. (And no, the PANS doesn't require the above behavior-- 10132708Swollman** but it *is* desirable.) 10142708Swollman** 10152708Swollman** The unused offset argument is for the benefit of mktime variants. 10162708Swollman*/ 10172708Swollman 10182708Swollman/*ARGSUSED*/ 10192708Swollmanstatic void 10202708Swollmanlocalsub(timep, offset, tmp) 10212708Swollmanconst time_t * const timep; 10222708Swollmanconst long offset; 10232708Swollmanstruct tm * const tmp; 10242708Swollman{ 10259936Swollman register struct state * sp; 10262708Swollman register const struct ttinfo * ttisp; 10272708Swollman register int i; 10282708Swollman const time_t t = *timep; 10292708Swollman 10302708Swollman sp = lclptr; 10312708Swollman#ifdef ALL_STATE 10322708Swollman if (sp == NULL) { 10332708Swollman gmtsub(timep, offset, tmp); 10342708Swollman return; 10352708Swollman } 10362708Swollman#endif /* defined ALL_STATE */ 10372708Swollman if (sp->timecnt == 0 || t < sp->ats[0]) { 10382708Swollman i = 0; 10392708Swollman while (sp->ttis[i].tt_isdst) 10402708Swollman if (++i >= sp->typecnt) { 10412708Swollman i = 0; 10422708Swollman break; 10432708Swollman } 10442708Swollman } else { 10452708Swollman for (i = 1; i < sp->timecnt; ++i) 10462708Swollman if (t < sp->ats[i]) 10472708Swollman break; 10482708Swollman i = sp->types[i - 1]; 10492708Swollman } 10502708Swollman ttisp = &sp->ttis[i]; 10512708Swollman /* 10522708Swollman ** To get (wrong) behavior that's compatible with System V Release 2.0 10532708Swollman ** you'd replace the statement below with 10542708Swollman ** t += ttisp->tt_gmtoff; 10552708Swollman ** timesub(&t, 0L, sp, tmp); 10562708Swollman */ 10572708Swollman timesub(&t, ttisp->tt_gmtoff, sp, tmp); 10582708Swollman tmp->tm_isdst = ttisp->tt_isdst; 10599936Swollman tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; 10602708Swollman#ifdef TM_ZONE 10619936Swollman tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; 10622708Swollman#endif /* defined TM_ZONE */ 10632708Swollman} 10642708Swollman 106513545Sjulian#ifdef _THREAD_SAFE 106613545Sjulianint 106713545Sjulianlocaltime_r(timep, p_tm) 106813545Sjulianconst time_t * const timep; 106913545Sjulianstruct tm *p_tm; 107013545Sjulian{ 107113545Sjulian pthread_mutex_lock(&lcl_mutex); 107213545Sjulian tzset(); 107313545Sjulian localsub(timep, 0L, p_tm); 107413545Sjulian pthread_mutex_unlock(&lcl_mutex); 107513545Sjulian return(0); 107613545Sjulian} 107713545Sjulian#endif 107813545Sjulian 10792708Swollmanstruct tm * 10802708Swollmanlocaltime(timep) 10812708Swollmanconst time_t * const timep; 10822708Swollman{ 108313545Sjulian#ifdef _THREAD_SAFE 108413545Sjulian static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER; 108513545Sjulian static pthread_key_t localtime_key = -1; 108613545Sjulian struct tm *p_tm; 108713545Sjulian 108813545Sjulian pthread_mutex_lock(&localtime_mutex); 108913545Sjulian if (localtime_key < 0) { 109013545Sjulian if (pthread_keycreate(&localtime_key, free) < 0) { 109113545Sjulian pthread_mutex_unlock(&localtime_mutex); 109213545Sjulian return(NULL); 109313545Sjulian } 109413545Sjulian } 109513545Sjulian pthread_mutex_unlock(&localtime_mutex); 109613545Sjulian if (pthread_getspecific(localtime_key,(void **) &p_tm) != 0) { 109713545Sjulian return(NULL); 109813545Sjulian } else if (p_tm == NULL) { 109913545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 110013545Sjulian return(NULL); 110113545Sjulian } 110213545Sjulian pthread_setspecific(localtime_key, p_tm); 110313545Sjulian } 110413545Sjulian pthread_mutex_lock(&lcl_mutex); 11059936Swollman tzset(); 110613545Sjulian localsub(timep, 0L, p_tm); 110713545Sjulian pthread_mutex_unlock(&lcl_mutex); 110813545Sjulian return p_tm; 110913545Sjulian#else 111013545Sjulian tzset(); 11112708Swollman localsub(timep, 0L, &tm); 11122708Swollman return &tm; 111313545Sjulian#endif 11142708Swollman} 11152708Swollman 11162708Swollman/* 11172708Swollman** gmtsub is to gmtime as localsub is to localtime. 11182708Swollman*/ 11192708Swollman 11202708Swollmanstatic void 11212708Swollmangmtsub(timep, offset, tmp) 11222708Swollmanconst time_t * const timep; 11232708Swollmanconst long offset; 11242708Swollmanstruct tm * const tmp; 11252708Swollman{ 112613545Sjulian#ifdef _THREAD_SAFE 112713545Sjulian pthread_mutex_lock(&gmt_mutex); 112813545Sjulian#endif 11292708Swollman if (!gmt_is_set) { 11302708Swollman gmt_is_set = TRUE; 11312708Swollman#ifdef ALL_STATE 11322708Swollman gmtptr = (struct state *) malloc(sizeof *gmtptr); 11332708Swollman if (gmtptr != NULL) 11342708Swollman#endif /* defined ALL_STATE */ 11352708Swollman gmtload(gmtptr); 11362708Swollman } 113713545Sjulian#ifdef _THREAD_SAFE 113813545Sjulian pthread_mutex_unlock(&gmt_mutex); 113913545Sjulian#endif 11402708Swollman timesub(timep, offset, gmtptr, tmp); 11412708Swollman#ifdef TM_ZONE 11422708Swollman /* 11432708Swollman ** Could get fancy here and deliver something such as 11442708Swollman ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 11452708Swollman ** but this is no time for a treasure hunt. 11462708Swollman */ 11472708Swollman if (offset != 0) 11489936Swollman tmp->TM_ZONE = wildabbr; 11492708Swollman else { 11502708Swollman#ifdef ALL_STATE 11512708Swollman if (gmtptr == NULL) 11529936Swollman tmp->TM_ZONE = gmt; 11532708Swollman else tmp->TM_ZONE = gmtptr->chars; 11542708Swollman#endif /* defined ALL_STATE */ 11552708Swollman#ifndef ALL_STATE 11562708Swollman tmp->TM_ZONE = gmtptr->chars; 11572708Swollman#endif /* State Farm */ 11582708Swollman } 11592708Swollman#endif /* defined TM_ZONE */ 11602708Swollman} 11612708Swollman 11622708Swollmanstruct tm * 11632708Swollmangmtime(timep) 11642708Swollmanconst time_t * const timep; 11652708Swollman{ 116613545Sjulian#ifdef _THREAD_SAFE 116713545Sjulian static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER; 116813545Sjulian static pthread_key_t gmtime_key = -1; 116913545Sjulian struct tm *p_tm; 117013545Sjulian 117113545Sjulian pthread_mutex_lock(&gmtime_mutex); 117213545Sjulian if (gmtime_key < 0) { 117313545Sjulian if (pthread_keycreate(&gmtime_key, free) < 0) { 117413545Sjulian pthread_mutex_unlock(&gmtime_mutex); 117513545Sjulian return(NULL); 117613545Sjulian } 117713545Sjulian } 117813545Sjulian pthread_mutex_unlock(&gmtime_mutex); 117913545Sjulian if (pthread_getspecific(gmtime_key,(void **) &p_tm) != 0) { 118013545Sjulian return(NULL); 118113545Sjulian } else if (p_tm == NULL) { 118213545Sjulian if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) { 118313545Sjulian return(NULL); 118413545Sjulian } 118513545Sjulian pthread_setspecific(gmtime_key, p_tm); 118613545Sjulian } 118713545Sjulian gmtsub(timep, 0L, p_tm); 118813545Sjulian return(p_tm); 118913545Sjulian#else 11902708Swollman gmtsub(timep, 0L, &tm); 11912708Swollman return &tm; 119213545Sjulian#endif 11932708Swollman} 11942708Swollman 119513545Sjulian#ifdef _THREAD_SAFE 119613545Sjulianint 119713545Sjuliangmtime_r(const time_t * timep, struct tm * tm) 119813545Sjulian{ 119913545Sjulian gmtsub(timep, 0L, tm); 120013545Sjulian return(0); 120113545Sjulian} 120213545Sjulian#endif 120313545Sjulian 12042708Swollman#ifdef STD_INSPIRED 12052708Swollman 12062708Swollmanstruct tm * 12072708Swollmanofftime(timep, offset) 12082708Swollmanconst time_t * const timep; 12092708Swollmanconst long offset; 12102708Swollman{ 12112708Swollman gmtsub(timep, offset, &tm); 12122708Swollman return &tm; 12132708Swollman} 12142708Swollman 12152708Swollman#endif /* defined STD_INSPIRED */ 12162708Swollman 12172708Swollmanstatic void 12182708Swollmantimesub(timep, offset, sp, tmp) 12192708Swollmanconst time_t * const timep; 12202708Swollmanconst long offset; 12212708Swollmanregister const struct state * const sp; 12222708Swollmanregister struct tm * const tmp; 12232708Swollman{ 12242708Swollman register const struct lsinfo * lp; 12252708Swollman register long days; 12262708Swollman register long rem; 12272708Swollman register int y; 12282708Swollman register int yleap; 12292708Swollman register const int * ip; 12302708Swollman register long corr; 12312708Swollman register int hit; 12322708Swollman register int i; 12332708Swollman 12342708Swollman corr = 0; 12352708Swollman hit = 0; 12362708Swollman#ifdef ALL_STATE 12372708Swollman i = (sp == NULL) ? 0 : sp->leapcnt; 12382708Swollman#endif /* defined ALL_STATE */ 12392708Swollman#ifndef ALL_STATE 12402708Swollman i = sp->leapcnt; 12412708Swollman#endif /* State Farm */ 12422708Swollman while (--i >= 0) { 12432708Swollman lp = &sp->lsis[i]; 12442708Swollman if (*timep >= lp->ls_trans) { 12452708Swollman if (*timep == lp->ls_trans) { 12462708Swollman hit = ((i == 0 && lp->ls_corr > 0) || 12472708Swollman lp->ls_corr > sp->lsis[i - 1].ls_corr); 12482708Swollman if (hit) 12492708Swollman while (i > 0 && 12502708Swollman sp->lsis[i].ls_trans == 12512708Swollman sp->lsis[i - 1].ls_trans + 1 && 12522708Swollman sp->lsis[i].ls_corr == 12532708Swollman sp->lsis[i - 1].ls_corr + 1) { 12542708Swollman ++hit; 12552708Swollman --i; 12562708Swollman } 12572708Swollman } 12582708Swollman corr = lp->ls_corr; 12592708Swollman break; 12602708Swollman } 12612708Swollman } 12622708Swollman days = *timep / SECSPERDAY; 12632708Swollman rem = *timep % SECSPERDAY; 12642708Swollman#ifdef mc68k 12652708Swollman if (*timep == 0x80000000) { 12662708Swollman /* 12672708Swollman ** A 3B1 muffs the division on the most negative number. 12682708Swollman */ 12692708Swollman days = -24855; 12702708Swollman rem = -11648; 12712708Swollman } 12729936Swollman#endif /* defined mc68k */ 12732708Swollman rem += (offset - corr); 12742708Swollman while (rem < 0) { 12752708Swollman rem += SECSPERDAY; 12762708Swollman --days; 12772708Swollman } 12782708Swollman while (rem >= SECSPERDAY) { 12792708Swollman rem -= SECSPERDAY; 12802708Swollman ++days; 12812708Swollman } 12822708Swollman tmp->tm_hour = (int) (rem / SECSPERHOUR); 12832708Swollman rem = rem % SECSPERHOUR; 12842708Swollman tmp->tm_min = (int) (rem / SECSPERMIN); 12852708Swollman tmp->tm_sec = (int) (rem % SECSPERMIN); 12862708Swollman if (hit) 12872708Swollman /* 12882708Swollman ** A positive leap second requires a special 12892708Swollman ** representation. This uses "... ??:59:60" et seq. 12902708Swollman */ 12912708Swollman tmp->tm_sec += hit; 12922708Swollman tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 12932708Swollman if (tmp->tm_wday < 0) 12942708Swollman tmp->tm_wday += DAYSPERWEEK; 12952708Swollman y = EPOCH_YEAR; 12962708Swollman if (days >= 0) 12972708Swollman for ( ; ; ) { 12982708Swollman yleap = isleap(y); 12992708Swollman if (days < (long) year_lengths[yleap]) 13002708Swollman break; 13012708Swollman ++y; 13022708Swollman days = days - (long) year_lengths[yleap]; 13032708Swollman } 13042708Swollman else do { 13052708Swollman --y; 13062708Swollman yleap = isleap(y); 13072708Swollman days = days + (long) year_lengths[yleap]; 13082708Swollman } while (days < 0); 13092708Swollman tmp->tm_year = y - TM_YEAR_BASE; 13102708Swollman tmp->tm_yday = (int) days; 13112708Swollman ip = mon_lengths[yleap]; 13122708Swollman for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 13132708Swollman days = days - (long) ip[tmp->tm_mon]; 13142708Swollman tmp->tm_mday = (int) (days + 1); 13152708Swollman tmp->tm_isdst = 0; 13162708Swollman#ifdef TM_GMTOFF 13172708Swollman tmp->TM_GMTOFF = offset; 13182708Swollman#endif /* defined TM_GMTOFF */ 13192708Swollman} 13202708Swollman 13212708Swollmanchar * 13222708Swollmanctime(timep) 13232708Swollmanconst time_t * const timep; 13242708Swollman{ 13259936Swollman/* 13269936Swollman** Section 4.12.3.2 of X3.159-1989 requires that 13279936Swollman** The ctime funciton converts the calendar time pointed to by timer 13289936Swollman** to local time in the form of a string. It is equivalent to 13299936Swollman** asctime(localtime(timer)) 13309936Swollman*/ 13312708Swollman return asctime(localtime(timep)); 13322708Swollman} 13332708Swollman 13342708Swollman/* 13352708Swollman** Adapted from code provided by Robert Elz, who writes: 13362708Swollman** The "best" way to do mktime I think is based on an idea of Bob 13372708Swollman** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 13382708Swollman** It does a binary search of the time_t space. Since time_t's are 13392708Swollman** just 32 bits, its a max of 32 iterations (even at 64 bits it 13402708Swollman** would still be very reasonable). 13412708Swollman*/ 13422708Swollman 13432708Swollman#ifndef WRONG 13442708Swollman#define WRONG (-1) 13452708Swollman#endif /* !defined WRONG */ 13462708Swollman 13472708Swollman/* 13482708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). 13492708Swollman*/ 13502708Swollman 13512708Swollmanstatic int 13522708Swollmanincrement_overflow(number, delta) 13532708Swollmanint * number; 13542708Swollmanint delta; 13552708Swollman{ 13569936Swollman int number0; 13578870Srgrimes 13582708Swollman number0 = *number; 13592708Swollman *number += delta; 13602708Swollman return (*number < number0) != (delta < 0); 13612708Swollman} 13622708Swollman 13632708Swollmanstatic int 13642708Swollmannormalize_overflow(tensptr, unitsptr, base) 13652708Swollmanint * const tensptr; 13662708Swollmanint * const unitsptr; 13672708Swollmanconst int base; 13682708Swollman{ 13692708Swollman register int tensdelta; 13702708Swollman 13712708Swollman tensdelta = (*unitsptr >= 0) ? 13722708Swollman (*unitsptr / base) : 13732708Swollman (-1 - (-1 - *unitsptr) / base); 13742708Swollman *unitsptr -= tensdelta * base; 13752708Swollman return increment_overflow(tensptr, tensdelta); 13762708Swollman} 13772708Swollman 13782708Swollmanstatic int 13792708Swollmantmcomp(atmp, btmp) 13802708Swollmanregister const struct tm * const atmp; 13812708Swollmanregister const struct tm * const btmp; 13822708Swollman{ 13832708Swollman register int result; 13842708Swollman 13852708Swollman if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 13862708Swollman (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 13872708Swollman (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 13882708Swollman (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 13892708Swollman (result = (atmp->tm_min - btmp->tm_min)) == 0) 13902708Swollman result = atmp->tm_sec - btmp->tm_sec; 13912708Swollman return result; 13922708Swollman} 13932708Swollman 13942708Swollmanstatic time_t 13952708Swollmantime2(tmp, funcp, offset, okayp) 13962708Swollmanstruct tm * const tmp; 13979936Swollmanvoid (* const funcp) P((const time_t*, long, struct tm*)); 13982708Swollmanconst long offset; 13992708Swollmanint * const okayp; 14002708Swollman{ 14012708Swollman register const struct state * sp; 14022708Swollman register int dir; 14032708Swollman register int bits; 14042708Swollman register int i, j ; 14052708Swollman register int saved_seconds; 14062708Swollman time_t newt; 14072708Swollman time_t t; 14082708Swollman struct tm yourtm, mytm; 14092708Swollman 14102708Swollman *okayp = FALSE; 14112708Swollman yourtm = *tmp; 14122708Swollman if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 14132708Swollman return WRONG; 14142708Swollman if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 14152708Swollman return WRONG; 14162708Swollman if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) 14172708Swollman return WRONG; 14182708Swollman /* 14192708Swollman ** Turn yourtm.tm_year into an actual year number for now. 14202708Swollman ** It is converted back to an offset from TM_YEAR_BASE later. 14212708Swollman */ 14222708Swollman if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) 14232708Swollman return WRONG; 14242708Swollman while (yourtm.tm_mday <= 0) { 14252708Swollman if (increment_overflow(&yourtm.tm_year, -1)) 14262708Swollman return WRONG; 14272708Swollman yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)]; 14282708Swollman } 14292708Swollman while (yourtm.tm_mday > DAYSPERLYEAR) { 14302708Swollman yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)]; 14312708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14322708Swollman return WRONG; 14332708Swollman } 14342708Swollman for ( ; ; ) { 14352708Swollman i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; 14362708Swollman if (yourtm.tm_mday <= i) 14372708Swollman break; 14382708Swollman yourtm.tm_mday -= i; 14392708Swollman if (++yourtm.tm_mon >= MONSPERYEAR) { 14402708Swollman yourtm.tm_mon = 0; 14412708Swollman if (increment_overflow(&yourtm.tm_year, 1)) 14422708Swollman return WRONG; 14432708Swollman } 14442708Swollman } 14452708Swollman if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) 14462708Swollman return WRONG; 14472708Swollman if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { 14482708Swollman /* 14492708Swollman ** We can't set tm_sec to 0, because that might push the 14502708Swollman ** time below the minimum representable time. 14512708Swollman ** Set tm_sec to 59 instead. 14522708Swollman ** This assumes that the minimum representable time is 14532708Swollman ** not in the same minute that a leap second was deleted from, 14542708Swollman ** which is a safer assumption than using 58 would be. 14552708Swollman */ 14562708Swollman if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 14572708Swollman return WRONG; 14582708Swollman saved_seconds = yourtm.tm_sec; 14592708Swollman yourtm.tm_sec = SECSPERMIN - 1; 14602708Swollman } else { 14612708Swollman saved_seconds = yourtm.tm_sec; 14622708Swollman yourtm.tm_sec = 0; 14632708Swollman } 14642708Swollman /* 14652708Swollman ** Calculate the number of magnitude bits in a time_t 14662708Swollman ** (this works regardless of whether time_t is 14672708Swollman ** signed or unsigned, though lint complains if unsigned). 14682708Swollman */ 14692708Swollman for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 14702708Swollman continue; 14712708Swollman /* 14722708Swollman ** If time_t is signed, then 0 is the median value, 14732708Swollman ** if time_t is unsigned, then 1 << bits is median. 14742708Swollman */ 14752708Swollman t = (t < 0) ? 0 : ((time_t) 1 << bits); 14762708Swollman for ( ; ; ) { 14772708Swollman (*funcp)(&t, offset, &mytm); 14782708Swollman dir = tmcomp(&mytm, &yourtm); 14792708Swollman if (dir != 0) { 14802708Swollman if (bits-- < 0) 14812708Swollman return WRONG; 14822708Swollman if (bits < 0) 14832708Swollman --t; 14842708Swollman else if (dir > 0) 14852708Swollman t -= (time_t) 1 << bits; 14862708Swollman else t += (time_t) 1 << bits; 14872708Swollman continue; 14882708Swollman } 14892708Swollman if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 14902708Swollman break; 14912708Swollman /* 14922708Swollman ** Right time, wrong type. 14932708Swollman ** Hunt for right time, right type. 14942708Swollman ** It's okay to guess wrong since the guess 14952708Swollman ** gets checked. 14962708Swollman */ 14972708Swollman /* 14982708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 14992708Swollman */ 15002708Swollman sp = (const struct state *) 15012708Swollman (((void *) funcp == (void *) localsub) ? 15022708Swollman lclptr : gmtptr); 15032708Swollman#ifdef ALL_STATE 15042708Swollman if (sp == NULL) 15052708Swollman return WRONG; 15062708Swollman#endif /* defined ALL_STATE */ 15072708Swollman for (i = 0; i < sp->typecnt; ++i) { 15082708Swollman if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 15092708Swollman continue; 15102708Swollman for (j = 0; j < sp->typecnt; ++j) { 15112708Swollman if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 15122708Swollman continue; 15132708Swollman newt = t + sp->ttis[j].tt_gmtoff - 15142708Swollman sp->ttis[i].tt_gmtoff; 15152708Swollman (*funcp)(&newt, offset, &mytm); 15162708Swollman if (tmcomp(&mytm, &yourtm) != 0) 15172708Swollman continue; 15182708Swollman if (mytm.tm_isdst != yourtm.tm_isdst) 15192708Swollman continue; 15202708Swollman /* 15212708Swollman ** We have a match. 15222708Swollman */ 15232708Swollman t = newt; 15242708Swollman goto label; 15252708Swollman } 15262708Swollman } 15272708Swollman return WRONG; 15282708Swollman } 15292708Swollmanlabel: 15302708Swollman newt = t + saved_seconds; 15312708Swollman if ((newt < t) != (saved_seconds < 0)) 15322708Swollman return WRONG; 15332708Swollman t = newt; 15342708Swollman (*funcp)(&t, offset, tmp); 15352708Swollman *okayp = TRUE; 15362708Swollman return t; 15372708Swollman} 15382708Swollman 15392708Swollmanstatic time_t 15402708Swollmantime1(tmp, funcp, offset) 15412708Swollmanstruct tm * const tmp; 15429936Swollmanvoid (* const funcp) P((const time_t*, long, struct tm*)); 15432708Swollmanconst long offset; 15442708Swollman{ 15452708Swollman register time_t t; 15462708Swollman register const struct state * sp; 15472708Swollman register int samei, otheri; 15482708Swollman int okay; 15492708Swollman 15502708Swollman if (tmp->tm_isdst > 1) 15512708Swollman tmp->tm_isdst = 1; 15522708Swollman t = time2(tmp, funcp, offset, &okay); 15532708Swollman#ifdef PCTS 15542708Swollman /* 15552708Swollman ** PCTS code courtesy Grant Sullivan (grant@osf.org). 15562708Swollman */ 15572708Swollman if (okay) 15582708Swollman return t; 15592708Swollman if (tmp->tm_isdst < 0) 15602708Swollman tmp->tm_isdst = 0; /* reset to std and try again */ 15612708Swollman#endif /* defined PCTS */ 15622708Swollman#ifndef PCTS 15632708Swollman if (okay || tmp->tm_isdst < 0) 15642708Swollman return t; 15652708Swollman#endif /* !defined PCTS */ 15662708Swollman /* 15672708Swollman ** We're supposed to assume that somebody took a time of one type 15682708Swollman ** and did some math on it that yielded a "struct tm" that's bad. 15692708Swollman ** We try to divine the type they started from and adjust to the 15702708Swollman ** type they need. 15712708Swollman */ 15722708Swollman /* 15732708Swollman ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. 15742708Swollman */ 15752708Swollman sp = (const struct state *) (((void *) funcp == (void *) localsub) ? 15762708Swollman lclptr : gmtptr); 15772708Swollman#ifdef ALL_STATE 15782708Swollman if (sp == NULL) 15792708Swollman return WRONG; 15802708Swollman#endif /* defined ALL_STATE */ 15812708Swollman for (samei = 0; samei < sp->typecnt; ++samei) { 15822708Swollman if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 15832708Swollman continue; 15842708Swollman for (otheri = 0; otheri < sp->typecnt; ++otheri) { 15852708Swollman if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 15862708Swollman continue; 15872708Swollman tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 15882708Swollman sp->ttis[samei].tt_gmtoff; 15892708Swollman tmp->tm_isdst = !tmp->tm_isdst; 15902708Swollman t = time2(tmp, funcp, offset, &okay); 15912708Swollman if (okay) 15922708Swollman return t; 15932708Swollman tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 15942708Swollman sp->ttis[samei].tt_gmtoff; 15952708Swollman tmp->tm_isdst = !tmp->tm_isdst; 15962708Swollman } 15972708Swollman } 15982708Swollman return WRONG; 15992708Swollman} 16002708Swollman 16012708Swollmantime_t 16022708Swollmanmktime(tmp) 16032708Swollmanstruct tm * const tmp; 16042708Swollman{ 160513545Sjulian time_t mktime_return_value; 160613545Sjulian#ifdef _THREAD_SAFE 160713545Sjulian pthread_mutex_lock(&lcl_mutex); 160813545Sjulian#endif 16099936Swollman tzset(); 161013545Sjulian mktime_return_value = time1(tmp, localsub, 0L); 161113545Sjulian#ifdef _THREAD_SAFE 161213545Sjulian pthread_mutex_unlock(&lcl_mutex); 161313545Sjulian#endif 161413545Sjulian return(mktime_return_value); 16152708Swollman} 16162708Swollman 16172708Swollman#ifdef STD_INSPIRED 16182708Swollman 16192708Swollmantime_t 16202708Swollmantimelocal(tmp) 16212708Swollmanstruct tm * const tmp; 16222708Swollman{ 16232708Swollman tmp->tm_isdst = -1; /* in case it wasn't initialized */ 16242708Swollman return mktime(tmp); 16252708Swollman} 16262708Swollman 16272708Swollmantime_t 16282708Swollmantimegm(tmp) 16292708Swollmanstruct tm * const tmp; 16302708Swollman{ 16312708Swollman tmp->tm_isdst = 0; 16322708Swollman return time1(tmp, gmtsub, 0L); 16332708Swollman} 16342708Swollman 16352708Swollmantime_t 16362708Swollmantimeoff(tmp, offset) 16372708Swollmanstruct tm * const tmp; 16382708Swollmanconst long offset; 16392708Swollman{ 16402708Swollman tmp->tm_isdst = 0; 16412708Swollman return time1(tmp, gmtsub, offset); 16422708Swollman} 16432708Swollman 16442708Swollman#endif /* defined STD_INSPIRED */ 16452708Swollman 16462708Swollman#ifdef CMUCS 16472708Swollman 16482708Swollman/* 16492708Swollman** The following is supplied for compatibility with 16502708Swollman** previous versions of the CMUCS runtime library. 16512708Swollman*/ 16522708Swollman 16532708Swollmanlong 16542708Swollmangtime(tmp) 16552708Swollmanstruct tm * const tmp; 16562708Swollman{ 16572708Swollman const time_t t = mktime(tmp); 16582708Swollman 16592708Swollman if (t == WRONG) 16602708Swollman return -1; 16612708Swollman return t; 16622708Swollman} 16632708Swollman 16642708Swollman#endif /* defined CMUCS */ 16652708Swollman 16662708Swollman/* 16672708Swollman** XXX--is the below the right way to conditionalize?? 16682708Swollman*/ 16692708Swollman 16702708Swollman#ifdef STD_INSPIRED 16712708Swollman 16722708Swollman/* 16732708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 16742708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which 16752708Swollman** is not the case if we are accounting for leap seconds. 16762708Swollman** So, we provide the following conversion routines for use 16772708Swollman** when exchanging timestamps with POSIX conforming systems. 16782708Swollman*/ 16792708Swollman 16802708Swollmanstatic long 16812708Swollmanleapcorr(timep) 16822708Swollmantime_t * timep; 16832708Swollman{ 16842708Swollman register struct state * sp; 16852708Swollman register struct lsinfo * lp; 16862708Swollman register int i; 16872708Swollman 16882708Swollman sp = lclptr; 16892708Swollman i = sp->leapcnt; 16902708Swollman while (--i >= 0) { 16912708Swollman lp = &sp->lsis[i]; 16922708Swollman if (*timep >= lp->ls_trans) 16932708Swollman return lp->ls_corr; 16942708Swollman } 16952708Swollman return 0; 16962708Swollman} 16972708Swollman 16982708Swollmantime_t 16992708Swollmantime2posix(t) 17002708Swollmantime_t t; 17012708Swollman{ 17029936Swollman tzset(); 17032708Swollman return t - leapcorr(&t); 17042708Swollman} 17052708Swollman 17062708Swollmantime_t 17072708Swollmanposix2time(t) 17082708Swollmantime_t t; 17092708Swollman{ 17102708Swollman time_t x; 17112708Swollman time_t y; 17122708Swollman 17139936Swollman tzset(); 17142708Swollman /* 17152708Swollman ** For a positive leap second hit, the result 17162708Swollman ** is not unique. For a negative leap second 17172708Swollman ** hit, the corresponding time doesn't exist, 17182708Swollman ** so we return an adjacent second. 17192708Swollman */ 17202708Swollman x = t + leapcorr(&t); 17212708Swollman y = x - leapcorr(&x); 17222708Swollman if (y < t) { 17232708Swollman do { 17242708Swollman x++; 17252708Swollman y = x - leapcorr(&x); 17262708Swollman } while (y < t); 17272708Swollman if (t != y) 17282708Swollman return x - 1; 17292708Swollman } else if (y > t) { 17302708Swollman do { 17312708Swollman --x; 17322708Swollman y = x - leapcorr(&x); 17332708Swollman } while (y > t); 17342708Swollman if (t != y) 17352708Swollman return x + 1; 17362708Swollman } 17372708Swollman return x; 17382708Swollman} 17392708Swollman 17402708Swollman#endif /* defined STD_INSPIRED */ 1741