]> git.saurik.com Git - apple/libc.git/blob - stdtime/localtime-fbsd.c
Libc-498.tar.gz
[apple/libc.git] / stdtime / localtime-fbsd.c
1 /*
2 ** This file is in the public domain, so clarified as of
3 ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
4 */
5
6 #include <sys/cdefs.h>
7 #ifndef lint
8 #ifndef NOID
9 static char elsieid[] __unused = "@(#)localtime.c 7.78";
10 #endif /* !defined NOID */
11 #endif /* !defined lint */
12 __FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.40 2004/08/24 00:15:37 peter Exp $");
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 "namespace.h"
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #include <fcntl.h>
27 #include <pthread.h>
28 #include <errno.h>
29 #ifdef NOTIFY_TZ
30 //#define NOTIFY_TZ_DEBUG
31 //#define NOTIFY_TZ_DEBUG_FILE "/var/log/localtime.debug"
32 //#define NOTIFY_TZ_LOG "/var/log/localtime.log"
33 /* force ALL_STATE if NOTIFY_TZ is set */
34 #ifndef ALL_STATE
35 #define ALL_STATE
36 #endif /* ALL_STATE */
37 #include <mach/mach_init.h>
38 #include <notify.h>
39 #include <alloca.h>
40 #endif /* NOTIFY_TZ */
41 #include "private.h"
42 #include "un-namespace.h"
43
44 #include "tzfile.h"
45
46 #include "libc_private.h"
47
48 #define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
49 #define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
50 extern int __pthread_tsd_first;
51
52 /*
53 ** SunOS 4.1.1 headers lack O_BINARY.
54 */
55
56 #ifdef O_BINARY
57 #define OPEN_MODE (O_RDONLY | O_BINARY)
58 #endif /* defined O_BINARY */
59 #ifndef O_BINARY
60 #define OPEN_MODE O_RDONLY
61 #endif /* !defined O_BINARY */
62
63 #ifndef WILDABBR
64 /*
65 ** Someone might make incorrect use of a time zone abbreviation:
66 ** 1. They might reference tzname[0] before calling tzset (explicitly
67 ** or implicitly).
68 ** 2. They might reference tzname[1] before calling tzset (explicitly
69 ** or implicitly).
70 ** 3. They might reference tzname[1] after setting to a time zone
71 ** in which Daylight Saving Time is never observed.
72 ** 4. They might reference tzname[0] after setting to a time zone
73 ** in which Standard Time is never observed.
74 ** 5. They might reference tm.TM_ZONE after calling offtime.
75 ** What's best to do in the above cases is open to debate;
76 ** for now, we just set things up so that in any of the five cases
77 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
78 ** string "tzname[0] used before set", and similarly for the other cases.
79 ** And another: initialize tzname[0] to "ERA", with an explanation in the
80 ** manual page of what this "time zone abbreviation" means (doing this so
81 ** that tzname[0] has the "normal" length of three characters).
82 */
83 #define WILDABBR " "
84 #endif /* !defined WILDABBR */
85
86 static char wildabbr[] = "WILDABBR";
87
88 /*
89 * In June 2004 it was decided UTC was a more appropriate default time
90 * zone than GMT.
91 */
92
93 static const char gmt[] = "UTC";
94
95 /*
96 ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
97 ** We default to US rules as of 1999-08-17.
98 ** POSIX 1003.1 section 8.1.1 says that the default DST rules are
99 ** implementation dependent; for historical reasons, US rules are a
100 ** common default.
101 */
102 #ifndef TZDEFRULESTRING
103 #define TZDEFRULESTRING ",M4.1.0,M10.5.0"
104 #endif /* !defined TZDEFDST */
105
106 struct ttinfo { /* time type information */
107 long tt_gmtoff; /* UTC offset in seconds */
108 int tt_isdst; /* used to set tm_isdst */
109 int tt_abbrind; /* abbreviation list index */
110 int tt_ttisstd; /* TRUE if transition is std time */
111 int tt_ttisgmt; /* TRUE if transition is UTC */
112 };
113
114 struct lsinfo { /* leap second information */
115 time_t ls_trans; /* transition time */
116 long ls_corr; /* correction to apply */
117 };
118
119 #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
120
121 #ifdef TZNAME_MAX
122 #define MY_TZNAME_MAX TZNAME_MAX
123 #endif /* defined TZNAME_MAX */
124 #ifndef TZNAME_MAX
125 #define MY_TZNAME_MAX 255
126 #endif /* !defined TZNAME_MAX */
127
128 struct state {
129 int leapcnt;
130 int timecnt;
131 int typecnt;
132 int charcnt;
133 time_t ats[TZ_MAX_TIMES];
134 unsigned char types[TZ_MAX_TIMES];
135 struct ttinfo ttis[TZ_MAX_TYPES];
136 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
137 (2 * (MY_TZNAME_MAX + 1)))];
138 struct lsinfo lsis[TZ_MAX_LEAPS];
139 };
140
141 struct rule {
142 int r_type; /* type of rule--see below */
143 int r_day; /* day number of rule */
144 int r_week; /* week number of rule */
145 int r_mon; /* month number of rule */
146 long r_time; /* transition time of rule */
147 };
148
149 #define JULIAN_DAY 0 /* Jn - Julian day */
150 #define DAY_OF_YEAR 1 /* n - day of year */
151 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
152
153 #ifdef NOTIFY_TZ
154 typedef struct {
155 int token;
156 int notify_was_off;
157 int is_set;
158 } notify_tz_t;
159
160 #define NOTIFY_TZ_NAME "com.apple.system.timezone"
161 #endif /* NOTIFY_TZ */
162
163 /*
164 ** Prototypes for static functions.
165 */
166 #define localsub _st_localsub
167 #define time1 _st_time1
168 #define tzset_basic _st_tzset_basic
169 __private_extern__
170 #ifdef __LP64__
171 struct tm * localsub(const time_t * timep, long offset,
172 struct tm * tmp);
173 #else /* !__LP64__ */
174 void localsub(const time_t * timep, long offset,
175 struct tm * tmp);
176 #endif /* __LP64__ */
177 __private_extern__
178 time_t time1(struct tm * tmp,
179 #ifdef __LP64__
180 struct tm *(*funcp) (const time_t *,
181 long, struct tm *),
182 #else /* !__LP64__ */
183 void(*funcp) (const time_t *,
184 long, struct tm *),
185 #endif /* __LP64__ */
186 long offset,
187 int unix03);
188 __private_extern__
189 void tzset_basic(void);
190
191 #define lcl_mutex _st_lcl_mutex
192
193 #if !BUILDING_VARIANT
194 static long detzcode(const char * codep);
195 static const char * getzname(const char * strp, char **name, size_t *len);
196 static const char * getnum(const char * strp, int * nump, int min,
197 int max);
198 static const char * getsecs(const char * strp, long * secsp);
199 static const char * getoffset(const char * strp, long * offsetp);
200 static const char * getrule(const char * strp, struct rule * rulep);
201 static void gmtload(struct state * sp);
202 #ifdef __LP64__
203 static struct tm * gmtsub(const time_t * timep, long offset,
204 struct tm * tmp);
205 #else /* !__LP64__ */
206 static void gmtsub(const time_t * timep, long offset,
207 struct tm * tmp);
208 #endif /* __LP64__ */
209 static int increment_overflow(int * number, int delta);
210 static int normalize_overflow(int * tensptr, int * unitsptr,
211 int base);
212 #ifdef NOTIFY_TZ
213 static void notify_check_tz(notify_tz_t *p);
214 static void notify_register_tz(char *file, notify_tz_t *p);
215 #endif /* NOTIFY_TZ */
216 static void settzname(void);
217 static time_t time2(struct tm *tmp,
218 #ifdef __LP64__
219 struct tm *(*funcp) (const time_t *,
220 long, struct tm*),
221 #else /* !__LP64__ */
222 void(*funcp) (const time_t *,
223 long, struct tm*),
224 #endif /* __LP64__ */
225 long offset, int * okayp, int unix03);
226 static time_t time2sub(struct tm *tmp,
227 #ifdef __LP64__
228 struct tm *(*funcp) (const time_t *,
229 long, struct tm*),
230 #else /* !__LP64__ */
231 void(*funcp) (const time_t *,
232 long, struct tm*),
233 #endif /* __LP64__ */
234 long offset, int * okayp, int do_norm_secs,
235 int unix03);
236 #ifdef __LP64__
237 static struct tm * timesub(const time_t * timep, long offset,
238 const struct state * sp, struct tm * tmp);
239 #else /* !__LP64__ */
240 static void timesub(const time_t * timep, long offset,
241 const struct state * sp, struct tm * tmp);
242 #endif /* __LP64__ */
243 static int tmcomp(const struct tm * atmp,
244 const struct tm * btmp);
245 static time_t transtime(time_t janfirst, int year,
246 const struct rule * rulep, long offset);
247 static int tzload(const char * name, struct state * sp);
248 static int tzparse(const char * name, struct state * sp,
249 int lastditch);
250
251 #ifdef ALL_STATE
252 static struct state * lclptr;
253 static struct state * gmtptr;
254 #endif /* defined ALL_STATE */
255
256 #ifndef ALL_STATE
257 static struct state lclmem;
258 static struct state gmtmem;
259 #define lclptr (&lclmem)
260 #define gmtptr (&gmtmem)
261 #endif /* State Farm */
262
263 #ifndef TZ_STRLEN_MAX
264 #define TZ_STRLEN_MAX 255
265 #endif /* !defined TZ_STRLEN_MAX */
266
267 static char lcl_TZname[TZ_STRLEN_MAX + 1];
268 #ifdef NOTIFY_TZ
269 #define lcl_is_set (lcl_notify.is_set)
270 #define gmt_is_set (gmt_notify.is_set)
271 #else /* ! NOTIFY_TZ */
272 static int lcl_is_set;
273 static int gmt_is_set;
274 #endif /* NOTIFY_TZ */
275 __private_extern__ pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
276 static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
277
278 char * tzname[2] = {
279 wildabbr,
280 wildabbr
281 };
282
283 /*
284 ** Section 4.12.3 of X3.159-1989 requires that
285 ** Except for the strftime function, these functions [asctime,
286 ** ctime, gmtime, localtime] return values in one of two static
287 ** objects: a broken-down time structure and an array of char.
288 ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
289 */
290
291 static struct tm tm;
292
293 #define USG_COMPAT
294 #define ALTZONE
295 #ifdef USG_COMPAT
296 int daylight = 0;
297 __private_extern__ void _st_set_timezone(long);
298 #endif /* defined USG_COMPAT */
299
300 #ifdef ALTZONE
301 __private_extern__ long __darwin_altzone = 0;
302 #define altzone __darwin_altzone
303 #endif /* defined ALTZONE */
304
305 #ifdef NOTIFY_TZ
306 #ifdef NOTIFY_TZ_DEBUG
307 #ifdef NOTIFY_TZ_DEBUG_FILE
308 #define NOTIFY_TZ_PRINTF(fmt, args...) \
309 { \
310 FILE *_notify_tz_fp_; \
311 if((_notify_tz_fp_ = fopen(NOTIFY_TZ_DEBUG_FILE, "a")) != NULL) { \
312 fprintf(_notify_tz_fp_, "%d: " fmt, getpid(), ## args); \
313 fclose(_notify_tz_fp_); \
314 } \
315 }
316 #else /* ! NOTIFY_TZ_DEBUG_FILE */
317 #define NOTIFY_TZ_PRINTF(args...) fprintf(stdout, ## args)
318 #endif /* NOTIFY_TZ_DEBUG_FILE */
319 #endif /* NOTIFY_TZ_DEBUG */
320 #ifdef NOTIFY_TZ_LOG
321 #define NOTIFY_LOG(fmt, args...) \
322 { \
323 FILE *_notify_log_fp_; \
324 if((_notify_log_fp_ = fopen(NOTIFY_TZ_LOG, "a")) != NULL) { \
325 fprintf(_notify_log_fp_, "%d: " fmt, getpid(), ## args); \
326 fclose(_notify_log_fp_); \
327 } \
328 }
329 #endif /* NOTIFY_TZ_LOG */
330 /*--------------------------------------------------------------------
331 * __notify_78945668_info__ is a global variable (defined in Libnotify)
332 * that can be used to disable the notify mechanism. Set to a negative
333 * value to disable. It can then be set back to zero to re-enable.
334 *-------------------------------------------------------------------- */
335 extern int __notify_78945668_info__;
336
337 /*--------------------------------------------------------------------
338 * fullname is used to pass the actual path of the timezone file to the
339 * notify routines. If it is a nil string, that means no timezone file
340 * is being used.
341 *-------------------------------------------------------------------- */
342 static char * fullname = NULL;
343
344 static notify_tz_t gmt_notify = {-1, 0, 0};
345 static notify_tz_t lcl_notify = {-1, 0, 0};
346 static char notify_tz_name[] = NOTIFY_TZ_NAME;
347 #endif /* NOTIFY_TZ */
348
349 static long
350 detzcode(codep)
351 const char * const codep;
352 {
353 long result;
354 int i;
355
356 result = (codep[0] & 0x80) ? ~0L : 0L;
357 for (i = 0; i < 4; ++i)
358 result = (result << 8) | (codep[i] & 0xff);
359 return result;
360 }
361
362 static void
363 settzname(void)
364 {
365 struct state * sp = lclptr;
366 int i;
367
368 tzname[0] = wildabbr;
369 tzname[1] = wildabbr;
370 #ifdef USG_COMPAT
371 daylight = 0;
372 _st_set_timezone(0);
373 #endif /* defined USG_COMPAT */
374 #ifdef ALTZONE
375 altzone = 0;
376 #endif /* defined ALTZONE */
377 #ifdef ALL_STATE
378 if (sp == NULL) {
379 tzname[0] = tzname[1] = (char *)gmt;
380 return;
381 }
382 #endif /* defined ALL_STATE */
383 for (i = 0; i < sp->typecnt; ++i) {
384 const struct ttinfo * const ttisp = &sp->ttis[i];
385
386 tzname[ttisp->tt_isdst] =
387 &sp->chars[ttisp->tt_abbrind];
388 #ifdef USG_COMPAT
389 if (ttisp->tt_isdst)
390 daylight = 1;
391 if (i == 0 || !ttisp->tt_isdst)
392 _st_set_timezone(-(ttisp->tt_gmtoff));
393 #endif /* defined USG_COMPAT */
394 #ifdef ALTZONE
395 if (i == 0 || ttisp->tt_isdst)
396 altzone = -(ttisp->tt_gmtoff);
397 #endif /* defined ALTZONE */
398 }
399 /*
400 ** And to get the latest zone names into tzname. . .
401 */
402 for (i = 0; i < sp->timecnt; ++i) {
403 const struct ttinfo * const ttisp =
404 &sp->ttis[
405 sp->types[i]];
406
407 tzname[ttisp->tt_isdst] =
408 &sp->chars[ttisp->tt_abbrind];
409 }
410 }
411
412 #ifdef NOTIFY_TZ
413 static void
414 notify_check_tz(notify_tz_t *p)
415 {
416 unsigned int nstat;
417 int ncheck;
418
419 if (__notify_78945668_info__ < 0) {
420 #ifdef NOTIFY_TZ_DEBUG
421 if(!p->notify_was_off) NOTIFY_TZ_PRINTF("notify_check_tz: setting %s_notify->notify_was_off\n", (p == &lcl_notify ? "lcl" : "gmt"));
422 #endif /* NOTIFY_TZ_DEBUG */
423 p->notify_was_off = 1;
424 return;
425 }
426 /* force rereading the timezone file if notify was off */
427 if (p->notify_was_off) {
428 #ifdef NOTIFY_TZ_DEBUG
429 NOTIFY_TZ_PRINTF("notify_check_tz: saw %s_notify->notify_was_off\n", (p == &lcl_notify ? "lcl" : "gmt"));
430 #endif /* NOTIFY_TZ_DEBUG */
431 p->is_set = 0;
432 p->notify_was_off = 0;
433 return;
434 }
435 if (p->token < 0)
436 return;
437 nstat = notify_check(p->token, &ncheck);
438 if (nstat || ncheck) {
439 p->is_set = 0;
440 #ifdef NOTIFY_TZ_DEBUG
441 NOTIFY_TZ_PRINTF("notify_check_tz: %s changed\n", (p == &lcl_notify) ? "lcl" : "gmt");
442 #endif /* NOTIFY_TZ_DEBUG */
443 }
444 #ifdef NOTIFY_TZ_DEBUG
445 NOTIFY_TZ_PRINTF("notify_check_tz: %s unchanged\n", (p == &lcl_notify) ? "lcl" : "gmt");
446 #endif /* NOTIFY_TZ_DEBUG */
447 }
448
449 extern uint32_t notify_monitor_file(int token, char *path, int flags);
450
451 static void
452 notify_register_tz(char *file, notify_tz_t *p)
453 {
454 char *name;
455 unsigned int nstat;
456 int ncheck;
457
458 if (__notify_78945668_info__ < 0)
459 return;
460 /*----------------------------------------------------------------
461 * Since we don't record the last time zone filename, just cancel
462 * (which should remove the file monitor) and setup from scratch
463 *----------------------------------------------------------------*/
464 if (p->token >= 0)
465 notify_cancel(p->token);
466 if (!file || *file == 0) {
467 /* no time zone file to monitor */
468 p->token = -1;
469 return;
470 }
471 /*----------------------------------------------------------------
472 * Just use com.apple.system.timezone if the path is /etc/localtime.
473 * Otherwise use com.apple.system.timezone.<fullpath>
474 *----------------------------------------------------------------*/
475 if (TZDEFAULT && strcmp(file, TZDEFAULT) == 0)
476 name = notify_tz_name;
477 else {
478 name = alloca(sizeof(notify_tz_name) + strlen(file) + 1);
479 if (name == NULL) {
480 p->token = -1;
481 return;
482 }
483 strcpy(name, notify_tz_name);
484 strcat(name, ".");
485 strcat(name, file);
486 }
487 #ifdef NOTIFY_TZ_DEBUG
488 NOTIFY_TZ_PRINTF("notify_register_tz: file=%s name=%s\n", file, name);
489 #endif /* NOTIFY_TZ_DEBUG */
490 nstat = notify_register_check(name, &p->token);
491 if (nstat != 0) {
492 p->token = -1;
493 p->is_set = 0;
494 #ifdef NOTIFY_TZ_DEBUG
495 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_register_check failed: %u\n", nstat);
496 #endif /* NOTIFY_TZ_DEBUG */
497 #ifdef NOTIFY_TZ_LOG
498 NOTIFY_LOG("notify_register_check(%s) failed: %u\n", name, nstat);
499 #endif /* NOTIFY_TZ_LOG */
500 return;
501 }
502 /* don't need to request monitoring /etc/localtime */
503 if (name != notify_tz_name) {
504 #ifdef NOTIFY_TZ_DEBUG
505 NOTIFY_TZ_PRINTF("notify_register_tz: monitor %s\n", file);
506 #endif /* NOTIFY_TZ_DEBUG */
507 nstat = notify_monitor_file(p->token, file, 0);
508 if (nstat != 0) {
509 notify_cancel(p->token);
510 p->token = -1;
511 p->is_set = 0;
512 #ifdef NOTIFY_TZ_DEBUG
513 NOTIFY_TZ_PRINTF("***notify_register_tz: notify_monitor_file failed: %u\n", nstat);
514 #endif /* NOTIFY_TZ_DEBUG */
515 #ifdef NOTIFY_TZ_LOG
516 NOTIFY_LOG("notify_monitor_file(%s) failed: %u\n", file, nstat);
517 #endif /* NOTIFY_TZ_LOG */
518 return;
519 }
520 }
521 notify_check(p->token, &ncheck); /* this always returns true */
522 }
523 #endif /* NOTIFY_TZ */
524
525 static int
526 tzload(name, sp)
527 const char * name;
528 struct state * const sp;
529 {
530 const char * p;
531 int i;
532 int fid;
533
534 #ifdef NOTIFY_TZ_DEBUG
535 NOTIFY_TZ_PRINTF("tzload: name=%s\n", name);
536 #endif /* NOTIFY_TZ_DEBUG */
537 /* XXX The following is from OpenBSD, and I'm not sure it is correct */
538 if (name != NULL && issetugid() != 0)
539 if ((name[0] == ':' && name[1] == '/') ||
540 name[0] == '/' || strchr(name, '.'))
541 name = NULL;
542 if (name == NULL && (name = TZDEFAULT) == NULL)
543 return -1;
544 {
545 int doaccess;
546 struct stat stab;
547 /*
548 ** Section 4.9.1 of the C standard says that
549 ** "FILENAME_MAX expands to an integral constant expression
550 ** that is the size needed for an array of char large enough
551 ** to hold the longest file name string that the implementation
552 ** guarantees can be opened."
553 */
554 #ifdef NOTIFY_TZ
555 if (!fullname) {
556 fullname = malloc(FILENAME_MAX + 1);
557 if (!fullname)
558 return -1;
559 }
560 #else /* ! NOTIFY_TZ */
561 char fullname[FILENAME_MAX + 1];
562 #endif /* NOTIFY_TZ */
563
564 if (name[0] == ':')
565 ++name;
566 doaccess = name[0] == '/';
567 if (!doaccess) {
568 if ((p = TZDIR) == NULL)
569 return -1;
570 #ifdef NOTIFY_TZ
571 if ((strlen(p) + 1 + strlen(name) + 1) >= (FILENAME_MAX + 1))
572 #else /* ! NOTIFY_TZ */
573 if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
574 #endif /* NOTIFY_TZ */
575 return -1;
576 (void) strcpy(fullname, p);
577 (void) strcat(fullname, "/");
578 (void) strcat(fullname, name);
579 /*
580 ** Set doaccess if '.' (as in "../") shows up in name.
581 */
582 if (strchr(name, '.') != NULL)
583 doaccess = TRUE;
584 name = fullname;
585 }
586 #ifdef NOTIFY_TZ
587 else
588 strcpy(fullname, name);
589 #endif /* NOTIFY_TZ */
590 if (doaccess && access(name, R_OK) != 0)
591 return -1;
592 if ((fid = _open(name, OPEN_MODE)) == -1)
593 return -1;
594 if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
595 _close(fid);
596 return -1;
597 }
598 }
599 {
600 struct tzhead * tzhp;
601 union {
602 struct tzhead tzhead;
603 char buf[sizeof *sp + sizeof *tzhp];
604 } u;
605 int ttisstdcnt;
606 int ttisgmtcnt;
607
608 #ifdef NOTIFY_TZ_DEBUG
609 NOTIFY_TZ_PRINTF("tzload: reading %s\n", name);
610 #endif /* NOTIFY_TZ_DEBUG */
611 i = _read(fid, u.buf, sizeof u.buf);
612 if (_close(fid) != 0)
613 return -1;
614 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
615 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
616 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
617 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
618 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
619 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
620 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
621 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
622 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
623 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
624 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
625 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
626 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
627 return -1;
628 if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
629 sp->timecnt + /* types */
630 sp->typecnt * (4 + 2) + /* ttinfos */
631 sp->charcnt + /* chars */
632 sp->leapcnt * (4 + 4) + /* lsinfos */
633 ttisstdcnt + /* ttisstds */
634 ttisgmtcnt) /* ttisgmts */
635 return -1;
636 for (i = 0; i < sp->timecnt; ++i) {
637 sp->ats[i] = detzcode(p);
638 p += 4;
639 }
640 for (i = 0; i < sp->timecnt; ++i) {
641 sp->types[i] = (unsigned char) *p++;
642 if (sp->types[i] >= sp->typecnt)
643 return -1;
644 }
645 for (i = 0; i < sp->typecnt; ++i) {
646 struct ttinfo * ttisp;
647
648 ttisp = &sp->ttis[i];
649 ttisp->tt_gmtoff = detzcode(p);
650 p += 4;
651 ttisp->tt_isdst = (unsigned char) *p++;
652 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
653 return -1;
654 ttisp->tt_abbrind = (unsigned char) *p++;
655 if (ttisp->tt_abbrind < 0 ||
656 ttisp->tt_abbrind > sp->charcnt)
657 return -1;
658 }
659 for (i = 0; i < sp->charcnt; ++i)
660 sp->chars[i] = *p++;
661 sp->chars[i] = '\0'; /* ensure '\0' at end */
662 for (i = 0; i < sp->leapcnt; ++i) {
663 struct lsinfo * lsisp;
664
665 lsisp = &sp->lsis[i];
666 lsisp->ls_trans = detzcode(p);
667 p += 4;
668 lsisp->ls_corr = detzcode(p);
669 p += 4;
670 }
671 for (i = 0; i < sp->typecnt; ++i) {
672 struct ttinfo * ttisp;
673
674 ttisp = &sp->ttis[i];
675 if (ttisstdcnt == 0)
676 ttisp->tt_ttisstd = FALSE;
677 else {
678 ttisp->tt_ttisstd = *p++;
679 if (ttisp->tt_ttisstd != TRUE &&
680 ttisp->tt_ttisstd != FALSE)
681 return -1;
682 }
683 }
684 for (i = 0; i < sp->typecnt; ++i) {
685 struct ttinfo * ttisp;
686
687 ttisp = &sp->ttis[i];
688 if (ttisgmtcnt == 0)
689 ttisp->tt_ttisgmt = FALSE;
690 else {
691 ttisp->tt_ttisgmt = *p++;
692 if (ttisp->tt_ttisgmt != TRUE &&
693 ttisp->tt_ttisgmt != FALSE)
694 return -1;
695 }
696 }
697 }
698 return 0;
699 }
700
701 static const int mon_lengths[2][MONSPERYEAR] = {
702 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
703 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
704 };
705
706 static const int year_lengths[2] = {
707 DAYSPERNYEAR, DAYSPERLYEAR
708 };
709
710 /*
711 ** Given a pointer into a time zone string, scan until a character that is not
712 ** a valid character in a zone name is found. Return a pointer to that
713 ** character.
714 */
715
716 static const char *
717 getzname(strp, name, len)
718 const char * strp;
719 char ** name;
720 size_t * len;
721 {
722 char c;
723 char * ket;
724
725 if (*strp == '<' && (ket = strchr(strp, '>')) != NULL) {
726 *name = (char *)(strp + 1);
727 *len = ket - strp - 1;
728 return ket + 1;
729 }
730 *name = (char *)strp;
731 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
732 c != '+')
733 ++strp;
734 *len = strp - *name;
735 return strp;
736 }
737
738 /*
739 ** Given a pointer into a time zone string, extract a number from that string.
740 ** Check that the number is within a specified range; if it is not, return
741 ** NULL.
742 ** Otherwise, return a pointer to the first character not part of the number.
743 */
744
745 static const char *
746 getnum(strp, nump, min, max)
747 const char * strp;
748 int * const nump;
749 const int min;
750 const int max;
751 {
752 char c;
753 int num;
754
755 if (strp == NULL || !is_digit(c = *strp))
756 return NULL;
757 num = 0;
758 do {
759 num = num * 10 + (c - '0');
760 if (num > max)
761 return NULL; /* illegal value */
762 c = *++strp;
763 } while (is_digit(c));
764 if (num < min)
765 return NULL; /* illegal value */
766 *nump = num;
767 return strp;
768 }
769
770 /*
771 ** Given a pointer into a time zone string, extract a number of seconds,
772 ** in hh[:mm[:ss]] form, from the string.
773 ** If any error occurs, return NULL.
774 ** Otherwise, return a pointer to the first character not part of the number
775 ** of seconds.
776 */
777
778 static const char *
779 getsecs(strp, secsp)
780 const char * strp;
781 long * const secsp;
782 {
783 int num;
784
785 /*
786 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
787 ** "M10.4.6/26", which does not conform to Posix,
788 ** but which specifies the equivalent of
789 ** ``02:00 on the first Sunday on or after 23 Oct''.
790 */
791 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
792 if (strp == NULL)
793 return NULL;
794 *secsp = num * (long) SECSPERHOUR;
795 if (*strp == ':') {
796 ++strp;
797 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
798 if (strp == NULL)
799 return NULL;
800 *secsp += num * SECSPERMIN;
801 if (*strp == ':') {
802 ++strp;
803 /* `SECSPERMIN' allows for leap seconds. */
804 strp = getnum(strp, &num, 0, SECSPERMIN);
805 if (strp == NULL)
806 return NULL;
807 *secsp += num;
808 }
809 }
810 return strp;
811 }
812
813 /*
814 ** Given a pointer into a time zone string, extract an offset, in
815 ** [+-]hh[:mm[:ss]] form, from the string.
816 ** If any error occurs, return NULL.
817 ** Otherwise, return a pointer to the first character not part of the time.
818 */
819
820 static const char *
821 getoffset(strp, offsetp)
822 const char * strp;
823 long * const offsetp;
824 {
825 int neg = 0;
826
827 if (*strp == '-') {
828 neg = 1;
829 ++strp;
830 } else if (*strp == '+')
831 ++strp;
832 strp = getsecs(strp, offsetp);
833 if (strp == NULL)
834 return NULL; /* illegal time */
835 if (neg)
836 *offsetp = -*offsetp;
837 return strp;
838 }
839
840 /*
841 ** Given a pointer into a time zone string, extract a rule in the form
842 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
843 ** If a valid rule is not found, return NULL.
844 ** Otherwise, return a pointer to the first character not part of the rule.
845 */
846
847 static const char *
848 getrule(strp, rulep)
849 const char * strp;
850 struct rule * const rulep;
851 {
852 if (*strp == 'J') {
853 /*
854 ** Julian day.
855 */
856 rulep->r_type = JULIAN_DAY;
857 ++strp;
858 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
859 } else if (*strp == 'M') {
860 /*
861 ** Month, week, day.
862 */
863 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
864 ++strp;
865 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
866 if (strp == NULL)
867 return NULL;
868 if (*strp++ != '.')
869 return NULL;
870 strp = getnum(strp, &rulep->r_week, 1, 5);
871 if (strp == NULL)
872 return NULL;
873 if (*strp++ != '.')
874 return NULL;
875 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
876 } else if (is_digit(*strp)) {
877 /*
878 ** Day of year.
879 */
880 rulep->r_type = DAY_OF_YEAR;
881 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
882 } else return NULL; /* invalid format */
883 if (strp == NULL)
884 return NULL;
885 if (*strp == '/') {
886 /*
887 ** Time specified.
888 */
889 ++strp;
890 strp = getsecs(strp, &rulep->r_time);
891 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
892 return strp;
893 }
894
895 /*
896 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
897 ** year, a rule, and the offset from UTC at the time that rule takes effect,
898 ** calculate the Epoch-relative time that rule takes effect.
899 */
900
901 static time_t
902 transtime(janfirst, year, rulep, offset)
903 const time_t janfirst;
904 const int year;
905 const struct rule * const rulep;
906 const long offset;
907 {
908 int leapyear;
909 time_t value;
910 int i;
911 int d, m1, yy0, yy1, yy2, dow;
912
913 INITIALIZE(value);
914 leapyear = isleap(year);
915 switch (rulep->r_type) {
916
917 case JULIAN_DAY:
918 /*
919 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
920 ** years.
921 ** In non-leap years, or if the day number is 59 or less, just
922 ** add SECSPERDAY times the day number-1 to the time of
923 ** January 1, midnight, to get the day.
924 */
925 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
926 if (leapyear && rulep->r_day >= 60)
927 value += SECSPERDAY;
928 break;
929
930 case DAY_OF_YEAR:
931 /*
932 ** n - day of year.
933 ** Just add SECSPERDAY times the day number to the time of
934 ** January 1, midnight, to get the day.
935 */
936 value = janfirst + rulep->r_day * SECSPERDAY;
937 break;
938
939 case MONTH_NTH_DAY_OF_WEEK:
940 /*
941 ** Mm.n.d - nth "dth day" of month m.
942 */
943 value = janfirst;
944 for (i = 0; i < rulep->r_mon - 1; ++i)
945 value += mon_lengths[leapyear][i] * SECSPERDAY;
946
947 /*
948 ** Use Zeller's Congruence to get day-of-week of first day of
949 ** month.
950 */
951 m1 = (rulep->r_mon + 9) % 12 + 1;
952 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
953 yy1 = yy0 / 100;
954 yy2 = yy0 % 100;
955 dow = ((26 * m1 - 2) / 10 +
956 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
957 if (dow < 0)
958 dow += DAYSPERWEEK;
959
960 /*
961 ** "dow" is the day-of-week of the first day of the month. Get
962 ** the day-of-month (zero-origin) of the first "dow" day of the
963 ** month.
964 */
965 d = rulep->r_day - dow;
966 if (d < 0)
967 d += DAYSPERWEEK;
968 for (i = 1; i < rulep->r_week; ++i) {
969 if (d + DAYSPERWEEK >=
970 mon_lengths[leapyear][rulep->r_mon - 1])
971 break;
972 d += DAYSPERWEEK;
973 }
974
975 /*
976 ** "d" is the day-of-month (zero-origin) of the day we want.
977 */
978 value += d * SECSPERDAY;
979 break;
980 }
981
982 /*
983 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
984 ** question. To get the Epoch-relative time of the specified local
985 ** time on that day, add the transition time and the current offset
986 ** from UTC.
987 */
988 return value + rulep->r_time + offset;
989 }
990
991 /*
992 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
993 ** appropriate.
994 */
995
996 static int
997 tzparse(name, sp, lastditch)
998 const char * name;
999 struct state * const sp;
1000 const int lastditch;
1001 {
1002 const char * stdname;
1003 const char * dstname;
1004 size_t stdlen;
1005 size_t dstlen;
1006 long stdoffset;
1007 long dstoffset;
1008 time_t * atp;
1009 unsigned char * typep;
1010 char * cp;
1011 int load_result;
1012
1013 INITIALIZE(dstname);
1014 if (lastditch) {
1015 stdname = name;
1016 stdlen = strlen(name); /* length of standard zone name */
1017 name += stdlen;
1018 if (stdlen >= sizeof sp->chars)
1019 stdlen = (sizeof sp->chars) - 1;
1020 stdoffset = 0;
1021 } else {
1022 name = getzname(name, (char **)&stdname, &stdlen);
1023 if (stdlen < 3)
1024 return -1;
1025 if (*name == '\0')
1026 return -1; /* was "stdoffset = 0;" */
1027 else {
1028 name = getoffset(name, &stdoffset);
1029 if (name == NULL)
1030 return -1;
1031 }
1032 }
1033 load_result = tzload(TZDEFRULES, sp);
1034 #ifdef NOTIFY_TZ
1035 *fullname = 0; /* mark fullname as invalid */
1036 #endif /* NOTIFY_TZ */
1037 if (load_result != 0)
1038 sp->leapcnt = 0; /* so, we're off a little */
1039 if (*name != '\0') {
1040 dstname = name;
1041 name = getzname(name, (char **)&dstname, &dstlen);
1042 if (dstlen < 3)
1043 return -1;
1044 if (*name != '\0' && *name != ',' && *name != ';') {
1045 name = getoffset(name, &dstoffset);
1046 if (name == NULL)
1047 return -1;
1048 } else dstoffset = stdoffset - SECSPERHOUR;
1049 if (*name == '\0' && load_result != 0)
1050 name = TZDEFRULESTRING;
1051 if (*name == ',' || *name == ';') {
1052 struct rule start;
1053 struct rule end;
1054 int year;
1055 time_t janfirst;
1056 time_t starttime;
1057 time_t endtime;
1058
1059 ++name;
1060 if ((name = getrule(name, &start)) == NULL)
1061 return -1;
1062 if (*name++ != ',')
1063 return -1;
1064 if ((name = getrule(name, &end)) == NULL)
1065 return -1;
1066 if (*name != '\0')
1067 return -1;
1068 sp->typecnt = 2; /* standard time and DST */
1069 /*
1070 ** Two transitions per year, from EPOCH_YEAR to 2037.
1071 */
1072 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
1073 if (sp->timecnt > TZ_MAX_TIMES)
1074 return -1;
1075 sp->ttis[0].tt_gmtoff = -dstoffset;
1076 sp->ttis[0].tt_isdst = 1;
1077 sp->ttis[0].tt_abbrind = stdlen + 1;
1078 sp->ttis[1].tt_gmtoff = -stdoffset;
1079 sp->ttis[1].tt_isdst = 0;
1080 sp->ttis[1].tt_abbrind = 0;
1081 atp = sp->ats;
1082 typep = sp->types;
1083 janfirst = 0;
1084 for (year = EPOCH_YEAR; year <= 2037; ++year) {
1085 starttime = transtime(janfirst, year, &start,
1086 stdoffset);
1087 endtime = transtime(janfirst, year, &end,
1088 dstoffset);
1089 if (starttime > endtime) {
1090 *atp++ = endtime;
1091 *typep++ = 1; /* DST ends */
1092 *atp++ = starttime;
1093 *typep++ = 0; /* DST begins */
1094 } else {
1095 *atp++ = starttime;
1096 *typep++ = 0; /* DST begins */
1097 *atp++ = endtime;
1098 *typep++ = 1; /* DST ends */
1099 }
1100 janfirst += year_lengths[isleap(year)] *
1101 SECSPERDAY;
1102 }
1103 } else {
1104 long theirstdoffset;
1105 long theirdstoffset;
1106 long theiroffset;
1107 int isdst;
1108 int i;
1109 int j;
1110
1111 if (*name != '\0')
1112 return -1;
1113 /*
1114 ** Initial values of theirstdoffset and theirdstoffset.
1115 */
1116 theirstdoffset = 0;
1117 for (i = 0; i < sp->timecnt; ++i) {
1118 j = sp->types[i];
1119 if (!sp->ttis[j].tt_isdst) {
1120 theirstdoffset =
1121 -sp->ttis[j].tt_gmtoff;
1122 break;
1123 }
1124 }
1125 theirdstoffset = 0;
1126 for (i = 0; i < sp->timecnt; ++i) {
1127 j = sp->types[i];
1128 if (sp->ttis[j].tt_isdst) {
1129 theirdstoffset =
1130 -sp->ttis[j].tt_gmtoff;
1131 break;
1132 }
1133 }
1134 /*
1135 ** Initially we're assumed to be in standard time.
1136 */
1137 isdst = FALSE;
1138 theiroffset = theirstdoffset;
1139 /*
1140 ** Now juggle transition times and types
1141 ** tracking offsets as you do.
1142 */
1143 for (i = 0; i < sp->timecnt; ++i) {
1144 j = sp->types[i];
1145 sp->types[i] = sp->ttis[j].tt_isdst;
1146 if (sp->ttis[j].tt_ttisgmt) {
1147 /* No adjustment to transition time */
1148 } else {
1149 /*
1150 ** If summer time is in effect, and the
1151 ** transition time was not specified as
1152 ** standard time, add the summer time
1153 ** offset to the transition time;
1154 ** otherwise, add the standard time
1155 ** offset to the transition time.
1156 */
1157 /*
1158 ** Transitions from DST to DDST
1159 ** will effectively disappear since
1160 ** POSIX provides for only one DST
1161 ** offset.
1162 */
1163 if (isdst && !sp->ttis[j].tt_ttisstd) {
1164 sp->ats[i] += dstoffset -
1165 theirdstoffset;
1166 } else {
1167 sp->ats[i] += stdoffset -
1168 theirstdoffset;
1169 }
1170 }
1171 theiroffset = -sp->ttis[j].tt_gmtoff;
1172 if (sp->ttis[j].tt_isdst)
1173 theirdstoffset = theiroffset;
1174 else theirstdoffset = theiroffset;
1175 }
1176 /*
1177 ** Finally, fill in ttis.
1178 ** ttisstd and ttisgmt need not be handled.
1179 */
1180 sp->ttis[0].tt_gmtoff = -stdoffset;
1181 sp->ttis[0].tt_isdst = FALSE;
1182 sp->ttis[0].tt_abbrind = 0;
1183 sp->ttis[1].tt_gmtoff = -dstoffset;
1184 sp->ttis[1].tt_isdst = TRUE;
1185 sp->ttis[1].tt_abbrind = stdlen + 1;
1186 sp->typecnt = 2;
1187 }
1188 } else {
1189 dstlen = 0;
1190 sp->typecnt = 1; /* only standard time */
1191 sp->timecnt = 0;
1192 sp->ttis[0].tt_gmtoff = -stdoffset;
1193 sp->ttis[0].tt_isdst = 0;
1194 sp->ttis[0].tt_abbrind = 0;
1195 }
1196 sp->charcnt = stdlen + 1;
1197 if (dstlen != 0)
1198 sp->charcnt += dstlen + 1;
1199 if ((size_t) sp->charcnt > sizeof sp->chars)
1200 return -1;
1201 cp = sp->chars;
1202 (void) strncpy(cp, stdname, stdlen);
1203 cp += stdlen;
1204 *cp++ = '\0';
1205 if (dstlen != 0) {
1206 (void) strncpy(cp, dstname, dstlen);
1207 *(cp + dstlen) = '\0';
1208 }
1209 return 0;
1210 }
1211
1212 static void
1213 gmtload(sp)
1214 struct state * const sp;
1215 {
1216 if (tzload(gmt, sp) != 0)
1217 (void) tzparse(gmt, sp, TRUE);
1218 }
1219
1220 static void
1221 tzsetwall_basic(void)
1222 {
1223 #ifdef NOTIFY_TZ
1224 notify_check_tz(&lcl_notify);
1225 #endif /* NOTIFY_TZ */
1226 #ifdef NOTIFY_TZ_DEBUG
1227 if (lcl_is_set < 0) {
1228 NOTIFY_TZ_PRINTF("tzsetwall_basic lcl_is_set < 0\n");
1229 return;
1230 }
1231 NOTIFY_TZ_PRINTF("tzsetwall_basic not set\n");
1232 #else /* ! NOTIFY_TZ_DEBUG */
1233 if (lcl_is_set < 0)
1234 return;
1235 #endif /* NOTIFY_TZ_DEBUG */
1236 lcl_is_set = -1;
1237
1238 #ifdef ALL_STATE
1239 if (lclptr == NULL) {
1240 lclptr = (struct state *) malloc(sizeof *lclptr);
1241 if (lclptr == NULL) {
1242 settzname(); /* all we can do */
1243 return;
1244 }
1245 }
1246 #endif /* defined ALL_STATE */
1247 if (tzload((char *) NULL, lclptr) != 0)
1248 gmtload(lclptr);
1249 #ifdef NOTIFY_TZ
1250 notify_register_tz(fullname, &lcl_notify);
1251 #endif /* NOTIFY_TZ */
1252 settzname();
1253 }
1254
1255 void
1256 tzsetwall(void)
1257 {
1258 #ifdef NOTIFY_TZ_DEBUG
1259 NOTIFY_TZ_PRINTF("tzsetwall called\n");
1260 #endif /* NOTIFY_TZ_DEBUG */
1261 _MUTEX_LOCK(&lcl_mutex);
1262 tzsetwall_basic();
1263 _MUTEX_UNLOCK(&lcl_mutex);
1264 }
1265
1266 __private_extern__ void
1267 tzset_basic(void)
1268 {
1269 const char * name;
1270
1271 name = getenv("TZ");
1272 if (name == NULL) {
1273 tzsetwall_basic();
1274 return;
1275 }
1276
1277 #ifdef NOTIFY_TZ
1278 notify_check_tz(&lcl_notify);
1279 #endif /* NOTIFY_TZ */
1280 #ifdef NOTIFY_TZ_DEBUG
1281 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) {
1282 NOTIFY_TZ_PRINTF("tzset_basic matched %s\n", lcl_TZname);
1283 return;
1284 }
1285 #else /* ! NOTIFY_TZ_DEBUG */
1286 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1287 return;
1288 #endif /* NOTIFY_TZ_DEBUG */
1289 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1290 if (lcl_is_set)
1291 (void) strcpy(lcl_TZname, name);
1292
1293 #ifdef ALL_STATE
1294 if (lclptr == NULL) {
1295 lclptr = (struct state *) malloc(sizeof *lclptr);
1296 if (lclptr == NULL) {
1297 settzname(); /* all we can do */
1298 return;
1299 }
1300 }
1301 #endif /* defined ALL_STATE */
1302 if (*name == '\0') {
1303 /*
1304 ** User wants it fast rather than right.
1305 */
1306 lclptr->leapcnt = 0; /* so, we're off a little */
1307 lclptr->timecnt = 0;
1308 lclptr->typecnt = 0;
1309 lclptr->ttis[0].tt_isdst = 0;
1310 lclptr->ttis[0].tt_gmtoff = 0;
1311 lclptr->ttis[0].tt_abbrind = 0;
1312 (void) strcpy(lclptr->chars, gmt);
1313 #ifdef NOTIFY_TZ
1314 if (fullname)
1315 *fullname = 0;
1316 #endif /* NOTIFY_TZ */
1317 } else if (tzload(name, lclptr) != 0)
1318 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1319 (void) gmtload(lclptr);
1320 #ifdef NOTIFY_TZ
1321 notify_register_tz(fullname, &lcl_notify);
1322 #endif /* NOTIFY_TZ */
1323 settzname();
1324 }
1325
1326 void
1327 tzset(void)
1328 {
1329 #ifdef NOTIFY_TZ_DEBUG
1330 NOTIFY_TZ_PRINTF("tzset called TZ=%s\n", getenv("TZ"));
1331 #endif /* NOTIFY_TZ_DEBUG */
1332 _MUTEX_LOCK(&lcl_mutex);
1333 tzset_basic();
1334 _MUTEX_UNLOCK(&lcl_mutex);
1335 }
1336
1337 /*
1338 ** The easy way to behave "as if no library function calls" localtime
1339 ** is to not call it--so we drop its guts into "localsub", which can be
1340 ** freely called. (And no, the PANS doesn't require the above behavior--
1341 ** but it *is* desirable.)
1342 **
1343 ** The unused offset argument is for the benefit of mktime variants.
1344 */
1345
1346 /*ARGSUSED*/
1347 #ifdef __LP64__
1348 __private_extern__ struct tm *
1349 #else /* !__LP64__ */
1350 __private_extern__ void
1351 #endif /* __LP64__ */
1352 localsub(timep, offset, tmp)
1353 const time_t * const timep;
1354 const long offset;
1355 struct tm * const tmp;
1356 {
1357 struct state * sp;
1358 const struct ttinfo * ttisp;
1359 int i;
1360 const time_t t = *timep;
1361
1362 #ifdef NOTIFY_TZ_DEBUG
1363 NOTIFY_TZ_PRINTF("localsub called\n");
1364 #endif /* NOTIFY_TZ_DEBUG */
1365 sp = lclptr;
1366 #ifdef ALL_STATE
1367 if (sp == NULL) {
1368 #ifdef __LP64__
1369 return gmtsub(timep, offset, tmp);
1370 #else /* !__LP64__ */
1371 gmtsub(timep, offset, tmp);
1372 return;
1373 #endif /* __LP64__ */
1374 }
1375 #endif /* defined ALL_STATE */
1376 if (sp->timecnt == 0 || t < sp->ats[0]) {
1377 i = 0;
1378 while (sp->ttis[i].tt_isdst)
1379 if (++i >= sp->typecnt) {
1380 i = 0;
1381 break;
1382 }
1383 } else {
1384 for (i = 1; i < sp->timecnt; ++i)
1385 if (t < sp->ats[i])
1386 break;
1387 i = sp->types[i - 1];
1388 }
1389 ttisp = &sp->ttis[i];
1390 /*
1391 ** To get (wrong) behavior that's compatible with System V Release 2.0
1392 ** you'd replace the statement below with
1393 ** t += ttisp->tt_gmtoff;
1394 ** timesub(&t, 0L, sp, tmp);
1395 */
1396 #ifdef __LP64__
1397 if (timesub(&t, ttisp->tt_gmtoff, sp, tmp) == NULL)
1398 return NULL;
1399 #else /* !__LP64__ */
1400 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1401 #endif /* __LP64__ */
1402 tmp->tm_isdst = ttisp->tt_isdst;
1403 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1404 #ifdef TM_ZONE
1405 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1406 #endif /* defined TM_ZONE */
1407 #ifdef __LP64__
1408 return tmp;
1409 #endif /* __LP64__ */
1410 }
1411
1412 struct tm *
1413 localtime(timep)
1414 const time_t * const timep;
1415 {
1416 static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
1417 static pthread_key_t localtime_key = -1;
1418 struct tm *p_tm;
1419
1420 if (__isthreaded != 0) {
1421 _pthread_mutex_lock(&localtime_mutex);
1422 if (localtime_key == (pthread_key_t)-1) {
1423 localtime_key = __pthread_tsd_first + 2;
1424 if (pthread_key_init_np(localtime_key, free) < 0) {
1425 _pthread_mutex_unlock(&localtime_mutex);
1426 return(NULL);
1427 }
1428 }
1429 _pthread_mutex_unlock(&localtime_mutex);
1430 p_tm = _pthread_getspecific(localtime_key);
1431 if (p_tm == NULL) {
1432 if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
1433 == NULL)
1434 return(NULL);
1435 _pthread_setspecific(localtime_key, p_tm);
1436 }
1437 _pthread_mutex_lock(&lcl_mutex);
1438 tzset_basic();
1439 #ifdef __LP64__
1440 p_tm = localsub(timep, 0L, p_tm);
1441 #else /* !__LP64__ */
1442 localsub(timep, 0L, p_tm);
1443 #endif /* __LP64__ */
1444 _pthread_mutex_unlock(&lcl_mutex);
1445 return(p_tm);
1446 } else {
1447 tzset_basic();
1448 #ifdef __LP64__
1449 return localsub(timep, 0L, &tm);
1450 #else /* !__LP64__ */
1451 localsub(timep, 0L, &tm);
1452 return(&tm);
1453 #endif /* __LP64__ */
1454 }
1455 }
1456
1457 /*
1458 ** Re-entrant version of localtime.
1459 */
1460
1461 struct tm *
1462 localtime_r(const time_t * const __restrict timep, struct tm * __restrict tm)
1463 {
1464 _MUTEX_LOCK(&lcl_mutex);
1465 tzset_basic();
1466 #ifdef __LP64__
1467 tm = localsub(timep, 0L, tm);
1468 #else /* !__LP64__ */
1469 localsub(timep, 0L, tm);
1470 #endif /* __LP64__ */
1471 _MUTEX_UNLOCK(&lcl_mutex);
1472 return tm;
1473 }
1474
1475 /*
1476 ** gmtsub is to gmtime as localsub is to localtime.
1477 */
1478
1479 #ifdef __LP64__
1480 static struct tm *
1481 #else /* !__LP64__ */
1482 static void
1483 #endif /* __LP64__ */
1484 gmtsub(timep, offset, tmp)
1485 const time_t * const timep;
1486 const long offset;
1487 struct tm * const tmp;
1488 {
1489 #ifdef NOTIFY_TZ_DEBUG
1490 NOTIFY_TZ_PRINTF("gmtsub called\n");
1491 #endif /* NOTIFY_TZ_DEBUG */
1492 _MUTEX_LOCK(&gmt_mutex);
1493 #ifdef NOTIFY_TZ
1494 notify_check_tz(&gmt_notify);
1495 #endif /* NOTIFY_TZ */
1496 if (!gmt_is_set) {
1497 gmt_is_set = TRUE;
1498 #ifdef ALL_STATE
1499 #ifdef NOTIFY_TZ
1500 if (gmtptr == NULL)
1501 #endif /* NOTIFY_TZ */
1502 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1503 if (gmtptr != NULL)
1504 #ifdef NOTIFY_TZ
1505 {
1506 #endif /* NOTIFY_TZ */
1507 #endif /* defined ALL_STATE */
1508 gmtload(gmtptr);
1509 #ifdef NOTIFY_TZ
1510 notify_register_tz(fullname, &gmt_notify);
1511 }
1512 #endif /* NOTIFY_TZ */
1513 }
1514 _MUTEX_UNLOCK(&gmt_mutex);
1515 #ifdef __LP64__
1516 if(timesub(timep, offset, gmtptr, tmp) == NULL)
1517 return NULL;
1518 #else /* !__LP64__ */
1519 timesub(timep, offset, gmtptr, tmp);
1520 #endif /* __LP64__ */
1521 #ifdef TM_ZONE
1522 /*
1523 ** Could get fancy here and deliver something such as
1524 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1525 ** but this is no time for a treasure hunt.
1526 */
1527 if (offset != 0)
1528 tmp->TM_ZONE = wildabbr;
1529 else {
1530 #ifdef ALL_STATE
1531 if (gmtptr == NULL)
1532 tmp->TM_ZONE = (char *)gmt;
1533 else tmp->TM_ZONE = gmtptr->chars;
1534 #endif /* defined ALL_STATE */
1535 #ifndef ALL_STATE
1536 tmp->TM_ZONE = gmtptr->chars;
1537 #endif /* State Farm */
1538 }
1539 #endif /* defined TM_ZONE */
1540 #ifdef __LP64__
1541 return tmp;
1542 #endif /* __LP64__ */
1543 }
1544
1545 struct tm *
1546 gmtime(timep)
1547 const time_t * const timep;
1548 {
1549 static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
1550 static pthread_key_t gmtime_key = -1;
1551 struct tm *p_tm;
1552
1553
1554 if (__isthreaded != 0) {
1555 _pthread_mutex_lock(&gmtime_mutex);
1556 if (gmtime_key == (pthread_key_t)-1) {
1557 gmtime_key = __pthread_tsd_first + 3;
1558 if (pthread_key_init_np(gmtime_key, free) < 0) {
1559 _pthread_mutex_unlock(&gmtime_mutex);
1560 return(NULL);
1561 }
1562 }
1563 _pthread_mutex_unlock(&gmtime_mutex);
1564 /*
1565 * Changed to follow POSIX.1 threads standard, which
1566 * is what BSD currently has.
1567 */
1568 if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
1569 if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
1570 == NULL) {
1571 return(NULL);
1572 }
1573 _pthread_setspecific(gmtime_key, p_tm);
1574 }
1575 #ifdef __LP64__
1576 return gmtsub(timep, 0L, p_tm);
1577 #else /* !__LP64__ */
1578 gmtsub(timep, 0L, p_tm);
1579 return(p_tm);
1580 #endif /* __LP64__ */
1581 }
1582 else {
1583 #ifdef __LP64__
1584 return gmtsub(timep, 0L, &tm);
1585 #else /* !__LP64__ */
1586 gmtsub(timep, 0L, &tm);
1587 return(&tm);
1588 #endif /* __LP64__ */
1589 }
1590 }
1591
1592 /*
1593 * Re-entrant version of gmtime.
1594 */
1595
1596 struct tm *
1597 gmtime_r(timep, tm)
1598 const time_t * const timep;
1599 struct tm * tm;
1600 {
1601
1602 #ifdef __LP64__
1603 return gmtsub(timep, 0L, tm);
1604 #else /* !__LP64__ */
1605 gmtsub(timep, 0L, tm);
1606 return tm;
1607 #endif /* __LP64__ */
1608 }
1609
1610 #ifdef STD_INSPIRED
1611
1612 struct tm *
1613 offtime(timep, offset)
1614 const time_t * const timep;
1615 const long offset;
1616 {
1617 #ifdef __LP64__
1618 return gmtsub(timep, offset, &tm);
1619 #else /* !__LP64__ */
1620 gmtsub(timep, offset, &tm);
1621 return &tm;
1622 #endif /* __LP64__ */
1623 }
1624
1625 #endif /* defined STD_INSPIRED */
1626
1627 #ifdef __LP64__
1628 static struct tm *
1629 #else /* !__LP64__ */
1630 static void
1631 #endif /* __LP64__ */
1632 timesub(timep, offset, sp, tmp)
1633 const time_t * const timep;
1634 const long offset;
1635 const struct state * const sp;
1636 struct tm * const tmp;
1637 {
1638 const struct lsinfo * lp;
1639 long days;
1640 long rem;
1641 long y;
1642 int yleap;
1643 const int * ip;
1644 long corr;
1645 int hit;
1646 int i;
1647
1648 corr = 0;
1649 hit = 0;
1650 #ifdef ALL_STATE
1651 i = (sp == NULL) ? 0 : sp->leapcnt;
1652 #endif /* defined ALL_STATE */
1653 #ifndef ALL_STATE
1654 i = sp->leapcnt;
1655 #endif /* State Farm */
1656 while (--i >= 0) {
1657 lp = &sp->lsis[i];
1658 if (*timep >= lp->ls_trans) {
1659 if (*timep == lp->ls_trans) {
1660 hit = ((i == 0 && lp->ls_corr > 0) ||
1661 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1662 if (hit)
1663 while (i > 0 &&
1664 sp->lsis[i].ls_trans ==
1665 sp->lsis[i - 1].ls_trans + 1 &&
1666 sp->lsis[i].ls_corr ==
1667 sp->lsis[i - 1].ls_corr + 1) {
1668 ++hit;
1669 --i;
1670 }
1671 }
1672 corr = lp->ls_corr;
1673 break;
1674 }
1675 }
1676 days = *timep / SECSPERDAY;
1677 rem = *timep % SECSPERDAY;
1678 #ifdef mc68k
1679 if (*timep == 0x80000000) {
1680 /*
1681 ** A 3B1 muffs the division on the most negative number.
1682 */
1683 days = -24855;
1684 rem = -11648;
1685 }
1686 #endif /* defined mc68k */
1687 rem += (offset - corr);
1688 while (rem < 0) {
1689 rem += SECSPERDAY;
1690 --days;
1691 }
1692 while (rem >= SECSPERDAY) {
1693 rem -= SECSPERDAY;
1694 ++days;
1695 }
1696 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1697 rem = rem % SECSPERHOUR;
1698 tmp->tm_min = (int) (rem / SECSPERMIN);
1699 /*
1700 ** A positive leap second requires a special
1701 ** representation. This uses "... ??:59:60" et seq.
1702 */
1703 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1704 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1705 if (tmp->tm_wday < 0)
1706 tmp->tm_wday += DAYSPERWEEK;
1707 y = EPOCH_YEAR;
1708 #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
1709 while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
1710 long newy;
1711
1712 newy = y + days / DAYSPERNYEAR;
1713 if (days < 0)
1714 --newy;
1715 days -= (newy - y) * DAYSPERNYEAR +
1716 LEAPS_THRU_END_OF(newy - 1) -
1717 LEAPS_THRU_END_OF(y - 1);
1718 y = newy;
1719 }
1720 #ifdef __LP64__
1721 y -= TM_YEAR_BASE;
1722 if (y < INT_MIN || y > INT_MAX) {
1723 errno = EOVERFLOW;
1724 return NULL;
1725 }
1726 tmp->tm_year = y;
1727 #else /* !__LP64__ */
1728 tmp->tm_year = y - TM_YEAR_BASE;
1729 #endif /* __LP64__ */
1730 tmp->tm_yday = (int) days;
1731 ip = mon_lengths[yleap];
1732 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1733 days = days - (long) ip[tmp->tm_mon];
1734 tmp->tm_mday = (int) (days + 1);
1735 tmp->tm_isdst = 0;
1736 #ifdef TM_GMTOFF
1737 tmp->TM_GMTOFF = offset;
1738 #endif /* defined TM_GMTOFF */
1739 #ifdef __LP64__
1740 return tmp;
1741 #endif /* __LP64__ */
1742 }
1743
1744 char *
1745 ctime(timep)
1746 const time_t * const timep;
1747 {
1748 /*
1749 ** Section 4.12.3.2 of X3.159-1989 requires that
1750 ** The ctime function converts the calendar time pointed to by timer
1751 ** to local time in the form of a string. It is equivalent to
1752 ** asctime(localtime(timer))
1753 */
1754 return asctime(localtime(timep));
1755 }
1756
1757 char *
1758 ctime_r(timep, buf)
1759 const time_t * const timep;
1760 char * buf;
1761 {
1762 struct tm tm;
1763
1764 return asctime_r(localtime_r(timep, &tm), buf);
1765 }
1766
1767 /*
1768 ** Adapted from code provided by Robert Elz, who writes:
1769 ** The "best" way to do mktime I think is based on an idea of Bob
1770 ** Kridle's (so its said...) from a long time ago.
1771 ** [kridle@xinet.com as of 1996-01-16.]
1772 ** It does a binary search of the time_t space. Since time_t's are
1773 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1774 ** would still be very reasonable).
1775 */
1776
1777 #ifndef WRONG
1778 #define WRONG (-1)
1779 #endif /* !defined WRONG */
1780
1781 /*
1782 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1783 */
1784
1785 static int
1786 increment_overflow(number, delta)
1787 int * number;
1788 int delta;
1789 {
1790 int number0;
1791
1792 number0 = *number;
1793 *number += delta;
1794 return (*number < number0) != (delta < 0);
1795 }
1796
1797 static int
1798 normalize_overflow(tensptr, unitsptr, base)
1799 int * const tensptr;
1800 int * const unitsptr;
1801 const int base;
1802 {
1803 int tensdelta;
1804
1805 tensdelta = (*unitsptr >= 0) ?
1806 (*unitsptr / base) :
1807 (-1 - (-1 - *unitsptr) / base);
1808 *unitsptr -= tensdelta * base;
1809 return increment_overflow(tensptr, tensdelta);
1810 }
1811
1812 static int
1813 tmcomp(atmp, btmp)
1814 const struct tm * const atmp;
1815 const struct tm * const btmp;
1816 {
1817 int result;
1818
1819 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1820 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1821 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1822 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1823 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1824 result = atmp->tm_sec - btmp->tm_sec;
1825 return result;
1826 }
1827
1828 static time_t
1829 time2sub(tmp, funcp, offset, okayp, do_norm_secs, unix03)
1830 struct tm * const tmp;
1831 #ifdef __LP64__
1832 struct tm *(* const funcp)(const time_t*, long, struct tm*);
1833 #else /* !__LP64__ */
1834 void (* const funcp)(const time_t*, long, struct tm*);
1835 #endif /* __LP64__ */
1836 const long offset;
1837 int * const okayp;
1838 const int do_norm_secs;
1839 int unix03;
1840 {
1841 const struct state * sp;
1842 int dir;
1843 int bits;
1844 int i, j ;
1845 int saved_seconds;
1846 time_t newt;
1847 time_t t;
1848 struct tm yourtm, mytm;
1849 #ifdef __LP64__
1850 long year, il;
1851 #endif /* __LP64__ */
1852
1853 *okayp = FALSE;
1854 yourtm = *tmp;
1855 if (do_norm_secs) {
1856 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1857 SECSPERMIN))
1858 return WRONG;
1859 }
1860 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1861 return WRONG;
1862 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1863 return WRONG;
1864 if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
1865 return WRONG;
1866 /*
1867 ** Turn yourtm.tm_year into an actual year number for now.
1868 ** It is converted back to an offset from TM_YEAR_BASE later.
1869 */
1870 #ifdef __LP64__
1871 year = (long)yourtm.tm_year + TM_YEAR_BASE;
1872 #else /* !__LP64__ */
1873 if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
1874 return WRONG;
1875 #endif /* __LP64__ */
1876 while (yourtm.tm_mday <= 0) {
1877 #ifdef __LP64__
1878 year--;
1879 il = year + (1 < yourtm.tm_mon);
1880 yourtm.tm_mday += year_lengths[isleap(il)];
1881 #else /* !__LP64__ */
1882 if (increment_overflow(&yourtm.tm_year, -1))
1883 return WRONG;
1884 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1885 yourtm.tm_mday += year_lengths[isleap(i)];
1886 #endif /* __LP64__ */
1887 }
1888 while (yourtm.tm_mday > DAYSPERLYEAR) {
1889 #ifdef __LP64__
1890 il = year + (1 < yourtm.tm_mon);
1891 yourtm.tm_mday -= year_lengths[isleap(il)];
1892 year++;
1893 #else /* !__LP64__ */
1894 i = yourtm.tm_year + (1 < yourtm.tm_mon);
1895 yourtm.tm_mday -= year_lengths[isleap(i)];
1896 if (increment_overflow(&yourtm.tm_year, 1))
1897 return WRONG;
1898 #endif /* __LP64__ */
1899 }
1900 for ( ; ; ) {
1901 #ifdef __LP64__
1902 i = mon_lengths[isleap(year)][yourtm.tm_mon];
1903 #else /* !__LP64__ */
1904 i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
1905 #endif /* __LP64__ */
1906 if (yourtm.tm_mday <= i)
1907 break;
1908 yourtm.tm_mday -= i;
1909 if (++yourtm.tm_mon >= MONSPERYEAR) {
1910 yourtm.tm_mon = 0;
1911 #ifdef __LP64__
1912 year++;
1913 #else /* !__LP64__ */
1914 if (increment_overflow(&yourtm.tm_year, 1))
1915 return WRONG;
1916 #endif /* __LP64__ */
1917 }
1918 }
1919 #ifdef __LP64__
1920 year -= TM_YEAR_BASE;
1921 if (year > INT_MAX || year < INT_MIN)
1922 return WRONG;
1923 yourtm.tm_year = year;
1924 #else /* !__LP64__ */
1925 if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
1926 return WRONG;
1927 #endif /* __LP64__ */
1928 /* Don't go below 1900 for POLA */
1929 if (yourtm.tm_year < 0)
1930 return WRONG;
1931 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1932 saved_seconds = 0;
1933 else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
1934 /*
1935 ** We can't set tm_sec to 0, because that might push the
1936 ** time below the minimum representable time.
1937 ** Set tm_sec to 59 instead.
1938 ** This assumes that the minimum representable time is
1939 ** not in the same minute that a leap second was deleted from,
1940 ** which is a safer assumption than using 58 would be.
1941 */
1942 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1943 return WRONG;
1944 saved_seconds = yourtm.tm_sec;
1945 yourtm.tm_sec = SECSPERMIN - 1;
1946 } else {
1947 saved_seconds = yourtm.tm_sec;
1948 yourtm.tm_sec = 0;
1949 }
1950 /*
1951 ** Divide the search space in half
1952 ** (this works whether time_t is signed or unsigned).
1953 */
1954 bits = TYPE_BIT(time_t) - 1;
1955 /*
1956 ** If we have more than this, we will overflow tm_year for tmcomp().
1957 ** We should really return an error if we cannot represent it.
1958 */
1959 if (bits > 56)
1960 bits = 56;
1961 /*
1962 ** If time_t is signed, then 0 is just above the median,
1963 ** assuming two's complement arithmetic.
1964 ** If time_t is unsigned, then (1 << bits) is just above the median.
1965 */
1966 t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
1967 for ( ; ; ) {
1968 #ifdef __LP64__
1969 if ((*funcp)(&t, offset, &mytm) == NULL) {
1970 /* we overflowed, so t is too big */
1971 dir = 1;
1972 goto skip_tmcomp;
1973 }
1974 #else /* !__LP64__ */
1975 (*funcp)(&t, offset, &mytm);
1976 #endif /* __LP64__ */
1977 dir = tmcomp(&mytm, &yourtm);
1978 #ifdef __LP64__
1979 skip_tmcomp:
1980 #endif /* __LP64__ */
1981 if (dir != 0) {
1982 if (bits-- < 0)
1983 return WRONG;
1984 if (bits < 0)
1985 --t; /* may be needed if new t is minimal */
1986 else if (dir > 0)
1987 t -= ((time_t) 1) << bits;
1988 else t += ((time_t) 1) << bits;
1989 continue;
1990 }
1991 sp = (funcp == localsub) ? lclptr : gmtptr;
1992 if (unix03 && sp->typecnt == 1 && yourtm.tm_isdst > 0)
1993 yourtm.tm_isdst = 0; /* alternative time does not apply */
1994 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1995 break;
1996 /*
1997 ** Right time, wrong type.
1998 ** Hunt for right time, right type.
1999 ** It's okay to guess wrong since the guess
2000 ** gets checked.
2001 */
2002 #ifdef ALL_STATE
2003 if (sp == NULL)
2004 return WRONG;
2005 #endif /* defined ALL_STATE */
2006 for (i = sp->typecnt - 1; i >= 0; --i) {
2007 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2008 continue;
2009 for (j = sp->typecnt - 1; j >= 0; --j) {
2010 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2011 continue;
2012 newt = t + sp->ttis[j].tt_gmtoff -
2013 sp->ttis[i].tt_gmtoff;
2014 #ifdef __LP64__
2015 if ((*funcp)(&newt, offset, &mytm) == NULL)
2016 return WRONG;
2017 #else /* !__LP64__ */
2018 (*funcp)(&newt, offset, &mytm);
2019 #endif /* __LP64__ */
2020 if (tmcomp(&mytm, &yourtm) != 0)
2021 continue;
2022 if (mytm.tm_isdst != yourtm.tm_isdst)
2023 continue;
2024 /*
2025 ** We have a match.
2026 */
2027 t = newt;
2028 goto label;
2029 }
2030 }
2031 return WRONG;
2032 }
2033 label:
2034 newt = t + saved_seconds;
2035 if ((newt < t) != (saved_seconds < 0))
2036 return WRONG;
2037 t = newt;
2038 #ifdef __LP64__
2039 if ((*funcp)(&t, offset, tmp) == NULL)
2040 return WRONG;
2041 #else /* !__LP64__ */
2042 (*funcp)(&t, offset, tmp);
2043 #endif /* __LP64__ */
2044 *okayp = TRUE;
2045 return t;
2046 }
2047
2048 static time_t
2049 time2(tmp, funcp, offset, okayp, unix03)
2050 struct tm * const tmp;
2051 #ifdef __LP64__
2052 struct tm *(* const funcp)(const time_t*, long, struct tm*);
2053 #else /* !__LP64__ */
2054 void (* const funcp)(const time_t*, long, struct tm*);
2055 #endif /* __LP64__ */
2056 const long offset;
2057 int * const okayp;
2058 int unix03;
2059 {
2060 time_t t;
2061
2062 /*
2063 ** First try without normalization of seconds
2064 ** (in case tm_sec contains a value associated with a leap second).
2065 ** If that fails, try with normalization of seconds.
2066 */
2067 t = time2sub(tmp, funcp, offset, okayp, FALSE, unix03);
2068 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, unix03);
2069 }
2070
2071 __private_extern__ time_t
2072 time1(tmp, funcp, offset, unix03)
2073 struct tm * const tmp;
2074 #ifdef __LP64__
2075 struct tm *(* const funcp)(const time_t *, long, struct tm *);
2076 #else /* !__LP64__ */
2077 void (* const funcp)(const time_t *, long, struct tm *);
2078 #endif /* __LP64__ */
2079 const long offset;
2080 int unix03;
2081 {
2082 time_t t;
2083 const struct state * sp;
2084 int samei, otheri;
2085 int sameind, otherind;
2086 int i;
2087 int nseen;
2088 int seen[TZ_MAX_TYPES];
2089 int types[TZ_MAX_TYPES];
2090 int okay;
2091
2092 if (tmp->tm_isdst > 1)
2093 tmp->tm_isdst = 1;
2094 t = time2(tmp, funcp, offset, &okay, unix03);
2095 #ifdef PCTS
2096 /*
2097 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
2098 */
2099 if (okay)
2100 return t;
2101 if (tmp->tm_isdst < 0)
2102 tmp->tm_isdst = 0; /* reset to std and try again */
2103 #endif /* defined PCTS */
2104 #ifndef PCTS
2105 if (okay || tmp->tm_isdst < 0)
2106 return t;
2107 #endif /* !defined PCTS */
2108 /*
2109 ** We're supposed to assume that somebody took a time of one type
2110 ** and did some math on it that yielded a "struct tm" that's bad.
2111 ** We try to divine the type they started from and adjust to the
2112 ** type they need.
2113 */
2114 sp = (funcp == localsub) ? lclptr : gmtptr;
2115 #ifdef ALL_STATE
2116 if (sp == NULL)
2117 return WRONG;
2118 #endif /* defined ALL_STATE */
2119 for (i = 0; i < sp->typecnt; ++i)
2120 seen[i] = FALSE;
2121 nseen = 0;
2122 for (i = sp->timecnt - 1; i >= 0; --i)
2123 if (!seen[sp->types[i]]) {
2124 seen[sp->types[i]] = TRUE;
2125 types[nseen++] = sp->types[i];
2126 }
2127 for (sameind = 0; sameind < nseen; ++sameind) {
2128 samei = types[sameind];
2129 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2130 continue;
2131 for (otherind = 0; otherind < nseen; ++otherind) {
2132 otheri = types[otherind];
2133 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2134 continue;
2135 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2136 sp->ttis[samei].tt_gmtoff;
2137 tmp->tm_isdst = !tmp->tm_isdst;
2138 t = time2(tmp, funcp, offset, &okay, unix03);
2139 if (okay)
2140 return t;
2141 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2142 sp->ttis[samei].tt_gmtoff;
2143 tmp->tm_isdst = !tmp->tm_isdst;
2144 }
2145 }
2146 return WRONG;
2147 }
2148 #else /* BUILDING_VARIANT */
2149 __private_extern__ pthread_mutex_t lcl_mutex;
2150 #endif /* BUILDING_VARIANT */
2151
2152 time_t
2153 mktime(tmp)
2154 struct tm * const tmp;
2155 {
2156 time_t mktime_return_value;
2157 int serrno = errno;
2158 _MUTEX_LOCK(&lcl_mutex);
2159 tzset_basic();
2160 mktime_return_value = time1(tmp, localsub, 0L, __DARWIN_UNIX03);
2161 _MUTEX_UNLOCK(&lcl_mutex);
2162 errno = serrno;
2163 return(mktime_return_value);
2164 }
2165
2166 #if !BUILDING_VARIANT
2167 #ifdef STD_INSPIRED
2168
2169 time_t
2170 timelocal(tmp)
2171 struct tm * const tmp;
2172 {
2173 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2174 return mktime(tmp);
2175 }
2176
2177 time_t
2178 timegm(tmp)
2179 struct tm * const tmp;
2180 {
2181 tmp->tm_isdst = 0;
2182 return time1(tmp, gmtsub, 0L, __DARWIN_UNIX03);
2183 }
2184
2185 time_t
2186 timeoff(tmp, offset)
2187 struct tm * const tmp;
2188 const long offset;
2189 {
2190 tmp->tm_isdst = 0;
2191 return time1(tmp, gmtsub, offset, __DARWIN_UNIX03);
2192 }
2193
2194 #endif /* defined STD_INSPIRED */
2195
2196 #ifdef CMUCS
2197
2198 /*
2199 ** The following is supplied for compatibility with
2200 ** previous versions of the CMUCS runtime library.
2201 */
2202
2203 long
2204 gtime(tmp)
2205 struct tm * const tmp;
2206 {
2207 const time_t t = mktime(tmp);
2208
2209 if (t == WRONG)
2210 return -1;
2211 return t;
2212 }
2213
2214 #endif /* defined CMUCS */
2215
2216 /*
2217 ** XXX--is the below the right way to conditionalize??
2218 */
2219
2220 #ifdef STD_INSPIRED
2221
2222 /*
2223 ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2224 ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2225 ** is not the case if we are accounting for leap seconds.
2226 ** So, we provide the following conversion routines for use
2227 ** when exchanging timestamps with POSIX conforming systems.
2228 */
2229
2230 static long
2231 leapcorr(timep)
2232 time_t * timep;
2233 {
2234 struct state * sp;
2235 struct lsinfo * lp;
2236 int i;
2237
2238 sp = lclptr;
2239 i = sp->leapcnt;
2240 while (--i >= 0) {
2241 lp = &sp->lsis[i];
2242 if (*timep >= lp->ls_trans)
2243 return lp->ls_corr;
2244 }
2245 return 0;
2246 }
2247
2248 time_t
2249 time2posix(t)
2250 time_t t;
2251 {
2252 tzset();
2253 return t - leapcorr(&t);
2254 }
2255
2256 time_t
2257 posix2time(t)
2258 time_t t;
2259 {
2260 time_t x;
2261 time_t y;
2262
2263 tzset();
2264 /*
2265 ** For a positive leap second hit, the result
2266 ** is not unique. For a negative leap second
2267 ** hit, the corresponding time doesn't exist,
2268 ** so we return an adjacent second.
2269 */
2270 x = t + leapcorr(&t);
2271 y = x - leapcorr(&x);
2272 if (y < t) {
2273 do {
2274 x++;
2275 y = x - leapcorr(&x);
2276 } while (y < t);
2277 if (t != y)
2278 return x - 1;
2279 } else if (y > t) {
2280 do {
2281 --x;
2282 y = x - leapcorr(&x);
2283 } while (y > t);
2284 if (t != y)
2285 return x + 1;
2286 }
2287 return x;
2288 }
2289
2290 #endif /* defined STD_INSPIRED */
2291 #endif /* !BUILDING_VARIANT */