localtime.c revision 1.1.1.4 1 #ifndef lint
2 #ifndef NOID
3 static char elsieid[] = "@(#)localtime.c 7.53";
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 = (codep[0] & 0x80) ? ~0L : 0L;
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' && !is_digit(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 || !is_digit(c = *strp))
442 return NULL;
443 num = 0;
444 do {
445 num = num * 10 + (c - '0');
446 if (num > max)
447 return NULL; /* illegal value */
448 c = *++strp;
449 } while (is_digit(c));
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 = 0;
512
513 if (*strp == '-') {
514 neg = 1;
515 ++strp;
516 } else if (*strp == '+')
517 ++strp;
518 strp = getsecs(strp, offsetp);
519 if (strp == NULL)
520 return NULL; /* illegal time */
521 if (neg)
522 *offsetp = -*offsetp;
523 return strp;
524 }
525
526 /*
527 ** Given a pointer into a time zone string, extract a rule in the form
528 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
529 ** If a valid rule is not found, return NULL.
530 ** Otherwise, return a pointer to the first character not part of the rule.
531 */
532
533 static const char *
534 getrule(strp, rulep)
535 const char * strp;
536 register struct rule * const rulep;
537 {
538 if (*strp == 'J') {
539 /*
540 ** Julian day.
541 */
542 rulep->r_type = JULIAN_DAY;
543 ++strp;
544 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
545 } else if (*strp == 'M') {
546 /*
547 ** Month, week, day.
548 */
549 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
550 ++strp;
551 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
552 if (strp == NULL)
553 return NULL;
554 if (*strp++ != '.')
555 return NULL;
556 strp = getnum(strp, &rulep->r_week, 1, 5);
557 if (strp == NULL)
558 return NULL;
559 if (*strp++ != '.')
560 return NULL;
561 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
562 } else if (is_digit(*strp)) {
563 /*
564 ** Day of year.
565 */
566 rulep->r_type = DAY_OF_YEAR;
567 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
568 } else return NULL; /* invalid format */
569 if (strp == NULL)
570 return NULL;
571 if (*strp == '/') {
572 /*
573 ** Time specified.
574 */
575 ++strp;
576 strp = getsecs(strp, &rulep->r_time);
577 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
578 return strp;
579 }
580
581 /*
582 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
583 ** year, a rule, and the offset from GMT at the time that rule takes effect,
584 ** calculate the Epoch-relative time that rule takes effect.
585 */
586
587 static time_t
588 transtime(janfirst, year, rulep, offset)
589 const time_t janfirst;
590 const int year;
591 register const struct rule * const rulep;
592 const long offset;
593 {
594 register int leapyear;
595 register time_t value;
596 register int i;
597 int d, m1, yy0, yy1, yy2, dow;
598
599 INITIALIZE(value);
600 leapyear = isleap(year);
601 switch (rulep->r_type) {
602
603 case JULIAN_DAY:
604 /*
605 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
606 ** years.
607 ** In non-leap years, or if the day number is 59 or less, just
608 ** add SECSPERDAY times the day number-1 to the time of
609 ** January 1, midnight, to get the day.
610 */
611 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
612 if (leapyear && rulep->r_day >= 60)
613 value += SECSPERDAY;
614 break;
615
616 case DAY_OF_YEAR:
617 /*
618 ** n - day of year.
619 ** Just add SECSPERDAY times the day number to the time of
620 ** January 1, midnight, to get the day.
621 */
622 value = janfirst + rulep->r_day * SECSPERDAY;
623 break;
624
625 case MONTH_NTH_DAY_OF_WEEK:
626 /*
627 ** Mm.n.d - nth "dth day" of month m.
628 */
629 value = janfirst;
630 for (i = 0; i < rulep->r_mon - 1; ++i)
631 value += mon_lengths[leapyear][i] * SECSPERDAY;
632
633 /*
634 ** Use Zeller's Congruence to get day-of-week of first day of
635 ** month.
636 */
637 m1 = (rulep->r_mon + 9) % 12 + 1;
638 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
639 yy1 = yy0 / 100;
640 yy2 = yy0 % 100;
641 dow = ((26 * m1 - 2) / 10 +
642 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
643 if (dow < 0)
644 dow += DAYSPERWEEK;
645
646 /*
647 ** "dow" is the day-of-week of the first day of the month. Get
648 ** the day-of-month (zero-origin) of the first "dow" day of the
649 ** month.
650 */
651 d = rulep->r_day - dow;
652 if (d < 0)
653 d += DAYSPERWEEK;
654 for (i = 1; i < rulep->r_week; ++i) {
655 if (d + DAYSPERWEEK >=
656 mon_lengths[leapyear][rulep->r_mon - 1])
657 break;
658 d += DAYSPERWEEK;
659 }
660
661 /*
662 ** "d" is the day-of-month (zero-origin) of the day we want.
663 */
664 value += d * SECSPERDAY;
665 break;
666 }
667
668 /*
669 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
670 ** question. To get the Epoch-relative time of the specified local
671 ** time on that day, add the transition time and the current offset
672 ** from GMT.
673 */
674 return value + rulep->r_time + offset;
675 }
676
677 /*
678 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
679 ** appropriate.
680 */
681
682 static int
683 tzparse(name, sp, lastditch)
684 const char * name;
685 register struct state * const sp;
686 const int lastditch;
687 {
688 const char * stdname;
689 const char * dstname;
690 size_t stdlen;
691 size_t dstlen;
692 long stdoffset;
693 long dstoffset;
694 register time_t * atp;
695 register unsigned char * typep;
696 register char * cp;
697 register int load_result;
698
699 INITIALIZE(dstname);
700 stdname = name;
701 if (lastditch) {
702 stdlen = strlen(name); /* length of standard zone name */
703 name += stdlen;
704 if (stdlen >= sizeof sp->chars)
705 stdlen = (sizeof sp->chars) - 1;
706 } else {
707 name = getzname(name);
708 stdlen = name - stdname;
709 if (stdlen < 3)
710 return -1;
711 }
712 if (*name == '\0')
713 return -1; /* was "stdoffset = 0;" */
714 else {
715 name = getoffset(name, &stdoffset);
716 if (name == NULL)
717 return -1;
718 }
719 load_result = tzload(TZDEFRULES, sp);
720 if (load_result != 0)
721 sp->leapcnt = 0; /* so, we're off a little */
722 if (*name != '\0') {
723 dstname = name;
724 name = getzname(name);
725 dstlen = name - dstname; /* length of DST zone name */
726 if (dstlen < 3)
727 return -1;
728 if (*name != '\0' && *name != ',' && *name != ';') {
729 name = getoffset(name, &dstoffset);
730 if (name == NULL)
731 return -1;
732 } else dstoffset = stdoffset - SECSPERHOUR;
733 if (*name == ',' || *name == ';') {
734 struct rule start;
735 struct rule end;
736 register int year;
737 register time_t janfirst;
738 time_t starttime;
739 time_t endtime;
740
741 ++name;
742 if ((name = getrule(name, &start)) == NULL)
743 return -1;
744 if (*name++ != ',')
745 return -1;
746 if ((name = getrule(name, &end)) == NULL)
747 return -1;
748 if (*name != '\0')
749 return -1;
750 sp->typecnt = 2; /* standard time and DST */
751 /*
752 ** Two transitions per year, from EPOCH_YEAR to 2037.
753 */
754 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
755 if (sp->timecnt > TZ_MAX_TIMES)
756 return -1;
757 sp->ttis[0].tt_gmtoff = -dstoffset;
758 sp->ttis[0].tt_isdst = 1;
759 sp->ttis[0].tt_abbrind = stdlen + 1;
760 sp->ttis[1].tt_gmtoff = -stdoffset;
761 sp->ttis[1].tt_isdst = 0;
762 sp->ttis[1].tt_abbrind = 0;
763 atp = sp->ats;
764 typep = sp->types;
765 janfirst = 0;
766 for (year = EPOCH_YEAR; year <= 2037; ++year) {
767 starttime = transtime(janfirst, year, &start,
768 stdoffset);
769 endtime = transtime(janfirst, year, &end,
770 dstoffset);
771 if (starttime > endtime) {
772 *atp++ = endtime;
773 *typep++ = 1; /* DST ends */
774 *atp++ = starttime;
775 *typep++ = 0; /* DST begins */
776 } else {
777 *atp++ = starttime;
778 *typep++ = 0; /* DST begins */
779 *atp++ = endtime;
780 *typep++ = 1; /* DST ends */
781 }
782 janfirst += year_lengths[isleap(year)] *
783 SECSPERDAY;
784 }
785 } else {
786 register long theirstdoffset;
787 register long theirdstoffset;
788 register long theiroffset;
789 register int isdst;
790 register int i;
791 register int j;
792
793 if (*name != '\0')
794 return -1;
795 if (load_result != 0)
796 return -1;
797 /*
798 ** Initial values of theirstdoffset and theirdstoffset.
799 */
800 theirstdoffset = 0;
801 for (i = 0; i < sp->timecnt; ++i) {
802 j = sp->types[i];
803 if (!sp->ttis[j].tt_isdst) {
804 theirstdoffset =
805 -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 =
814 -sp->ttis[j].tt_gmtoff;
815 break;
816 }
817 }
818 /*
819 ** Initially we're assumed to be in standard time.
820 */
821 isdst = FALSE;
822 theiroffset = theirstdoffset;
823 /*
824 ** Now juggle transition times and types
825 ** tracking offsets as you do.
826 */
827 for (i = 0; i < sp->timecnt; ++i) {
828 j = sp->types[i];
829 sp->types[i] = sp->ttis[j].tt_isdst;
830 if (sp->ttis[j].tt_ttisgmt) {
831 /* No adjustment to transition time */
832 } else {
833 /*
834 ** If summer time is in effect, and the
835 ** transition time was not specified as
836 ** standard time, add the summer time
837 ** offset to the transition time;
838 ** otherwise, add the standard time
839 ** offset to the transition time.
840 */
841 /*
842 ** Transitions from DST to DDST
843 ** will effectively disappear since
844 ** POSIX provides for only one DST
845 ** offset.
846 */
847 if (isdst && !sp->ttis[j].tt_ttisstd) {
848 sp->ats[i] += dstoffset -
849 theirdstoffset;
850 } else {
851 sp->ats[i] += stdoffset -
852 theirstdoffset;
853 }
854 }
855 theiroffset = -sp->ttis[j].tt_gmtoff;
856 if (sp->ttis[j].tt_isdst)
857 theirdstoffset = theiroffset;
858 else theirstdoffset = theiroffset;
859 }
860 /*
861 ** Finally, fill in ttis.
862 ** ttisstd and ttisgmt need not be handled.
863 */
864 sp->ttis[0].tt_gmtoff = -stdoffset;
865 sp->ttis[0].tt_isdst = FALSE;
866 sp->ttis[0].tt_abbrind = 0;
867 sp->ttis[1].tt_gmtoff = -dstoffset;
868 sp->ttis[1].tt_isdst = TRUE;
869 sp->ttis[1].tt_abbrind = stdlen + 1;
870 }
871 } else {
872 dstlen = 0;
873 sp->typecnt = 1; /* only standard time */
874 sp->timecnt = 0;
875 sp->ttis[0].tt_gmtoff = -stdoffset;
876 sp->ttis[0].tt_isdst = 0;
877 sp->ttis[0].tt_abbrind = 0;
878 }
879 sp->charcnt = stdlen + 1;
880 if (dstlen != 0)
881 sp->charcnt += dstlen + 1;
882 if (sp->charcnt > sizeof sp->chars)
883 return -1;
884 cp = sp->chars;
885 (void) strncpy(cp, stdname, stdlen);
886 cp += stdlen;
887 *cp++ = '\0';
888 if (dstlen != 0) {
889 (void) strncpy(cp, dstname, dstlen);
890 *(cp + dstlen) = '\0';
891 }
892 return 0;
893 }
894
895 static void
896 gmtload(sp)
897 struct state * const sp;
898 {
899 if (tzload(gmt, sp) != 0)
900 (void) tzparse(gmt, sp, TRUE);
901 }
902
903 #ifndef STD_INSPIRED
904 /*
905 ** A non-static declaration of tzsetwall in a system header file
906 ** may cause a warning about this upcoming static declaration...
907 */
908 static
909 #endif /* !defined STD_INSPIRED */
910 void
911 tzsetwall P((void))
912 {
913 if (lcl_is_set < 0)
914 return;
915 lcl_is_set = -1;
916
917 #ifdef ALL_STATE
918 if (lclptr == NULL) {
919 lclptr = (struct state *) malloc(sizeof *lclptr);
920 if (lclptr == NULL) {
921 settzname(); /* all we can do */
922 return;
923 }
924 }
925 #endif /* defined ALL_STATE */
926 if (tzload((char *) NULL, lclptr) != 0)
927 gmtload(lclptr);
928 settzname();
929 }
930
931 void
932 tzset P((void))
933 {
934 register const char * name;
935
936 name = getenv("TZ");
937 if (name == NULL) {
938 tzsetwall();
939 return;
940 }
941
942 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
943 return;
944 lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
945 if (lcl_is_set)
946 (void) strcpy(lcl_TZname, name);
947
948 #ifdef ALL_STATE
949 if (lclptr == NULL) {
950 lclptr = (struct state *) malloc(sizeof *lclptr);
951 if (lclptr == NULL) {
952 settzname(); /* all we can do */
953 return;
954 }
955 }
956 #endif /* defined ALL_STATE */
957 if (*name == '\0') {
958 /*
959 ** User wants it fast rather than right.
960 */
961 lclptr->leapcnt = 0; /* so, we're off a little */
962 lclptr->timecnt = 0;
963 lclptr->ttis[0].tt_gmtoff = 0;
964 lclptr->ttis[0].tt_abbrind = 0;
965 (void) strcpy(lclptr->chars, gmt);
966 } else if (tzload(name, lclptr) != 0)
967 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
968 (void) gmtload(lclptr);
969 settzname();
970 }
971
972 /*
973 ** The easy way to behave "as if no library function calls" localtime
974 ** is to not call it--so we drop its guts into "localsub", which can be
975 ** freely called. (And no, the PANS doesn't require the above behavior--
976 ** but it *is* desirable.)
977 **
978 ** The unused offset argument is for the benefit of mktime variants.
979 */
980
981 /*ARGSUSED*/
982 static void
983 localsub(timep, offset, tmp)
984 const time_t * const timep;
985 const long offset;
986 struct tm * const tmp;
987 {
988 register struct state * sp;
989 register const struct ttinfo * ttisp;
990 register int i;
991 const time_t t = *timep;
992
993 sp = lclptr;
994 #ifdef ALL_STATE
995 if (sp == NULL) {
996 gmtsub(timep, offset, tmp);
997 return;
998 }
999 #endif /* defined ALL_STATE */
1000 if (sp->timecnt == 0 || t < sp->ats[0]) {
1001 i = 0;
1002 while (sp->ttis[i].tt_isdst)
1003 if (++i >= sp->typecnt) {
1004 i = 0;
1005 break;
1006 }
1007 } else {
1008 for (i = 1; i < sp->timecnt; ++i)
1009 if (t < sp->ats[i])
1010 break;
1011 i = sp->types[i - 1];
1012 }
1013 ttisp = &sp->ttis[i];
1014 /*
1015 ** To get (wrong) behavior that's compatible with System V Release 2.0
1016 ** you'd replace the statement below with
1017 ** t += ttisp->tt_gmtoff;
1018 ** timesub(&t, 0L, sp, tmp);
1019 */
1020 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1021 tmp->tm_isdst = ttisp->tt_isdst;
1022 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1023 #ifdef TM_ZONE
1024 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1025 #endif /* defined TM_ZONE */
1026 }
1027
1028 struct tm *
1029 localtime(timep)
1030 const time_t * const timep;
1031 {
1032 tzset();
1033 localsub(timep, 0L, &tm);
1034 return &tm;
1035 }
1036
1037 /*
1038 ** gmtsub is to gmtime as localsub is to localtime.
1039 */
1040
1041 static void
1042 gmtsub(timep, offset, tmp)
1043 const time_t * const timep;
1044 const long offset;
1045 struct tm * const tmp;
1046 {
1047 if (!gmt_is_set) {
1048 gmt_is_set = TRUE;
1049 #ifdef ALL_STATE
1050 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1051 if (gmtptr != NULL)
1052 #endif /* defined ALL_STATE */
1053 gmtload(gmtptr);
1054 }
1055 timesub(timep, offset, gmtptr, tmp);
1056 #ifdef TM_ZONE
1057 /*
1058 ** Could get fancy here and deliver something such as
1059 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1060 ** but this is no time for a treasure hunt.
1061 */
1062 if (offset != 0)
1063 tmp->TM_ZONE = wildabbr;
1064 else {
1065 #ifdef ALL_STATE
1066 if (gmtptr == NULL)
1067 tmp->TM_ZONE = gmt;
1068 else tmp->TM_ZONE = gmtptr->chars;
1069 #endif /* defined ALL_STATE */
1070 #ifndef ALL_STATE
1071 tmp->TM_ZONE = gmtptr->chars;
1072 #endif /* State Farm */
1073 }
1074 #endif /* defined TM_ZONE */
1075 }
1076
1077 struct tm *
1078 gmtime(timep)
1079 const time_t * const timep;
1080 {
1081 gmtsub(timep, 0L, &tm);
1082 return &tm;
1083 }
1084
1085 #ifdef STD_INSPIRED
1086
1087 struct tm *
1088 offtime(timep, offset)
1089 const time_t * const timep;
1090 const long offset;
1091 {
1092 gmtsub(timep, offset, &tm);
1093 return &tm;
1094 }
1095
1096 #endif /* defined STD_INSPIRED */
1097
1098 static void
1099 timesub(timep, offset, sp, tmp)
1100 const time_t * const timep;
1101 const long offset;
1102 register const struct state * const sp;
1103 register struct tm * const tmp;
1104 {
1105 register const struct lsinfo * lp;
1106 register long days;
1107 register long rem;
1108 register int y;
1109 register int yleap;
1110 register const int * ip;
1111 register long corr;
1112 register int hit;
1113 register int i;
1114
1115 corr = 0;
1116 hit = 0;
1117 #ifdef ALL_STATE
1118 i = (sp == NULL) ? 0 : sp->leapcnt;
1119 #endif /* defined ALL_STATE */
1120 #ifndef ALL_STATE
1121 i = sp->leapcnt;
1122 #endif /* State Farm */
1123 while (--i >= 0) {
1124 lp = &sp->lsis[i];
1125 if (*timep >= lp->ls_trans) {
1126 if (*timep == lp->ls_trans) {
1127 hit = ((i == 0 && lp->ls_corr > 0) ||
1128 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1129 if (hit)
1130 while (i > 0 &&
1131 sp->lsis[i].ls_trans ==
1132 sp->lsis[i - 1].ls_trans + 1 &&
1133 sp->lsis[i].ls_corr ==
1134 sp->lsis[i - 1].ls_corr + 1) {
1135 ++hit;
1136 --i;
1137 }
1138 }
1139 corr = lp->ls_corr;
1140 break;
1141 }
1142 }
1143 days = *timep / SECSPERDAY;
1144 rem = *timep % SECSPERDAY;
1145 #ifdef mc68k
1146 if (*timep == 0x80000000) {
1147 /*
1148 ** A 3B1 muffs the division on the most negative number.
1149 */
1150 days = -24855;
1151 rem = -11648;
1152 }
1153 #endif /* defined mc68k */
1154 rem += (offset - corr);
1155 while (rem < 0) {
1156 rem += SECSPERDAY;
1157 --days;
1158 }
1159 while (rem >= SECSPERDAY) {
1160 rem -= SECSPERDAY;
1161 ++days;
1162 }
1163 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1164 rem = rem % SECSPERHOUR;
1165 tmp->tm_min = (int) (rem / SECSPERMIN);
1166 /*
1167 ** A positive leap second requires a special
1168 ** representation. This uses "... ??:59:60" et seq.
1169 */
1170 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1171 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1172 if (tmp->tm_wday < 0)
1173 tmp->tm_wday += DAYSPERWEEK;
1174 y = EPOCH_YEAR;
1175 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
1176 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
1177 register int newy;
1178
1179 newy = y + days / DAYSPERNYEAR;
1180 if (days < 0)
1181 --newy;
1182 days -= (newy - y) * DAYSPERNYEAR +
1183 LEAPS_THRU_END_OF(newy - 1) -
1184 LEAPS_THRU_END_OF(y - 1);
1185 y = newy;
1186 }
1187 tmp->tm_year = y - TM_YEAR_BASE;
1188 tmp->tm_yday = (int) days;
1189 ip = mon_lengths[yleap];
1190 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1191 days = days - (long) ip[tmp->tm_mon];
1192 tmp->tm_mday = (int) (days + 1);
1193 tmp->tm_isdst = 0;
1194 #ifdef TM_GMTOFF
1195 tmp->TM_GMTOFF = offset;
1196 #endif /* defined TM_GMTOFF */
1197 }
1198
1199 char *
1200 ctime(timep)
1201 const time_t * const timep;
1202 {
1203 /*
1204 ** Section 4.12.3.2 of X3.159-1989 requires that
1205 ** The ctime funciton converts the calendar time pointed to by timer
1206 ** to local time in the form of a string. It is equivalent to
1207 ** asctime(localtime(timer))
1208 */
1209 return asctime(localtime(timep));
1210 }
1211
1212 /*
1213 ** Adapted from code provided by Robert Elz, who writes:
1214 ** The "best" way to do mktime I think is based on an idea of Bob
1215 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1216 ** It does a binary search of the time_t space. Since time_t's are
1217 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1218 ** would still be very reasonable).
1219 */
1220
1221 #ifndef WRONG
1222 #define WRONG (-1)
1223 #endif /* !defined WRONG */
1224
1225 /*
1226 ** Simplified normalize logic courtesy Paul Eggert (eggert (at) twinsun.com).
1227 */
1228
1229 static int
1230 increment_overflow(number, delta)
1231 int * number;
1232 int delta;
1233 {
1234 int number0;
1235
1236 number0 = *number;
1237 *number += delta;
1238 return (*number < number0) != (delta < 0);
1239 }
1240
1241 static int
1242 normalize_overflow(tensptr, unitsptr, base)
1243 int * const tensptr;
1244 int * const unitsptr;
1245 const int base;
1246 {
1247 register int tensdelta;
1248
1249 tensdelta = (*unitsptr >= 0) ?
1250 (*unitsptr / base) :
1251 (-1 - (-1 - *unitsptr) / base);
1252 *unitsptr -= tensdelta * base;
1253 return increment_overflow(tensptr, tensdelta);
1254 }
1255
1256 static int
1257 tmcomp(atmp, btmp)
1258 register const struct tm * const atmp;
1259 register const struct tm * const btmp;
1260 {
1261 register int result;
1262
1263 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1264 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1265 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1266 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1267 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1268 result = atmp->tm_sec - btmp->tm_sec;
1269 return result;
1270 }
1271
1272 static time_t
1273 time2(tmp, funcp, offset, okayp)
1274 struct tm * const tmp;
1275 void (* const funcp) P((const time_t*, long, struct tm*));
1276 const long offset;
1277 int * const okayp;
1278 {
1279 register const struct state * sp;
1280 register int dir;
1281 register int bits;
1282 register int i, j ;
1283 register int saved_seconds;
1284 time_t newt;
1285 time_t t;
1286 struct tm yourtm, mytm;
1287
1288 *okayp = FALSE;
1289 yourtm = *tmp;
1290 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1291 return WRONG;
1292 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1293 return WRONG;
1294 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
1295 return WRONG;
1296 /*
1297 ** Turn yourtm.tm_year into an actual year number for now.
1298 ** It is converted back to an offset from TM_YEAR_BASE later.
1299 */
1300 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
1301 return WRONG;
1302 while (yourtm.tm_mday <= 0) {
1303 if (increment_overflow(&yourtm.tm_year, -1))
1304 return WRONG;
1305 yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
1306 }
1307 while (yourtm.tm_mday > DAYSPERLYEAR) {
1308 yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
1309 if (increment_overflow(&yourtm.tm_year, 1))
1310 return WRONG;
1311 }
1312 for ( ; ; ) {
1313 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
1314 if (yourtm.tm_mday <= i)
1315 break;
1316 yourtm.tm_mday -= i;
1317 if (++yourtm.tm_mon >= MONSPERYEAR) {
1318 yourtm.tm_mon = 0;
1319 if (increment_overflow(&yourtm.tm_year, 1))
1320 return WRONG;
1321 }
1322 }
1323 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
1324 return WRONG;
1325 if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
1326 /*
1327 ** We can't set tm_sec to 0, because that might push the
1328 ** time below the minimum representable time.
1329 ** Set tm_sec to 59 instead.
1330 ** This assumes that the minimum representable time is
1331 ** not in the same minute that a leap second was deleted from,
1332 ** which is a safer assumption than using 58 would be.
1333 */
1334 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1335 return WRONG;
1336 saved_seconds = yourtm.tm_sec;
1337 yourtm.tm_sec = SECSPERMIN - 1;
1338 } else {
1339 saved_seconds = yourtm.tm_sec;
1340 yourtm.tm_sec = 0;
1341 }
1342 /*
1343 ** Divide the search space in half
1344 ** (this works whether time_t is signed or unsigned).
1345 */
1346 bits = TYPE_BIT(time_t) - 1;
1347 /*
1348 ** If time_t is signed, then 0 is just above the median,
1349 ** assuming two's complement arithmetic.
1350 ** If time_t is unsigned, then (1 << bits) is just above the median.
1351 */
1352 t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
1353 for ( ; ; ) {
1354 (*funcp)(&t, offset, &mytm);
1355 dir = tmcomp(&mytm, &yourtm);
1356 if (dir != 0) {
1357 if (bits-- < 0)
1358 return WRONG;
1359 if (bits < 0)
1360 --t; /* may be needed if new t is minimal */
1361 else if (dir > 0)
1362 t -= ((time_t) 1) << bits;
1363 else t += ((time_t) 1) << bits;
1364 continue;
1365 }
1366 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1367 break;
1368 /*
1369 ** Right time, wrong type.
1370 ** Hunt for right time, right type.
1371 ** It's okay to guess wrong since the guess
1372 ** gets checked.
1373 */
1374 /*
1375 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1376 */
1377 sp = (const struct state *)
1378 (((void *) funcp == (void *) localsub) ?
1379 lclptr : gmtptr);
1380 #ifdef ALL_STATE
1381 if (sp == NULL)
1382 return WRONG;
1383 #endif /* defined ALL_STATE */
1384 for (i = sp->typecnt - 1; i >= 0; --i) {
1385 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1386 continue;
1387 for (j = sp->typecnt - 1; j >= 0; --j) {
1388 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1389 continue;
1390 newt = t + sp->ttis[j].tt_gmtoff -
1391 sp->ttis[i].tt_gmtoff;
1392 (*funcp)(&newt, offset, &mytm);
1393 if (tmcomp(&mytm, &yourtm) != 0)
1394 continue;
1395 if (mytm.tm_isdst != yourtm.tm_isdst)
1396 continue;
1397 /*
1398 ** We have a match.
1399 */
1400 t = newt;
1401 goto label;
1402 }
1403 }
1404 return WRONG;
1405 }
1406 label:
1407 newt = t + saved_seconds;
1408 if ((newt < t) != (saved_seconds < 0))
1409 return WRONG;
1410 t = newt;
1411 (*funcp)(&t, offset, tmp);
1412 *okayp = TRUE;
1413 return t;
1414 }
1415
1416 static time_t
1417 time1(tmp, funcp, offset)
1418 struct tm * const tmp;
1419 void (* const funcp) P((const time_t *, long, struct tm *));
1420 const long offset;
1421 {
1422 register time_t t;
1423 register const struct state * sp;
1424 register int samei, otheri;
1425 int okay;
1426
1427 if (tmp->tm_isdst > 1)
1428 tmp->tm_isdst = 1;
1429 t = time2(tmp, funcp, offset, &okay);
1430 #ifdef PCTS
1431 /*
1432 ** PCTS code courtesy Grant Sullivan (grant (at) osf.org).
1433 */
1434 if (okay)
1435 return t;
1436 if (tmp->tm_isdst < 0)
1437 tmp->tm_isdst = 0; /* reset to std and try again */
1438 #endif /* defined PCTS */
1439 #ifndef PCTS
1440 if (okay || tmp->tm_isdst < 0)
1441 return t;
1442 #endif /* !defined PCTS */
1443 /*
1444 ** We're supposed to assume that somebody took a time of one type
1445 ** and did some math on it that yielded a "struct tm" that's bad.
1446 ** We try to divine the type they started from and adjust to the
1447 ** type they need.
1448 */
1449 /*
1450 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1451 */
1452 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
1453 lclptr : gmtptr);
1454 #ifdef ALL_STATE
1455 if (sp == NULL)
1456 return WRONG;
1457 #endif /* defined ALL_STATE */
1458 for (samei = sp->typecnt - 1; samei >= 0; --samei) {
1459 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1460 continue;
1461 for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
1462 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1463 continue;
1464 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1465 sp->ttis[samei].tt_gmtoff;
1466 tmp->tm_isdst = !tmp->tm_isdst;
1467 t = time2(tmp, funcp, offset, &okay);
1468 if (okay)
1469 return t;
1470 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1471 sp->ttis[samei].tt_gmtoff;
1472 tmp->tm_isdst = !tmp->tm_isdst;
1473 }
1474 }
1475 return WRONG;
1476 }
1477
1478 time_t
1479 mktime(tmp)
1480 struct tm * const tmp;
1481 {
1482 tzset();
1483 return time1(tmp, localsub, 0L);
1484 }
1485
1486 #ifdef STD_INSPIRED
1487
1488 time_t
1489 timelocal(tmp)
1490 struct tm * const tmp;
1491 {
1492 tmp->tm_isdst = -1; /* in case it wasn't initialized */
1493 return mktime(tmp);
1494 }
1495
1496 time_t
1497 timegm(tmp)
1498 struct tm * const tmp;
1499 {
1500 tmp->tm_isdst = 0;
1501 return time1(tmp, gmtsub, 0L);
1502 }
1503
1504 time_t
1505 timeoff(tmp, offset)
1506 struct tm * const tmp;
1507 const long offset;
1508 {
1509 tmp->tm_isdst = 0;
1510 return time1(tmp, gmtsub, offset);
1511 }
1512
1513 #endif /* defined STD_INSPIRED */
1514
1515 #ifdef CMUCS
1516
1517 /*
1518 ** The following is supplied for compatibility with
1519 ** previous versions of the CMUCS runtime library.
1520 */
1521
1522 long
1523 gtime(tmp)
1524 struct tm * const tmp;
1525 {
1526 const time_t t = mktime(tmp);
1527
1528 if (t == WRONG)
1529 return -1;
1530 return t;
1531 }
1532
1533 #endif /* defined CMUCS */
1534
1535 /*
1536 ** XXX--is the below the right way to conditionalize??
1537 */
1538
1539 #ifdef STD_INSPIRED
1540
1541 /*
1542 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
1543 ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
1544 ** is not the case if we are accounting for leap seconds.
1545 ** So, we provide the following conversion routines for use
1546 ** when exchanging timestamps with POSIX conforming systems.
1547 */
1548
1549 static long
1550 leapcorr(timep)
1551 time_t * timep;
1552 {
1553 register struct state * sp;
1554 register struct lsinfo * lp;
1555 register int i;
1556
1557 sp = lclptr;
1558 i = sp->leapcnt;
1559 while (--i >= 0) {
1560 lp = &sp->lsis[i];
1561 if (*timep >= lp->ls_trans)
1562 return lp->ls_corr;
1563 }
1564 return 0;
1565 }
1566
1567 time_t
1568 time2posix(t)
1569 time_t t;
1570 {
1571 tzset();
1572 return t - leapcorr(&t);
1573 }
1574
1575 time_t
1576 posix2time(t)
1577 time_t t;
1578 {
1579 time_t x;
1580 time_t y;
1581
1582 tzset();
1583 /*
1584 ** For a positive leap second hit, the result
1585 ** is not unique. For a negative leap second
1586 ** hit, the corresponding time doesn't exist,
1587 ** so we return an adjacent second.
1588 */
1589 x = t + leapcorr(&t);
1590 y = x - leapcorr(&x);
1591 if (y < t) {
1592 do {
1593 x++;
1594 y = x - leapcorr(&x);
1595 } while (y < t);
1596 if (t != y)
1597 return x - 1;
1598 } else if (y > t) {
1599 do {
1600 --x;
1601 y = x - leapcorr(&x);
1602 } while (y > t);
1603 if (t != y)
1604 return x + 1;
1605 }
1606 return x;
1607 }
1608
1609 #endif /* defined STD_INSPIRED */
1610