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