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