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