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