blob: 8d84a92ddd2b621a28df365a766e26a1248d5dc5 [file] [log] [blame]
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001/*
2** This file is in the public domain, so clarified as of
3** 1996-06-05 by Arthur David Olson.
4*/
5
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00006/*
7** Leap second handling from Bradley White.
8** POSIX-style TZ environment variable handling from Guy Harris.
9*/
10
11/*LINTLIBRARY*/
12
Frank Tang1f164ee2022-11-08 12:31:27 -080013#include <stdbool.h>
14
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000015#include "private.h"
16#include "tzfile.h"
17#include "fcntl.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000018
19#ifndef TZ_ABBR_MAX_LEN
20#define TZ_ABBR_MAX_LEN 16
21#endif /* !defined TZ_ABBR_MAX_LEN */
22
23#ifndef TZ_ABBR_CHAR_SET
24#define TZ_ABBR_CHAR_SET \
25 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
26#endif /* !defined TZ_ABBR_CHAR_SET */
27
28#ifndef TZ_ABBR_ERR_CHAR
29#define TZ_ABBR_ERR_CHAR '_'
30#endif /* !defined TZ_ABBR_ERR_CHAR */
31
32/*
33** SunOS 4.1.1 headers lack O_BINARY.
34*/
35
36#ifdef O_BINARY
37#define OPEN_MODE (O_RDONLY | O_BINARY)
38#endif /* defined O_BINARY */
39#ifndef O_BINARY
40#define OPEN_MODE O_RDONLY
41#endif /* !defined O_BINARY */
42
43#ifndef WILDABBR
44/*
45** Someone might make incorrect use of a time zone abbreviation:
46** 1. They might reference tzname[0] before calling tzset (explicitly
47** or implicitly).
48** 2. They might reference tzname[1] before calling tzset (explicitly
49** or implicitly).
50** 3. They might reference tzname[1] after setting to a time zone
51** in which Daylight Saving Time is never observed.
52** 4. They might reference tzname[0] after setting to a time zone
53** in which Standard Time is never observed.
54** 5. They might reference tm.TM_ZONE after calling offtime.
55** What's best to do in the above cases is open to debate;
56** for now, we just set things up so that in any of the five cases
57** WILDABBR is used. Another possibility: initialize tzname[0] to the
58** string "tzname[0] used before set", and similarly for the other cases.
59** And another: initialize tzname[0] to "ERA", with an explanation in the
60** manual page of what this "time zone abbreviation" means (doing this so
61** that tzname[0] has the "normal" length of three characters).
62*/
63#define WILDABBR " "
64#endif /* !defined WILDABBR */
65
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080066static const char wildabbr[] = WILDABBR;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000067
68static const char gmt[] = "GMT";
69
70/*
71** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
72** We default to US rules as of 1999-08-17.
73** POSIX 1003.1 section 8.1.1 says that the default DST rules are
74** implementation dependent; for historical reasons, US rules are a
75** common default.
76*/
77#ifndef TZDEFRULESTRING
78#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
79#endif /* !defined TZDEFDST */
80
81struct ttinfo { /* time type information */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080082 int_fast32_t tt_gmtoff; /* UT offset in seconds */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000083 int tt_isdst; /* used to set tm_isdst */
84 int tt_abbrind; /* abbreviation list index */
Frank Tang1f164ee2022-11-08 12:31:27 -080085 int tt_ttisstd; /* true if transition is std time */
86 int tt_ttisgmt; /* true if transition is UT */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000087};
88
89struct lsinfo { /* leap second information */
90 time_t ls_trans; /* transition time */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080091 int_fast64_t ls_corr; /* correction to apply */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000092};
93
94#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
95
96#ifdef TZNAME_MAX
97#define MY_TZNAME_MAX TZNAME_MAX
98#endif /* defined TZNAME_MAX */
99#ifndef TZNAME_MAX
100#define MY_TZNAME_MAX 255
101#endif /* !defined TZNAME_MAX */
102
103struct state {
104 int leapcnt;
105 int timecnt;
106 int typecnt;
107 int charcnt;
108 int goback;
109 int goahead;
110 time_t ats[TZ_MAX_TIMES];
111 unsigned char types[TZ_MAX_TIMES];
112 struct ttinfo ttis[TZ_MAX_TYPES];
113 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
114 (2 * (MY_TZNAME_MAX + 1)))];
115 struct lsinfo lsis[TZ_MAX_LEAPS];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800116 int defaulttype; /* for early times or if no transitions */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000117};
118
119struct rule {
120 int r_type; /* type of rule--see below */
121 int r_day; /* day number of rule */
122 int r_week; /* week number of rule */
123 int r_mon; /* month number of rule */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800124 int_fast32_t r_time; /* transition time of rule */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000125};
126
127#define JULIAN_DAY 0 /* Jn - Julian day */
128#define DAY_OF_YEAR 1 /* n - day of year */
129#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
130
131/*
132** Prototypes for static functions.
133*/
134
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800135static int_fast32_t detzcode(const char * codep);
136static int_fast64_t detzcode64(const char * codep);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000137static int differ_by_repeat(time_t t1, time_t t0);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800138static const char * getzname(const char * strp) ATTRIBUTE_PURE;
139static const char * getqzname(const char * strp, const int delim)
140 ATTRIBUTE_PURE;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000141static const char * getnum(const char * strp, int * nump, int min,
142 int max);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800143static const char * getsecs(const char * strp, int_fast32_t * secsp);
144static const char * getoffset(const char * strp, int_fast32_t * offsetp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000145static const char * getrule(const char * strp, struct rule * rulep);
146static void gmtload(struct state * sp);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800147static struct tm * gmtsub(const time_t * timep, int_fast32_t offset,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000148 struct tm * tmp);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800149static struct tm * localsub(const time_t * timep, int_fast32_t offset,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000150 struct tm * tmp);
151static int increment_overflow(int * number, int delta);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800152static int leaps_thru_end_of(int y) ATTRIBUTE_PURE;
153static int increment_overflow32(int_fast32_t * number, int delta);
154static int increment_overflow_time(time_t *t, int_fast32_t delta);
155static int normalize_overflow32(int_fast32_t * tensptr,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000156 int * unitsptr, int base);
157static int normalize_overflow(int * tensptr, int * unitsptr,
158 int base);
159static void settzname(void);
160static time_t time1(struct tm * tmp,
161 struct tm * (*funcp)(const time_t *,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800162 int_fast32_t, struct tm *),
163 int_fast32_t offset);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000164static time_t time2(struct tm *tmp,
165 struct tm * (*funcp)(const time_t *,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800166 int_fast32_t, struct tm*),
167 int_fast32_t offset, int * okayp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000168static time_t time2sub(struct tm *tmp,
169 struct tm * (*funcp)(const time_t *,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800170 int_fast32_t, struct tm*),
171 int_fast32_t offset, int * okayp, int do_norm_secs);
172static struct tm * timesub(const time_t * timep, int_fast32_t offset,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000173 const struct state * sp, struct tm * tmp);
174static int tmcomp(const struct tm * atmp,
175 const struct tm * btmp);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800176static int_fast32_t transtime(int year, const struct rule * rulep,
177 int_fast32_t offset)
178 ATTRIBUTE_PURE;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000179static int typesequiv(const struct state * sp, int a, int b);
180static int tzload(const char * name, struct state * sp,
181 int doextend);
182static int tzparse(const char * name, struct state * sp,
183 int lastditch);
184
185#ifdef ALL_STATE
186static struct state * lclptr;
187static struct state * gmtptr;
188#endif /* defined ALL_STATE */
189
190#ifndef ALL_STATE
191static struct state lclmem;
192static struct state gmtmem;
193#define lclptr (&lclmem)
194#define gmtptr (&gmtmem)
195#endif /* State Farm */
196
197#ifndef TZ_STRLEN_MAX
198#define TZ_STRLEN_MAX 255
199#endif /* !defined TZ_STRLEN_MAX */
200
201static char lcl_TZname[TZ_STRLEN_MAX + 1];
202static int lcl_is_set;
203static int gmt_is_set;
204
205char * tzname[2] = {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800206 (char *) wildabbr,
207 (char *) wildabbr
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000208};
209
210/*
211** Section 4.12.3 of X3.159-1989 requires that
212** Except for the strftime function, these functions [asctime,
213** ctime, gmtime, localtime] return values in one of two static
214** objects: a broken-down time structure and an array of char.
215** Thanks to Paul Eggert for noting this.
216*/
217
218static struct tm tm;
219
220#ifdef USG_COMPAT
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800221long timezone = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000222int daylight = 0;
223#endif /* defined USG_COMPAT */
224
225#ifdef ALTZONE
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800226long altzone = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000227#endif /* defined ALTZONE */
228
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800229static int_fast32_t
230detzcode(const char *const codep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000231{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800232 register int_fast32_t result;
233 register int i;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000234
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800235 result = (codep[0] & 0x80) ? -1 : 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000236 for (i = 0; i < 4; ++i)
237 result = (result << 8) | (codep[i] & 0xff);
238 return result;
239}
240
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800241static int_fast64_t
242detzcode64(const char *const codep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000243{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800244 register int_fast64_t result;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000245 register int i;
246
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800247 result = (codep[0] & 0x80) ? -1 : 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000248 for (i = 0; i < 8; ++i)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800249 result = (result << 8) | (codep[i] & 0xff);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000250 return result;
251}
252
253static void
254settzname(void)
255{
256 register struct state * const sp = lclptr;
257 register int i;
258
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800259 tzname[0] = tzname[1] = (char *) wildabbr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000260#ifdef USG_COMPAT
261 daylight = 0;
262 timezone = 0;
263#endif /* defined USG_COMPAT */
264#ifdef ALTZONE
265 altzone = 0;
266#endif /* defined ALTZONE */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000267 if (sp == NULL) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800268 tzname[0] = tzname[1] = (char *) gmt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000269 return;
270 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000271 /*
272 ** And to get the latest zone names into tzname. . .
273 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800274 for (i = 0; i < sp->typecnt; ++i) {
275 register const struct ttinfo * const ttisp = &sp->ttis[i];
276
277 tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
278 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000279 for (i = 0; i < sp->timecnt; ++i) {
280 register const struct ttinfo * const ttisp =
281 &sp->ttis[
282 sp->types[i]];
283
284 tzname[ttisp->tt_isdst] =
285 &sp->chars[ttisp->tt_abbrind];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800286#ifdef USG_COMPAT
287 if (ttisp->tt_isdst)
288 daylight = 1;
289 if (!ttisp->tt_isdst)
290 timezone = -(ttisp->tt_gmtoff);
291#endif /* defined USG_COMPAT */
292#ifdef ALTZONE
293 if (ttisp->tt_isdst)
294 altzone = -(ttisp->tt_gmtoff);
295#endif /* defined ALTZONE */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000296 }
297 /*
298 ** Finally, scrub the abbreviations.
299 ** First, replace bogus characters.
300 */
301 for (i = 0; i < sp->charcnt; ++i)
302 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
303 sp->chars[i] = TZ_ABBR_ERR_CHAR;
304 /*
305 ** Second, truncate long abbreviations.
306 */
307 for (i = 0; i < sp->typecnt; ++i) {
308 register const struct ttinfo * const ttisp = &sp->ttis[i];
309 register char * cp = &sp->chars[ttisp->tt_abbrind];
310
311 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
312 strcmp(cp, GRANDPARENTED) != 0)
313 *(cp + TZ_ABBR_MAX_LEN) = '\0';
314 }
315}
316
317static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800318differ_by_repeat(const time_t t1, const time_t t0)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000319{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800320 if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
321 return 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000322 return t1 - t0 == SECSPERREPEAT;
323}
324
325static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800326tzload(register const char *name, register struct state *const sp,
327 register const int doextend)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000328{
329 register const char * p;
330 register int i;
331 register int fid;
332 register int stored;
333 register int nread;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800334 typedef union {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000335 struct tzhead tzhead;
336 char buf[2 * sizeof(struct tzhead) +
337 2 * sizeof *sp +
338 4 * TZ_MAX_TIMES];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800339 } u_t;
340#ifdef ALL_STATE
341 register u_t * const up = malloc(sizeof *up);
342#else /* !defined ALL_STATE */
343 u_t u;
344 register u_t * const up = &u;
345#endif /* !defined ALL_STATE */
346
Frank Tang1f164ee2022-11-08 12:31:27 -0800347 sp->goback = sp->goahead = false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800348
349 if (up == NULL)
350 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000351
352 if (name == NULL && (name = TZDEFAULT) == NULL)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800353 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000354 {
355 register int doaccess;
356 /*
357 ** Section 4.9.1 of the C standard says that
358 ** "FILENAME_MAX expands to an integral constant expression
359 ** that is the size needed for an array of char large enough
360 ** to hold the longest file name string that the implementation
361 ** guarantees can be opened."
362 */
363 char fullname[FILENAME_MAX + 1];
364
365 if (name[0] == ':')
366 ++name;
367 doaccess = name[0] == '/';
368 if (!doaccess) {
369 if ((p = TZDIR) == NULL)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800370 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000371 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800372 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000373 (void) strcpy(fullname, p);
374 (void) strcat(fullname, "/");
375 (void) strcat(fullname, name);
376 /*
377 ** Set doaccess if '.' (as in "../") shows up in name.
378 */
379 if (strchr(name, '.') != NULL)
Frank Tang1f164ee2022-11-08 12:31:27 -0800380 doaccess = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000381 name = fullname;
382 }
383 if (doaccess && access(name, R_OK) != 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800384 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000385 if ((fid = open(name, OPEN_MODE)) == -1)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800386 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000387 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800388 nread = read(fid, up->buf, sizeof up->buf);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000389 if (close(fid) < 0 || nread <= 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800390 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000391 for (stored = 4; stored <= 8; stored *= 2) {
392 int ttisstdcnt;
393 int ttisgmtcnt;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800394 int timecnt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000395
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800396 ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
397 ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
398 sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
399 sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
400 sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
401 sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
402 p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000403 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
404 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
405 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
406 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
407 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
408 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800409 goto oops;
410 if (nread - (p - up->buf) <
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000411 sp->timecnt * stored + /* ats */
412 sp->timecnt + /* types */
413 sp->typecnt * 6 + /* ttinfos */
414 sp->charcnt + /* chars */
415 sp->leapcnt * (stored + 4) + /* lsinfos */
416 ttisstdcnt + /* ttisstds */
417 ttisgmtcnt) /* ttisgmts */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800418 goto oops;
419 timecnt = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000420 for (i = 0; i < sp->timecnt; ++i) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800421 int_fast64_t at
422 = stored == 4 ? detzcode(p) : detzcode64(p);
423 sp->types[i] = ((TYPE_SIGNED(time_t)
424 ? time_t_min <= at
425 : 0 <= at)
426 && at <= time_t_max);
427 if (sp->types[i]) {
428 if (i && !timecnt && at != time_t_min) {
429 /*
430 ** Keep the earlier record, but tweak
431 ** it so that it starts with the
432 ** minimum time_t value.
433 */
434 sp->types[i - 1] = 1;
435 sp->ats[timecnt++] = time_t_min;
436 }
437 sp->ats[timecnt++] = at;
438 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000439 p += stored;
440 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800441 timecnt = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000442 for (i = 0; i < sp->timecnt; ++i) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800443 unsigned char typ = *p++;
444 if (sp->typecnt <= typ)
445 goto oops;
446 if (sp->types[i])
447 sp->types[timecnt++] = typ;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000448 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800449 sp->timecnt = timecnt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000450 for (i = 0; i < sp->typecnt; ++i) {
451 register struct ttinfo * ttisp;
452
453 ttisp = &sp->ttis[i];
454 ttisp->tt_gmtoff = detzcode(p);
455 p += 4;
456 ttisp->tt_isdst = (unsigned char) *p++;
457 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800458 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000459 ttisp->tt_abbrind = (unsigned char) *p++;
460 if (ttisp->tt_abbrind < 0 ||
461 ttisp->tt_abbrind > sp->charcnt)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800462 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000463 }
464 for (i = 0; i < sp->charcnt; ++i)
465 sp->chars[i] = *p++;
466 sp->chars[i] = '\0'; /* ensure '\0' at end */
467 for (i = 0; i < sp->leapcnt; ++i) {
468 register struct lsinfo * lsisp;
469
470 lsisp = &sp->lsis[i];
471 lsisp->ls_trans = (stored == 4) ?
472 detzcode(p) : detzcode64(p);
473 p += stored;
474 lsisp->ls_corr = detzcode(p);
475 p += 4;
476 }
477 for (i = 0; i < sp->typecnt; ++i) {
478 register struct ttinfo * ttisp;
479
480 ttisp = &sp->ttis[i];
481 if (ttisstdcnt == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -0800482 ttisp->tt_ttisstd = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000483 else {
484 ttisp->tt_ttisstd = *p++;
Frank Tang1f164ee2022-11-08 12:31:27 -0800485 if (ttisp->tt_ttisstd != true &&
486 ttisp->tt_ttisstd != false)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800487 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000488 }
489 }
490 for (i = 0; i < sp->typecnt; ++i) {
491 register struct ttinfo * ttisp;
492
493 ttisp = &sp->ttis[i];
494 if (ttisgmtcnt == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -0800495 ttisp->tt_ttisgmt = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000496 else {
497 ttisp->tt_ttisgmt = *p++;
Frank Tang1f164ee2022-11-08 12:31:27 -0800498 if (ttisp->tt_ttisgmt != true &&
499 ttisp->tt_ttisgmt != false)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800500 goto oops;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000501 }
502 }
503 /*
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000504 ** If this is an old file, we're done.
505 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800506 if (up->tzhead.tzh_version[0] == '\0')
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000507 break;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800508 nread -= p - up->buf;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000509 for (i = 0; i < nread; ++i)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800510 up->buf[i] = p[i];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000511 /*
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800512 ** If this is a signed narrow time_t system, we're done.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000513 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800514 if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000515 break;
516 }
517 if (doextend && nread > 2 &&
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800518 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000519 sp->typecnt + 2 <= TZ_MAX_TYPES) {
520 struct state ts;
521 register int result;
522
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800523 up->buf[nread - 1] = '\0';
Frank Tang1f164ee2022-11-08 12:31:27 -0800524 result = tzparse(&up->buf[1], &ts, false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000525 if (result == 0 && ts.typecnt == 2 &&
526 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
527 for (i = 0; i < 2; ++i)
528 ts.ttis[i].tt_abbrind +=
529 sp->charcnt;
530 for (i = 0; i < ts.charcnt; ++i)
531 sp->chars[sp->charcnt++] =
532 ts.chars[i];
533 i = 0;
534 while (i < ts.timecnt &&
535 ts.ats[i] <=
536 sp->ats[sp->timecnt - 1])
537 ++i;
538 while (i < ts.timecnt &&
539 sp->timecnt < TZ_MAX_TIMES) {
540 sp->ats[sp->timecnt] =
541 ts.ats[i];
542 sp->types[sp->timecnt] =
543 sp->typecnt +
544 ts.types[i];
545 ++sp->timecnt;
546 ++i;
547 }
548 sp->ttis[sp->typecnt++] = ts.ttis[0];
549 sp->ttis[sp->typecnt++] = ts.ttis[1];
550 }
551 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000552 if (sp->timecnt > 1) {
553 for (i = 1; i < sp->timecnt; ++i)
554 if (typesequiv(sp, sp->types[i], sp->types[0]) &&
555 differ_by_repeat(sp->ats[i], sp->ats[0])) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800556 sp->goback = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000557 break;
558 }
559 for (i = sp->timecnt - 2; i >= 0; --i)
560 if (typesequiv(sp, sp->types[sp->timecnt - 1],
561 sp->types[i]) &&
562 differ_by_repeat(sp->ats[sp->timecnt - 1],
563 sp->ats[i])) {
Frank Tang1f164ee2022-11-08 12:31:27 -0800564 sp->goahead = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000565 break;
566 }
567 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800568 /*
Frank Tang3e05d9d2021-11-08 14:04:04 -0800569 ** If type 0 is unused in transitions,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800570 ** it's the type to use for early times.
571 */
572 for (i = 0; i < sp->typecnt; ++i)
573 if (sp->types[i] == 0)
574 break;
575 i = (i >= sp->typecnt) ? 0 : -1;
576 /*
577 ** Absent the above,
578 ** if there are transition times
579 ** and the first transition is to a daylight time
580 ** find the standard type less than and closest to
581 ** the type of the first transition.
582 */
583 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
584 i = sp->types[0];
585 while (--i >= 0)
586 if (!sp->ttis[i].tt_isdst)
587 break;
588 }
589 /*
590 ** If no result yet, find the first standard type.
591 ** If there is none, punt to type zero.
592 */
593 if (i < 0) {
594 i = 0;
595 while (sp->ttis[i].tt_isdst)
596 if (++i >= sp->typecnt) {
597 i = 0;
598 break;
599 }
600 }
601 sp->defaulttype = i;
602#ifdef ALL_STATE
603 free(up);
604#endif /* defined ALL_STATE */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000605 return 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800606oops:
607#ifdef ALL_STATE
608 free(up);
609#endif /* defined ALL_STATE */
610 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000611}
612
613static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800614typesequiv(const struct state *const sp, const int a, const int b)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000615{
616 register int result;
617
618 if (sp == NULL ||
619 a < 0 || a >= sp->typecnt ||
620 b < 0 || b >= sp->typecnt)
Frank Tang1f164ee2022-11-08 12:31:27 -0800621 result = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000622 else {
623 register const struct ttinfo * ap = &sp->ttis[a];
624 register const struct ttinfo * bp = &sp->ttis[b];
625 result = ap->tt_gmtoff == bp->tt_gmtoff &&
626 ap->tt_isdst == bp->tt_isdst &&
627 ap->tt_ttisstd == bp->tt_ttisstd &&
628 ap->tt_ttisgmt == bp->tt_ttisgmt &&
629 strcmp(&sp->chars[ap->tt_abbrind],
630 &sp->chars[bp->tt_abbrind]) == 0;
631 }
632 return result;
633}
634
635static const int mon_lengths[2][MONSPERYEAR] = {
636 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
637 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
638};
639
640static const int year_lengths[2] = {
641 DAYSPERNYEAR, DAYSPERLYEAR
642};
643
644/*
645** Given a pointer into a time zone string, scan until a character that is not
646** a valid character in a zone name is found. Return a pointer to that
647** character.
648*/
649
650static const char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800651getzname(register const char *strp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000652{
653 register char c;
654
655 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
656 c != '+')
657 ++strp;
658 return strp;
659}
660
661/*
662** Given a pointer into an extended time zone string, scan until the ending
663** delimiter of the zone name is located. Return a pointer to the delimiter.
664**
665** As with getzname above, the legal character set is actually quite
666** restricted, with other characters producing undefined results.
667** We don't do any checking here; checking is done later in common-case code.
668*/
669
670static const char *
671getqzname(register const char *strp, const int delim)
672{
673 register int c;
674
675 while ((c = *strp) != '\0' && c != delim)
676 ++strp;
677 return strp;
678}
679
680/*
681** Given a pointer into a time zone string, extract a number from that string.
682** Check that the number is within a specified range; if it is not, return
683** NULL.
684** Otherwise, return a pointer to the first character not part of the number.
685*/
686
687static const char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800688getnum(register const char *strp, int *const nump, const int min, const int max)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000689{
690 register char c;
691 register int num;
692
693 if (strp == NULL || !is_digit(c = *strp))
694 return NULL;
695 num = 0;
696 do {
697 num = num * 10 + (c - '0');
698 if (num > max)
699 return NULL; /* illegal value */
700 c = *++strp;
701 } while (is_digit(c));
702 if (num < min)
703 return NULL; /* illegal value */
704 *nump = num;
705 return strp;
706}
707
708/*
709** Given a pointer into a time zone string, extract a number of seconds,
710** in hh[:mm[:ss]] form, from the string.
711** If any error occurs, return NULL.
712** Otherwise, return a pointer to the first character not part of the number
713** of seconds.
714*/
715
716static const char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800717getsecs(register const char *strp, int_fast32_t *const secsp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000718{
719 int num;
720
721 /*
722 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
723 ** "M10.4.6/26", which does not conform to Posix,
724 ** but which specifies the equivalent of
725 ** ``02:00 on the first Sunday on or after 23 Oct''.
726 */
727 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
728 if (strp == NULL)
729 return NULL;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800730 *secsp = num * (int_fast32_t) SECSPERHOUR;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000731 if (*strp == ':') {
732 ++strp;
733 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
734 if (strp == NULL)
735 return NULL;
736 *secsp += num * SECSPERMIN;
737 if (*strp == ':') {
738 ++strp;
739 /* `SECSPERMIN' allows for leap seconds. */
740 strp = getnum(strp, &num, 0, SECSPERMIN);
741 if (strp == NULL)
742 return NULL;
743 *secsp += num;
744 }
745 }
746 return strp;
747}
748
749/*
750** Given a pointer into a time zone string, extract an offset, in
751** [+-]hh[:mm[:ss]] form, from the string.
752** If any error occurs, return NULL.
753** Otherwise, return a pointer to the first character not part of the time.
754*/
755
756static const char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800757getoffset(register const char *strp, int_fast32_t *const offsetp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000758{
759 register int neg = 0;
760
761 if (*strp == '-') {
762 neg = 1;
763 ++strp;
764 } else if (*strp == '+')
765 ++strp;
766 strp = getsecs(strp, offsetp);
767 if (strp == NULL)
768 return NULL; /* illegal time */
769 if (neg)
770 *offsetp = -*offsetp;
771 return strp;
772}
773
774/*
775** Given a pointer into a time zone string, extract a rule in the form
776** date[/time]. See POSIX section 8 for the format of "date" and "time".
777** If a valid rule is not found, return NULL.
778** Otherwise, return a pointer to the first character not part of the rule.
779*/
780
781static const char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800782getrule(const char *strp, register struct rule *const rulep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000783{
784 if (*strp == 'J') {
785 /*
786 ** Julian day.
787 */
788 rulep->r_type = JULIAN_DAY;
789 ++strp;
790 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
791 } else if (*strp == 'M') {
792 /*
793 ** Month, week, day.
794 */
795 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
796 ++strp;
797 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
798 if (strp == NULL)
799 return NULL;
800 if (*strp++ != '.')
801 return NULL;
802 strp = getnum(strp, &rulep->r_week, 1, 5);
803 if (strp == NULL)
804 return NULL;
805 if (*strp++ != '.')
806 return NULL;
807 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
808 } else if (is_digit(*strp)) {
809 /*
810 ** Day of year.
811 */
812 rulep->r_type = DAY_OF_YEAR;
813 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
814 } else return NULL; /* invalid format */
815 if (strp == NULL)
816 return NULL;
817 if (*strp == '/') {
818 /*
819 ** Time specified.
820 */
821 ++strp;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800822 strp = getoffset(strp, &rulep->r_time);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000823 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
824 return strp;
825}
826
827/*
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800828** Given a year, a rule, and the offset from UT at the time that rule takes
829** effect, calculate the year-relative time that rule takes effect.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000830*/
831
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800832static int_fast32_t
833transtime(const int year, register const struct rule *const rulep,
834 const int_fast32_t offset)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000835{
836 register int leapyear;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800837 register int_fast32_t value;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000838 register int i;
839 int d, m1, yy0, yy1, yy2, dow;
840
841 INITIALIZE(value);
842 leapyear = isleap(year);
843 switch (rulep->r_type) {
844
845 case JULIAN_DAY:
846 /*
847 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
848 ** years.
849 ** In non-leap years, or if the day number is 59 or less, just
850 ** add SECSPERDAY times the day number-1 to the time of
851 ** January 1, midnight, to get the day.
852 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800853 value = (rulep->r_day - 1) * SECSPERDAY;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000854 if (leapyear && rulep->r_day >= 60)
855 value += SECSPERDAY;
856 break;
857
858 case DAY_OF_YEAR:
859 /*
860 ** n - day of year.
861 ** Just add SECSPERDAY times the day number to the time of
862 ** January 1, midnight, to get the day.
863 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800864 value = rulep->r_day * SECSPERDAY;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000865 break;
866
867 case MONTH_NTH_DAY_OF_WEEK:
868 /*
869 ** Mm.n.d - nth "dth day" of month m.
870 */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000871
872 /*
873 ** Use Zeller's Congruence to get day-of-week of first day of
874 ** month.
875 */
876 m1 = (rulep->r_mon + 9) % 12 + 1;
877 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
878 yy1 = yy0 / 100;
879 yy2 = yy0 % 100;
880 dow = ((26 * m1 - 2) / 10 +
881 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
882 if (dow < 0)
883 dow += DAYSPERWEEK;
884
885 /*
886 ** "dow" is the day-of-week of the first day of the month. Get
887 ** the day-of-month (zero-origin) of the first "dow" day of the
888 ** month.
889 */
890 d = rulep->r_day - dow;
891 if (d < 0)
892 d += DAYSPERWEEK;
893 for (i = 1; i < rulep->r_week; ++i) {
894 if (d + DAYSPERWEEK >=
895 mon_lengths[leapyear][rulep->r_mon - 1])
896 break;
897 d += DAYSPERWEEK;
898 }
899
900 /*
901 ** "d" is the day-of-month (zero-origin) of the day we want.
902 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800903 value = d * SECSPERDAY;
904 for (i = 0; i < rulep->r_mon - 1; ++i)
905 value += mon_lengths[leapyear][i] * SECSPERDAY;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000906 break;
907 }
908
909 /*
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800910 ** "value" is the year-relative time of 00:00:00 UT on the day in
911 ** question. To get the year-relative time of the specified local
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000912 ** time on that day, add the transition time and the current offset
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800913 ** from UT.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000914 */
915 return value + rulep->r_time + offset;
916}
917
918/*
919** Given a POSIX section 8-style TZ string, fill in the rule tables as
920** appropriate.
921*/
922
923static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800924tzparse(const char *name, register struct state *const sp,
925 const int lastditch)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000926{
927 const char * stdname;
928 const char * dstname;
929 size_t stdlen;
930 size_t dstlen;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800931 int_fast32_t stdoffset;
932 int_fast32_t dstoffset;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000933 register char * cp;
934 register int load_result;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800935 static struct ttinfo zttinfo;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000936
937 INITIALIZE(dstname);
938 stdname = name;
939 if (lastditch) {
940 stdlen = strlen(name); /* length of standard zone name */
941 name += stdlen;
942 if (stdlen >= sizeof sp->chars)
943 stdlen = (sizeof sp->chars) - 1;
944 stdoffset = 0;
945 } else {
946 if (*name == '<') {
947 name++;
948 stdname = name;
949 name = getqzname(name, '>');
950 if (*name != '>')
951 return (-1);
952 stdlen = name - stdname;
953 name++;
954 } else {
955 name = getzname(name);
956 stdlen = name - stdname;
957 }
958 if (*name == '\0')
959 return -1;
960 name = getoffset(name, &stdoffset);
961 if (name == NULL)
962 return -1;
963 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800964 load_result = tzload(TZDEFRULES, sp, false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000965 if (load_result != 0)
966 sp->leapcnt = 0; /* so, we're off a little */
967 if (*name != '\0') {
968 if (*name == '<') {
969 dstname = ++name;
970 name = getqzname(name, '>');
971 if (*name != '>')
972 return -1;
973 dstlen = name - dstname;
974 name++;
975 } else {
976 dstname = name;
977 name = getzname(name);
978 dstlen = name - dstname; /* length of DST zone name */
979 }
980 if (*name != '\0' && *name != ',' && *name != ';') {
981 name = getoffset(name, &dstoffset);
982 if (name == NULL)
983 return -1;
984 } else dstoffset = stdoffset - SECSPERHOUR;
985 if (*name == '\0' && load_result != 0)
986 name = TZDEFRULESTRING;
987 if (*name == ',' || *name == ';') {
988 struct rule start;
989 struct rule end;
990 register int year;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800991 register int yearlim;
992 register int timecnt;
993 time_t janfirst;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000994
995 ++name;
996 if ((name = getrule(name, &start)) == NULL)
997 return -1;
998 if (*name++ != ',')
999 return -1;
1000 if ((name = getrule(name, &end)) == NULL)
1001 return -1;
1002 if (*name != '\0')
1003 return -1;
1004 sp->typecnt = 2; /* standard time and DST */
1005 /*
1006 ** Two transitions per year, from EPOCH_YEAR forward.
1007 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001008 sp->ttis[0] = sp->ttis[1] = zttinfo;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001009 sp->ttis[0].tt_gmtoff = -dstoffset;
1010 sp->ttis[0].tt_isdst = 1;
1011 sp->ttis[0].tt_abbrind = stdlen + 1;
1012 sp->ttis[1].tt_gmtoff = -stdoffset;
1013 sp->ttis[1].tt_isdst = 0;
1014 sp->ttis[1].tt_abbrind = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001015 sp->defaulttype = 0;
1016 timecnt = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001017 janfirst = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001018 yearlim = EPOCH_YEAR + YEARSPERREPEAT;
1019 for (year = EPOCH_YEAR; year < yearlim; year++) {
1020 int_fast32_t
1021 starttime = transtime(year, &start, stdoffset),
1022 endtime = transtime(year, &end, dstoffset);
1023 int_fast32_t
1024 yearsecs = (year_lengths[isleap(year)]
1025 * SECSPERDAY);
1026 int reversed = endtime < starttime;
1027 if (reversed) {
1028 int_fast32_t swap = starttime;
1029 starttime = endtime;
1030 endtime = swap;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001031 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001032 if (reversed
1033 || (starttime < endtime
1034 && (endtime - starttime
1035 < (yearsecs
1036 + (stdoffset - dstoffset))))) {
1037 if (TZ_MAX_TIMES - 2 < timecnt)
1038 break;
1039 yearlim = year + YEARSPERREPEAT + 1;
1040 sp->ats[timecnt] = janfirst;
1041 if (increment_overflow_time
1042 (&sp->ats[timecnt], starttime))
1043 break;
1044 sp->types[timecnt++] = reversed;
1045 sp->ats[timecnt] = janfirst;
1046 if (increment_overflow_time
1047 (&sp->ats[timecnt], endtime))
1048 break;
1049 sp->types[timecnt++] = !reversed;
1050 }
1051 if (increment_overflow_time(&janfirst, yearsecs))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001052 break;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001053 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001054 sp->timecnt = timecnt;
1055 if (!timecnt)
1056 sp->typecnt = 1; /* Perpetual DST. */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001057 } else {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001058 register int_fast32_t theirstdoffset;
1059 register int_fast32_t theirdstoffset;
1060 register int_fast32_t theiroffset;
1061 register int isdst;
1062 register int i;
1063 register int j;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001064
1065 if (*name != '\0')
1066 return -1;
1067 /*
1068 ** Initial values of theirstdoffset and theirdstoffset.
1069 */
1070 theirstdoffset = 0;
1071 for (i = 0; i < sp->timecnt; ++i) {
1072 j = sp->types[i];
1073 if (!sp->ttis[j].tt_isdst) {
1074 theirstdoffset =
1075 -sp->ttis[j].tt_gmtoff;
1076 break;
1077 }
1078 }
1079 theirdstoffset = 0;
1080 for (i = 0; i < sp->timecnt; ++i) {
1081 j = sp->types[i];
1082 if (sp->ttis[j].tt_isdst) {
1083 theirdstoffset =
1084 -sp->ttis[j].tt_gmtoff;
1085 break;
1086 }
1087 }
1088 /*
1089 ** Initially we're assumed to be in standard time.
1090 */
Frank Tang1f164ee2022-11-08 12:31:27 -08001091 isdst = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001092 theiroffset = theirstdoffset;
1093 /*
1094 ** Now juggle transition times and types
1095 ** tracking offsets as you do.
1096 */
1097 for (i = 0; i < sp->timecnt; ++i) {
1098 j = sp->types[i];
1099 sp->types[i] = sp->ttis[j].tt_isdst;
1100 if (sp->ttis[j].tt_ttisgmt) {
1101 /* No adjustment to transition time */
1102 } else {
1103 /*
1104 ** If summer time is in effect, and the
1105 ** transition time was not specified as
1106 ** standard time, add the summer time
1107 ** offset to the transition time;
1108 ** otherwise, add the standard time
1109 ** offset to the transition time.
1110 */
1111 /*
1112 ** Transitions from DST to DDST
1113 ** will effectively disappear since
1114 ** POSIX provides for only one DST
1115 ** offset.
1116 */
1117 if (isdst && !sp->ttis[j].tt_ttisstd) {
1118 sp->ats[i] += dstoffset -
1119 theirdstoffset;
1120 } else {
1121 sp->ats[i] += stdoffset -
1122 theirstdoffset;
1123 }
1124 }
1125 theiroffset = -sp->ttis[j].tt_gmtoff;
1126 if (sp->ttis[j].tt_isdst)
1127 theirdstoffset = theiroffset;
1128 else theirstdoffset = theiroffset;
1129 }
1130 /*
1131 ** Finally, fill in ttis.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001132 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001133 sp->ttis[0] = sp->ttis[1] = zttinfo;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001134 sp->ttis[0].tt_gmtoff = -stdoffset;
Frank Tang1f164ee2022-11-08 12:31:27 -08001135 sp->ttis[0].tt_isdst = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001136 sp->ttis[0].tt_abbrind = 0;
1137 sp->ttis[1].tt_gmtoff = -dstoffset;
Frank Tang1f164ee2022-11-08 12:31:27 -08001138 sp->ttis[1].tt_isdst = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001139 sp->ttis[1].tt_abbrind = stdlen + 1;
1140 sp->typecnt = 2;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001141 sp->defaulttype = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001142 }
1143 } else {
1144 dstlen = 0;
1145 sp->typecnt = 1; /* only standard time */
1146 sp->timecnt = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001147 sp->ttis[0] = zttinfo;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001148 sp->ttis[0].tt_gmtoff = -stdoffset;
1149 sp->ttis[0].tt_isdst = 0;
1150 sp->ttis[0].tt_abbrind = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001151 sp->defaulttype = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001152 }
1153 sp->charcnt = stdlen + 1;
1154 if (dstlen != 0)
1155 sp->charcnt += dstlen + 1;
1156 if ((size_t) sp->charcnt > sizeof sp->chars)
1157 return -1;
1158 cp = sp->chars;
1159 (void) strncpy(cp, stdname, stdlen);
1160 cp += stdlen;
1161 *cp++ = '\0';
1162 if (dstlen != 0) {
1163 (void) strncpy(cp, dstname, dstlen);
1164 *(cp + dstlen) = '\0';
1165 }
1166 return 0;
1167}
1168
1169static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001170gmtload(struct state *const sp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001171{
Frank Tang1f164ee2022-11-08 12:31:27 -08001172 if (tzload(gmt, sp, true) != 0)
1173 (void) tzparse(gmt, sp, true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001174}
1175
1176#ifndef STD_INSPIRED
1177/*
1178** A non-static declaration of tzsetwall in a system header file
1179** may cause a warning about this upcoming static declaration...
1180*/
1181static
1182#endif /* !defined STD_INSPIRED */
1183void
1184tzsetwall(void)
1185{
1186 if (lcl_is_set < 0)
1187 return;
1188 lcl_is_set = -1;
1189
1190#ifdef ALL_STATE
1191 if (lclptr == NULL) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001192 lclptr = malloc(sizeof *lclptr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001193 if (lclptr == NULL) {
1194 settzname(); /* all we can do */
1195 return;
1196 }
1197 }
1198#endif /* defined ALL_STATE */
Frank Tang1f164ee2022-11-08 12:31:27 -08001199 if (tzload(NULL, lclptr, true) != 0)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001200 gmtload(lclptr);
1201 settzname();
1202}
1203
1204void
1205tzset(void)
1206{
1207 register const char * name;
1208
1209 name = getenv("TZ");
1210 if (name == NULL) {
1211 tzsetwall();
1212 return;
1213 }
1214
1215 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1216 return;
1217 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1218 if (lcl_is_set)
1219 (void) strcpy(lcl_TZname, name);
1220
1221#ifdef ALL_STATE
1222 if (lclptr == NULL) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001223 lclptr = malloc(sizeof *lclptr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001224 if (lclptr == NULL) {
1225 settzname(); /* all we can do */
1226 return;
1227 }
1228 }
1229#endif /* defined ALL_STATE */
1230 if (*name == '\0') {
1231 /*
1232 ** User wants it fast rather than right.
1233 */
1234 lclptr->leapcnt = 0; /* so, we're off a little */
1235 lclptr->timecnt = 0;
1236 lclptr->typecnt = 0;
1237 lclptr->ttis[0].tt_isdst = 0;
1238 lclptr->ttis[0].tt_gmtoff = 0;
1239 lclptr->ttis[0].tt_abbrind = 0;
1240 (void) strcpy(lclptr->chars, gmt);
Frank Tang1f164ee2022-11-08 12:31:27 -08001241 } else if (tzload(name, lclptr, true) != 0)
1242 if (name[0] == ':' || tzparse(name, lclptr, false) != 0)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001243 (void) gmtload(lclptr);
1244 settzname();
1245}
1246
1247/*
1248** The easy way to behave "as if no library function calls" localtime
1249** is to not call it--so we drop its guts into "localsub", which can be
1250** freely called. (And no, the PANS doesn't require the above behavior--
1251** but it *is* desirable.)
1252**
1253** The unused offset argument is for the benefit of mktime variants.
1254*/
1255
1256/*ARGSUSED*/
1257static struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001258localsub(const time_t *const timep, const int_fast32_t offset,
1259 struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001260{
1261 register struct state * sp;
1262 register const struct ttinfo * ttisp;
1263 register int i;
1264 register struct tm * result;
1265 const time_t t = *timep;
1266
1267 sp = lclptr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001268 if (sp == NULL)
1269 return gmtsub(timep, offset, tmp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001270 if ((sp->goback && t < sp->ats[0]) ||
1271 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1272 time_t newt = t;
1273 register time_t seconds;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001274 register time_t years;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001275
1276 if (t < sp->ats[0])
1277 seconds = sp->ats[0] - t;
1278 else seconds = t - sp->ats[sp->timecnt - 1];
1279 --seconds;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001280 years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
1281 seconds = years * AVGSECSPERYEAR;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001282 if (t < sp->ats[0])
1283 newt += seconds;
1284 else newt -= seconds;
1285 if (newt < sp->ats[0] ||
1286 newt > sp->ats[sp->timecnt - 1])
1287 return NULL; /* "cannot happen" */
1288 result = localsub(&newt, offset, tmp);
1289 if (result == tmp) {
1290 register time_t newy;
1291
1292 newy = tmp->tm_year;
1293 if (t < sp->ats[0])
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001294 newy -= years;
1295 else newy += years;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001296 tmp->tm_year = newy;
1297 if (tmp->tm_year != newy)
1298 return NULL;
1299 }
1300 return result;
1301 }
1302 if (sp->timecnt == 0 || t < sp->ats[0]) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001303 i = sp->defaulttype;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001304 } else {
1305 register int lo = 1;
1306 register int hi = sp->timecnt;
1307
1308 while (lo < hi) {
1309 register int mid = (lo + hi) >> 1;
1310
1311 if (t < sp->ats[mid])
1312 hi = mid;
1313 else lo = mid + 1;
1314 }
1315 i = (int) sp->types[lo - 1];
1316 }
1317 ttisp = &sp->ttis[i];
1318 /*
1319 ** To get (wrong) behavior that's compatible with System V Release 2.0
1320 ** you'd replace the statement below with
1321 ** t += ttisp->tt_gmtoff;
1322 ** timesub(&t, 0L, sp, tmp);
1323 */
1324 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1325 tmp->tm_isdst = ttisp->tt_isdst;
1326 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1327#ifdef TM_ZONE
1328 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1329#endif /* defined TM_ZONE */
1330 return result;
1331}
1332
1333struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001334localtime(const time_t *const timep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001335{
1336 tzset();
1337 return localsub(timep, 0L, &tm);
1338}
1339
1340/*
1341** Re-entrant version of localtime.
1342*/
1343
1344struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001345localtime_r(const time_t *const timep, struct tm *tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001346{
1347 return localsub(timep, 0L, tmp);
1348}
1349
1350/*
1351** gmtsub is to gmtime as localsub is to localtime.
1352*/
1353
1354static struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001355gmtsub(const time_t *const timep, const int_fast32_t offset,
1356 struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001357{
1358 register struct tm * result;
1359
1360 if (!gmt_is_set) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001361 gmt_is_set = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001362#ifdef ALL_STATE
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001363 gmtptr = malloc(sizeof *gmtptr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001364#endif /* defined ALL_STATE */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001365 if (gmtptr != NULL)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001366 gmtload(gmtptr);
1367 }
1368 result = timesub(timep, offset, gmtptr, tmp);
1369#ifdef TM_ZONE
1370 /*
1371 ** Could get fancy here and deliver something such as
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001372 ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001373 ** but this is no time for a treasure hunt.
1374 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001375 tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001376#endif /* defined TM_ZONE */
1377 return result;
1378}
1379
1380struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001381gmtime(const time_t *const timep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001382{
1383 return gmtsub(timep, 0L, &tm);
1384}
1385
1386/*
1387* Re-entrant version of gmtime.
1388*/
1389
1390struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001391gmtime_r(const time_t *const timep, struct tm *tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001392{
1393 return gmtsub(timep, 0L, tmp);
1394}
1395
1396#ifdef STD_INSPIRED
1397
1398struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001399offtime(const time_t *const timep, const long offset)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001400{
1401 return gmtsub(timep, offset, &tm);
1402}
1403
1404#endif /* defined STD_INSPIRED */
1405
1406/*
1407** Return the number of leap years through the end of the given year
1408** where, to make the math easy, the answer for year zero is defined as zero.
1409*/
1410
1411static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001412leaps_thru_end_of(register const int y)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001413{
1414 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1415 -(leaps_thru_end_of(-(y + 1)) + 1);
1416}
1417
1418static struct tm *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001419timesub(const time_t *const timep, const int_fast32_t offset,
1420 register const struct state *const sp,
1421 register struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001422{
1423 register const struct lsinfo * lp;
1424 register time_t tdays;
1425 register int idays; /* unsigned would be so 2003 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001426 register int_fast64_t rem;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001427 int y;
1428 register const int * ip;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001429 register int_fast64_t corr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001430 register int hit;
1431 register int i;
1432
1433 corr = 0;
1434 hit = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001435 i = (sp == NULL) ? 0 : sp->leapcnt;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001436 while (--i >= 0) {
1437 lp = &sp->lsis[i];
1438 if (*timep >= lp->ls_trans) {
1439 if (*timep == lp->ls_trans) {
1440 hit = ((i == 0 && lp->ls_corr > 0) ||
1441 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1442 if (hit)
1443 while (i > 0 &&
1444 sp->lsis[i].ls_trans ==
1445 sp->lsis[i - 1].ls_trans + 1 &&
1446 sp->lsis[i].ls_corr ==
1447 sp->lsis[i - 1].ls_corr + 1) {
1448 ++hit;
1449 --i;
1450 }
1451 }
1452 corr = lp->ls_corr;
1453 break;
1454 }
1455 }
1456 y = EPOCH_YEAR;
1457 tdays = *timep / SECSPERDAY;
1458 rem = *timep - tdays * SECSPERDAY;
1459 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1460 int newy;
1461 register time_t tdelta;
1462 register int idelta;
1463 register int leapdays;
1464
1465 tdelta = tdays / DAYSPERLYEAR;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001466 if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
1467 && tdelta <= INT_MAX))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001468 return NULL;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001469 idelta = tdelta;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001470 if (idelta == 0)
1471 idelta = (tdays < 0) ? -1 : 1;
1472 newy = y;
1473 if (increment_overflow(&newy, idelta))
1474 return NULL;
1475 leapdays = leaps_thru_end_of(newy - 1) -
1476 leaps_thru_end_of(y - 1);
1477 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1478 tdays -= leapdays;
1479 y = newy;
1480 }
1481 {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001482 register int_fast32_t seconds;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001483
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001484 seconds = tdays * SECSPERDAY;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001485 tdays = seconds / SECSPERDAY;
1486 rem += seconds - tdays * SECSPERDAY;
1487 }
1488 /*
1489 ** Given the range, we can now fearlessly cast...
1490 */
1491 idays = tdays;
1492 rem += offset - corr;
1493 while (rem < 0) {
1494 rem += SECSPERDAY;
1495 --idays;
1496 }
1497 while (rem >= SECSPERDAY) {
1498 rem -= SECSPERDAY;
1499 ++idays;
1500 }
1501 while (idays < 0) {
1502 if (increment_overflow(&y, -1))
1503 return NULL;
1504 idays += year_lengths[isleap(y)];
1505 }
1506 while (idays >= year_lengths[isleap(y)]) {
1507 idays -= year_lengths[isleap(y)];
1508 if (increment_overflow(&y, 1))
1509 return NULL;
1510 }
1511 tmp->tm_year = y;
1512 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1513 return NULL;
1514 tmp->tm_yday = idays;
1515 /*
1516 ** The "extra" mods below avoid overflow problems.
1517 */
1518 tmp->tm_wday = EPOCH_WDAY +
1519 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1520 (DAYSPERNYEAR % DAYSPERWEEK) +
1521 leaps_thru_end_of(y - 1) -
1522 leaps_thru_end_of(EPOCH_YEAR - 1) +
1523 idays;
1524 tmp->tm_wday %= DAYSPERWEEK;
1525 if (tmp->tm_wday < 0)
1526 tmp->tm_wday += DAYSPERWEEK;
1527 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1528 rem %= SECSPERHOUR;
1529 tmp->tm_min = (int) (rem / SECSPERMIN);
1530 /*
1531 ** A positive leap second requires a special
1532 ** representation. This uses "... ??:59:60" et seq.
1533 */
1534 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1535 ip = mon_lengths[isleap(y)];
1536 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1537 idays -= ip[tmp->tm_mon];
1538 tmp->tm_mday = (int) (idays + 1);
1539 tmp->tm_isdst = 0;
1540#ifdef TM_GMTOFF
1541 tmp->TM_GMTOFF = offset;
1542#endif /* defined TM_GMTOFF */
1543 return tmp;
1544}
1545
1546char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001547ctime(const time_t *const timep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001548{
1549/*
1550** Section 4.12.3.2 of X3.159-1989 requires that
1551** The ctime function converts the calendar time pointed to by timer
1552** to local time in the form of a string. It is equivalent to
1553** asctime(localtime(timer))
1554*/
1555 return asctime(localtime(timep));
1556}
1557
1558char *
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001559ctime_r(const time_t *const timep, char *buf)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001560{
1561 struct tm mytm;
1562
1563 return asctime_r(localtime_r(timep, &mytm), buf);
1564}
1565
1566/*
1567** Adapted from code provided by Robert Elz, who writes:
1568** The "best" way to do mktime I think is based on an idea of Bob
1569** Kridle's (so its said...) from a long time ago.
1570** It does a binary search of the time_t space. Since time_t's are
1571** just 32 bits, its a max of 32 iterations (even at 64 bits it
1572** would still be very reasonable).
1573*/
1574
1575#ifndef WRONG
1576#define WRONG (-1)
1577#endif /* !defined WRONG */
1578
1579/*
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001580** Normalize logic courtesy Paul Eggert.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001581*/
1582
1583static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001584increment_overflow(int *const ip, int j)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001585{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001586 register int const i = *ip;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001587
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001588 /*
1589 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1590 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1591 ** If i < 0 there can only be overflow if i + j < INT_MIN
1592 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1593 */
1594 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
Frank Tang1f164ee2022-11-08 12:31:27 -08001595 return true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001596 *ip += j;
Frank Tang1f164ee2022-11-08 12:31:27 -08001597 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001598}
1599
1600static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001601increment_overflow32(int_fast32_t *const lp, int const m)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001602{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001603 register int_fast32_t const l = *lp;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001604
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001605 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
Frank Tang1f164ee2022-11-08 12:31:27 -08001606 return true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001607 *lp += m;
Frank Tang1f164ee2022-11-08 12:31:27 -08001608 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001609}
1610
1611static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001612increment_overflow_time(time_t *tp, int_fast32_t j)
1613{
1614 /*
1615 ** This is like
1616 ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
1617 ** except that it does the right thing even if *tp + j would overflow.
1618 */
1619 if (! (j < 0
1620 ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
1621 : *tp <= time_t_max - j))
Frank Tang1f164ee2022-11-08 12:31:27 -08001622 return true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001623 *tp += j;
Frank Tang1f164ee2022-11-08 12:31:27 -08001624 return false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001625}
1626
1627static int
1628normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001629{
1630 register int tensdelta;
1631
1632 tensdelta = (*unitsptr >= 0) ?
1633 (*unitsptr / base) :
1634 (-1 - (-1 - *unitsptr) / base);
1635 *unitsptr -= tensdelta * base;
1636 return increment_overflow(tensptr, tensdelta);
1637}
1638
1639static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001640normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
1641 const int base)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001642{
1643 register int tensdelta;
1644
1645 tensdelta = (*unitsptr >= 0) ?
1646 (*unitsptr / base) :
1647 (-1 - (-1 - *unitsptr) / base);
1648 *unitsptr -= tensdelta * base;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001649 return increment_overflow32(tensptr, tensdelta);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001650}
1651
1652static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001653tmcomp(register const struct tm *const atmp,
1654 register const struct tm *const btmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001655{
1656 register int result;
1657
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001658 if (atmp->tm_year != btmp->tm_year)
1659 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1660 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001661 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1662 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1663 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1664 result = atmp->tm_sec - btmp->tm_sec;
1665 return result;
1666}
1667
1668static time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001669time2sub(struct tm *const tmp,
1670 struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *),
1671 const int_fast32_t offset,
1672 int *const okayp,
1673 const int do_norm_secs)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001674{
1675 register const struct state * sp;
1676 register int dir;
1677 register int i, j;
1678 register int saved_seconds;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001679 register int_fast32_t li;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001680 register time_t lo;
1681 register time_t hi;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001682 int_fast32_t y;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001683 time_t newt;
1684 time_t t;
1685 struct tm yourtm, mytm;
1686
Frank Tang1f164ee2022-11-08 12:31:27 -08001687 *okayp = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001688 yourtm = *tmp;
1689 if (do_norm_secs) {
1690 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1691 SECSPERMIN))
1692 return WRONG;
1693 }
1694 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1695 return WRONG;
1696 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1697 return WRONG;
1698 y = yourtm.tm_year;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001699 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001700 return WRONG;
1701 /*
1702 ** Turn y into an actual year number for now.
1703 ** It is converted back to an offset from TM_YEAR_BASE later.
1704 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001705 if (increment_overflow32(&y, TM_YEAR_BASE))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001706 return WRONG;
1707 while (yourtm.tm_mday <= 0) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001708 if (increment_overflow32(&y, -1))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001709 return WRONG;
1710 li = y + (1 < yourtm.tm_mon);
1711 yourtm.tm_mday += year_lengths[isleap(li)];
1712 }
1713 while (yourtm.tm_mday > DAYSPERLYEAR) {
1714 li = y + (1 < yourtm.tm_mon);
1715 yourtm.tm_mday -= year_lengths[isleap(li)];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001716 if (increment_overflow32(&y, 1))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001717 return WRONG;
1718 }
1719 for ( ; ; ) {
1720 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1721 if (yourtm.tm_mday <= i)
1722 break;
1723 yourtm.tm_mday -= i;
1724 if (++yourtm.tm_mon >= MONSPERYEAR) {
1725 yourtm.tm_mon = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001726 if (increment_overflow32(&y, 1))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001727 return WRONG;
1728 }
1729 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001730 if (increment_overflow32(&y, -TM_YEAR_BASE))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001731 return WRONG;
1732 yourtm.tm_year = y;
1733 if (yourtm.tm_year != y)
1734 return WRONG;
1735 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1736 saved_seconds = 0;
1737 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1738 /*
1739 ** We can't set tm_sec to 0, because that might push the
1740 ** time below the minimum representable time.
1741 ** Set tm_sec to 59 instead.
1742 ** This assumes that the minimum representable time is
1743 ** not in the same minute that a leap second was deleted from,
1744 ** which is a safer assumption than using 58 would be.
1745 */
1746 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1747 return WRONG;
1748 saved_seconds = yourtm.tm_sec;
1749 yourtm.tm_sec = SECSPERMIN - 1;
1750 } else {
1751 saved_seconds = yourtm.tm_sec;
1752 yourtm.tm_sec = 0;
1753 }
1754 /*
1755 ** Do a binary search (this works whatever time_t's type is).
1756 */
1757 if (!TYPE_SIGNED(time_t)) {
1758 lo = 0;
1759 hi = lo - 1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001760 } else {
1761 lo = 1;
1762 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1763 lo *= 2;
1764 hi = -(lo + 1);
1765 }
1766 for ( ; ; ) {
1767 t = lo / 2 + hi / 2;
1768 if (t < lo)
1769 t = lo;
1770 else if (t > hi)
1771 t = hi;
1772 if ((*funcp)(&t, offset, &mytm) == NULL) {
1773 /*
1774 ** Assume that t is too extreme to be represented in
1775 ** a struct tm; arrange things so that it is less
1776 ** extreme on the next pass.
1777 */
1778 dir = (t > 0) ? 1 : -1;
1779 } else dir = tmcomp(&mytm, &yourtm);
1780 if (dir != 0) {
1781 if (t == lo) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001782 if (t == time_t_max)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001783 return WRONG;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001784 ++t;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001785 ++lo;
1786 } else if (t == hi) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001787 if (t == time_t_min)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001788 return WRONG;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001789 --t;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001790 --hi;
1791 }
1792 if (lo > hi)
1793 return WRONG;
1794 if (dir > 0)
1795 hi = t;
1796 else lo = t;
1797 continue;
1798 }
1799 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1800 break;
1801 /*
1802 ** Right time, wrong type.
1803 ** Hunt for right time, right type.
1804 ** It's okay to guess wrong since the guess
1805 ** gets checked.
1806 */
1807 sp = (const struct state *)
1808 ((funcp == localsub) ? lclptr : gmtptr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001809 if (sp == NULL)
1810 return WRONG;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001811 for (i = sp->typecnt - 1; i >= 0; --i) {
1812 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1813 continue;
1814 for (j = sp->typecnt - 1; j >= 0; --j) {
1815 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1816 continue;
1817 newt = t + sp->ttis[j].tt_gmtoff -
1818 sp->ttis[i].tt_gmtoff;
1819 if ((*funcp)(&newt, offset, &mytm) == NULL)
1820 continue;
1821 if (tmcomp(&mytm, &yourtm) != 0)
1822 continue;
1823 if (mytm.tm_isdst != yourtm.tm_isdst)
1824 continue;
1825 /*
1826 ** We have a match.
1827 */
1828 t = newt;
1829 goto label;
1830 }
1831 }
1832 return WRONG;
1833 }
1834label:
1835 newt = t + saved_seconds;
1836 if ((newt < t) != (saved_seconds < 0))
1837 return WRONG;
1838 t = newt;
1839 if ((*funcp)(&t, offset, tmp))
Frank Tang1f164ee2022-11-08 12:31:27 -08001840 *okayp = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001841 return t;
1842}
1843
1844static time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001845time2(struct tm * const tmp,
1846 struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *),
1847 const int_fast32_t offset,
1848 int *const okayp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001849{
1850 time_t t;
1851
1852 /*
1853 ** First try without normalization of seconds
1854 ** (in case tm_sec contains a value associated with a leap second).
1855 ** If that fails, try with normalization of seconds.
1856 */
Frank Tang1f164ee2022-11-08 12:31:27 -08001857 t = time2sub(tmp, funcp, offset, okayp, false);
1858 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001859}
1860
1861static time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001862time1(struct tm *const tmp,
1863 struct tm *(*const funcp) (const time_t *, int_fast32_t, struct tm *),
1864 const int_fast32_t offset)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001865{
1866 register time_t t;
1867 register const struct state * sp;
1868 register int samei, otheri;
1869 register int sameind, otherind;
1870 register int i;
1871 register int nseen;
1872 int seen[TZ_MAX_TYPES];
1873 int types[TZ_MAX_TYPES];
1874 int okay;
1875
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001876 if (tmp == NULL) {
1877 errno = EINVAL;
1878 return WRONG;
1879 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001880 if (tmp->tm_isdst > 1)
1881 tmp->tm_isdst = 1;
1882 t = time2(tmp, funcp, offset, &okay);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001883 if (okay)
1884 return t;
1885 if (tmp->tm_isdst < 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001886#ifdef PCTS
1887 /*
1888 ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
1889 */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001890 tmp->tm_isdst = 0; /* reset to std and try again */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001891#else
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001892 return t;
1893#endif /* !defined PCTS */
1894 /*
1895 ** We're supposed to assume that somebody took a time of one type
1896 ** and did some math on it that yielded a "struct tm" that's bad.
1897 ** We try to divine the type they started from and adjust to the
1898 ** type they need.
1899 */
1900 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001901 if (sp == NULL)
1902 return WRONG;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001903 for (i = 0; i < sp->typecnt; ++i)
Frank Tang1f164ee2022-11-08 12:31:27 -08001904 seen[i] = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001905 nseen = 0;
1906 for (i = sp->timecnt - 1; i >= 0; --i)
1907 if (!seen[sp->types[i]]) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001908 seen[sp->types[i]] = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001909 types[nseen++] = sp->types[i];
1910 }
1911 for (sameind = 0; sameind < nseen; ++sameind) {
1912 samei = types[sameind];
1913 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1914 continue;
1915 for (otherind = 0; otherind < nseen; ++otherind) {
1916 otheri = types[otherind];
1917 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1918 continue;
1919 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1920 sp->ttis[samei].tt_gmtoff;
1921 tmp->tm_isdst = !tmp->tm_isdst;
1922 t = time2(tmp, funcp, offset, &okay);
1923 if (okay)
1924 return t;
1925 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1926 sp->ttis[samei].tt_gmtoff;
1927 tmp->tm_isdst = !tmp->tm_isdst;
1928 }
1929 }
1930 return WRONG;
1931}
1932
1933time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001934mktime(struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001935{
1936 tzset();
1937 return time1(tmp, localsub, 0L);
1938}
1939
1940#ifdef STD_INSPIRED
1941
1942time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001943timelocal(struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001944{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001945 if (tmp != NULL)
1946 tmp->tm_isdst = -1; /* in case it wasn't initialized */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001947 return mktime(tmp);
1948}
1949
1950time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001951timegm(struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001952{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001953 if (tmp != NULL)
1954 tmp->tm_isdst = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001955 return time1(tmp, gmtsub, 0L);
1956}
1957
1958time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001959timeoff(struct tm *const tmp, const long offset)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001960{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001961 if (tmp != NULL)
1962 tmp->tm_isdst = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001963 return time1(tmp, gmtsub, offset);
1964}
1965
1966#endif /* defined STD_INSPIRED */
1967
1968#ifdef CMUCS
1969
1970/*
1971** The following is supplied for compatibility with
1972** previous versions of the CMUCS runtime library.
1973*/
1974
1975long
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001976gtime(struct tm *const tmp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001977{
1978 const time_t t = mktime(tmp);
1979
1980 if (t == WRONG)
1981 return -1;
1982 return t;
1983}
1984
1985#endif /* defined CMUCS */
1986
1987/*
1988** XXX--is the below the right way to conditionalize??
1989*/
1990
1991#ifdef STD_INSPIRED
1992
1993/*
1994** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
1995** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
1996** is not the case if we are accounting for leap seconds.
1997** So, we provide the following conversion routines for use
1998** when exchanging timestamps with POSIX conforming systems.
1999*/
2000
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002001static int_fast64_t
2002leapcorr(time_t *timep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002003{
2004 register struct state * sp;
2005 register struct lsinfo * lp;
2006 register int i;
2007
2008 sp = lclptr;
2009 i = sp->leapcnt;
2010 while (--i >= 0) {
2011 lp = &sp->lsis[i];
2012 if (*timep >= lp->ls_trans)
2013 return lp->ls_corr;
2014 }
2015 return 0;
2016}
2017
2018time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002019time2posix(time_t t)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002020{
2021 tzset();
2022 return t - leapcorr(&t);
2023}
2024
2025time_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002026posix2time(time_t t)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002027{
2028 time_t x;
2029 time_t y;
2030
2031 tzset();
2032 /*
2033 ** For a positive leap second hit, the result
2034 ** is not unique. For a negative leap second
2035 ** hit, the corresponding time doesn't exist,
2036 ** so we return an adjacent second.
2037 */
2038 x = t + leapcorr(&t);
2039 y = x - leapcorr(&x);
2040 if (y < t) {
2041 do {
2042 x++;
2043 y = x - leapcorr(&x);
2044 } while (y < t);
2045 if (t != y)
2046 return x - 1;
2047 } else if (y > t) {
2048 do {
2049 --x;
2050 y = x - leapcorr(&x);
2051 } while (y > t);
2052 if (t != y)
2053 return x + 1;
2054 }
2055 return x;
2056}
2057
2058#endif /* defined STD_INSPIRED */