intl/icu/source/tools/tzcode/localtime.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 ** This file is in the public domain, so clarified as of
michael@0 3 ** 1996-06-05 by Arthur David Olson.
michael@0 4 */
michael@0 5
michael@0 6 #ifndef lint
michael@0 7 #ifndef NOID
michael@0 8 static char elsieid[] = "@(#)localtime.c 8.9";
michael@0 9 #endif /* !defined NOID */
michael@0 10 #endif /* !defined lint */
michael@0 11
michael@0 12 /*
michael@0 13 ** Leap second handling from Bradley White.
michael@0 14 ** POSIX-style TZ environment variable handling from Guy Harris.
michael@0 15 */
michael@0 16
michael@0 17 /*LINTLIBRARY*/
michael@0 18
michael@0 19 #include "private.h"
michael@0 20 #include "tzfile.h"
michael@0 21 #include "fcntl.h"
michael@0 22 #include "float.h" /* for FLT_MAX and DBL_MAX */
michael@0 23
michael@0 24 #ifndef TZ_ABBR_MAX_LEN
michael@0 25 #define TZ_ABBR_MAX_LEN 16
michael@0 26 #endif /* !defined TZ_ABBR_MAX_LEN */
michael@0 27
michael@0 28 #ifndef TZ_ABBR_CHAR_SET
michael@0 29 #define TZ_ABBR_CHAR_SET \
michael@0 30 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
michael@0 31 #endif /* !defined TZ_ABBR_CHAR_SET */
michael@0 32
michael@0 33 #ifndef TZ_ABBR_ERR_CHAR
michael@0 34 #define TZ_ABBR_ERR_CHAR '_'
michael@0 35 #endif /* !defined TZ_ABBR_ERR_CHAR */
michael@0 36
michael@0 37 /*
michael@0 38 ** SunOS 4.1.1 headers lack O_BINARY.
michael@0 39 */
michael@0 40
michael@0 41 #ifdef O_BINARY
michael@0 42 #define OPEN_MODE (O_RDONLY | O_BINARY)
michael@0 43 #endif /* defined O_BINARY */
michael@0 44 #ifndef O_BINARY
michael@0 45 #define OPEN_MODE O_RDONLY
michael@0 46 #endif /* !defined O_BINARY */
michael@0 47
michael@0 48 #ifndef WILDABBR
michael@0 49 /*
michael@0 50 ** Someone might make incorrect use of a time zone abbreviation:
michael@0 51 ** 1. They might reference tzname[0] before calling tzset (explicitly
michael@0 52 ** or implicitly).
michael@0 53 ** 2. They might reference tzname[1] before calling tzset (explicitly
michael@0 54 ** or implicitly).
michael@0 55 ** 3. They might reference tzname[1] after setting to a time zone
michael@0 56 ** in which Daylight Saving Time is never observed.
michael@0 57 ** 4. They might reference tzname[0] after setting to a time zone
michael@0 58 ** in which Standard Time is never observed.
michael@0 59 ** 5. They might reference tm.TM_ZONE after calling offtime.
michael@0 60 ** What's best to do in the above cases is open to debate;
michael@0 61 ** for now, we just set things up so that in any of the five cases
michael@0 62 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
michael@0 63 ** string "tzname[0] used before set", and similarly for the other cases.
michael@0 64 ** And another: initialize tzname[0] to "ERA", with an explanation in the
michael@0 65 ** manual page of what this "time zone abbreviation" means (doing this so
michael@0 66 ** that tzname[0] has the "normal" length of three characters).
michael@0 67 */
michael@0 68 #define WILDABBR " "
michael@0 69 #endif /* !defined WILDABBR */
michael@0 70
michael@0 71 static char wildabbr[] = WILDABBR;
michael@0 72
michael@0 73 static const char gmt[] = "GMT";
michael@0 74
michael@0 75 /*
michael@0 76 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
michael@0 77 ** We default to US rules as of 1999-08-17.
michael@0 78 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
michael@0 79 ** implementation dependent; for historical reasons, US rules are a
michael@0 80 ** common default.
michael@0 81 */
michael@0 82 #ifndef TZDEFRULESTRING
michael@0 83 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
michael@0 84 #endif /* !defined TZDEFDST */
michael@0 85
michael@0 86 struct ttinfo { /* time type information */
michael@0 87 long tt_gmtoff; /* UTC offset in seconds */
michael@0 88 int tt_isdst; /* used to set tm_isdst */
michael@0 89 int tt_abbrind; /* abbreviation list index */
michael@0 90 int tt_ttisstd; /* TRUE if transition is std time */
michael@0 91 int tt_ttisgmt; /* TRUE if transition is UTC */
michael@0 92 };
michael@0 93
michael@0 94 struct lsinfo { /* leap second information */
michael@0 95 time_t ls_trans; /* transition time */
michael@0 96 long ls_corr; /* correction to apply */
michael@0 97 };
michael@0 98
michael@0 99 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
michael@0 100
michael@0 101 #ifdef TZNAME_MAX
michael@0 102 #define MY_TZNAME_MAX TZNAME_MAX
michael@0 103 #endif /* defined TZNAME_MAX */
michael@0 104 #ifndef TZNAME_MAX
michael@0 105 #define MY_TZNAME_MAX 255
michael@0 106 #endif /* !defined TZNAME_MAX */
michael@0 107
michael@0 108 struct state {
michael@0 109 int leapcnt;
michael@0 110 int timecnt;
michael@0 111 int typecnt;
michael@0 112 int charcnt;
michael@0 113 int goback;
michael@0 114 int goahead;
michael@0 115 time_t ats[TZ_MAX_TIMES];
michael@0 116 unsigned char types[TZ_MAX_TIMES];
michael@0 117 struct ttinfo ttis[TZ_MAX_TYPES];
michael@0 118 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
michael@0 119 (2 * (MY_TZNAME_MAX + 1)))];
michael@0 120 struct lsinfo lsis[TZ_MAX_LEAPS];
michael@0 121 };
michael@0 122
michael@0 123 struct rule {
michael@0 124 int r_type; /* type of rule--see below */
michael@0 125 int r_day; /* day number of rule */
michael@0 126 int r_week; /* week number of rule */
michael@0 127 int r_mon; /* month number of rule */
michael@0 128 long r_time; /* transition time of rule */
michael@0 129 };
michael@0 130
michael@0 131 #define JULIAN_DAY 0 /* Jn - Julian day */
michael@0 132 #define DAY_OF_YEAR 1 /* n - day of year */
michael@0 133 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
michael@0 134
michael@0 135 /*
michael@0 136 ** Prototypes for static functions.
michael@0 137 */
michael@0 138
michael@0 139 static long detzcode(const char * codep);
michael@0 140 static time_t detzcode64(const char * codep);
michael@0 141 static int differ_by_repeat(time_t t1, time_t t0);
michael@0 142 static const char * getzname(const char * strp);
michael@0 143 static const char * getqzname(const char * strp, const int delim);
michael@0 144 static const char * getnum(const char * strp, int * nump, int min,
michael@0 145 int max);
michael@0 146 static const char * getsecs(const char * strp, long * secsp);
michael@0 147 static const char * getoffset(const char * strp, long * offsetp);
michael@0 148 static const char * getrule(const char * strp, struct rule * rulep);
michael@0 149 static void gmtload(struct state * sp);
michael@0 150 static struct tm * gmtsub(const time_t * timep, long offset,
michael@0 151 struct tm * tmp);
michael@0 152 static struct tm * localsub(const time_t * timep, long offset,
michael@0 153 struct tm * tmp);
michael@0 154 static int increment_overflow(int * number, int delta);
michael@0 155 static int leaps_thru_end_of(int y);
michael@0 156 static int long_increment_overflow(long * number, int delta);
michael@0 157 static int long_normalize_overflow(long * tensptr,
michael@0 158 int * unitsptr, int base);
michael@0 159 static int normalize_overflow(int * tensptr, int * unitsptr,
michael@0 160 int base);
michael@0 161 static void settzname(void);
michael@0 162 static time_t time1(struct tm * tmp,
michael@0 163 struct tm * (*funcp)(const time_t *,
michael@0 164 long, struct tm *),
michael@0 165 long offset);
michael@0 166 static time_t time2(struct tm *tmp,
michael@0 167 struct tm * (*funcp)(const time_t *,
michael@0 168 long, struct tm*),
michael@0 169 long offset, int * okayp);
michael@0 170 static time_t time2sub(struct tm *tmp,
michael@0 171 struct tm * (*funcp)(const time_t *,
michael@0 172 long, struct tm*),
michael@0 173 long offset, int * okayp, int do_norm_secs);
michael@0 174 static struct tm * timesub(const time_t * timep, long offset,
michael@0 175 const struct state * sp, struct tm * tmp);
michael@0 176 static int tmcomp(const struct tm * atmp,
michael@0 177 const struct tm * btmp);
michael@0 178 static time_t transtime(time_t janfirst, int year,
michael@0 179 const struct rule * rulep, long offset);
michael@0 180 static int typesequiv(const struct state * sp, int a, int b);
michael@0 181 static int tzload(const char * name, struct state * sp,
michael@0 182 int doextend);
michael@0 183 static int tzparse(const char * name, struct state * sp,
michael@0 184 int lastditch);
michael@0 185
michael@0 186 #ifdef ALL_STATE
michael@0 187 static struct state * lclptr;
michael@0 188 static struct state * gmtptr;
michael@0 189 #endif /* defined ALL_STATE */
michael@0 190
michael@0 191 #ifndef ALL_STATE
michael@0 192 static struct state lclmem;
michael@0 193 static struct state gmtmem;
michael@0 194 #define lclptr (&lclmem)
michael@0 195 #define gmtptr (&gmtmem)
michael@0 196 #endif /* State Farm */
michael@0 197
michael@0 198 #ifndef TZ_STRLEN_MAX
michael@0 199 #define TZ_STRLEN_MAX 255
michael@0 200 #endif /* !defined TZ_STRLEN_MAX */
michael@0 201
michael@0 202 static char lcl_TZname[TZ_STRLEN_MAX + 1];
michael@0 203 static int lcl_is_set;
michael@0 204 static int gmt_is_set;
michael@0 205
michael@0 206 char * tzname[2] = {
michael@0 207 wildabbr,
michael@0 208 wildabbr
michael@0 209 };
michael@0 210
michael@0 211 /*
michael@0 212 ** Section 4.12.3 of X3.159-1989 requires that
michael@0 213 ** Except for the strftime function, these functions [asctime,
michael@0 214 ** ctime, gmtime, localtime] return values in one of two static
michael@0 215 ** objects: a broken-down time structure and an array of char.
michael@0 216 ** Thanks to Paul Eggert for noting this.
michael@0 217 */
michael@0 218
michael@0 219 static struct tm tm;
michael@0 220
michael@0 221 #ifdef USG_COMPAT
michael@0 222 time_t timezone = 0;
michael@0 223 int daylight = 0;
michael@0 224 #endif /* defined USG_COMPAT */
michael@0 225
michael@0 226 #ifdef ALTZONE
michael@0 227 time_t altzone = 0;
michael@0 228 #endif /* defined ALTZONE */
michael@0 229
michael@0 230 static long
michael@0 231 detzcode(codep)
michael@0 232 const char * const codep;
michael@0 233 {
michael@0 234 register long result;
michael@0 235 register int i;
michael@0 236
michael@0 237 result = (codep[0] & 0x80) ? ~0L : 0;
michael@0 238 for (i = 0; i < 4; ++i)
michael@0 239 result = (result << 8) | (codep[i] & 0xff);
michael@0 240 return result;
michael@0 241 }
michael@0 242
michael@0 243 static time_t
michael@0 244 detzcode64(codep)
michael@0 245 const char * const codep;
michael@0 246 {
michael@0 247 register time_t result;
michael@0 248 register int i;
michael@0 249
michael@0 250 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
michael@0 251 for (i = 0; i < 8; ++i)
michael@0 252 result = result * 256 + (codep[i] & 0xff);
michael@0 253 return result;
michael@0 254 }
michael@0 255
michael@0 256 static void
michael@0 257 settzname(void)
michael@0 258 {
michael@0 259 register struct state * const sp = lclptr;
michael@0 260 register int i;
michael@0 261
michael@0 262 tzname[0] = wildabbr;
michael@0 263 tzname[1] = wildabbr;
michael@0 264 #ifdef USG_COMPAT
michael@0 265 daylight = 0;
michael@0 266 timezone = 0;
michael@0 267 #endif /* defined USG_COMPAT */
michael@0 268 #ifdef ALTZONE
michael@0 269 altzone = 0;
michael@0 270 #endif /* defined ALTZONE */
michael@0 271 #ifdef ALL_STATE
michael@0 272 if (sp == NULL) {
michael@0 273 tzname[0] = tzname[1] = gmt;
michael@0 274 return;
michael@0 275 }
michael@0 276 #endif /* defined ALL_STATE */
michael@0 277 for (i = 0; i < sp->typecnt; ++i) {
michael@0 278 register const struct ttinfo * const ttisp = &sp->ttis[i];
michael@0 279
michael@0 280 tzname[ttisp->tt_isdst] =
michael@0 281 &sp->chars[ttisp->tt_abbrind];
michael@0 282 #ifdef USG_COMPAT
michael@0 283 if (ttisp->tt_isdst)
michael@0 284 daylight = 1;
michael@0 285 if (i == 0 || !ttisp->tt_isdst)
michael@0 286 timezone = -(ttisp->tt_gmtoff);
michael@0 287 #endif /* defined USG_COMPAT */
michael@0 288 #ifdef ALTZONE
michael@0 289 if (i == 0 || ttisp->tt_isdst)
michael@0 290 altzone = -(ttisp->tt_gmtoff);
michael@0 291 #endif /* defined ALTZONE */
michael@0 292 }
michael@0 293 /*
michael@0 294 ** And to get the latest zone names into tzname. . .
michael@0 295 */
michael@0 296 for (i = 0; i < sp->timecnt; ++i) {
michael@0 297 register const struct ttinfo * const ttisp =
michael@0 298 &sp->ttis[
michael@0 299 sp->types[i]];
michael@0 300
michael@0 301 tzname[ttisp->tt_isdst] =
michael@0 302 &sp->chars[ttisp->tt_abbrind];
michael@0 303 }
michael@0 304 /*
michael@0 305 ** Finally, scrub the abbreviations.
michael@0 306 ** First, replace bogus characters.
michael@0 307 */
michael@0 308 for (i = 0; i < sp->charcnt; ++i)
michael@0 309 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
michael@0 310 sp->chars[i] = TZ_ABBR_ERR_CHAR;
michael@0 311 /*
michael@0 312 ** Second, truncate long abbreviations.
michael@0 313 */
michael@0 314 for (i = 0; i < sp->typecnt; ++i) {
michael@0 315 register const struct ttinfo * const ttisp = &sp->ttis[i];
michael@0 316 register char * cp = &sp->chars[ttisp->tt_abbrind];
michael@0 317
michael@0 318 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
michael@0 319 strcmp(cp, GRANDPARENTED) != 0)
michael@0 320 *(cp + TZ_ABBR_MAX_LEN) = '\0';
michael@0 321 }
michael@0 322 }
michael@0 323
michael@0 324 static int
michael@0 325 differ_by_repeat(t1, t0)
michael@0 326 const time_t t1;
michael@0 327 const time_t t0;
michael@0 328 {
michael@0 329 if (TYPE_INTEGRAL(time_t) &&
michael@0 330 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
michael@0 331 return 0;
michael@0 332 return t1 - t0 == SECSPERREPEAT;
michael@0 333 }
michael@0 334
michael@0 335 static int
michael@0 336 tzload(name, sp, doextend)
michael@0 337 register const char * name;
michael@0 338 register struct state * const sp;
michael@0 339 register const int doextend;
michael@0 340 {
michael@0 341 register const char * p;
michael@0 342 register int i;
michael@0 343 register int fid;
michael@0 344 register int stored;
michael@0 345 register int nread;
michael@0 346 union {
michael@0 347 struct tzhead tzhead;
michael@0 348 char buf[2 * sizeof(struct tzhead) +
michael@0 349 2 * sizeof *sp +
michael@0 350 4 * TZ_MAX_TIMES];
michael@0 351 } u;
michael@0 352
michael@0 353 if (name == NULL && (name = TZDEFAULT) == NULL)
michael@0 354 return -1;
michael@0 355 {
michael@0 356 register int doaccess;
michael@0 357 /*
michael@0 358 ** Section 4.9.1 of the C standard says that
michael@0 359 ** "FILENAME_MAX expands to an integral constant expression
michael@0 360 ** that is the size needed for an array of char large enough
michael@0 361 ** to hold the longest file name string that the implementation
michael@0 362 ** guarantees can be opened."
michael@0 363 */
michael@0 364 char fullname[FILENAME_MAX + 1];
michael@0 365
michael@0 366 if (name[0] == ':')
michael@0 367 ++name;
michael@0 368 doaccess = name[0] == '/';
michael@0 369 if (!doaccess) {
michael@0 370 if ((p = TZDIR) == NULL)
michael@0 371 return -1;
michael@0 372 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
michael@0 373 return -1;
michael@0 374 (void) strcpy(fullname, p);
michael@0 375 (void) strcat(fullname, "/");
michael@0 376 (void) strcat(fullname, name);
michael@0 377 /*
michael@0 378 ** Set doaccess if '.' (as in "../") shows up in name.
michael@0 379 */
michael@0 380 if (strchr(name, '.') != NULL)
michael@0 381 doaccess = TRUE;
michael@0 382 name = fullname;
michael@0 383 }
michael@0 384 if (doaccess && access(name, R_OK) != 0)
michael@0 385 return -1;
michael@0 386 if ((fid = open(name, OPEN_MODE)) == -1)
michael@0 387 return -1;
michael@0 388 }
michael@0 389 nread = read(fid, u.buf, sizeof u.buf);
michael@0 390 if (close(fid) < 0 || nread <= 0)
michael@0 391 return -1;
michael@0 392 for (stored = 4; stored <= 8; stored *= 2) {
michael@0 393 int ttisstdcnt;
michael@0 394 int ttisgmtcnt;
michael@0 395
michael@0 396 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
michael@0 397 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
michael@0 398 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
michael@0 399 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
michael@0 400 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
michael@0 401 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
michael@0 402 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
michael@0 403 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
michael@0 404 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
michael@0 405 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
michael@0 406 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
michael@0 407 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
michael@0 408 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
michael@0 409 return -1;
michael@0 410 if (nread - (p - u.buf) <
michael@0 411 sp->timecnt * stored + /* ats */
michael@0 412 sp->timecnt + /* types */
michael@0 413 sp->typecnt * 6 + /* ttinfos */
michael@0 414 sp->charcnt + /* chars */
michael@0 415 sp->leapcnt * (stored + 4) + /* lsinfos */
michael@0 416 ttisstdcnt + /* ttisstds */
michael@0 417 ttisgmtcnt) /* ttisgmts */
michael@0 418 return -1;
michael@0 419 for (i = 0; i < sp->timecnt; ++i) {
michael@0 420 sp->ats[i] = (stored == 4) ?
michael@0 421 detzcode(p) : detzcode64(p);
michael@0 422 p += stored;
michael@0 423 }
michael@0 424 for (i = 0; i < sp->timecnt; ++i) {
michael@0 425 sp->types[i] = (unsigned char) *p++;
michael@0 426 if (sp->types[i] >= sp->typecnt)
michael@0 427 return -1;
michael@0 428 }
michael@0 429 for (i = 0; i < sp->typecnt; ++i) {
michael@0 430 register struct ttinfo * ttisp;
michael@0 431
michael@0 432 ttisp = &sp->ttis[i];
michael@0 433 ttisp->tt_gmtoff = detzcode(p);
michael@0 434 p += 4;
michael@0 435 ttisp->tt_isdst = (unsigned char) *p++;
michael@0 436 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
michael@0 437 return -1;
michael@0 438 ttisp->tt_abbrind = (unsigned char) *p++;
michael@0 439 if (ttisp->tt_abbrind < 0 ||
michael@0 440 ttisp->tt_abbrind > sp->charcnt)
michael@0 441 return -1;
michael@0 442 }
michael@0 443 for (i = 0; i < sp->charcnt; ++i)
michael@0 444 sp->chars[i] = *p++;
michael@0 445 sp->chars[i] = '\0'; /* ensure '\0' at end */
michael@0 446 for (i = 0; i < sp->leapcnt; ++i) {
michael@0 447 register struct lsinfo * lsisp;
michael@0 448
michael@0 449 lsisp = &sp->lsis[i];
michael@0 450 lsisp->ls_trans = (stored == 4) ?
michael@0 451 detzcode(p) : detzcode64(p);
michael@0 452 p += stored;
michael@0 453 lsisp->ls_corr = detzcode(p);
michael@0 454 p += 4;
michael@0 455 }
michael@0 456 for (i = 0; i < sp->typecnt; ++i) {
michael@0 457 register struct ttinfo * ttisp;
michael@0 458
michael@0 459 ttisp = &sp->ttis[i];
michael@0 460 if (ttisstdcnt == 0)
michael@0 461 ttisp->tt_ttisstd = FALSE;
michael@0 462 else {
michael@0 463 ttisp->tt_ttisstd = *p++;
michael@0 464 if (ttisp->tt_ttisstd != TRUE &&
michael@0 465 ttisp->tt_ttisstd != FALSE)
michael@0 466 return -1;
michael@0 467 }
michael@0 468 }
michael@0 469 for (i = 0; i < sp->typecnt; ++i) {
michael@0 470 register struct ttinfo * ttisp;
michael@0 471
michael@0 472 ttisp = &sp->ttis[i];
michael@0 473 if (ttisgmtcnt == 0)
michael@0 474 ttisp->tt_ttisgmt = FALSE;
michael@0 475 else {
michael@0 476 ttisp->tt_ttisgmt = *p++;
michael@0 477 if (ttisp->tt_ttisgmt != TRUE &&
michael@0 478 ttisp->tt_ttisgmt != FALSE)
michael@0 479 return -1;
michael@0 480 }
michael@0 481 }
michael@0 482 /*
michael@0 483 ** Out-of-sort ats should mean we're running on a
michael@0 484 ** signed time_t system but using a data file with
michael@0 485 ** unsigned values (or vice versa).
michael@0 486 */
michael@0 487 for (i = 0; i < sp->timecnt - 2; ++i)
michael@0 488 if (sp->ats[i] > sp->ats[i + 1]) {
michael@0 489 ++i;
michael@0 490 if (TYPE_SIGNED(time_t)) {
michael@0 491 /*
michael@0 492 ** Ignore the end (easy).
michael@0 493 */
michael@0 494 sp->timecnt = i;
michael@0 495 } else {
michael@0 496 /*
michael@0 497 ** Ignore the beginning (harder).
michael@0 498 */
michael@0 499 register int j;
michael@0 500
michael@0 501 for (j = 0; j + i < sp->timecnt; ++j) {
michael@0 502 sp->ats[j] = sp->ats[j + i];
michael@0 503 sp->types[j] = sp->types[j + i];
michael@0 504 }
michael@0 505 sp->timecnt = j;
michael@0 506 }
michael@0 507 break;
michael@0 508 }
michael@0 509 /*
michael@0 510 ** If this is an old file, we're done.
michael@0 511 */
michael@0 512 if (u.tzhead.tzh_version[0] == '\0')
michael@0 513 break;
michael@0 514 nread -= p - u.buf;
michael@0 515 for (i = 0; i < nread; ++i)
michael@0 516 u.buf[i] = p[i];
michael@0 517 /*
michael@0 518 ** If this is a narrow integer time_t system, we're done.
michael@0 519 */
michael@0 520 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
michael@0 521 break;
michael@0 522 }
michael@0 523 if (doextend && nread > 2 &&
michael@0 524 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
michael@0 525 sp->typecnt + 2 <= TZ_MAX_TYPES) {
michael@0 526 struct state ts;
michael@0 527 register int result;
michael@0 528
michael@0 529 u.buf[nread - 1] = '\0';
michael@0 530 result = tzparse(&u.buf[1], &ts, FALSE);
michael@0 531 if (result == 0 && ts.typecnt == 2 &&
michael@0 532 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
michael@0 533 for (i = 0; i < 2; ++i)
michael@0 534 ts.ttis[i].tt_abbrind +=
michael@0 535 sp->charcnt;
michael@0 536 for (i = 0; i < ts.charcnt; ++i)
michael@0 537 sp->chars[sp->charcnt++] =
michael@0 538 ts.chars[i];
michael@0 539 i = 0;
michael@0 540 while (i < ts.timecnt &&
michael@0 541 ts.ats[i] <=
michael@0 542 sp->ats[sp->timecnt - 1])
michael@0 543 ++i;
michael@0 544 while (i < ts.timecnt &&
michael@0 545 sp->timecnt < TZ_MAX_TIMES) {
michael@0 546 sp->ats[sp->timecnt] =
michael@0 547 ts.ats[i];
michael@0 548 sp->types[sp->timecnt] =
michael@0 549 sp->typecnt +
michael@0 550 ts.types[i];
michael@0 551 ++sp->timecnt;
michael@0 552 ++i;
michael@0 553 }
michael@0 554 sp->ttis[sp->typecnt++] = ts.ttis[0];
michael@0 555 sp->ttis[sp->typecnt++] = ts.ttis[1];
michael@0 556 }
michael@0 557 }
michael@0 558 sp->goback = sp->goahead = FALSE;
michael@0 559 if (sp->timecnt > 1) {
michael@0 560 for (i = 1; i < sp->timecnt; ++i)
michael@0 561 if (typesequiv(sp, sp->types[i], sp->types[0]) &&
michael@0 562 differ_by_repeat(sp->ats[i], sp->ats[0])) {
michael@0 563 sp->goback = TRUE;
michael@0 564 break;
michael@0 565 }
michael@0 566 for (i = sp->timecnt - 2; i >= 0; --i)
michael@0 567 if (typesequiv(sp, sp->types[sp->timecnt - 1],
michael@0 568 sp->types[i]) &&
michael@0 569 differ_by_repeat(sp->ats[sp->timecnt - 1],
michael@0 570 sp->ats[i])) {
michael@0 571 sp->goahead = TRUE;
michael@0 572 break;
michael@0 573 }
michael@0 574 }
michael@0 575 return 0;
michael@0 576 }
michael@0 577
michael@0 578 static int
michael@0 579 typesequiv(sp, a, b)
michael@0 580 const struct state * const sp;
michael@0 581 const int a;
michael@0 582 const int b;
michael@0 583 {
michael@0 584 register int result;
michael@0 585
michael@0 586 if (sp == NULL ||
michael@0 587 a < 0 || a >= sp->typecnt ||
michael@0 588 b < 0 || b >= sp->typecnt)
michael@0 589 result = FALSE;
michael@0 590 else {
michael@0 591 register const struct ttinfo * ap = &sp->ttis[a];
michael@0 592 register const struct ttinfo * bp = &sp->ttis[b];
michael@0 593 result = ap->tt_gmtoff == bp->tt_gmtoff &&
michael@0 594 ap->tt_isdst == bp->tt_isdst &&
michael@0 595 ap->tt_ttisstd == bp->tt_ttisstd &&
michael@0 596 ap->tt_ttisgmt == bp->tt_ttisgmt &&
michael@0 597 strcmp(&sp->chars[ap->tt_abbrind],
michael@0 598 &sp->chars[bp->tt_abbrind]) == 0;
michael@0 599 }
michael@0 600 return result;
michael@0 601 }
michael@0 602
michael@0 603 static const int mon_lengths[2][MONSPERYEAR] = {
michael@0 604 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
michael@0 605 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
michael@0 606 };
michael@0 607
michael@0 608 static const int year_lengths[2] = {
michael@0 609 DAYSPERNYEAR, DAYSPERLYEAR
michael@0 610 };
michael@0 611
michael@0 612 /*
michael@0 613 ** Given a pointer into a time zone string, scan until a character that is not
michael@0 614 ** a valid character in a zone name is found. Return a pointer to that
michael@0 615 ** character.
michael@0 616 */
michael@0 617
michael@0 618 static const char *
michael@0 619 getzname(strp)
michael@0 620 register const char * strp;
michael@0 621 {
michael@0 622 register char c;
michael@0 623
michael@0 624 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
michael@0 625 c != '+')
michael@0 626 ++strp;
michael@0 627 return strp;
michael@0 628 }
michael@0 629
michael@0 630 /*
michael@0 631 ** Given a pointer into an extended time zone string, scan until the ending
michael@0 632 ** delimiter of the zone name is located. Return a pointer to the delimiter.
michael@0 633 **
michael@0 634 ** As with getzname above, the legal character set is actually quite
michael@0 635 ** restricted, with other characters producing undefined results.
michael@0 636 ** We don't do any checking here; checking is done later in common-case code.
michael@0 637 */
michael@0 638
michael@0 639 static const char *
michael@0 640 getqzname(register const char *strp, const int delim)
michael@0 641 {
michael@0 642 register int c;
michael@0 643
michael@0 644 while ((c = *strp) != '\0' && c != delim)
michael@0 645 ++strp;
michael@0 646 return strp;
michael@0 647 }
michael@0 648
michael@0 649 /*
michael@0 650 ** Given a pointer into a time zone string, extract a number from that string.
michael@0 651 ** Check that the number is within a specified range; if it is not, return
michael@0 652 ** NULL.
michael@0 653 ** Otherwise, return a pointer to the first character not part of the number.
michael@0 654 */
michael@0 655
michael@0 656 static const char *
michael@0 657 getnum(strp, nump, min, max)
michael@0 658 register const char * strp;
michael@0 659 int * const nump;
michael@0 660 const int min;
michael@0 661 const int max;
michael@0 662 {
michael@0 663 register char c;
michael@0 664 register int num;
michael@0 665
michael@0 666 if (strp == NULL || !is_digit(c = *strp))
michael@0 667 return NULL;
michael@0 668 num = 0;
michael@0 669 do {
michael@0 670 num = num * 10 + (c - '0');
michael@0 671 if (num > max)
michael@0 672 return NULL; /* illegal value */
michael@0 673 c = *++strp;
michael@0 674 } while (is_digit(c));
michael@0 675 if (num < min)
michael@0 676 return NULL; /* illegal value */
michael@0 677 *nump = num;
michael@0 678 return strp;
michael@0 679 }
michael@0 680
michael@0 681 /*
michael@0 682 ** Given a pointer into a time zone string, extract a number of seconds,
michael@0 683 ** in hh[:mm[:ss]] form, from the string.
michael@0 684 ** If any error occurs, return NULL.
michael@0 685 ** Otherwise, return a pointer to the first character not part of the number
michael@0 686 ** of seconds.
michael@0 687 */
michael@0 688
michael@0 689 static const char *
michael@0 690 getsecs(strp, secsp)
michael@0 691 register const char * strp;
michael@0 692 long * const secsp;
michael@0 693 {
michael@0 694 int num;
michael@0 695
michael@0 696 /*
michael@0 697 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
michael@0 698 ** "M10.4.6/26", which does not conform to Posix,
michael@0 699 ** but which specifies the equivalent of
michael@0 700 ** ``02:00 on the first Sunday on or after 23 Oct''.
michael@0 701 */
michael@0 702 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
michael@0 703 if (strp == NULL)
michael@0 704 return NULL;
michael@0 705 *secsp = num * (long) SECSPERHOUR;
michael@0 706 if (*strp == ':') {
michael@0 707 ++strp;
michael@0 708 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
michael@0 709 if (strp == NULL)
michael@0 710 return NULL;
michael@0 711 *secsp += num * SECSPERMIN;
michael@0 712 if (*strp == ':') {
michael@0 713 ++strp;
michael@0 714 /* `SECSPERMIN' allows for leap seconds. */
michael@0 715 strp = getnum(strp, &num, 0, SECSPERMIN);
michael@0 716 if (strp == NULL)
michael@0 717 return NULL;
michael@0 718 *secsp += num;
michael@0 719 }
michael@0 720 }
michael@0 721 return strp;
michael@0 722 }
michael@0 723
michael@0 724 /*
michael@0 725 ** Given a pointer into a time zone string, extract an offset, in
michael@0 726 ** [+-]hh[:mm[:ss]] form, from the string.
michael@0 727 ** If any error occurs, return NULL.
michael@0 728 ** Otherwise, return a pointer to the first character not part of the time.
michael@0 729 */
michael@0 730
michael@0 731 static const char *
michael@0 732 getoffset(strp, offsetp)
michael@0 733 register const char * strp;
michael@0 734 long * const offsetp;
michael@0 735 {
michael@0 736 register int neg = 0;
michael@0 737
michael@0 738 if (*strp == '-') {
michael@0 739 neg = 1;
michael@0 740 ++strp;
michael@0 741 } else if (*strp == '+')
michael@0 742 ++strp;
michael@0 743 strp = getsecs(strp, offsetp);
michael@0 744 if (strp == NULL)
michael@0 745 return NULL; /* illegal time */
michael@0 746 if (neg)
michael@0 747 *offsetp = -*offsetp;
michael@0 748 return strp;
michael@0 749 }
michael@0 750
michael@0 751 /*
michael@0 752 ** Given a pointer into a time zone string, extract a rule in the form
michael@0 753 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
michael@0 754 ** If a valid rule is not found, return NULL.
michael@0 755 ** Otherwise, return a pointer to the first character not part of the rule.
michael@0 756 */
michael@0 757
michael@0 758 static const char *
michael@0 759 getrule(strp, rulep)
michael@0 760 const char * strp;
michael@0 761 register struct rule * const rulep;
michael@0 762 {
michael@0 763 if (*strp == 'J') {
michael@0 764 /*
michael@0 765 ** Julian day.
michael@0 766 */
michael@0 767 rulep->r_type = JULIAN_DAY;
michael@0 768 ++strp;
michael@0 769 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
michael@0 770 } else if (*strp == 'M') {
michael@0 771 /*
michael@0 772 ** Month, week, day.
michael@0 773 */
michael@0 774 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
michael@0 775 ++strp;
michael@0 776 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
michael@0 777 if (strp == NULL)
michael@0 778 return NULL;
michael@0 779 if (*strp++ != '.')
michael@0 780 return NULL;
michael@0 781 strp = getnum(strp, &rulep->r_week, 1, 5);
michael@0 782 if (strp == NULL)
michael@0 783 return NULL;
michael@0 784 if (*strp++ != '.')
michael@0 785 return NULL;
michael@0 786 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
michael@0 787 } else if (is_digit(*strp)) {
michael@0 788 /*
michael@0 789 ** Day of year.
michael@0 790 */
michael@0 791 rulep->r_type = DAY_OF_YEAR;
michael@0 792 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
michael@0 793 } else return NULL; /* invalid format */
michael@0 794 if (strp == NULL)
michael@0 795 return NULL;
michael@0 796 if (*strp == '/') {
michael@0 797 /*
michael@0 798 ** Time specified.
michael@0 799 */
michael@0 800 ++strp;
michael@0 801 strp = getsecs(strp, &rulep->r_time);
michael@0 802 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
michael@0 803 return strp;
michael@0 804 }
michael@0 805
michael@0 806 /*
michael@0 807 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
michael@0 808 ** year, a rule, and the offset from UTC at the time that rule takes effect,
michael@0 809 ** calculate the Epoch-relative time that rule takes effect.
michael@0 810 */
michael@0 811
michael@0 812 static time_t
michael@0 813 transtime(janfirst, year, rulep, offset)
michael@0 814 const time_t janfirst;
michael@0 815 const int year;
michael@0 816 register const struct rule * const rulep;
michael@0 817 const long offset;
michael@0 818 {
michael@0 819 register int leapyear;
michael@0 820 register time_t value;
michael@0 821 register int i;
michael@0 822 int d, m1, yy0, yy1, yy2, dow;
michael@0 823
michael@0 824 INITIALIZE(value);
michael@0 825 leapyear = isleap(year);
michael@0 826 switch (rulep->r_type) {
michael@0 827
michael@0 828 case JULIAN_DAY:
michael@0 829 /*
michael@0 830 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
michael@0 831 ** years.
michael@0 832 ** In non-leap years, or if the day number is 59 or less, just
michael@0 833 ** add SECSPERDAY times the day number-1 to the time of
michael@0 834 ** January 1, midnight, to get the day.
michael@0 835 */
michael@0 836 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
michael@0 837 if (leapyear && rulep->r_day >= 60)
michael@0 838 value += SECSPERDAY;
michael@0 839 break;
michael@0 840
michael@0 841 case DAY_OF_YEAR:
michael@0 842 /*
michael@0 843 ** n - day of year.
michael@0 844 ** Just add SECSPERDAY times the day number to the time of
michael@0 845 ** January 1, midnight, to get the day.
michael@0 846 */
michael@0 847 value = janfirst + rulep->r_day * SECSPERDAY;
michael@0 848 break;
michael@0 849
michael@0 850 case MONTH_NTH_DAY_OF_WEEK:
michael@0 851 /*
michael@0 852 ** Mm.n.d - nth "dth day" of month m.
michael@0 853 */
michael@0 854 value = janfirst;
michael@0 855 for (i = 0; i < rulep->r_mon - 1; ++i)
michael@0 856 value += mon_lengths[leapyear][i] * SECSPERDAY;
michael@0 857
michael@0 858 /*
michael@0 859 ** Use Zeller's Congruence to get day-of-week of first day of
michael@0 860 ** month.
michael@0 861 */
michael@0 862 m1 = (rulep->r_mon + 9) % 12 + 1;
michael@0 863 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
michael@0 864 yy1 = yy0 / 100;
michael@0 865 yy2 = yy0 % 100;
michael@0 866 dow = ((26 * m1 - 2) / 10 +
michael@0 867 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
michael@0 868 if (dow < 0)
michael@0 869 dow += DAYSPERWEEK;
michael@0 870
michael@0 871 /*
michael@0 872 ** "dow" is the day-of-week of the first day of the month. Get
michael@0 873 ** the day-of-month (zero-origin) of the first "dow" day of the
michael@0 874 ** month.
michael@0 875 */
michael@0 876 d = rulep->r_day - dow;
michael@0 877 if (d < 0)
michael@0 878 d += DAYSPERWEEK;
michael@0 879 for (i = 1; i < rulep->r_week; ++i) {
michael@0 880 if (d + DAYSPERWEEK >=
michael@0 881 mon_lengths[leapyear][rulep->r_mon - 1])
michael@0 882 break;
michael@0 883 d += DAYSPERWEEK;
michael@0 884 }
michael@0 885
michael@0 886 /*
michael@0 887 ** "d" is the day-of-month (zero-origin) of the day we want.
michael@0 888 */
michael@0 889 value += d * SECSPERDAY;
michael@0 890 break;
michael@0 891 }
michael@0 892
michael@0 893 /*
michael@0 894 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
michael@0 895 ** question. To get the Epoch-relative time of the specified local
michael@0 896 ** time on that day, add the transition time and the current offset
michael@0 897 ** from UTC.
michael@0 898 */
michael@0 899 return value + rulep->r_time + offset;
michael@0 900 }
michael@0 901
michael@0 902 /*
michael@0 903 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
michael@0 904 ** appropriate.
michael@0 905 */
michael@0 906
michael@0 907 static int
michael@0 908 tzparse(name, sp, lastditch)
michael@0 909 const char * name;
michael@0 910 register struct state * const sp;
michael@0 911 const int lastditch;
michael@0 912 {
michael@0 913 const char * stdname;
michael@0 914 const char * dstname;
michael@0 915 size_t stdlen;
michael@0 916 size_t dstlen;
michael@0 917 long stdoffset;
michael@0 918 long dstoffset;
michael@0 919 register time_t * atp;
michael@0 920 register unsigned char * typep;
michael@0 921 register char * cp;
michael@0 922 register int load_result;
michael@0 923
michael@0 924 INITIALIZE(dstname);
michael@0 925 stdname = name;
michael@0 926 if (lastditch) {
michael@0 927 stdlen = strlen(name); /* length of standard zone name */
michael@0 928 name += stdlen;
michael@0 929 if (stdlen >= sizeof sp->chars)
michael@0 930 stdlen = (sizeof sp->chars) - 1;
michael@0 931 stdoffset = 0;
michael@0 932 } else {
michael@0 933 if (*name == '<') {
michael@0 934 name++;
michael@0 935 stdname = name;
michael@0 936 name = getqzname(name, '>');
michael@0 937 if (*name != '>')
michael@0 938 return (-1);
michael@0 939 stdlen = name - stdname;
michael@0 940 name++;
michael@0 941 } else {
michael@0 942 name = getzname(name);
michael@0 943 stdlen = name - stdname;
michael@0 944 }
michael@0 945 if (*name == '\0')
michael@0 946 return -1;
michael@0 947 name = getoffset(name, &stdoffset);
michael@0 948 if (name == NULL)
michael@0 949 return -1;
michael@0 950 }
michael@0 951 load_result = tzload(TZDEFRULES, sp, FALSE);
michael@0 952 if (load_result != 0)
michael@0 953 sp->leapcnt = 0; /* so, we're off a little */
michael@0 954 if (*name != '\0') {
michael@0 955 if (*name == '<') {
michael@0 956 dstname = ++name;
michael@0 957 name = getqzname(name, '>');
michael@0 958 if (*name != '>')
michael@0 959 return -1;
michael@0 960 dstlen = name - dstname;
michael@0 961 name++;
michael@0 962 } else {
michael@0 963 dstname = name;
michael@0 964 name = getzname(name);
michael@0 965 dstlen = name - dstname; /* length of DST zone name */
michael@0 966 }
michael@0 967 if (*name != '\0' && *name != ',' && *name != ';') {
michael@0 968 name = getoffset(name, &dstoffset);
michael@0 969 if (name == NULL)
michael@0 970 return -1;
michael@0 971 } else dstoffset = stdoffset - SECSPERHOUR;
michael@0 972 if (*name == '\0' && load_result != 0)
michael@0 973 name = TZDEFRULESTRING;
michael@0 974 if (*name == ',' || *name == ';') {
michael@0 975 struct rule start;
michael@0 976 struct rule end;
michael@0 977 register int year;
michael@0 978 register time_t janfirst;
michael@0 979 time_t starttime;
michael@0 980 time_t endtime;
michael@0 981
michael@0 982 ++name;
michael@0 983 if ((name = getrule(name, &start)) == NULL)
michael@0 984 return -1;
michael@0 985 if (*name++ != ',')
michael@0 986 return -1;
michael@0 987 if ((name = getrule(name, &end)) == NULL)
michael@0 988 return -1;
michael@0 989 if (*name != '\0')
michael@0 990 return -1;
michael@0 991 sp->typecnt = 2; /* standard time and DST */
michael@0 992 /*
michael@0 993 ** Two transitions per year, from EPOCH_YEAR forward.
michael@0 994 */
michael@0 995 sp->ttis[0].tt_gmtoff = -dstoffset;
michael@0 996 sp->ttis[0].tt_isdst = 1;
michael@0 997 sp->ttis[0].tt_abbrind = stdlen + 1;
michael@0 998 sp->ttis[1].tt_gmtoff = -stdoffset;
michael@0 999 sp->ttis[1].tt_isdst = 0;
michael@0 1000 sp->ttis[1].tt_abbrind = 0;
michael@0 1001 atp = sp->ats;
michael@0 1002 typep = sp->types;
michael@0 1003 janfirst = 0;
michael@0 1004 sp->timecnt = 0;
michael@0 1005 for (year = EPOCH_YEAR;
michael@0 1006 sp->timecnt + 2 <= TZ_MAX_TIMES;
michael@0 1007 ++year) {
michael@0 1008 time_t newfirst;
michael@0 1009
michael@0 1010 starttime = transtime(janfirst, year, &start,
michael@0 1011 stdoffset);
michael@0 1012 endtime = transtime(janfirst, year, &end,
michael@0 1013 dstoffset);
michael@0 1014 if (starttime > endtime) {
michael@0 1015 *atp++ = endtime;
michael@0 1016 *typep++ = 1; /* DST ends */
michael@0 1017 *atp++ = starttime;
michael@0 1018 *typep++ = 0; /* DST begins */
michael@0 1019 } else {
michael@0 1020 *atp++ = starttime;
michael@0 1021 *typep++ = 0; /* DST begins */
michael@0 1022 *atp++ = endtime;
michael@0 1023 *typep++ = 1; /* DST ends */
michael@0 1024 }
michael@0 1025 sp->timecnt += 2;
michael@0 1026 newfirst = janfirst;
michael@0 1027 newfirst += year_lengths[isleap(year)] *
michael@0 1028 SECSPERDAY;
michael@0 1029 if (newfirst <= janfirst)
michael@0 1030 break;
michael@0 1031 janfirst = newfirst;
michael@0 1032 }
michael@0 1033 } else {
michael@0 1034 register long theirstdoffset;
michael@0 1035 register long theirdstoffset;
michael@0 1036 register long theiroffset;
michael@0 1037 register int isdst;
michael@0 1038 register int i;
michael@0 1039 register int j;
michael@0 1040
michael@0 1041 if (*name != '\0')
michael@0 1042 return -1;
michael@0 1043 /*
michael@0 1044 ** Initial values of theirstdoffset and theirdstoffset.
michael@0 1045 */
michael@0 1046 theirstdoffset = 0;
michael@0 1047 for (i = 0; i < sp->timecnt; ++i) {
michael@0 1048 j = sp->types[i];
michael@0 1049 if (!sp->ttis[j].tt_isdst) {
michael@0 1050 theirstdoffset =
michael@0 1051 -sp->ttis[j].tt_gmtoff;
michael@0 1052 break;
michael@0 1053 }
michael@0 1054 }
michael@0 1055 theirdstoffset = 0;
michael@0 1056 for (i = 0; i < sp->timecnt; ++i) {
michael@0 1057 j = sp->types[i];
michael@0 1058 if (sp->ttis[j].tt_isdst) {
michael@0 1059 theirdstoffset =
michael@0 1060 -sp->ttis[j].tt_gmtoff;
michael@0 1061 break;
michael@0 1062 }
michael@0 1063 }
michael@0 1064 /*
michael@0 1065 ** Initially we're assumed to be in standard time.
michael@0 1066 */
michael@0 1067 isdst = FALSE;
michael@0 1068 theiroffset = theirstdoffset;
michael@0 1069 /*
michael@0 1070 ** Now juggle transition times and types
michael@0 1071 ** tracking offsets as you do.
michael@0 1072 */
michael@0 1073 for (i = 0; i < sp->timecnt; ++i) {
michael@0 1074 j = sp->types[i];
michael@0 1075 sp->types[i] = sp->ttis[j].tt_isdst;
michael@0 1076 if (sp->ttis[j].tt_ttisgmt) {
michael@0 1077 /* No adjustment to transition time */
michael@0 1078 } else {
michael@0 1079 /*
michael@0 1080 ** If summer time is in effect, and the
michael@0 1081 ** transition time was not specified as
michael@0 1082 ** standard time, add the summer time
michael@0 1083 ** offset to the transition time;
michael@0 1084 ** otherwise, add the standard time
michael@0 1085 ** offset to the transition time.
michael@0 1086 */
michael@0 1087 /*
michael@0 1088 ** Transitions from DST to DDST
michael@0 1089 ** will effectively disappear since
michael@0 1090 ** POSIX provides for only one DST
michael@0 1091 ** offset.
michael@0 1092 */
michael@0 1093 if (isdst && !sp->ttis[j].tt_ttisstd) {
michael@0 1094 sp->ats[i] += dstoffset -
michael@0 1095 theirdstoffset;
michael@0 1096 } else {
michael@0 1097 sp->ats[i] += stdoffset -
michael@0 1098 theirstdoffset;
michael@0 1099 }
michael@0 1100 }
michael@0 1101 theiroffset = -sp->ttis[j].tt_gmtoff;
michael@0 1102 if (sp->ttis[j].tt_isdst)
michael@0 1103 theirdstoffset = theiroffset;
michael@0 1104 else theirstdoffset = theiroffset;
michael@0 1105 }
michael@0 1106 /*
michael@0 1107 ** Finally, fill in ttis.
michael@0 1108 ** ttisstd and ttisgmt need not be handled.
michael@0 1109 */
michael@0 1110 sp->ttis[0].tt_gmtoff = -stdoffset;
michael@0 1111 sp->ttis[0].tt_isdst = FALSE;
michael@0 1112 sp->ttis[0].tt_abbrind = 0;
michael@0 1113 sp->ttis[1].tt_gmtoff = -dstoffset;
michael@0 1114 sp->ttis[1].tt_isdst = TRUE;
michael@0 1115 sp->ttis[1].tt_abbrind = stdlen + 1;
michael@0 1116 sp->typecnt = 2;
michael@0 1117 }
michael@0 1118 } else {
michael@0 1119 dstlen = 0;
michael@0 1120 sp->typecnt = 1; /* only standard time */
michael@0 1121 sp->timecnt = 0;
michael@0 1122 sp->ttis[0].tt_gmtoff = -stdoffset;
michael@0 1123 sp->ttis[0].tt_isdst = 0;
michael@0 1124 sp->ttis[0].tt_abbrind = 0;
michael@0 1125 }
michael@0 1126 sp->charcnt = stdlen + 1;
michael@0 1127 if (dstlen != 0)
michael@0 1128 sp->charcnt += dstlen + 1;
michael@0 1129 if ((size_t) sp->charcnt > sizeof sp->chars)
michael@0 1130 return -1;
michael@0 1131 cp = sp->chars;
michael@0 1132 (void) strncpy(cp, stdname, stdlen);
michael@0 1133 cp += stdlen;
michael@0 1134 *cp++ = '\0';
michael@0 1135 if (dstlen != 0) {
michael@0 1136 (void) strncpy(cp, dstname, dstlen);
michael@0 1137 *(cp + dstlen) = '\0';
michael@0 1138 }
michael@0 1139 return 0;
michael@0 1140 }
michael@0 1141
michael@0 1142 static void
michael@0 1143 gmtload(sp)
michael@0 1144 struct state * const sp;
michael@0 1145 {
michael@0 1146 if (tzload(gmt, sp, TRUE) != 0)
michael@0 1147 (void) tzparse(gmt, sp, TRUE);
michael@0 1148 }
michael@0 1149
michael@0 1150 #ifndef STD_INSPIRED
michael@0 1151 /*
michael@0 1152 ** A non-static declaration of tzsetwall in a system header file
michael@0 1153 ** may cause a warning about this upcoming static declaration...
michael@0 1154 */
michael@0 1155 static
michael@0 1156 #endif /* !defined STD_INSPIRED */
michael@0 1157 void
michael@0 1158 tzsetwall(void)
michael@0 1159 {
michael@0 1160 if (lcl_is_set < 0)
michael@0 1161 return;
michael@0 1162 lcl_is_set = -1;
michael@0 1163
michael@0 1164 #ifdef ALL_STATE
michael@0 1165 if (lclptr == NULL) {
michael@0 1166 lclptr = (struct state *) malloc(sizeof *lclptr);
michael@0 1167 if (lclptr == NULL) {
michael@0 1168 settzname(); /* all we can do */
michael@0 1169 return;
michael@0 1170 }
michael@0 1171 }
michael@0 1172 #endif /* defined ALL_STATE */
michael@0 1173 if (tzload((char *) NULL, lclptr, TRUE) != 0)
michael@0 1174 gmtload(lclptr);
michael@0 1175 settzname();
michael@0 1176 }
michael@0 1177
michael@0 1178 void
michael@0 1179 tzset(void)
michael@0 1180 {
michael@0 1181 register const char * name;
michael@0 1182
michael@0 1183 name = getenv("TZ");
michael@0 1184 if (name == NULL) {
michael@0 1185 tzsetwall();
michael@0 1186 return;
michael@0 1187 }
michael@0 1188
michael@0 1189 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
michael@0 1190 return;
michael@0 1191 lcl_is_set = strlen(name) < sizeof lcl_TZname;
michael@0 1192 if (lcl_is_set)
michael@0 1193 (void) strcpy(lcl_TZname, name);
michael@0 1194
michael@0 1195 #ifdef ALL_STATE
michael@0 1196 if (lclptr == NULL) {
michael@0 1197 lclptr = (struct state *) malloc(sizeof *lclptr);
michael@0 1198 if (lclptr == NULL) {
michael@0 1199 settzname(); /* all we can do */
michael@0 1200 return;
michael@0 1201 }
michael@0 1202 }
michael@0 1203 #endif /* defined ALL_STATE */
michael@0 1204 if (*name == '\0') {
michael@0 1205 /*
michael@0 1206 ** User wants it fast rather than right.
michael@0 1207 */
michael@0 1208 lclptr->leapcnt = 0; /* so, we're off a little */
michael@0 1209 lclptr->timecnt = 0;
michael@0 1210 lclptr->typecnt = 0;
michael@0 1211 lclptr->ttis[0].tt_isdst = 0;
michael@0 1212 lclptr->ttis[0].tt_gmtoff = 0;
michael@0 1213 lclptr->ttis[0].tt_abbrind = 0;
michael@0 1214 (void) strcpy(lclptr->chars, gmt);
michael@0 1215 } else if (tzload(name, lclptr, TRUE) != 0)
michael@0 1216 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
michael@0 1217 (void) gmtload(lclptr);
michael@0 1218 settzname();
michael@0 1219 }
michael@0 1220
michael@0 1221 /*
michael@0 1222 ** The easy way to behave "as if no library function calls" localtime
michael@0 1223 ** is to not call it--so we drop its guts into "localsub", which can be
michael@0 1224 ** freely called. (And no, the PANS doesn't require the above behavior--
michael@0 1225 ** but it *is* desirable.)
michael@0 1226 **
michael@0 1227 ** The unused offset argument is for the benefit of mktime variants.
michael@0 1228 */
michael@0 1229
michael@0 1230 /*ARGSUSED*/
michael@0 1231 static struct tm *
michael@0 1232 localsub(timep, offset, tmp)
michael@0 1233 const time_t * const timep;
michael@0 1234 const long offset;
michael@0 1235 struct tm * const tmp;
michael@0 1236 {
michael@0 1237 register struct state * sp;
michael@0 1238 register const struct ttinfo * ttisp;
michael@0 1239 register int i;
michael@0 1240 register struct tm * result;
michael@0 1241 const time_t t = *timep;
michael@0 1242
michael@0 1243 sp = lclptr;
michael@0 1244 #ifdef ALL_STATE
michael@0 1245 if (sp == NULL)
michael@0 1246 return gmtsub(timep, offset, tmp);
michael@0 1247 #endif /* defined ALL_STATE */
michael@0 1248 if ((sp->goback && t < sp->ats[0]) ||
michael@0 1249 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
michael@0 1250 time_t newt = t;
michael@0 1251 register time_t seconds;
michael@0 1252 register time_t tcycles;
michael@0 1253 register int_fast64_t icycles;
michael@0 1254
michael@0 1255 if (t < sp->ats[0])
michael@0 1256 seconds = sp->ats[0] - t;
michael@0 1257 else seconds = t - sp->ats[sp->timecnt - 1];
michael@0 1258 --seconds;
michael@0 1259 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
michael@0 1260 ++tcycles;
michael@0 1261 icycles = tcycles;
michael@0 1262 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
michael@0 1263 return NULL;
michael@0 1264 seconds = icycles;
michael@0 1265 seconds *= YEARSPERREPEAT;
michael@0 1266 seconds *= AVGSECSPERYEAR;
michael@0 1267 if (t < sp->ats[0])
michael@0 1268 newt += seconds;
michael@0 1269 else newt -= seconds;
michael@0 1270 if (newt < sp->ats[0] ||
michael@0 1271 newt > sp->ats[sp->timecnt - 1])
michael@0 1272 return NULL; /* "cannot happen" */
michael@0 1273 result = localsub(&newt, offset, tmp);
michael@0 1274 if (result == tmp) {
michael@0 1275 register time_t newy;
michael@0 1276
michael@0 1277 newy = tmp->tm_year;
michael@0 1278 if (t < sp->ats[0])
michael@0 1279 newy -= icycles * YEARSPERREPEAT;
michael@0 1280 else newy += icycles * YEARSPERREPEAT;
michael@0 1281 tmp->tm_year = newy;
michael@0 1282 if (tmp->tm_year != newy)
michael@0 1283 return NULL;
michael@0 1284 }
michael@0 1285 return result;
michael@0 1286 }
michael@0 1287 if (sp->timecnt == 0 || t < sp->ats[0]) {
michael@0 1288 i = 0;
michael@0 1289 while (sp->ttis[i].tt_isdst)
michael@0 1290 if (++i >= sp->typecnt) {
michael@0 1291 i = 0;
michael@0 1292 break;
michael@0 1293 }
michael@0 1294 } else {
michael@0 1295 register int lo = 1;
michael@0 1296 register int hi = sp->timecnt;
michael@0 1297
michael@0 1298 while (lo < hi) {
michael@0 1299 register int mid = (lo + hi) >> 1;
michael@0 1300
michael@0 1301 if (t < sp->ats[mid])
michael@0 1302 hi = mid;
michael@0 1303 else lo = mid + 1;
michael@0 1304 }
michael@0 1305 i = (int) sp->types[lo - 1];
michael@0 1306 }
michael@0 1307 ttisp = &sp->ttis[i];
michael@0 1308 /*
michael@0 1309 ** To get (wrong) behavior that's compatible with System V Release 2.0
michael@0 1310 ** you'd replace the statement below with
michael@0 1311 ** t += ttisp->tt_gmtoff;
michael@0 1312 ** timesub(&t, 0L, sp, tmp);
michael@0 1313 */
michael@0 1314 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
michael@0 1315 tmp->tm_isdst = ttisp->tt_isdst;
michael@0 1316 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
michael@0 1317 #ifdef TM_ZONE
michael@0 1318 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
michael@0 1319 #endif /* defined TM_ZONE */
michael@0 1320 return result;
michael@0 1321 }
michael@0 1322
michael@0 1323 struct tm *
michael@0 1324 localtime(timep)
michael@0 1325 const time_t * const timep;
michael@0 1326 {
michael@0 1327 tzset();
michael@0 1328 return localsub(timep, 0L, &tm);
michael@0 1329 }
michael@0 1330
michael@0 1331 /*
michael@0 1332 ** Re-entrant version of localtime.
michael@0 1333 */
michael@0 1334
michael@0 1335 struct tm *
michael@0 1336 localtime_r(timep, tmp)
michael@0 1337 const time_t * const timep;
michael@0 1338 struct tm * tmp;
michael@0 1339 {
michael@0 1340 return localsub(timep, 0L, tmp);
michael@0 1341 }
michael@0 1342
michael@0 1343 /*
michael@0 1344 ** gmtsub is to gmtime as localsub is to localtime.
michael@0 1345 */
michael@0 1346
michael@0 1347 static struct tm *
michael@0 1348 gmtsub(timep, offset, tmp)
michael@0 1349 const time_t * const timep;
michael@0 1350 const long offset;
michael@0 1351 struct tm * const tmp;
michael@0 1352 {
michael@0 1353 register struct tm * result;
michael@0 1354
michael@0 1355 if (!gmt_is_set) {
michael@0 1356 gmt_is_set = TRUE;
michael@0 1357 #ifdef ALL_STATE
michael@0 1358 gmtptr = (struct state *) malloc(sizeof *gmtptr);
michael@0 1359 if (gmtptr != NULL)
michael@0 1360 #endif /* defined ALL_STATE */
michael@0 1361 gmtload(gmtptr);
michael@0 1362 }
michael@0 1363 result = timesub(timep, offset, gmtptr, tmp);
michael@0 1364 #ifdef TM_ZONE
michael@0 1365 /*
michael@0 1366 ** Could get fancy here and deliver something such as
michael@0 1367 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
michael@0 1368 ** but this is no time for a treasure hunt.
michael@0 1369 */
michael@0 1370 if (offset != 0)
michael@0 1371 tmp->TM_ZONE = wildabbr;
michael@0 1372 else {
michael@0 1373 #ifdef ALL_STATE
michael@0 1374 if (gmtptr == NULL)
michael@0 1375 tmp->TM_ZONE = gmt;
michael@0 1376 else tmp->TM_ZONE = gmtptr->chars;
michael@0 1377 #endif /* defined ALL_STATE */
michael@0 1378 #ifndef ALL_STATE
michael@0 1379 tmp->TM_ZONE = gmtptr->chars;
michael@0 1380 #endif /* State Farm */
michael@0 1381 }
michael@0 1382 #endif /* defined TM_ZONE */
michael@0 1383 return result;
michael@0 1384 }
michael@0 1385
michael@0 1386 struct tm *
michael@0 1387 gmtime(timep)
michael@0 1388 const time_t * const timep;
michael@0 1389 {
michael@0 1390 return gmtsub(timep, 0L, &tm);
michael@0 1391 }
michael@0 1392
michael@0 1393 /*
michael@0 1394 * Re-entrant version of gmtime.
michael@0 1395 */
michael@0 1396
michael@0 1397 struct tm *
michael@0 1398 gmtime_r(timep, tmp)
michael@0 1399 const time_t * const timep;
michael@0 1400 struct tm * tmp;
michael@0 1401 {
michael@0 1402 return gmtsub(timep, 0L, tmp);
michael@0 1403 }
michael@0 1404
michael@0 1405 #ifdef STD_INSPIRED
michael@0 1406
michael@0 1407 struct tm *
michael@0 1408 offtime(timep, offset)
michael@0 1409 const time_t * const timep;
michael@0 1410 const long offset;
michael@0 1411 {
michael@0 1412 return gmtsub(timep, offset, &tm);
michael@0 1413 }
michael@0 1414
michael@0 1415 #endif /* defined STD_INSPIRED */
michael@0 1416
michael@0 1417 /*
michael@0 1418 ** Return the number of leap years through the end of the given year
michael@0 1419 ** where, to make the math easy, the answer for year zero is defined as zero.
michael@0 1420 */
michael@0 1421
michael@0 1422 static int
michael@0 1423 leaps_thru_end_of(y)
michael@0 1424 register const int y;
michael@0 1425 {
michael@0 1426 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
michael@0 1427 -(leaps_thru_end_of(-(y + 1)) + 1);
michael@0 1428 }
michael@0 1429
michael@0 1430 static struct tm *
michael@0 1431 timesub(timep, offset, sp, tmp)
michael@0 1432 const time_t * const timep;
michael@0 1433 const long offset;
michael@0 1434 register const struct state * const sp;
michael@0 1435 register struct tm * const tmp;
michael@0 1436 {
michael@0 1437 register const struct lsinfo * lp;
michael@0 1438 register time_t tdays;
michael@0 1439 register int idays; /* unsigned would be so 2003 */
michael@0 1440 register long rem;
michael@0 1441 int y;
michael@0 1442 register const int * ip;
michael@0 1443 register long corr;
michael@0 1444 register int hit;
michael@0 1445 register int i;
michael@0 1446
michael@0 1447 corr = 0;
michael@0 1448 hit = 0;
michael@0 1449 #ifdef ALL_STATE
michael@0 1450 i = (sp == NULL) ? 0 : sp->leapcnt;
michael@0 1451 #endif /* defined ALL_STATE */
michael@0 1452 #ifndef ALL_STATE
michael@0 1453 i = sp->leapcnt;
michael@0 1454 #endif /* State Farm */
michael@0 1455 while (--i >= 0) {
michael@0 1456 lp = &sp->lsis[i];
michael@0 1457 if (*timep >= lp->ls_trans) {
michael@0 1458 if (*timep == lp->ls_trans) {
michael@0 1459 hit = ((i == 0 && lp->ls_corr > 0) ||
michael@0 1460 lp->ls_corr > sp->lsis[i - 1].ls_corr);
michael@0 1461 if (hit)
michael@0 1462 while (i > 0 &&
michael@0 1463 sp->lsis[i].ls_trans ==
michael@0 1464 sp->lsis[i - 1].ls_trans + 1 &&
michael@0 1465 sp->lsis[i].ls_corr ==
michael@0 1466 sp->lsis[i - 1].ls_corr + 1) {
michael@0 1467 ++hit;
michael@0 1468 --i;
michael@0 1469 }
michael@0 1470 }
michael@0 1471 corr = lp->ls_corr;
michael@0 1472 break;
michael@0 1473 }
michael@0 1474 }
michael@0 1475 y = EPOCH_YEAR;
michael@0 1476 tdays = *timep / SECSPERDAY;
michael@0 1477 rem = *timep - tdays * SECSPERDAY;
michael@0 1478 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
michael@0 1479 int newy;
michael@0 1480 register time_t tdelta;
michael@0 1481 register int idelta;
michael@0 1482 register int leapdays;
michael@0 1483
michael@0 1484 tdelta = tdays / DAYSPERLYEAR;
michael@0 1485 idelta = tdelta;
michael@0 1486 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
michael@0 1487 return NULL;
michael@0 1488 if (idelta == 0)
michael@0 1489 idelta = (tdays < 0) ? -1 : 1;
michael@0 1490 newy = y;
michael@0 1491 if (increment_overflow(&newy, idelta))
michael@0 1492 return NULL;
michael@0 1493 leapdays = leaps_thru_end_of(newy - 1) -
michael@0 1494 leaps_thru_end_of(y - 1);
michael@0 1495 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
michael@0 1496 tdays -= leapdays;
michael@0 1497 y = newy;
michael@0 1498 }
michael@0 1499 {
michael@0 1500 register long seconds;
michael@0 1501
michael@0 1502 seconds = tdays * SECSPERDAY + 0.5;
michael@0 1503 tdays = seconds / SECSPERDAY;
michael@0 1504 rem += seconds - tdays * SECSPERDAY;
michael@0 1505 }
michael@0 1506 /*
michael@0 1507 ** Given the range, we can now fearlessly cast...
michael@0 1508 */
michael@0 1509 idays = tdays;
michael@0 1510 rem += offset - corr;
michael@0 1511 while (rem < 0) {
michael@0 1512 rem += SECSPERDAY;
michael@0 1513 --idays;
michael@0 1514 }
michael@0 1515 while (rem >= SECSPERDAY) {
michael@0 1516 rem -= SECSPERDAY;
michael@0 1517 ++idays;
michael@0 1518 }
michael@0 1519 while (idays < 0) {
michael@0 1520 if (increment_overflow(&y, -1))
michael@0 1521 return NULL;
michael@0 1522 idays += year_lengths[isleap(y)];
michael@0 1523 }
michael@0 1524 while (idays >= year_lengths[isleap(y)]) {
michael@0 1525 idays -= year_lengths[isleap(y)];
michael@0 1526 if (increment_overflow(&y, 1))
michael@0 1527 return NULL;
michael@0 1528 }
michael@0 1529 tmp->tm_year = y;
michael@0 1530 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
michael@0 1531 return NULL;
michael@0 1532 tmp->tm_yday = idays;
michael@0 1533 /*
michael@0 1534 ** The "extra" mods below avoid overflow problems.
michael@0 1535 */
michael@0 1536 tmp->tm_wday = EPOCH_WDAY +
michael@0 1537 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
michael@0 1538 (DAYSPERNYEAR % DAYSPERWEEK) +
michael@0 1539 leaps_thru_end_of(y - 1) -
michael@0 1540 leaps_thru_end_of(EPOCH_YEAR - 1) +
michael@0 1541 idays;
michael@0 1542 tmp->tm_wday %= DAYSPERWEEK;
michael@0 1543 if (tmp->tm_wday < 0)
michael@0 1544 tmp->tm_wday += DAYSPERWEEK;
michael@0 1545 tmp->tm_hour = (int) (rem / SECSPERHOUR);
michael@0 1546 rem %= SECSPERHOUR;
michael@0 1547 tmp->tm_min = (int) (rem / SECSPERMIN);
michael@0 1548 /*
michael@0 1549 ** A positive leap second requires a special
michael@0 1550 ** representation. This uses "... ??:59:60" et seq.
michael@0 1551 */
michael@0 1552 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
michael@0 1553 ip = mon_lengths[isleap(y)];
michael@0 1554 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
michael@0 1555 idays -= ip[tmp->tm_mon];
michael@0 1556 tmp->tm_mday = (int) (idays + 1);
michael@0 1557 tmp->tm_isdst = 0;
michael@0 1558 #ifdef TM_GMTOFF
michael@0 1559 tmp->TM_GMTOFF = offset;
michael@0 1560 #endif /* defined TM_GMTOFF */
michael@0 1561 return tmp;
michael@0 1562 }
michael@0 1563
michael@0 1564 char *
michael@0 1565 ctime(timep)
michael@0 1566 const time_t * const timep;
michael@0 1567 {
michael@0 1568 /*
michael@0 1569 ** Section 4.12.3.2 of X3.159-1989 requires that
michael@0 1570 ** The ctime function converts the calendar time pointed to by timer
michael@0 1571 ** to local time in the form of a string. It is equivalent to
michael@0 1572 ** asctime(localtime(timer))
michael@0 1573 */
michael@0 1574 return asctime(localtime(timep));
michael@0 1575 }
michael@0 1576
michael@0 1577 char *
michael@0 1578 ctime_r(timep, buf)
michael@0 1579 const time_t * const timep;
michael@0 1580 char * buf;
michael@0 1581 {
michael@0 1582 struct tm mytm;
michael@0 1583
michael@0 1584 return asctime_r(localtime_r(timep, &mytm), buf);
michael@0 1585 }
michael@0 1586
michael@0 1587 /*
michael@0 1588 ** Adapted from code provided by Robert Elz, who writes:
michael@0 1589 ** The "best" way to do mktime I think is based on an idea of Bob
michael@0 1590 ** Kridle's (so its said...) from a long time ago.
michael@0 1591 ** It does a binary search of the time_t space. Since time_t's are
michael@0 1592 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
michael@0 1593 ** would still be very reasonable).
michael@0 1594 */
michael@0 1595
michael@0 1596 #ifndef WRONG
michael@0 1597 #define WRONG (-1)
michael@0 1598 #endif /* !defined WRONG */
michael@0 1599
michael@0 1600 /*
michael@0 1601 ** Simplified normalize logic courtesy Paul Eggert.
michael@0 1602 */
michael@0 1603
michael@0 1604 static int
michael@0 1605 increment_overflow(number, delta)
michael@0 1606 int * number;
michael@0 1607 int delta;
michael@0 1608 {
michael@0 1609 int number0;
michael@0 1610
michael@0 1611 number0 = *number;
michael@0 1612 *number += delta;
michael@0 1613 return (*number < number0) != (delta < 0);
michael@0 1614 }
michael@0 1615
michael@0 1616 static int
michael@0 1617 long_increment_overflow(number, delta)
michael@0 1618 long * number;
michael@0 1619 int delta;
michael@0 1620 {
michael@0 1621 long number0;
michael@0 1622
michael@0 1623 number0 = *number;
michael@0 1624 *number += delta;
michael@0 1625 return (*number < number0) != (delta < 0);
michael@0 1626 }
michael@0 1627
michael@0 1628 static int
michael@0 1629 normalize_overflow(tensptr, unitsptr, base)
michael@0 1630 int * const tensptr;
michael@0 1631 int * const unitsptr;
michael@0 1632 const int base;
michael@0 1633 {
michael@0 1634 register int tensdelta;
michael@0 1635
michael@0 1636 tensdelta = (*unitsptr >= 0) ?
michael@0 1637 (*unitsptr / base) :
michael@0 1638 (-1 - (-1 - *unitsptr) / base);
michael@0 1639 *unitsptr -= tensdelta * base;
michael@0 1640 return increment_overflow(tensptr, tensdelta);
michael@0 1641 }
michael@0 1642
michael@0 1643 static int
michael@0 1644 long_normalize_overflow(tensptr, unitsptr, base)
michael@0 1645 long * const tensptr;
michael@0 1646 int * const unitsptr;
michael@0 1647 const int base;
michael@0 1648 {
michael@0 1649 register int tensdelta;
michael@0 1650
michael@0 1651 tensdelta = (*unitsptr >= 0) ?
michael@0 1652 (*unitsptr / base) :
michael@0 1653 (-1 - (-1 - *unitsptr) / base);
michael@0 1654 *unitsptr -= tensdelta * base;
michael@0 1655 return long_increment_overflow(tensptr, tensdelta);
michael@0 1656 }
michael@0 1657
michael@0 1658 static int
michael@0 1659 tmcomp(atmp, btmp)
michael@0 1660 register const struct tm * const atmp;
michael@0 1661 register const struct tm * const btmp;
michael@0 1662 {
michael@0 1663 register int result;
michael@0 1664
michael@0 1665 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
michael@0 1666 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
michael@0 1667 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
michael@0 1668 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
michael@0 1669 (result = (atmp->tm_min - btmp->tm_min)) == 0)
michael@0 1670 result = atmp->tm_sec - btmp->tm_sec;
michael@0 1671 return result;
michael@0 1672 }
michael@0 1673
michael@0 1674 static time_t
michael@0 1675 time2sub(tmp, funcp, offset, okayp, do_norm_secs)
michael@0 1676 struct tm * const tmp;
michael@0 1677 struct tm * (* const funcp)(const time_t*, long, struct tm*);
michael@0 1678 const long offset;
michael@0 1679 int * const okayp;
michael@0 1680 const int do_norm_secs;
michael@0 1681 {
michael@0 1682 register const struct state * sp;
michael@0 1683 register int dir;
michael@0 1684 register int i, j;
michael@0 1685 register int saved_seconds;
michael@0 1686 register long li;
michael@0 1687 register time_t lo;
michael@0 1688 register time_t hi;
michael@0 1689 long y;
michael@0 1690 time_t newt;
michael@0 1691 time_t t;
michael@0 1692 struct tm yourtm, mytm;
michael@0 1693
michael@0 1694 *okayp = FALSE;
michael@0 1695 yourtm = *tmp;
michael@0 1696 if (do_norm_secs) {
michael@0 1697 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
michael@0 1698 SECSPERMIN))
michael@0 1699 return WRONG;
michael@0 1700 }
michael@0 1701 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
michael@0 1702 return WRONG;
michael@0 1703 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
michael@0 1704 return WRONG;
michael@0 1705 y = yourtm.tm_year;
michael@0 1706 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
michael@0 1707 return WRONG;
michael@0 1708 /*
michael@0 1709 ** Turn y into an actual year number for now.
michael@0 1710 ** It is converted back to an offset from TM_YEAR_BASE later.
michael@0 1711 */
michael@0 1712 if (long_increment_overflow(&y, TM_YEAR_BASE))
michael@0 1713 return WRONG;
michael@0 1714 while (yourtm.tm_mday <= 0) {
michael@0 1715 if (long_increment_overflow(&y, -1))
michael@0 1716 return WRONG;
michael@0 1717 li = y + (1 < yourtm.tm_mon);
michael@0 1718 yourtm.tm_mday += year_lengths[isleap(li)];
michael@0 1719 }
michael@0 1720 while (yourtm.tm_mday > DAYSPERLYEAR) {
michael@0 1721 li = y + (1 < yourtm.tm_mon);
michael@0 1722 yourtm.tm_mday -= year_lengths[isleap(li)];
michael@0 1723 if (long_increment_overflow(&y, 1))
michael@0 1724 return WRONG;
michael@0 1725 }
michael@0 1726 for ( ; ; ) {
michael@0 1727 i = mon_lengths[isleap(y)][yourtm.tm_mon];
michael@0 1728 if (yourtm.tm_mday <= i)
michael@0 1729 break;
michael@0 1730 yourtm.tm_mday -= i;
michael@0 1731 if (++yourtm.tm_mon >= MONSPERYEAR) {
michael@0 1732 yourtm.tm_mon = 0;
michael@0 1733 if (long_increment_overflow(&y, 1))
michael@0 1734 return WRONG;
michael@0 1735 }
michael@0 1736 }
michael@0 1737 if (long_increment_overflow(&y, -TM_YEAR_BASE))
michael@0 1738 return WRONG;
michael@0 1739 yourtm.tm_year = y;
michael@0 1740 if (yourtm.tm_year != y)
michael@0 1741 return WRONG;
michael@0 1742 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
michael@0 1743 saved_seconds = 0;
michael@0 1744 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
michael@0 1745 /*
michael@0 1746 ** We can't set tm_sec to 0, because that might push the
michael@0 1747 ** time below the minimum representable time.
michael@0 1748 ** Set tm_sec to 59 instead.
michael@0 1749 ** This assumes that the minimum representable time is
michael@0 1750 ** not in the same minute that a leap second was deleted from,
michael@0 1751 ** which is a safer assumption than using 58 would be.
michael@0 1752 */
michael@0 1753 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
michael@0 1754 return WRONG;
michael@0 1755 saved_seconds = yourtm.tm_sec;
michael@0 1756 yourtm.tm_sec = SECSPERMIN - 1;
michael@0 1757 } else {
michael@0 1758 saved_seconds = yourtm.tm_sec;
michael@0 1759 yourtm.tm_sec = 0;
michael@0 1760 }
michael@0 1761 /*
michael@0 1762 ** Do a binary search (this works whatever time_t's type is).
michael@0 1763 */
michael@0 1764 if (!TYPE_SIGNED(time_t)) {
michael@0 1765 lo = 0;
michael@0 1766 hi = lo - 1;
michael@0 1767 } else if (!TYPE_INTEGRAL(time_t)) {
michael@0 1768 if (sizeof(time_t) > sizeof(float))
michael@0 1769 hi = (time_t) DBL_MAX;
michael@0 1770 else hi = (time_t) FLT_MAX;
michael@0 1771 lo = -hi;
michael@0 1772 } else {
michael@0 1773 lo = 1;
michael@0 1774 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
michael@0 1775 lo *= 2;
michael@0 1776 hi = -(lo + 1);
michael@0 1777 }
michael@0 1778 for ( ; ; ) {
michael@0 1779 t = lo / 2 + hi / 2;
michael@0 1780 if (t < lo)
michael@0 1781 t = lo;
michael@0 1782 else if (t > hi)
michael@0 1783 t = hi;
michael@0 1784 if ((*funcp)(&t, offset, &mytm) == NULL) {
michael@0 1785 /*
michael@0 1786 ** Assume that t is too extreme to be represented in
michael@0 1787 ** a struct tm; arrange things so that it is less
michael@0 1788 ** extreme on the next pass.
michael@0 1789 */
michael@0 1790 dir = (t > 0) ? 1 : -1;
michael@0 1791 } else dir = tmcomp(&mytm, &yourtm);
michael@0 1792 if (dir != 0) {
michael@0 1793 if (t == lo) {
michael@0 1794 ++t;
michael@0 1795 if (t <= lo)
michael@0 1796 return WRONG;
michael@0 1797 ++lo;
michael@0 1798 } else if (t == hi) {
michael@0 1799 --t;
michael@0 1800 if (t >= hi)
michael@0 1801 return WRONG;
michael@0 1802 --hi;
michael@0 1803 }
michael@0 1804 if (lo > hi)
michael@0 1805 return WRONG;
michael@0 1806 if (dir > 0)
michael@0 1807 hi = t;
michael@0 1808 else lo = t;
michael@0 1809 continue;
michael@0 1810 }
michael@0 1811 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
michael@0 1812 break;
michael@0 1813 /*
michael@0 1814 ** Right time, wrong type.
michael@0 1815 ** Hunt for right time, right type.
michael@0 1816 ** It's okay to guess wrong since the guess
michael@0 1817 ** gets checked.
michael@0 1818 */
michael@0 1819 sp = (const struct state *)
michael@0 1820 ((funcp == localsub) ? lclptr : gmtptr);
michael@0 1821 #ifdef ALL_STATE
michael@0 1822 if (sp == NULL)
michael@0 1823 return WRONG;
michael@0 1824 #endif /* defined ALL_STATE */
michael@0 1825 for (i = sp->typecnt - 1; i >= 0; --i) {
michael@0 1826 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
michael@0 1827 continue;
michael@0 1828 for (j = sp->typecnt - 1; j >= 0; --j) {
michael@0 1829 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
michael@0 1830 continue;
michael@0 1831 newt = t + sp->ttis[j].tt_gmtoff -
michael@0 1832 sp->ttis[i].tt_gmtoff;
michael@0 1833 if ((*funcp)(&newt, offset, &mytm) == NULL)
michael@0 1834 continue;
michael@0 1835 if (tmcomp(&mytm, &yourtm) != 0)
michael@0 1836 continue;
michael@0 1837 if (mytm.tm_isdst != yourtm.tm_isdst)
michael@0 1838 continue;
michael@0 1839 /*
michael@0 1840 ** We have a match.
michael@0 1841 */
michael@0 1842 t = newt;
michael@0 1843 goto label;
michael@0 1844 }
michael@0 1845 }
michael@0 1846 return WRONG;
michael@0 1847 }
michael@0 1848 label:
michael@0 1849 newt = t + saved_seconds;
michael@0 1850 if ((newt < t) != (saved_seconds < 0))
michael@0 1851 return WRONG;
michael@0 1852 t = newt;
michael@0 1853 if ((*funcp)(&t, offset, tmp))
michael@0 1854 *okayp = TRUE;
michael@0 1855 return t;
michael@0 1856 }
michael@0 1857
michael@0 1858 static time_t
michael@0 1859 time2(tmp, funcp, offset, okayp)
michael@0 1860 struct tm * const tmp;
michael@0 1861 struct tm * (* const funcp)(const time_t*, long, struct tm*);
michael@0 1862 const long offset;
michael@0 1863 int * const okayp;
michael@0 1864 {
michael@0 1865 time_t t;
michael@0 1866
michael@0 1867 /*
michael@0 1868 ** First try without normalization of seconds
michael@0 1869 ** (in case tm_sec contains a value associated with a leap second).
michael@0 1870 ** If that fails, try with normalization of seconds.
michael@0 1871 */
michael@0 1872 t = time2sub(tmp, funcp, offset, okayp, FALSE);
michael@0 1873 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
michael@0 1874 }
michael@0 1875
michael@0 1876 static time_t
michael@0 1877 time1(tmp, funcp, offset)
michael@0 1878 struct tm * const tmp;
michael@0 1879 struct tm * (* const funcp)(const time_t *, long, struct tm *);
michael@0 1880 const long offset;
michael@0 1881 {
michael@0 1882 register time_t t;
michael@0 1883 register const struct state * sp;
michael@0 1884 register int samei, otheri;
michael@0 1885 register int sameind, otherind;
michael@0 1886 register int i;
michael@0 1887 register int nseen;
michael@0 1888 int seen[TZ_MAX_TYPES];
michael@0 1889 int types[TZ_MAX_TYPES];
michael@0 1890 int okay;
michael@0 1891
michael@0 1892 if (tmp->tm_isdst > 1)
michael@0 1893 tmp->tm_isdst = 1;
michael@0 1894 t = time2(tmp, funcp, offset, &okay);
michael@0 1895 #ifdef PCTS
michael@0 1896 /*
michael@0 1897 ** PCTS code courtesy Grant Sullivan.
michael@0 1898 */
michael@0 1899 if (okay)
michael@0 1900 return t;
michael@0 1901 if (tmp->tm_isdst < 0)
michael@0 1902 tmp->tm_isdst = 0; /* reset to std and try again */
michael@0 1903 #endif /* defined PCTS */
michael@0 1904 #ifndef PCTS
michael@0 1905 if (okay || tmp->tm_isdst < 0)
michael@0 1906 return t;
michael@0 1907 #endif /* !defined PCTS */
michael@0 1908 /*
michael@0 1909 ** We're supposed to assume that somebody took a time of one type
michael@0 1910 ** and did some math on it that yielded a "struct tm" that's bad.
michael@0 1911 ** We try to divine the type they started from and adjust to the
michael@0 1912 ** type they need.
michael@0 1913 */
michael@0 1914 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
michael@0 1915 #ifdef ALL_STATE
michael@0 1916 if (sp == NULL)
michael@0 1917 return WRONG;
michael@0 1918 #endif /* defined ALL_STATE */
michael@0 1919 for (i = 0; i < sp->typecnt; ++i)
michael@0 1920 seen[i] = FALSE;
michael@0 1921 nseen = 0;
michael@0 1922 for (i = sp->timecnt - 1; i >= 0; --i)
michael@0 1923 if (!seen[sp->types[i]]) {
michael@0 1924 seen[sp->types[i]] = TRUE;
michael@0 1925 types[nseen++] = sp->types[i];
michael@0 1926 }
michael@0 1927 for (sameind = 0; sameind < nseen; ++sameind) {
michael@0 1928 samei = types[sameind];
michael@0 1929 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
michael@0 1930 continue;
michael@0 1931 for (otherind = 0; otherind < nseen; ++otherind) {
michael@0 1932 otheri = types[otherind];
michael@0 1933 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
michael@0 1934 continue;
michael@0 1935 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
michael@0 1936 sp->ttis[samei].tt_gmtoff;
michael@0 1937 tmp->tm_isdst = !tmp->tm_isdst;
michael@0 1938 t = time2(tmp, funcp, offset, &okay);
michael@0 1939 if (okay)
michael@0 1940 return t;
michael@0 1941 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
michael@0 1942 sp->ttis[samei].tt_gmtoff;
michael@0 1943 tmp->tm_isdst = !tmp->tm_isdst;
michael@0 1944 }
michael@0 1945 }
michael@0 1946 return WRONG;
michael@0 1947 }
michael@0 1948
michael@0 1949 time_t
michael@0 1950 mktime(tmp)
michael@0 1951 struct tm * const tmp;
michael@0 1952 {
michael@0 1953 tzset();
michael@0 1954 return time1(tmp, localsub, 0L);
michael@0 1955 }
michael@0 1956
michael@0 1957 #ifdef STD_INSPIRED
michael@0 1958
michael@0 1959 time_t
michael@0 1960 timelocal(tmp)
michael@0 1961 struct tm * const tmp;
michael@0 1962 {
michael@0 1963 tmp->tm_isdst = -1; /* in case it wasn't initialized */
michael@0 1964 return mktime(tmp);
michael@0 1965 }
michael@0 1966
michael@0 1967 time_t
michael@0 1968 timegm(tmp)
michael@0 1969 struct tm * const tmp;
michael@0 1970 {
michael@0 1971 tmp->tm_isdst = 0;
michael@0 1972 return time1(tmp, gmtsub, 0L);
michael@0 1973 }
michael@0 1974
michael@0 1975 time_t
michael@0 1976 timeoff(tmp, offset)
michael@0 1977 struct tm * const tmp;
michael@0 1978 const long offset;
michael@0 1979 {
michael@0 1980 tmp->tm_isdst = 0;
michael@0 1981 return time1(tmp, gmtsub, offset);
michael@0 1982 }
michael@0 1983
michael@0 1984 #endif /* defined STD_INSPIRED */
michael@0 1985
michael@0 1986 #ifdef CMUCS
michael@0 1987
michael@0 1988 /*
michael@0 1989 ** The following is supplied for compatibility with
michael@0 1990 ** previous versions of the CMUCS runtime library.
michael@0 1991 */
michael@0 1992
michael@0 1993 long
michael@0 1994 gtime(tmp)
michael@0 1995 struct tm * const tmp;
michael@0 1996 {
michael@0 1997 const time_t t = mktime(tmp);
michael@0 1998
michael@0 1999 if (t == WRONG)
michael@0 2000 return -1;
michael@0 2001 return t;
michael@0 2002 }
michael@0 2003
michael@0 2004 #endif /* defined CMUCS */
michael@0 2005
michael@0 2006 /*
michael@0 2007 ** XXX--is the below the right way to conditionalize??
michael@0 2008 */
michael@0 2009
michael@0 2010 #ifdef STD_INSPIRED
michael@0 2011
michael@0 2012 /*
michael@0 2013 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
michael@0 2014 ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
michael@0 2015 ** is not the case if we are accounting for leap seconds.
michael@0 2016 ** So, we provide the following conversion routines for use
michael@0 2017 ** when exchanging timestamps with POSIX conforming systems.
michael@0 2018 */
michael@0 2019
michael@0 2020 static long
michael@0 2021 leapcorr(timep)
michael@0 2022 time_t * timep;
michael@0 2023 {
michael@0 2024 register struct state * sp;
michael@0 2025 register struct lsinfo * lp;
michael@0 2026 register int i;
michael@0 2027
michael@0 2028 sp = lclptr;
michael@0 2029 i = sp->leapcnt;
michael@0 2030 while (--i >= 0) {
michael@0 2031 lp = &sp->lsis[i];
michael@0 2032 if (*timep >= lp->ls_trans)
michael@0 2033 return lp->ls_corr;
michael@0 2034 }
michael@0 2035 return 0;
michael@0 2036 }
michael@0 2037
michael@0 2038 time_t
michael@0 2039 time2posix(t)
michael@0 2040 time_t t;
michael@0 2041 {
michael@0 2042 tzset();
michael@0 2043 return t - leapcorr(&t);
michael@0 2044 }
michael@0 2045
michael@0 2046 time_t
michael@0 2047 posix2time(t)
michael@0 2048 time_t t;
michael@0 2049 {
michael@0 2050 time_t x;
michael@0 2051 time_t y;
michael@0 2052
michael@0 2053 tzset();
michael@0 2054 /*
michael@0 2055 ** For a positive leap second hit, the result
michael@0 2056 ** is not unique. For a negative leap second
michael@0 2057 ** hit, the corresponding time doesn't exist,
michael@0 2058 ** so we return an adjacent second.
michael@0 2059 */
michael@0 2060 x = t + leapcorr(&t);
michael@0 2061 y = x - leapcorr(&x);
michael@0 2062 if (y < t) {
michael@0 2063 do {
michael@0 2064 x++;
michael@0 2065 y = x - leapcorr(&x);
michael@0 2066 } while (y < t);
michael@0 2067 if (t != y)
michael@0 2068 return x - 1;
michael@0 2069 } else if (y > t) {
michael@0 2070 do {
michael@0 2071 --x;
michael@0 2072 y = x - leapcorr(&x);
michael@0 2073 } while (y > t);
michael@0 2074 if (t != y)
michael@0 2075 return x + 1;
michael@0 2076 }
michael@0 2077 return x;
michael@0 2078 }
michael@0 2079
michael@0 2080 #endif /* defined STD_INSPIRED */

mercurial