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