1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate /* from Arthur Olson's 6.1 */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <tzfile.h> 33*7c478bd9Sstevel@tonic-gate #include <time.h> 34*7c478bd9Sstevel@tonic-gate #include <string.h> 35*7c478bd9Sstevel@tonic-gate #include <ctype.h> 36*7c478bd9Sstevel@tonic-gate #include <stdio.h> /* for NULL */ 37*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <sys/param.h> /* for MAXPATHLEN */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #undef FILENAME_MAX 42*7c478bd9Sstevel@tonic-gate #define FILENAME_MAX MAXPATHLEN 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #ifdef __STDC__ 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #define P(s) s 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #else /* !defined __STDC__ */ 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate ** Memory management functions 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate extern char * calloc(); 55*7c478bd9Sstevel@tonic-gate extern char * malloc(); 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate /* 58*7c478bd9Sstevel@tonic-gate ** Communication with the environment 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate extern char * getenv(); 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #define ASTERISK * 64*7c478bd9Sstevel@tonic-gate #define P(s) (/ASTERISK s ASTERISK/) 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #define const 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #endif /* !defined __STDC__ */ 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #ifndef TRUE 71*7c478bd9Sstevel@tonic-gate #define TRUE 1 72*7c478bd9Sstevel@tonic-gate #define FALSE 0 73*7c478bd9Sstevel@tonic-gate #endif /* !defined TRUE */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #define ACCESS_MODE O_RDONLY 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #define OPEN_MODE O_RDONLY 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate ** Someone might make incorrect use of a time zone abbreviation: 81*7c478bd9Sstevel@tonic-gate ** 1. They might reference tzname[0] before calling tzset (explicitly 82*7c478bd9Sstevel@tonic-gate ** or implicitly). 83*7c478bd9Sstevel@tonic-gate ** 2. They might reference tzname[1] before calling tzset (explicitly 84*7c478bd9Sstevel@tonic-gate ** or implicitly). 85*7c478bd9Sstevel@tonic-gate ** 3. They might reference tzname[1] after setting to a time zone 86*7c478bd9Sstevel@tonic-gate ** in which Daylight Saving Time is never observed. 87*7c478bd9Sstevel@tonic-gate ** 4. They might reference tzname[0] after setting to a time zone 88*7c478bd9Sstevel@tonic-gate ** in which Standard Time is never observed. 89*7c478bd9Sstevel@tonic-gate ** 5. They might reference tm.TM_ZONE after calling offtime. 90*7c478bd9Sstevel@tonic-gate ** What's best to do in the above cases is open to debate; 91*7c478bd9Sstevel@tonic-gate ** for now, we just set things up so that in any of the five cases 92*7c478bd9Sstevel@tonic-gate ** WILDABBR is used. Another possibility: initialize tzname[0] to the 93*7c478bd9Sstevel@tonic-gate ** string "tzname[0] used before set", and similarly for the other cases. 94*7c478bd9Sstevel@tonic-gate ** And another: initialize tzname[0] to "ERA", with an explanation in the 95*7c478bd9Sstevel@tonic-gate ** manual page of what this "time zone abbreviation" means (doing this so 96*7c478bd9Sstevel@tonic-gate ** that tzname[0] has the "normal" length of three characters). 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate static const char *WILDABBR = " "; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate static const char *GMT = "GMT"; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate struct ttinfo { /* time type information */ 103*7c478bd9Sstevel@tonic-gate long tt_gmtoff; /* GMT offset in seconds */ 104*7c478bd9Sstevel@tonic-gate int tt_isdst; /* used to set tm_isdst */ 105*7c478bd9Sstevel@tonic-gate int tt_abbrind; /* abbreviation list index */ 106*7c478bd9Sstevel@tonic-gate int tt_ttisstd; /* TRUE if transition is std time */ 107*7c478bd9Sstevel@tonic-gate }; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate struct state { 110*7c478bd9Sstevel@tonic-gate int timecnt; 111*7c478bd9Sstevel@tonic-gate int typecnt; 112*7c478bd9Sstevel@tonic-gate int charcnt; 113*7c478bd9Sstevel@tonic-gate time_t *ats; 114*7c478bd9Sstevel@tonic-gate unsigned char *types; 115*7c478bd9Sstevel@tonic-gate struct ttinfo *ttis; 116*7c478bd9Sstevel@tonic-gate char *chars; 117*7c478bd9Sstevel@tonic-gate char *last_tzload; /* name of file tzload() last opened */ 118*7c478bd9Sstevel@tonic-gate }; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate struct rule { 121*7c478bd9Sstevel@tonic-gate int r_type; /* type of rule--see below */ 122*7c478bd9Sstevel@tonic-gate int r_day; /* day number of rule */ 123*7c478bd9Sstevel@tonic-gate int r_week; /* week number of rule */ 124*7c478bd9Sstevel@tonic-gate int r_mon; /* month number of rule */ 125*7c478bd9Sstevel@tonic-gate long r_time; /* transition time of rule */ 126*7c478bd9Sstevel@tonic-gate }; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate #define JULIAN_DAY 0 /* Jn - Julian day */ 129*7c478bd9Sstevel@tonic-gate #define DAY_OF_YEAR 1 /* n - day of year */ 130*7c478bd9Sstevel@tonic-gate #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate ** Prototypes for static functions. 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate static int allocall P((register struct state * sp)); 137*7c478bd9Sstevel@tonic-gate static long detzcode P((const char * codep)); 138*7c478bd9Sstevel@tonic-gate static void freeall P((register struct state * sp)); 139*7c478bd9Sstevel@tonic-gate static const char * getzname P((const char * strp, const int i)); 140*7c478bd9Sstevel@tonic-gate static const char * getnum P((const char * strp, int * nump, int min, 141*7c478bd9Sstevel@tonic-gate int max)); 142*7c478bd9Sstevel@tonic-gate static const char * getsecs P((const char * strp, long * secsp)); 143*7c478bd9Sstevel@tonic-gate static const char * getoffset P((const char * strp, long * offsetp)); 144*7c478bd9Sstevel@tonic-gate static const char * getrule P((const char * strp, struct rule * rulep)); 145*7c478bd9Sstevel@tonic-gate static void gmtload P((struct state * sp)); 146*7c478bd9Sstevel@tonic-gate static void gmtsub P((const time_t * timep, long offset, 147*7c478bd9Sstevel@tonic-gate struct tm * tmp)); 148*7c478bd9Sstevel@tonic-gate static void localsub P((const time_t * timep, long offset, 149*7c478bd9Sstevel@tonic-gate struct tm * tmp)); 150*7c478bd9Sstevel@tonic-gate static void normalize P((int * tensptr, int * unitsptr, int base)); 151*7c478bd9Sstevel@tonic-gate static void settzname P((void)); 152*7c478bd9Sstevel@tonic-gate static time_t time1 P((struct tm * tmp, void (* funcp)(), 153*7c478bd9Sstevel@tonic-gate long offset)); 154*7c478bd9Sstevel@tonic-gate static time_t time2 P((struct tm *tmp, void (* funcp)(), 155*7c478bd9Sstevel@tonic-gate long offset, int * okayp)); 156*7c478bd9Sstevel@tonic-gate static void timesub P((const time_t * timep, long offset, 157*7c478bd9Sstevel@tonic-gate struct tm * tmp)); 158*7c478bd9Sstevel@tonic-gate static int tmcomp P((const struct tm * atmp, 159*7c478bd9Sstevel@tonic-gate const struct tm * btmp)); 160*7c478bd9Sstevel@tonic-gate static time_t transtime P((time_t janfirst, int year, 161*7c478bd9Sstevel@tonic-gate const struct rule * rulep, long offset)); 162*7c478bd9Sstevel@tonic-gate static int tzload P((const char * name, struct state * sp)); 163*7c478bd9Sstevel@tonic-gate static int tzparse P((const char * name, struct state * sp, 164*7c478bd9Sstevel@tonic-gate int lastditch)); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate static struct state * lclptr; 167*7c478bd9Sstevel@tonic-gate static struct state * gmtptr; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate static int lcl_is_set; 170*7c478bd9Sstevel@tonic-gate static int gmt_is_set; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 173*7c478bd9Sstevel@tonic-gate char * tzname[2] = { 174*7c478bd9Sstevel@tonic-gate "GMT", 175*7c478bd9Sstevel@tonic-gate " ", 176*7c478bd9Sstevel@tonic-gate }; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate time_t timezone = 0; 179*7c478bd9Sstevel@tonic-gate time_t altzone = 0; 180*7c478bd9Sstevel@tonic-gate int daylight = 0; 181*7c478bd9Sstevel@tonic-gate #endif /* defined S5EMUL */ 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate static long 184*7c478bd9Sstevel@tonic-gate detzcode(codep) 185*7c478bd9Sstevel@tonic-gate const char * const codep; 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate register long result; 188*7c478bd9Sstevel@tonic-gate register int i; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate result = 0; 191*7c478bd9Sstevel@tonic-gate for (i = 0; i < 4; ++i) 192*7c478bd9Sstevel@tonic-gate result = (result << 8) | (codep[i] & 0xff); 193*7c478bd9Sstevel@tonic-gate return result; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate ** Free up existing items pointed to by the specified "state" structure, 198*7c478bd9Sstevel@tonic-gate ** and allocate new ones of sizes specified by that "state" structure. 199*7c478bd9Sstevel@tonic-gate ** Return 0 on success; return -1 and free all previously-allocated items 200*7c478bd9Sstevel@tonic-gate ** on failure. 201*7c478bd9Sstevel@tonic-gate */ 202*7c478bd9Sstevel@tonic-gate static int 203*7c478bd9Sstevel@tonic-gate allocall(sp) 204*7c478bd9Sstevel@tonic-gate register struct state * const sp; 205*7c478bd9Sstevel@tonic-gate { 206*7c478bd9Sstevel@tonic-gate freeall(sp); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate if (sp->timecnt != 0) { 209*7c478bd9Sstevel@tonic-gate sp->ats = (time_t *)calloc((unsigned)sp->timecnt, 210*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (time_t)); 211*7c478bd9Sstevel@tonic-gate if (sp->ats == NULL) 212*7c478bd9Sstevel@tonic-gate return -1; 213*7c478bd9Sstevel@tonic-gate sp->types = 214*7c478bd9Sstevel@tonic-gate (unsigned char *)calloc((unsigned)sp->timecnt, 215*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (unsigned char)); 216*7c478bd9Sstevel@tonic-gate if (sp->types == NULL) { 217*7c478bd9Sstevel@tonic-gate freeall(sp); 218*7c478bd9Sstevel@tonic-gate return -1; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate sp->ttis = 222*7c478bd9Sstevel@tonic-gate (struct ttinfo *)calloc((unsigned)sp->typecnt, 223*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (struct ttinfo)); 224*7c478bd9Sstevel@tonic-gate if (sp->ttis == NULL) { 225*7c478bd9Sstevel@tonic-gate freeall(sp); 226*7c478bd9Sstevel@tonic-gate return -1; 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate sp->chars = (char *)calloc((unsigned)sp->charcnt + 1, 229*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (char)); 230*7c478bd9Sstevel@tonic-gate if (sp->chars == NULL) { 231*7c478bd9Sstevel@tonic-gate freeall(sp); 232*7c478bd9Sstevel@tonic-gate return -1; 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate return 0; 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate ** Free all the items pointed to by the specified "state" structure (except for 239*7c478bd9Sstevel@tonic-gate ** "chars", which might have other references to it), and zero out all the 240*7c478bd9Sstevel@tonic-gate ** pointers to those items. 241*7c478bd9Sstevel@tonic-gate */ 242*7c478bd9Sstevel@tonic-gate static void 243*7c478bd9Sstevel@tonic-gate freeall(sp) 244*7c478bd9Sstevel@tonic-gate register struct state * const sp; 245*7c478bd9Sstevel@tonic-gate { 246*7c478bd9Sstevel@tonic-gate if (sp->ttis) { 247*7c478bd9Sstevel@tonic-gate free((char *)sp->ttis); 248*7c478bd9Sstevel@tonic-gate sp->ttis = 0; 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate if (sp->types) { 251*7c478bd9Sstevel@tonic-gate free((char *)sp->types); 252*7c478bd9Sstevel@tonic-gate sp->types = 0; 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate if (sp->ats) { 255*7c478bd9Sstevel@tonic-gate free((char *)sp->ats); 256*7c478bd9Sstevel@tonic-gate sp->ats = 0; 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 261*7c478bd9Sstevel@tonic-gate static void 262*7c478bd9Sstevel@tonic-gate settzname() 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate register const struct state * const sp = lclptr; 265*7c478bd9Sstevel@tonic-gate register int i; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate tzname[0] = (char *)GMT; 268*7c478bd9Sstevel@tonic-gate tzname[1] = (char *)WILDABBR; 269*7c478bd9Sstevel@tonic-gate daylight = 0; 270*7c478bd9Sstevel@tonic-gate timezone = 0; 271*7c478bd9Sstevel@tonic-gate altzone = 0; 272*7c478bd9Sstevel@tonic-gate if (sp == NULL) 273*7c478bd9Sstevel@tonic-gate return; 274*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->typecnt; ++i) { 275*7c478bd9Sstevel@tonic-gate register const struct ttinfo * const ttisp = &sp->ttis[i]; 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate tzname[ttisp->tt_isdst] = 278*7c478bd9Sstevel@tonic-gate (char *) &sp->chars[ttisp->tt_abbrind]; 279*7c478bd9Sstevel@tonic-gate if (ttisp->tt_isdst) 280*7c478bd9Sstevel@tonic-gate daylight = 1; 281*7c478bd9Sstevel@tonic-gate if (i == 0 || !ttisp->tt_isdst) 282*7c478bd9Sstevel@tonic-gate timezone = -(ttisp->tt_gmtoff); 283*7c478bd9Sstevel@tonic-gate if (i == 0 || ttisp->tt_isdst) 284*7c478bd9Sstevel@tonic-gate altzone = -(ttisp->tt_gmtoff); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate ** And to get the latest zone names into tzname. . . 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->timecnt; ++i) { 290*7c478bd9Sstevel@tonic-gate register const struct ttinfo * const ttisp = 291*7c478bd9Sstevel@tonic-gate &sp->ttis[sp->types[i]]; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate tzname[ttisp->tt_isdst] = 294*7c478bd9Sstevel@tonic-gate (char *) &sp->chars[ttisp->tt_abbrind]; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate #endif 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate /* 300*7c478bd9Sstevel@tonic-gate ** Maximum size of a time zone file. 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate #define MAX_TZFILESZ (sizeof (struct tzhead) + \ 303*7c478bd9Sstevel@tonic-gate TZ_MAX_TIMES * (4 + sizeof (char)) + \ 304*7c478bd9Sstevel@tonic-gate TZ_MAX_TYPES * (4 + 2 * sizeof (char)) + \ 305*7c478bd9Sstevel@tonic-gate TZ_MAX_CHARS * sizeof (char) + \ 306*7c478bd9Sstevel@tonic-gate TZ_MAX_LEAPS * 2 * 4 + \ 307*7c478bd9Sstevel@tonic-gate TZ_MAX_TYPES * sizeof (char)) 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate static int 310*7c478bd9Sstevel@tonic-gate tzload(name, sp) 311*7c478bd9Sstevel@tonic-gate register const char * name; 312*7c478bd9Sstevel@tonic-gate register struct state * const sp; 313*7c478bd9Sstevel@tonic-gate { 314*7c478bd9Sstevel@tonic-gate register const char * p; 315*7c478bd9Sstevel@tonic-gate register int i; 316*7c478bd9Sstevel@tonic-gate register int fid; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (name == NULL && (name = (const char *)TZDEFAULT) == NULL) 319*7c478bd9Sstevel@tonic-gate return -1; 320*7c478bd9Sstevel@tonic-gate { 321*7c478bd9Sstevel@tonic-gate register int doaccess; 322*7c478bd9Sstevel@tonic-gate char fullname[FILENAME_MAX + 1]; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate if (name[0] == ':') 325*7c478bd9Sstevel@tonic-gate ++name; 326*7c478bd9Sstevel@tonic-gate doaccess = name[0] == '/'; 327*7c478bd9Sstevel@tonic-gate if (!doaccess) { 328*7c478bd9Sstevel@tonic-gate if ((p = TZDIR) == NULL) 329*7c478bd9Sstevel@tonic-gate return -1; 330*7c478bd9Sstevel@tonic-gate if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 331*7c478bd9Sstevel@tonic-gate return -1; 332*7c478bd9Sstevel@tonic-gate (void) strcpy(fullname, p); 333*7c478bd9Sstevel@tonic-gate (void) strcat(fullname, "/"); 334*7c478bd9Sstevel@tonic-gate (void) strcat(fullname, name); 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate ** Set doaccess if '.' (as in "../") shows up in name. 337*7c478bd9Sstevel@tonic-gate */ 338*7c478bd9Sstevel@tonic-gate if (strchr(name, '.') != NULL) 339*7c478bd9Sstevel@tonic-gate doaccess = TRUE; 340*7c478bd9Sstevel@tonic-gate name = fullname; 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate if (sp->last_tzload && strcmp(sp->last_tzload, name) == 0) 343*7c478bd9Sstevel@tonic-gate return (0); 344*7c478bd9Sstevel@tonic-gate if (doaccess && access(name, ACCESS_MODE) != 0) 345*7c478bd9Sstevel@tonic-gate return -1; 346*7c478bd9Sstevel@tonic-gate if ((fid = open(name, OPEN_MODE)) == -1) 347*7c478bd9Sstevel@tonic-gate return -1; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate { 350*7c478bd9Sstevel@tonic-gate register const struct tzhead * tzhp; 351*7c478bd9Sstevel@tonic-gate char buf[MAX_TZFILESZ]; 352*7c478bd9Sstevel@tonic-gate int leapcnt; 353*7c478bd9Sstevel@tonic-gate int ttisstdcnt; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate i = read(fid, buf, sizeof buf); 356*7c478bd9Sstevel@tonic-gate if (close(fid) != 0 || i < sizeof *tzhp) 357*7c478bd9Sstevel@tonic-gate return -1; 358*7c478bd9Sstevel@tonic-gate tzhp = (struct tzhead *) buf; 359*7c478bd9Sstevel@tonic-gate ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); 360*7c478bd9Sstevel@tonic-gate leapcnt = (int) detzcode(tzhp->tzh_leapcnt); 361*7c478bd9Sstevel@tonic-gate sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); 362*7c478bd9Sstevel@tonic-gate sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); 363*7c478bd9Sstevel@tonic-gate sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); 364*7c478bd9Sstevel@tonic-gate if (leapcnt < 0 || leapcnt > TZ_MAX_LEAPS || 365*7c478bd9Sstevel@tonic-gate sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || 366*7c478bd9Sstevel@tonic-gate sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || 367*7c478bd9Sstevel@tonic-gate sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || 368*7c478bd9Sstevel@tonic-gate (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) 369*7c478bd9Sstevel@tonic-gate return -1; 370*7c478bd9Sstevel@tonic-gate if (i < sizeof *tzhp + 371*7c478bd9Sstevel@tonic-gate sp->timecnt * (4 + sizeof (char)) + 372*7c478bd9Sstevel@tonic-gate sp->typecnt * (4 + 2 * sizeof (char)) + 373*7c478bd9Sstevel@tonic-gate sp->charcnt * sizeof (char) + 374*7c478bd9Sstevel@tonic-gate leapcnt * 2 * 4 + 375*7c478bd9Sstevel@tonic-gate ttisstdcnt * sizeof (char)) 376*7c478bd9Sstevel@tonic-gate return -1; 377*7c478bd9Sstevel@tonic-gate if (allocall(sp) < 0) 378*7c478bd9Sstevel@tonic-gate return -1; 379*7c478bd9Sstevel@tonic-gate p = buf + sizeof *tzhp; 380*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->timecnt; ++i) { 381*7c478bd9Sstevel@tonic-gate sp->ats[i] = detzcode(p); 382*7c478bd9Sstevel@tonic-gate p += 4; 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->timecnt; ++i) { 385*7c478bd9Sstevel@tonic-gate sp->types[i] = (unsigned char) *p++; 386*7c478bd9Sstevel@tonic-gate if (sp->types[i] >= sp->typecnt) 387*7c478bd9Sstevel@tonic-gate return -1; 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->typecnt; ++i) { 390*7c478bd9Sstevel@tonic-gate register struct ttinfo * ttisp; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate ttisp = &sp->ttis[i]; 393*7c478bd9Sstevel@tonic-gate ttisp->tt_gmtoff = detzcode(p); 394*7c478bd9Sstevel@tonic-gate p += 4; 395*7c478bd9Sstevel@tonic-gate ttisp->tt_isdst = (unsigned char) *p++; 396*7c478bd9Sstevel@tonic-gate if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) 397*7c478bd9Sstevel@tonic-gate return -1; 398*7c478bd9Sstevel@tonic-gate ttisp->tt_abbrind = (unsigned char) *p++; 399*7c478bd9Sstevel@tonic-gate if (ttisp->tt_abbrind < 0 || 400*7c478bd9Sstevel@tonic-gate ttisp->tt_abbrind > sp->charcnt) 401*7c478bd9Sstevel@tonic-gate return -1; 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->charcnt-1; ++i) 404*7c478bd9Sstevel@tonic-gate sp->chars[i] = *p++; 405*7c478bd9Sstevel@tonic-gate sp->chars[i] = '\0'; /* ensure '\0' at end */ 406*7c478bd9Sstevel@tonic-gate p += (4 + 4) * leapcnt; /* skip leap seconds list */ 407*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->typecnt; ++i) { 408*7c478bd9Sstevel@tonic-gate register struct ttinfo * ttisp; 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate ttisp = &sp->ttis[i]; 411*7c478bd9Sstevel@tonic-gate if (ttisstdcnt == 0) 412*7c478bd9Sstevel@tonic-gate ttisp->tt_ttisstd = FALSE; 413*7c478bd9Sstevel@tonic-gate else { 414*7c478bd9Sstevel@tonic-gate ttisp->tt_ttisstd = *p++; 415*7c478bd9Sstevel@tonic-gate if (ttisp->tt_ttisstd != TRUE && 416*7c478bd9Sstevel@tonic-gate ttisp->tt_ttisstd != FALSE) 417*7c478bd9Sstevel@tonic-gate return -1; 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate if (sp->last_tzload) 422*7c478bd9Sstevel@tonic-gate free(sp->last_tzload); 423*7c478bd9Sstevel@tonic-gate sp->last_tzload = strdup(name); 424*7c478bd9Sstevel@tonic-gate return 0; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate static const int mon_lengths[2][MONSPERYEAR] = { 428*7c478bd9Sstevel@tonic-gate 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 429*7c478bd9Sstevel@tonic-gate 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 430*7c478bd9Sstevel@tonic-gate }; 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate static const int year_lengths[2] = { 433*7c478bd9Sstevel@tonic-gate DAYSPERNYEAR, DAYSPERLYEAR 434*7c478bd9Sstevel@tonic-gate }; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* 437*7c478bd9Sstevel@tonic-gate ** Given a pointer into a time zone string, scan until a character that is not 438*7c478bd9Sstevel@tonic-gate ** a valid character in a zone name is found. Return a pointer to that 439*7c478bd9Sstevel@tonic-gate ** character. 440*7c478bd9Sstevel@tonic-gate ** Support both quoted and unquoted timezones. 441*7c478bd9Sstevel@tonic-gate */ 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate static const char * 444*7c478bd9Sstevel@tonic-gate getzname(strp, quoted) 445*7c478bd9Sstevel@tonic-gate const char * strp; 446*7c478bd9Sstevel@tonic-gate int quoted; 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate unsigned char c; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (quoted) { 451*7c478bd9Sstevel@tonic-gate while ((c = (unsigned char)*strp) != '\0' && 452*7c478bd9Sstevel@tonic-gate (isalnum(c) || (c == '+') || (c == '-'))) 453*7c478bd9Sstevel@tonic-gate ++strp; 454*7c478bd9Sstevel@tonic-gate } else { 455*7c478bd9Sstevel@tonic-gate while ((c = (unsigned char)*strp) != '\0' && !isdigit(c) 456*7c478bd9Sstevel@tonic-gate && (c != ',') && (c != '-') && (c != '+')) 457*7c478bd9Sstevel@tonic-gate ++strp; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate return strp; 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* 463*7c478bd9Sstevel@tonic-gate ** Given a pointer into a time zone string, extract a number from that string. 464*7c478bd9Sstevel@tonic-gate ** Check that the number is within a specified range; if it is not, return 465*7c478bd9Sstevel@tonic-gate ** NULL. 466*7c478bd9Sstevel@tonic-gate ** Otherwise, return a pointer to the first character not part of the number. 467*7c478bd9Sstevel@tonic-gate */ 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate static const char * 470*7c478bd9Sstevel@tonic-gate getnum(strp, nump, min, max) 471*7c478bd9Sstevel@tonic-gate register const char * strp; 472*7c478bd9Sstevel@tonic-gate int * const nump; 473*7c478bd9Sstevel@tonic-gate const int min; 474*7c478bd9Sstevel@tonic-gate const int max; 475*7c478bd9Sstevel@tonic-gate { 476*7c478bd9Sstevel@tonic-gate register char c; 477*7c478bd9Sstevel@tonic-gate register int num; 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate if (strp == NULL || !isdigit(*strp)) 480*7c478bd9Sstevel@tonic-gate return NULL; 481*7c478bd9Sstevel@tonic-gate num = 0; 482*7c478bd9Sstevel@tonic-gate while ((c = *strp) != '\0' && isdigit(c)) { 483*7c478bd9Sstevel@tonic-gate num = num * 10 + (c - '0'); 484*7c478bd9Sstevel@tonic-gate if (num > max) 485*7c478bd9Sstevel@tonic-gate return NULL; /* illegal value */ 486*7c478bd9Sstevel@tonic-gate ++strp; 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate if (num < min) 489*7c478bd9Sstevel@tonic-gate return NULL; /* illegal value */ 490*7c478bd9Sstevel@tonic-gate *nump = num; 491*7c478bd9Sstevel@tonic-gate return strp; 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate ** Given a pointer into a time zone string, extract a number of seconds, 496*7c478bd9Sstevel@tonic-gate ** in hh[:mm[:ss]] form, from the string. 497*7c478bd9Sstevel@tonic-gate ** If any error occurs, return NULL. 498*7c478bd9Sstevel@tonic-gate ** Otherwise, return a pointer to the first character not part of the number 499*7c478bd9Sstevel@tonic-gate ** of seconds. 500*7c478bd9Sstevel@tonic-gate */ 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate static const char * 503*7c478bd9Sstevel@tonic-gate getsecs(strp, secsp) 504*7c478bd9Sstevel@tonic-gate register const char * strp; 505*7c478bd9Sstevel@tonic-gate long * const secsp; 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate int num; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &num, 0, HOURSPERDAY); 510*7c478bd9Sstevel@tonic-gate if (strp == NULL) 511*7c478bd9Sstevel@tonic-gate return NULL; 512*7c478bd9Sstevel@tonic-gate *secsp = num * SECSPERHOUR; 513*7c478bd9Sstevel@tonic-gate if (*strp == ':') { 514*7c478bd9Sstevel@tonic-gate ++strp; 515*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 516*7c478bd9Sstevel@tonic-gate if (strp == NULL) 517*7c478bd9Sstevel@tonic-gate return NULL; 518*7c478bd9Sstevel@tonic-gate *secsp += num * SECSPERMIN; 519*7c478bd9Sstevel@tonic-gate if (*strp == ':') { 520*7c478bd9Sstevel@tonic-gate ++strp; 521*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &num, 0, SECSPERMIN - 1); 522*7c478bd9Sstevel@tonic-gate if (strp == NULL) 523*7c478bd9Sstevel@tonic-gate return NULL; 524*7c478bd9Sstevel@tonic-gate *secsp += num; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate return strp; 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* 531*7c478bd9Sstevel@tonic-gate ** Given a pointer into a time zone string, extract an offset, in 532*7c478bd9Sstevel@tonic-gate ** [+-]hh[:mm[:ss]] form, from the string. 533*7c478bd9Sstevel@tonic-gate ** If any error occurs, return NULL. 534*7c478bd9Sstevel@tonic-gate ** Otherwise, return a pointer to the first character not part of the time. 535*7c478bd9Sstevel@tonic-gate */ 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate static const char * 538*7c478bd9Sstevel@tonic-gate getoffset(strp, offsetp) 539*7c478bd9Sstevel@tonic-gate register const char * strp; 540*7c478bd9Sstevel@tonic-gate long * const offsetp; 541*7c478bd9Sstevel@tonic-gate { 542*7c478bd9Sstevel@tonic-gate register int neg; 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate if (*strp == '-') { 545*7c478bd9Sstevel@tonic-gate neg = 1; 546*7c478bd9Sstevel@tonic-gate ++strp; 547*7c478bd9Sstevel@tonic-gate } else if (isdigit(*strp) || *strp++ == '+') 548*7c478bd9Sstevel@tonic-gate neg = 0; 549*7c478bd9Sstevel@tonic-gate else return NULL; /* illegal offset */ 550*7c478bd9Sstevel@tonic-gate strp = getsecs(strp, offsetp); 551*7c478bd9Sstevel@tonic-gate if (strp == NULL) 552*7c478bd9Sstevel@tonic-gate return NULL; /* illegal time */ 553*7c478bd9Sstevel@tonic-gate if (neg) 554*7c478bd9Sstevel@tonic-gate *offsetp = -*offsetp; 555*7c478bd9Sstevel@tonic-gate return strp; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate ** Given a pointer into a time zone string, extract a rule in the form 560*7c478bd9Sstevel@tonic-gate ** date[/time]. See POSIX section 8 for the format of "date" and "time". 561*7c478bd9Sstevel@tonic-gate ** If a valid rule is not found, return NULL. 562*7c478bd9Sstevel@tonic-gate ** Otherwise, return a pointer to the first character not part of the rule. 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate static const char * 566*7c478bd9Sstevel@tonic-gate getrule(strp, rulep) 567*7c478bd9Sstevel@tonic-gate const char * strp; 568*7c478bd9Sstevel@tonic-gate register struct rule * const rulep; 569*7c478bd9Sstevel@tonic-gate { 570*7c478bd9Sstevel@tonic-gate if (*strp == 'J') { 571*7c478bd9Sstevel@tonic-gate /* 572*7c478bd9Sstevel@tonic-gate ** Julian day. 573*7c478bd9Sstevel@tonic-gate */ 574*7c478bd9Sstevel@tonic-gate rulep->r_type = JULIAN_DAY; 575*7c478bd9Sstevel@tonic-gate ++strp; 576*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 577*7c478bd9Sstevel@tonic-gate } else if (*strp == 'M') { 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate ** Month, week, day. 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 582*7c478bd9Sstevel@tonic-gate ++strp; 583*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 584*7c478bd9Sstevel@tonic-gate if (strp == NULL) 585*7c478bd9Sstevel@tonic-gate return NULL; 586*7c478bd9Sstevel@tonic-gate if (*strp++ != '.') 587*7c478bd9Sstevel@tonic-gate return NULL; 588*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &rulep->r_week, 1, 5); 589*7c478bd9Sstevel@tonic-gate if (strp == NULL) 590*7c478bd9Sstevel@tonic-gate return NULL; 591*7c478bd9Sstevel@tonic-gate if (*strp++ != '.') 592*7c478bd9Sstevel@tonic-gate return NULL; 593*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 594*7c478bd9Sstevel@tonic-gate } else if (isdigit(*strp)) { 595*7c478bd9Sstevel@tonic-gate /* 596*7c478bd9Sstevel@tonic-gate ** Day of year. 597*7c478bd9Sstevel@tonic-gate */ 598*7c478bd9Sstevel@tonic-gate rulep->r_type = DAY_OF_YEAR; 599*7c478bd9Sstevel@tonic-gate strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 600*7c478bd9Sstevel@tonic-gate } else return NULL; /* invalid format */ 601*7c478bd9Sstevel@tonic-gate if (strp == NULL) 602*7c478bd9Sstevel@tonic-gate return NULL; 603*7c478bd9Sstevel@tonic-gate if (*strp == '/') { 604*7c478bd9Sstevel@tonic-gate /* 605*7c478bd9Sstevel@tonic-gate ** Time specified. 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate ++strp; 608*7c478bd9Sstevel@tonic-gate strp = getsecs(strp, &rulep->r_time); 609*7c478bd9Sstevel@tonic-gate } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 610*7c478bd9Sstevel@tonic-gate return strp; 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the 615*7c478bd9Sstevel@tonic-gate ** year, a rule, and the offset from GMT at the time that rule takes effect, 616*7c478bd9Sstevel@tonic-gate ** calculate the Epoch-relative time that rule takes effect. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate static time_t 620*7c478bd9Sstevel@tonic-gate transtime(janfirst, year, rulep, offset) 621*7c478bd9Sstevel@tonic-gate const time_t janfirst; 622*7c478bd9Sstevel@tonic-gate const int year; 623*7c478bd9Sstevel@tonic-gate register const struct rule * const rulep; 624*7c478bd9Sstevel@tonic-gate const long offset; 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate register int leapyear; 627*7c478bd9Sstevel@tonic-gate register time_t value; 628*7c478bd9Sstevel@tonic-gate register int i; 629*7c478bd9Sstevel@tonic-gate int d, m1, yy0, yy1, yy2, dow; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate leapyear = isleap(year); 632*7c478bd9Sstevel@tonic-gate switch (rulep->r_type) { 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate case JULIAN_DAY: 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 637*7c478bd9Sstevel@tonic-gate ** years. 638*7c478bd9Sstevel@tonic-gate ** In non-leap years, or if the day number is 59 or less, just 639*7c478bd9Sstevel@tonic-gate ** add SECSPERDAY times the day number-1 to the time of 640*7c478bd9Sstevel@tonic-gate ** January 1, midnight, to get the day. 641*7c478bd9Sstevel@tonic-gate */ 642*7c478bd9Sstevel@tonic-gate value = janfirst + (rulep->r_day - 1) * SECSPERDAY; 643*7c478bd9Sstevel@tonic-gate if (leapyear && rulep->r_day >= 60) 644*7c478bd9Sstevel@tonic-gate value += SECSPERDAY; 645*7c478bd9Sstevel@tonic-gate break; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate case DAY_OF_YEAR: 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate ** n - day of year. 650*7c478bd9Sstevel@tonic-gate ** Just add SECSPERDAY times the day number to the time of 651*7c478bd9Sstevel@tonic-gate ** January 1, midnight, to get the day. 652*7c478bd9Sstevel@tonic-gate */ 653*7c478bd9Sstevel@tonic-gate value = janfirst + rulep->r_day * SECSPERDAY; 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate case MONTH_NTH_DAY_OF_WEEK: 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate ** Mm.n.d - nth "dth day" of month m. 659*7c478bd9Sstevel@tonic-gate */ 660*7c478bd9Sstevel@tonic-gate value = janfirst; 661*7c478bd9Sstevel@tonic-gate for (i = 0; i < rulep->r_mon - 1; ++i) 662*7c478bd9Sstevel@tonic-gate value += mon_lengths[leapyear][i] * SECSPERDAY; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* 665*7c478bd9Sstevel@tonic-gate ** Use Zeller's Congruence to get day-of-week of first day of 666*7c478bd9Sstevel@tonic-gate ** month. 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate m1 = (rulep->r_mon + 9) % 12 + 1; 669*7c478bd9Sstevel@tonic-gate yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 670*7c478bd9Sstevel@tonic-gate yy1 = yy0 / 100; 671*7c478bd9Sstevel@tonic-gate yy2 = yy0 % 100; 672*7c478bd9Sstevel@tonic-gate dow = ((26 * m1 - 2) / 10 + 673*7c478bd9Sstevel@tonic-gate 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 674*7c478bd9Sstevel@tonic-gate if (dow < 0) 675*7c478bd9Sstevel@tonic-gate dow += DAYSPERWEEK; 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* 678*7c478bd9Sstevel@tonic-gate ** "dow" is the day-of-week of the first day of the month. Get 679*7c478bd9Sstevel@tonic-gate ** the day-of-month (zero-origin) of the first "dow" day of the 680*7c478bd9Sstevel@tonic-gate ** month. 681*7c478bd9Sstevel@tonic-gate */ 682*7c478bd9Sstevel@tonic-gate d = rulep->r_day - dow; 683*7c478bd9Sstevel@tonic-gate if (d < 0) 684*7c478bd9Sstevel@tonic-gate d += DAYSPERWEEK; 685*7c478bd9Sstevel@tonic-gate for (i = 1; i < rulep->r_week; ++i) { 686*7c478bd9Sstevel@tonic-gate if (d + DAYSPERWEEK >= 687*7c478bd9Sstevel@tonic-gate mon_lengths[leapyear][rulep->r_mon - 1]) 688*7c478bd9Sstevel@tonic-gate break; 689*7c478bd9Sstevel@tonic-gate d += DAYSPERWEEK; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate ** "d" is the day-of-month (zero-origin) of the day we want. 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate value += d * SECSPERDAY; 696*7c478bd9Sstevel@tonic-gate break; 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* 700*7c478bd9Sstevel@tonic-gate ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in 701*7c478bd9Sstevel@tonic-gate ** question. To get the Epoch-relative time of the specified local 702*7c478bd9Sstevel@tonic-gate ** time on that day, add the transition time and the current offset 703*7c478bd9Sstevel@tonic-gate ** from GMT. 704*7c478bd9Sstevel@tonic-gate */ 705*7c478bd9Sstevel@tonic-gate return value + rulep->r_time + offset; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate ** Given a POSIX section 8-style TZ string, fill in the rule tables as 710*7c478bd9Sstevel@tonic-gate ** appropriate. 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate static int 714*7c478bd9Sstevel@tonic-gate tzparse(name, sp, lastditch) 715*7c478bd9Sstevel@tonic-gate const char * name; 716*7c478bd9Sstevel@tonic-gate struct state * const sp; 717*7c478bd9Sstevel@tonic-gate const int lastditch; 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate const char * stdname; 720*7c478bd9Sstevel@tonic-gate const char * dstname; 721*7c478bd9Sstevel@tonic-gate int stdlen; 722*7c478bd9Sstevel@tonic-gate int dstlen; 723*7c478bd9Sstevel@tonic-gate long stdoffset; 724*7c478bd9Sstevel@tonic-gate long dstoffset; 725*7c478bd9Sstevel@tonic-gate time_t * atp; 726*7c478bd9Sstevel@tonic-gate unsigned char * typep; 727*7c478bd9Sstevel@tonic-gate char * cp; 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate freeall(sp); /* */ 730*7c478bd9Sstevel@tonic-gate stdname = name; 731*7c478bd9Sstevel@tonic-gate if (lastditch) { 732*7c478bd9Sstevel@tonic-gate stdlen = strlen(name); /* length of standard zone name */ 733*7c478bd9Sstevel@tonic-gate name += stdlen; 734*7c478bd9Sstevel@tonic-gate if (stdlen >= sizeof sp->chars) 735*7c478bd9Sstevel@tonic-gate stdlen = (sizeof sp->chars) - 1; 736*7c478bd9Sstevel@tonic-gate } else { 737*7c478bd9Sstevel@tonic-gate if (*name == '<') { 738*7c478bd9Sstevel@tonic-gate name++; 739*7c478bd9Sstevel@tonic-gate stdname++; 740*7c478bd9Sstevel@tonic-gate name = getzname(name, 1); 741*7c478bd9Sstevel@tonic-gate if (*name != '>') { 742*7c478bd9Sstevel@tonic-gate return (-1); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate stdlen = name - stdname; 745*7c478bd9Sstevel@tonic-gate name++; 746*7c478bd9Sstevel@tonic-gate } else { 747*7c478bd9Sstevel@tonic-gate name = getzname(name, 0); 748*7c478bd9Sstevel@tonic-gate stdlen = name - stdname; 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate if (stdlen < 3) 751*7c478bd9Sstevel@tonic-gate return -1; 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate if (*name == '\0') 754*7c478bd9Sstevel@tonic-gate stdoffset = 0; 755*7c478bd9Sstevel@tonic-gate else { 756*7c478bd9Sstevel@tonic-gate name = getoffset(name, &stdoffset); 757*7c478bd9Sstevel@tonic-gate if (name == NULL) 758*7c478bd9Sstevel@tonic-gate return -1; 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate if (*name != '\0') { 761*7c478bd9Sstevel@tonic-gate dstname = name; 762*7c478bd9Sstevel@tonic-gate if (*name == '<') { 763*7c478bd9Sstevel@tonic-gate name++; 764*7c478bd9Sstevel@tonic-gate dstname++; 765*7c478bd9Sstevel@tonic-gate name = getzname(name, 1); 766*7c478bd9Sstevel@tonic-gate if (*name != '>') { 767*7c478bd9Sstevel@tonic-gate return (-1); 768*7c478bd9Sstevel@tonic-gate } 769*7c478bd9Sstevel@tonic-gate dstlen = name - dstname; 770*7c478bd9Sstevel@tonic-gate name++; 771*7c478bd9Sstevel@tonic-gate } else { 772*7c478bd9Sstevel@tonic-gate name = getzname(name, 0); 773*7c478bd9Sstevel@tonic-gate dstlen = name - dstname; 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate if (dstlen < 3) 776*7c478bd9Sstevel@tonic-gate return -1; 777*7c478bd9Sstevel@tonic-gate if (*name != '\0' && *name != ',' && *name != ';') { 778*7c478bd9Sstevel@tonic-gate name = getoffset(name, &dstoffset); 779*7c478bd9Sstevel@tonic-gate if (name == NULL) 780*7c478bd9Sstevel@tonic-gate return -1; 781*7c478bd9Sstevel@tonic-gate } else dstoffset = stdoffset - SECSPERHOUR; 782*7c478bd9Sstevel@tonic-gate if (*name == ',' || *name == ';') { 783*7c478bd9Sstevel@tonic-gate struct rule start; 784*7c478bd9Sstevel@tonic-gate struct rule end; 785*7c478bd9Sstevel@tonic-gate register int year; 786*7c478bd9Sstevel@tonic-gate register time_t janfirst; 787*7c478bd9Sstevel@tonic-gate time_t starttime; 788*7c478bd9Sstevel@tonic-gate time_t endtime; 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate ++name; 791*7c478bd9Sstevel@tonic-gate if ((name = getrule(name, &start)) == NULL) 792*7c478bd9Sstevel@tonic-gate return -1; 793*7c478bd9Sstevel@tonic-gate if (*name++ != ',') 794*7c478bd9Sstevel@tonic-gate return -1; 795*7c478bd9Sstevel@tonic-gate if ((name = getrule(name, &end)) == NULL) 796*7c478bd9Sstevel@tonic-gate return -1; 797*7c478bd9Sstevel@tonic-gate if (*name != '\0') 798*7c478bd9Sstevel@tonic-gate return -1; 799*7c478bd9Sstevel@tonic-gate sp->typecnt = 2; /* standard time and DST */ 800*7c478bd9Sstevel@tonic-gate /* 801*7c478bd9Sstevel@tonic-gate ** Two transitions per year, from EPOCH_YEAR to 2037. 802*7c478bd9Sstevel@tonic-gate */ 803*7c478bd9Sstevel@tonic-gate sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); 804*7c478bd9Sstevel@tonic-gate if (sp->timecnt > TZ_MAX_TIMES) 805*7c478bd9Sstevel@tonic-gate return -1; 806*7c478bd9Sstevel@tonic-gate sp->charcnt = stdlen + 1 + dstlen + 1; 807*7c478bd9Sstevel@tonic-gate if (allocall(sp) < 0) 808*7c478bd9Sstevel@tonic-gate return -1; 809*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_gmtoff = -dstoffset; 810*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_isdst = 1; 811*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_abbrind = stdlen + 1; 812*7c478bd9Sstevel@tonic-gate sp->ttis[1].tt_gmtoff = -stdoffset; 813*7c478bd9Sstevel@tonic-gate sp->ttis[1].tt_isdst = 0; 814*7c478bd9Sstevel@tonic-gate sp->ttis[1].tt_abbrind = 0; 815*7c478bd9Sstevel@tonic-gate atp = sp->ats; 816*7c478bd9Sstevel@tonic-gate typep = sp->types; 817*7c478bd9Sstevel@tonic-gate janfirst = 0; 818*7c478bd9Sstevel@tonic-gate for (year = EPOCH_YEAR; year <= 2037; ++year) { 819*7c478bd9Sstevel@tonic-gate starttime = transtime(janfirst, year, &start, 820*7c478bd9Sstevel@tonic-gate stdoffset); 821*7c478bd9Sstevel@tonic-gate endtime = transtime(janfirst, year, &end, 822*7c478bd9Sstevel@tonic-gate dstoffset); 823*7c478bd9Sstevel@tonic-gate if (starttime > endtime) { 824*7c478bd9Sstevel@tonic-gate *atp++ = endtime; 825*7c478bd9Sstevel@tonic-gate *typep++ = 1; /* DST ends */ 826*7c478bd9Sstevel@tonic-gate *atp++ = starttime; 827*7c478bd9Sstevel@tonic-gate *typep++ = 0; /* DST begins */ 828*7c478bd9Sstevel@tonic-gate } else { 829*7c478bd9Sstevel@tonic-gate *atp++ = starttime; 830*7c478bd9Sstevel@tonic-gate *typep++ = 0; /* DST begins */ 831*7c478bd9Sstevel@tonic-gate *atp++ = endtime; 832*7c478bd9Sstevel@tonic-gate *typep++ = 1; /* DST ends */ 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate janfirst += 835*7c478bd9Sstevel@tonic-gate year_lengths[isleap(year)] * SECSPERDAY; 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate } else { 838*7c478bd9Sstevel@tonic-gate int sawstd; 839*7c478bd9Sstevel@tonic-gate int sawdst; 840*7c478bd9Sstevel@tonic-gate long stdfix; 841*7c478bd9Sstevel@tonic-gate long dstfix; 842*7c478bd9Sstevel@tonic-gate long oldfix; 843*7c478bd9Sstevel@tonic-gate int isdst; 844*7c478bd9Sstevel@tonic-gate register int i; 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate if (*name != '\0') 847*7c478bd9Sstevel@tonic-gate return -1; 848*7c478bd9Sstevel@tonic-gate if (tzload(TZDEFRULES, sp) != 0) { 849*7c478bd9Sstevel@tonic-gate freeall(sp); 850*7c478bd9Sstevel@tonic-gate return -1; 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate /* 853*7c478bd9Sstevel@tonic-gate ** Discard zone abbreviations from file, and allocate 854*7c478bd9Sstevel@tonic-gate ** space for the ones from TZ. 855*7c478bd9Sstevel@tonic-gate */ 856*7c478bd9Sstevel@tonic-gate free(sp->chars); 857*7c478bd9Sstevel@tonic-gate sp->charcnt = stdlen + 1 + dstlen + 1; 858*7c478bd9Sstevel@tonic-gate sp->chars = (char *)calloc((unsigned)sp->charcnt, 859*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (char)); 860*7c478bd9Sstevel@tonic-gate /* 861*7c478bd9Sstevel@tonic-gate ** Compute the difference between the real and 862*7c478bd9Sstevel@tonic-gate ** prototype standard and summer time offsets 863*7c478bd9Sstevel@tonic-gate ** from GMT, and put the real standard and summer 864*7c478bd9Sstevel@tonic-gate ** time offsets into the rules in place of the 865*7c478bd9Sstevel@tonic-gate ** prototype offsets. 866*7c478bd9Sstevel@tonic-gate */ 867*7c478bd9Sstevel@tonic-gate sawstd = FALSE; 868*7c478bd9Sstevel@tonic-gate sawdst = FALSE; 869*7c478bd9Sstevel@tonic-gate stdfix = 0; 870*7c478bd9Sstevel@tonic-gate dstfix = 0; 871*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->typecnt; ++i) { 872*7c478bd9Sstevel@tonic-gate if (sp->ttis[i].tt_isdst) { 873*7c478bd9Sstevel@tonic-gate oldfix = dstfix; 874*7c478bd9Sstevel@tonic-gate dstfix = 875*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_gmtoff + dstoffset; 876*7c478bd9Sstevel@tonic-gate if (sawdst && (oldfix != dstfix)) 877*7c478bd9Sstevel@tonic-gate return -1; 878*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_gmtoff = -dstoffset; 879*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_abbrind = stdlen + 1; 880*7c478bd9Sstevel@tonic-gate sawdst = TRUE; 881*7c478bd9Sstevel@tonic-gate } else { 882*7c478bd9Sstevel@tonic-gate oldfix = stdfix; 883*7c478bd9Sstevel@tonic-gate stdfix = 884*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_gmtoff + stdoffset; 885*7c478bd9Sstevel@tonic-gate if (sawstd && (oldfix != stdfix)) 886*7c478bd9Sstevel@tonic-gate return -1; 887*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_gmtoff = -stdoffset; 888*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_abbrind = 0; 889*7c478bd9Sstevel@tonic-gate sawstd = TRUE; 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate ** Make sure we have both standard and summer time. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate if (!sawdst || !sawstd) 896*7c478bd9Sstevel@tonic-gate return -1; 897*7c478bd9Sstevel@tonic-gate /* 898*7c478bd9Sstevel@tonic-gate ** Now correct the transition times by shifting 899*7c478bd9Sstevel@tonic-gate ** them by the difference between the real and 900*7c478bd9Sstevel@tonic-gate ** prototype offsets. Note that this difference 901*7c478bd9Sstevel@tonic-gate ** can be different in standard and summer time; 902*7c478bd9Sstevel@tonic-gate ** the prototype probably has a 1-hour difference 903*7c478bd9Sstevel@tonic-gate ** between standard and summer time, but a different 904*7c478bd9Sstevel@tonic-gate ** difference can be specified in TZ. 905*7c478bd9Sstevel@tonic-gate */ 906*7c478bd9Sstevel@tonic-gate isdst = FALSE; /* we start in standard time */ 907*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->timecnt; ++i) { 908*7c478bd9Sstevel@tonic-gate register const struct ttinfo * ttisp; 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate /* 911*7c478bd9Sstevel@tonic-gate ** If summer time is in effect, and the 912*7c478bd9Sstevel@tonic-gate ** transition time was not specified as 913*7c478bd9Sstevel@tonic-gate ** standard time, add the summer time 914*7c478bd9Sstevel@tonic-gate ** offset to the transition time; 915*7c478bd9Sstevel@tonic-gate ** otherwise, add the standard time offset 916*7c478bd9Sstevel@tonic-gate ** to the transition time. 917*7c478bd9Sstevel@tonic-gate */ 918*7c478bd9Sstevel@tonic-gate ttisp = &sp->ttis[sp->types[i]]; 919*7c478bd9Sstevel@tonic-gate sp->ats[i] += 920*7c478bd9Sstevel@tonic-gate (isdst && !ttisp->tt_ttisstd) ? 921*7c478bd9Sstevel@tonic-gate dstfix : stdfix; 922*7c478bd9Sstevel@tonic-gate isdst = ttisp->tt_isdst; 923*7c478bd9Sstevel@tonic-gate } 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate } else { 926*7c478bd9Sstevel@tonic-gate dstlen = 0; 927*7c478bd9Sstevel@tonic-gate sp->typecnt = 1; /* only standard time */ 928*7c478bd9Sstevel@tonic-gate sp->timecnt = 0; 929*7c478bd9Sstevel@tonic-gate sp->charcnt = stdlen + 1; 930*7c478bd9Sstevel@tonic-gate if (allocall(sp) < 0) 931*7c478bd9Sstevel@tonic-gate return -1; 932*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_gmtoff = -stdoffset; 933*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_isdst = 0; 934*7c478bd9Sstevel@tonic-gate sp->ttis[0].tt_abbrind = 0; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate cp = sp->chars; 937*7c478bd9Sstevel@tonic-gate (void) strncpy(cp, stdname, stdlen); 938*7c478bd9Sstevel@tonic-gate cp += stdlen; 939*7c478bd9Sstevel@tonic-gate *cp++ = '\0'; 940*7c478bd9Sstevel@tonic-gate if (dstlen != 0) { 941*7c478bd9Sstevel@tonic-gate (void) strncpy(cp, dstname, dstlen); 942*7c478bd9Sstevel@tonic-gate *(cp + dstlen) = '\0'; 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate return 0; 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate static void 948*7c478bd9Sstevel@tonic-gate gmtload(sp) 949*7c478bd9Sstevel@tonic-gate struct state * const sp; 950*7c478bd9Sstevel@tonic-gate { 951*7c478bd9Sstevel@tonic-gate if (tzload(GMT, sp) != 0) 952*7c478bd9Sstevel@tonic-gate (void) tzparse(GMT, sp, TRUE); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate void 956*7c478bd9Sstevel@tonic-gate tzsetwall() 957*7c478bd9Sstevel@tonic-gate { 958*7c478bd9Sstevel@tonic-gate lcl_is_set = TRUE; 959*7c478bd9Sstevel@tonic-gate if (lclptr == NULL) { 960*7c478bd9Sstevel@tonic-gate lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr); 961*7c478bd9Sstevel@tonic-gate if (lclptr == NULL) { 962*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 963*7c478bd9Sstevel@tonic-gate settzname(); /* all we can do */ 964*7c478bd9Sstevel@tonic-gate #endif 965*7c478bd9Sstevel@tonic-gate return; 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate if (tzload((char *) NULL, lclptr) != 0) 969*7c478bd9Sstevel@tonic-gate gmtload(lclptr); 970*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 971*7c478bd9Sstevel@tonic-gate settzname(); 972*7c478bd9Sstevel@tonic-gate #endif 973*7c478bd9Sstevel@tonic-gate } 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate void 976*7c478bd9Sstevel@tonic-gate tzset() 977*7c478bd9Sstevel@tonic-gate { 978*7c478bd9Sstevel@tonic-gate register const char * name; 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate name = (const char *)getenv("TZ"); 981*7c478bd9Sstevel@tonic-gate if (name == NULL) { 982*7c478bd9Sstevel@tonic-gate tzsetwall(); 983*7c478bd9Sstevel@tonic-gate return; 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate lcl_is_set = TRUE; 986*7c478bd9Sstevel@tonic-gate if (lclptr == NULL) { 987*7c478bd9Sstevel@tonic-gate lclptr = (struct state *) calloc(1, (unsigned)sizeof *lclptr); 988*7c478bd9Sstevel@tonic-gate if (lclptr == NULL) { 989*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 990*7c478bd9Sstevel@tonic-gate settzname(); /* all we can do */ 991*7c478bd9Sstevel@tonic-gate #endif 992*7c478bd9Sstevel@tonic-gate return; 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate } 995*7c478bd9Sstevel@tonic-gate if (*name == '\0') { 996*7c478bd9Sstevel@tonic-gate /* 997*7c478bd9Sstevel@tonic-gate ** User wants it fast rather than right. 998*7c478bd9Sstevel@tonic-gate */ 999*7c478bd9Sstevel@tonic-gate lclptr->timecnt = 0; 1000*7c478bd9Sstevel@tonic-gate lclptr->typecnt = 1; 1001*7c478bd9Sstevel@tonic-gate lclptr->charcnt = sizeof GMT; 1002*7c478bd9Sstevel@tonic-gate if (allocall(lclptr) < 0) 1003*7c478bd9Sstevel@tonic-gate return; 1004*7c478bd9Sstevel@tonic-gate lclptr->ttis[0].tt_gmtoff = 0; 1005*7c478bd9Sstevel@tonic-gate lclptr->ttis[0].tt_abbrind = 0; 1006*7c478bd9Sstevel@tonic-gate (void) strcpy(lclptr->chars, GMT); 1007*7c478bd9Sstevel@tonic-gate } else if (tzload(name, lclptr) != 0) 1008*7c478bd9Sstevel@tonic-gate if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) 1009*7c478bd9Sstevel@tonic-gate (void) tzparse(name, lclptr, TRUE); 1010*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 1011*7c478bd9Sstevel@tonic-gate settzname(); 1012*7c478bd9Sstevel@tonic-gate #endif 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate ** The easy way to behave "as if no library function calls" localtime 1017*7c478bd9Sstevel@tonic-gate ** is to not call it--so we drop its guts into "localsub", which can be 1018*7c478bd9Sstevel@tonic-gate ** freely called. (And no, the PANS doesn't require the above behavior-- 1019*7c478bd9Sstevel@tonic-gate ** but it *is* desirable.) 1020*7c478bd9Sstevel@tonic-gate ** 1021*7c478bd9Sstevel@tonic-gate ** The unused offset argument is for the benefit of mktime variants. 1022*7c478bd9Sstevel@tonic-gate */ 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate static struct tm tm; 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1027*7c478bd9Sstevel@tonic-gate static void 1028*7c478bd9Sstevel@tonic-gate localsub(timep, offset, tmp) 1029*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1030*7c478bd9Sstevel@tonic-gate const long offset; 1031*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1032*7c478bd9Sstevel@tonic-gate { 1033*7c478bd9Sstevel@tonic-gate register const struct state * sp; 1034*7c478bd9Sstevel@tonic-gate register const struct ttinfo * ttisp; 1035*7c478bd9Sstevel@tonic-gate register int i; 1036*7c478bd9Sstevel@tonic-gate const time_t t = *timep; 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate if (!lcl_is_set) 1039*7c478bd9Sstevel@tonic-gate tzset(); 1040*7c478bd9Sstevel@tonic-gate sp = lclptr; 1041*7c478bd9Sstevel@tonic-gate if (sp == NULL) { 1042*7c478bd9Sstevel@tonic-gate gmtsub(timep, offset, tmp); 1043*7c478bd9Sstevel@tonic-gate return; 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate if (sp->timecnt == 0 || t < sp->ats[0]) { 1046*7c478bd9Sstevel@tonic-gate i = 0; 1047*7c478bd9Sstevel@tonic-gate while (sp->ttis[i].tt_isdst) 1048*7c478bd9Sstevel@tonic-gate if (++i >= sp->typecnt) { 1049*7c478bd9Sstevel@tonic-gate i = 0; 1050*7c478bd9Sstevel@tonic-gate break; 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate } else { 1053*7c478bd9Sstevel@tonic-gate for (i = 1; i < sp->timecnt; ++i) 1054*7c478bd9Sstevel@tonic-gate if (t < sp->ats[i]) 1055*7c478bd9Sstevel@tonic-gate break; 1056*7c478bd9Sstevel@tonic-gate i = sp->types[i - 1]; 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate ttisp = &sp->ttis[i]; 1059*7c478bd9Sstevel@tonic-gate timesub(&t, ttisp->tt_gmtoff, tmp); 1060*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = ttisp->tt_isdst; 1061*7c478bd9Sstevel@tonic-gate #ifdef S5EMUL 1062*7c478bd9Sstevel@tonic-gate tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; 1063*7c478bd9Sstevel@tonic-gate #endif /* S5EMUL */ 1064*7c478bd9Sstevel@tonic-gate tmp->tm_zone = &sp->chars[ttisp->tt_abbrind]; 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate struct tm * 1068*7c478bd9Sstevel@tonic-gate localtime(timep) 1069*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1070*7c478bd9Sstevel@tonic-gate { 1071*7c478bd9Sstevel@tonic-gate time_t temp_time = *(const time_t*)timep; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate _ltzset(&temp_time); /* 1074*7c478bd9Sstevel@tonic-gate * base localtime calls this to initialize 1075*7c478bd9Sstevel@tonic-gate * some things, so we'll do it here, too. 1076*7c478bd9Sstevel@tonic-gate */ 1077*7c478bd9Sstevel@tonic-gate localsub(timep, 0L, &tm); 1078*7c478bd9Sstevel@tonic-gate return &tm; 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate /* 1082*7c478bd9Sstevel@tonic-gate ** gmtsub is to gmtime as localsub is to localtime. 1083*7c478bd9Sstevel@tonic-gate */ 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate static void 1086*7c478bd9Sstevel@tonic-gate gmtsub(timep, offset, tmp) 1087*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1088*7c478bd9Sstevel@tonic-gate const long offset; 1089*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1090*7c478bd9Sstevel@tonic-gate { 1091*7c478bd9Sstevel@tonic-gate if (!gmt_is_set) { 1092*7c478bd9Sstevel@tonic-gate gmt_is_set = TRUE; 1093*7c478bd9Sstevel@tonic-gate gmtptr = (struct state *) calloc(1, (unsigned)sizeof *gmtptr); 1094*7c478bd9Sstevel@tonic-gate if (gmtptr != NULL) 1095*7c478bd9Sstevel@tonic-gate gmtload(gmtptr); 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate timesub(timep, offset, tmp); 1098*7c478bd9Sstevel@tonic-gate /* 1099*7c478bd9Sstevel@tonic-gate ** Could get fancy here and deliver something such as 1100*7c478bd9Sstevel@tonic-gate ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, 1101*7c478bd9Sstevel@tonic-gate ** but this is no time for a treasure hunt. 1102*7c478bd9Sstevel@tonic-gate */ 1103*7c478bd9Sstevel@tonic-gate if (offset != 0) 1104*7c478bd9Sstevel@tonic-gate tmp->tm_zone = (char *)WILDABBR; 1105*7c478bd9Sstevel@tonic-gate else { 1106*7c478bd9Sstevel@tonic-gate if (gmtptr == NULL) 1107*7c478bd9Sstevel@tonic-gate tmp->tm_zone = (char *)GMT; 1108*7c478bd9Sstevel@tonic-gate else tmp->tm_zone = gmtptr->chars; 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate struct tm * 1113*7c478bd9Sstevel@tonic-gate gmtime(timep) 1114*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1115*7c478bd9Sstevel@tonic-gate { 1116*7c478bd9Sstevel@tonic-gate gmtsub(timep, 0L, &tm); 1117*7c478bd9Sstevel@tonic-gate return &tm; 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate struct tm * 1121*7c478bd9Sstevel@tonic-gate offtime(timep, offset) 1122*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1123*7c478bd9Sstevel@tonic-gate const long offset; 1124*7c478bd9Sstevel@tonic-gate { 1125*7c478bd9Sstevel@tonic-gate gmtsub(timep, offset, &tm); 1126*7c478bd9Sstevel@tonic-gate return &tm; 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate static void 1130*7c478bd9Sstevel@tonic-gate timesub(timep, offset, tmp) 1131*7c478bd9Sstevel@tonic-gate const time_t * const timep; 1132*7c478bd9Sstevel@tonic-gate const long offset; 1133*7c478bd9Sstevel@tonic-gate register struct tm * const tmp; 1134*7c478bd9Sstevel@tonic-gate { 1135*7c478bd9Sstevel@tonic-gate register long days; 1136*7c478bd9Sstevel@tonic-gate register long rem; 1137*7c478bd9Sstevel@tonic-gate register int y; 1138*7c478bd9Sstevel@tonic-gate register int yleap; 1139*7c478bd9Sstevel@tonic-gate register const int * ip; 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate days = *timep / SECSPERDAY; 1142*7c478bd9Sstevel@tonic-gate rem = *timep % SECSPERDAY; 1143*7c478bd9Sstevel@tonic-gate rem += offset; 1144*7c478bd9Sstevel@tonic-gate while (rem < 0) { 1145*7c478bd9Sstevel@tonic-gate rem += SECSPERDAY; 1146*7c478bd9Sstevel@tonic-gate --days; 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate while (rem >= SECSPERDAY) { 1149*7c478bd9Sstevel@tonic-gate rem -= SECSPERDAY; 1150*7c478bd9Sstevel@tonic-gate ++days; 1151*7c478bd9Sstevel@tonic-gate } 1152*7c478bd9Sstevel@tonic-gate tmp->tm_hour = (int) (rem / SECSPERHOUR); 1153*7c478bd9Sstevel@tonic-gate rem = rem % SECSPERHOUR; 1154*7c478bd9Sstevel@tonic-gate tmp->tm_min = (int) (rem / SECSPERMIN); 1155*7c478bd9Sstevel@tonic-gate tmp->tm_sec = (int) (rem % SECSPERMIN); 1156*7c478bd9Sstevel@tonic-gate tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); 1157*7c478bd9Sstevel@tonic-gate if (tmp->tm_wday < 0) 1158*7c478bd9Sstevel@tonic-gate tmp->tm_wday += DAYSPERWEEK; 1159*7c478bd9Sstevel@tonic-gate y = EPOCH_YEAR; 1160*7c478bd9Sstevel@tonic-gate if (days >= 0) 1161*7c478bd9Sstevel@tonic-gate for ( ; ; ) { 1162*7c478bd9Sstevel@tonic-gate yleap = isleap(y); 1163*7c478bd9Sstevel@tonic-gate if (days < (long) year_lengths[yleap]) 1164*7c478bd9Sstevel@tonic-gate break; 1165*7c478bd9Sstevel@tonic-gate ++y; 1166*7c478bd9Sstevel@tonic-gate days = days - (long) year_lengths[yleap]; 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate else do { 1169*7c478bd9Sstevel@tonic-gate --y; 1170*7c478bd9Sstevel@tonic-gate yleap = isleap(y); 1171*7c478bd9Sstevel@tonic-gate days = days + (long) year_lengths[yleap]; 1172*7c478bd9Sstevel@tonic-gate } while (days < 0); 1173*7c478bd9Sstevel@tonic-gate tmp->tm_year = y - TM_YEAR_BASE; 1174*7c478bd9Sstevel@tonic-gate tmp->tm_yday = (int) days; 1175*7c478bd9Sstevel@tonic-gate ip = mon_lengths[yleap]; 1176*7c478bd9Sstevel@tonic-gate for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1177*7c478bd9Sstevel@tonic-gate days = days - (long) ip[tmp->tm_mon]; 1178*7c478bd9Sstevel@tonic-gate tmp->tm_mday = (int) (days + 1); 1179*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = 0; 1180*7c478bd9Sstevel@tonic-gate tmp->tm_gmtoff = offset; 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate /* 1184*7c478bd9Sstevel@tonic-gate ** Adapted from code provided by Robert Elz, who writes: 1185*7c478bd9Sstevel@tonic-gate ** The "best" way to do mktime I think is based on an idea of Bob 1186*7c478bd9Sstevel@tonic-gate ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 1187*7c478bd9Sstevel@tonic-gate ** It does a binary search of the time_t space. Since time_t's are 1188*7c478bd9Sstevel@tonic-gate ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1189*7c478bd9Sstevel@tonic-gate ** would still be very reasonable). 1190*7c478bd9Sstevel@tonic-gate */ 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate #ifndef WRONG 1193*7c478bd9Sstevel@tonic-gate #define WRONG (-1) 1194*7c478bd9Sstevel@tonic-gate #endif /* !defined WRONG */ 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate static void 1197*7c478bd9Sstevel@tonic-gate normalize(tensptr, unitsptr, base) 1198*7c478bd9Sstevel@tonic-gate int * const tensptr; 1199*7c478bd9Sstevel@tonic-gate int * const unitsptr; 1200*7c478bd9Sstevel@tonic-gate const int base; 1201*7c478bd9Sstevel@tonic-gate { 1202*7c478bd9Sstevel@tonic-gate int tmp; 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate if (*unitsptr >= base) { 1205*7c478bd9Sstevel@tonic-gate *tensptr += *unitsptr / base; 1206*7c478bd9Sstevel@tonic-gate *unitsptr %= base; 1207*7c478bd9Sstevel@tonic-gate } else if (*unitsptr < 0) { 1208*7c478bd9Sstevel@tonic-gate /* tmp has the range 0 to abs(*unitptr) -1 */ 1209*7c478bd9Sstevel@tonic-gate tmp = -1 - (*unitsptr); 1210*7c478bd9Sstevel@tonic-gate *tensptr -= (tmp/base + 1); 1211*7c478bd9Sstevel@tonic-gate *unitsptr = (base - 1) - (tmp % base); 1212*7c478bd9Sstevel@tonic-gate } 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate static int 1216*7c478bd9Sstevel@tonic-gate tmcomp(atmp, btmp) 1217*7c478bd9Sstevel@tonic-gate register const struct tm * const atmp; 1218*7c478bd9Sstevel@tonic-gate register const struct tm * const btmp; 1219*7c478bd9Sstevel@tonic-gate { 1220*7c478bd9Sstevel@tonic-gate register int result; 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 1223*7c478bd9Sstevel@tonic-gate (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 1224*7c478bd9Sstevel@tonic-gate (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 1225*7c478bd9Sstevel@tonic-gate (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 1226*7c478bd9Sstevel@tonic-gate (result = (atmp->tm_min - btmp->tm_min)) == 0) 1227*7c478bd9Sstevel@tonic-gate result = atmp->tm_sec - btmp->tm_sec; 1228*7c478bd9Sstevel@tonic-gate return result; 1229*7c478bd9Sstevel@tonic-gate } 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate static time_t 1232*7c478bd9Sstevel@tonic-gate time2(tmp, funcp, offset, okayp) 1233*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1234*7c478bd9Sstevel@tonic-gate void (* const funcp)(); 1235*7c478bd9Sstevel@tonic-gate const long offset; 1236*7c478bd9Sstevel@tonic-gate int * const okayp; 1237*7c478bd9Sstevel@tonic-gate { 1238*7c478bd9Sstevel@tonic-gate register const struct state * sp; 1239*7c478bd9Sstevel@tonic-gate register int dir; 1240*7c478bd9Sstevel@tonic-gate register int bits; 1241*7c478bd9Sstevel@tonic-gate register int i, j ; 1242*7c478bd9Sstevel@tonic-gate register int saved_seconds; 1243*7c478bd9Sstevel@tonic-gate time_t newt; 1244*7c478bd9Sstevel@tonic-gate time_t t; 1245*7c478bd9Sstevel@tonic-gate struct tm yourtm, mytm; 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate *okayp = FALSE; 1248*7c478bd9Sstevel@tonic-gate yourtm = *tmp; 1249*7c478bd9Sstevel@tonic-gate if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) 1250*7c478bd9Sstevel@tonic-gate normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); 1251*7c478bd9Sstevel@tonic-gate normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); 1252*7c478bd9Sstevel@tonic-gate normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); 1253*7c478bd9Sstevel@tonic-gate normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); 1254*7c478bd9Sstevel@tonic-gate while (yourtm.tm_mday <= 0) { 1255*7c478bd9Sstevel@tonic-gate if (yourtm.tm_mon == 0) { 1256*7c478bd9Sstevel@tonic-gate yourtm.tm_mon = 12; 1257*7c478bd9Sstevel@tonic-gate --yourtm.tm_year; 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate yourtm.tm_mday += 1260*7c478bd9Sstevel@tonic-gate mon_lengths[isleap(yourtm.tm_year + 1261*7c478bd9Sstevel@tonic-gate TM_YEAR_BASE)][--yourtm.tm_mon]; 1262*7c478bd9Sstevel@tonic-gate if (yourtm.tm_mon >= MONSPERYEAR) { 1263*7c478bd9Sstevel@tonic-gate yourtm.tm_mon = 0; 1264*7c478bd9Sstevel@tonic-gate --yourtm.tm_year; 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate for ( ; ; ) { 1268*7c478bd9Sstevel@tonic-gate i = mon_lengths[isleap(yourtm.tm_year + 1269*7c478bd9Sstevel@tonic-gate TM_YEAR_BASE)][yourtm.tm_mon]; 1270*7c478bd9Sstevel@tonic-gate if (yourtm.tm_mday <= i) 1271*7c478bd9Sstevel@tonic-gate break; 1272*7c478bd9Sstevel@tonic-gate yourtm.tm_mday -= i; 1273*7c478bd9Sstevel@tonic-gate if (++yourtm.tm_mon >= MONSPERYEAR) { 1274*7c478bd9Sstevel@tonic-gate yourtm.tm_mon = 0; 1275*7c478bd9Sstevel@tonic-gate ++yourtm.tm_year; 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate saved_seconds = yourtm.tm_sec; 1279*7c478bd9Sstevel@tonic-gate yourtm.tm_sec = 0; 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate ** Calculate the number of magnitude bits in a time_t 1282*7c478bd9Sstevel@tonic-gate ** (this works regardless of whether time_t is 1283*7c478bd9Sstevel@tonic-gate ** signed or unsigned, though lint complains if unsigned). 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 1286*7c478bd9Sstevel@tonic-gate ; 1287*7c478bd9Sstevel@tonic-gate /* 1288*7c478bd9Sstevel@tonic-gate ** If time_t is signed, then 0 is the median value, 1289*7c478bd9Sstevel@tonic-gate ** if time_t is unsigned, then 1 << bits is median. 1290*7c478bd9Sstevel@tonic-gate */ 1291*7c478bd9Sstevel@tonic-gate t = (t < 0) ? 0 : ((time_t) 1 << bits); 1292*7c478bd9Sstevel@tonic-gate for ( ; ; ) { 1293*7c478bd9Sstevel@tonic-gate (*funcp)(&t, offset, &mytm); 1294*7c478bd9Sstevel@tonic-gate dir = tmcomp(&mytm, &yourtm); 1295*7c478bd9Sstevel@tonic-gate if (dir != 0) { 1296*7c478bd9Sstevel@tonic-gate if (bits-- < 0) 1297*7c478bd9Sstevel@tonic-gate return WRONG; 1298*7c478bd9Sstevel@tonic-gate if (bits < 0) 1299*7c478bd9Sstevel@tonic-gate --t; 1300*7c478bd9Sstevel@tonic-gate else if (dir > 0) 1301*7c478bd9Sstevel@tonic-gate t -= (time_t) 1 << bits; 1302*7c478bd9Sstevel@tonic-gate else t += (time_t) 1 << bits; 1303*7c478bd9Sstevel@tonic-gate continue; 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 1306*7c478bd9Sstevel@tonic-gate break; 1307*7c478bd9Sstevel@tonic-gate /* 1308*7c478bd9Sstevel@tonic-gate ** Right time, wrong type. 1309*7c478bd9Sstevel@tonic-gate ** Hunt for right time, right type. 1310*7c478bd9Sstevel@tonic-gate ** It's okay to guess wrong since the guess 1311*7c478bd9Sstevel@tonic-gate ** gets checked. 1312*7c478bd9Sstevel@tonic-gate */ 1313*7c478bd9Sstevel@tonic-gate sp = (const struct state *) 1314*7c478bd9Sstevel@tonic-gate ((funcp == localsub) ? lclptr : gmtptr); 1315*7c478bd9Sstevel@tonic-gate if (sp == NULL) 1316*7c478bd9Sstevel@tonic-gate return WRONG; 1317*7c478bd9Sstevel@tonic-gate for (i = 0; i < sp->typecnt; ++i) { 1318*7c478bd9Sstevel@tonic-gate if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 1319*7c478bd9Sstevel@tonic-gate continue; 1320*7c478bd9Sstevel@tonic-gate for (j = 0; j < sp->typecnt; ++j) { 1321*7c478bd9Sstevel@tonic-gate if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 1322*7c478bd9Sstevel@tonic-gate continue; 1323*7c478bd9Sstevel@tonic-gate newt = t + sp->ttis[j].tt_gmtoff - 1324*7c478bd9Sstevel@tonic-gate sp->ttis[i].tt_gmtoff; 1325*7c478bd9Sstevel@tonic-gate (*funcp)(&newt, offset, &mytm); 1326*7c478bd9Sstevel@tonic-gate if (tmcomp(&mytm, &yourtm) != 0) 1327*7c478bd9Sstevel@tonic-gate continue; 1328*7c478bd9Sstevel@tonic-gate if (mytm.tm_isdst != yourtm.tm_isdst) 1329*7c478bd9Sstevel@tonic-gate continue; 1330*7c478bd9Sstevel@tonic-gate /* 1331*7c478bd9Sstevel@tonic-gate ** We have a match. 1332*7c478bd9Sstevel@tonic-gate */ 1333*7c478bd9Sstevel@tonic-gate t = newt; 1334*7c478bd9Sstevel@tonic-gate goto label; 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate } 1337*7c478bd9Sstevel@tonic-gate return WRONG; 1338*7c478bd9Sstevel@tonic-gate } 1339*7c478bd9Sstevel@tonic-gate label: 1340*7c478bd9Sstevel@tonic-gate t += saved_seconds; 1341*7c478bd9Sstevel@tonic-gate (*funcp)(&t, offset, tmp); 1342*7c478bd9Sstevel@tonic-gate *okayp = TRUE; 1343*7c478bd9Sstevel@tonic-gate return t; 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate static time_t 1347*7c478bd9Sstevel@tonic-gate time1(tmp, funcp, offset) 1348*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1349*7c478bd9Sstevel@tonic-gate void (* const funcp)(); 1350*7c478bd9Sstevel@tonic-gate const long offset; 1351*7c478bd9Sstevel@tonic-gate { 1352*7c478bd9Sstevel@tonic-gate register time_t t; 1353*7c478bd9Sstevel@tonic-gate register const struct state * sp; 1354*7c478bd9Sstevel@tonic-gate register int samei, otheri; 1355*7c478bd9Sstevel@tonic-gate int okay; 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate if (tmp->tm_isdst > 1) 1359*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = 1; 1360*7c478bd9Sstevel@tonic-gate t = time2(tmp, funcp, offset, &okay); 1361*7c478bd9Sstevel@tonic-gate if (okay || tmp->tm_isdst < 0) 1362*7c478bd9Sstevel@tonic-gate return t; 1363*7c478bd9Sstevel@tonic-gate /* 1364*7c478bd9Sstevel@tonic-gate ** We're supposed to assume that somebody took a time of one type 1365*7c478bd9Sstevel@tonic-gate ** and did some math on it that yielded a "struct tm" that's bad. 1366*7c478bd9Sstevel@tonic-gate ** We try to divine the type they started from and adjust to the 1367*7c478bd9Sstevel@tonic-gate ** type they need. 1368*7c478bd9Sstevel@tonic-gate */ 1369*7c478bd9Sstevel@tonic-gate sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); 1370*7c478bd9Sstevel@tonic-gate if (sp == NULL) 1371*7c478bd9Sstevel@tonic-gate return WRONG; 1372*7c478bd9Sstevel@tonic-gate for (samei = 0; samei < sp->typecnt; ++samei) { 1373*7c478bd9Sstevel@tonic-gate if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 1374*7c478bd9Sstevel@tonic-gate continue; 1375*7c478bd9Sstevel@tonic-gate for (otheri = 0; otheri < sp->typecnt; ++otheri) { 1376*7c478bd9Sstevel@tonic-gate if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 1377*7c478bd9Sstevel@tonic-gate continue; 1378*7c478bd9Sstevel@tonic-gate tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - 1379*7c478bd9Sstevel@tonic-gate sp->ttis[samei].tt_gmtoff; 1380*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = !tmp->tm_isdst; 1381*7c478bd9Sstevel@tonic-gate t = time2(tmp, funcp, offset, &okay); 1382*7c478bd9Sstevel@tonic-gate if (okay) 1383*7c478bd9Sstevel@tonic-gate return t; 1384*7c478bd9Sstevel@tonic-gate tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - 1385*7c478bd9Sstevel@tonic-gate sp->ttis[samei].tt_gmtoff; 1386*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = !tmp->tm_isdst; 1387*7c478bd9Sstevel@tonic-gate } 1388*7c478bd9Sstevel@tonic-gate } 1389*7c478bd9Sstevel@tonic-gate return WRONG; 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate time_t 1393*7c478bd9Sstevel@tonic-gate mktime(tmp) 1394*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1395*7c478bd9Sstevel@tonic-gate { 1396*7c478bd9Sstevel@tonic-gate return time1(tmp, localsub, 0L); 1397*7c478bd9Sstevel@tonic-gate } 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate time_t 1400*7c478bd9Sstevel@tonic-gate timelocal(tmp) 1401*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1402*7c478bd9Sstevel@tonic-gate { 1403*7c478bd9Sstevel@tonic-gate tmp->tm_isdst = -1; 1404*7c478bd9Sstevel@tonic-gate return mktime(tmp); 1405*7c478bd9Sstevel@tonic-gate } 1406*7c478bd9Sstevel@tonic-gate 1407*7c478bd9Sstevel@tonic-gate time_t 1408*7c478bd9Sstevel@tonic-gate timegm(tmp) 1409*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1410*7c478bd9Sstevel@tonic-gate { 1411*7c478bd9Sstevel@tonic-gate return time1(tmp, gmtsub, 0L); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate time_t 1415*7c478bd9Sstevel@tonic-gate timeoff(tmp, offset) 1416*7c478bd9Sstevel@tonic-gate struct tm * const tmp; 1417*7c478bd9Sstevel@tonic-gate const long offset; 1418*7c478bd9Sstevel@tonic-gate { 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate return time1(tmp, gmtsub, offset); 1421*7c478bd9Sstevel@tonic-gate } 1422