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