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