blob: 8ff5ceeb321097c3e95d9dba0a8886f37e4239f6 [file] [log] [blame]
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001/* Convert timestamp from time_t to struct tm. */
2
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003/*
4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson.
6*/
7
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08008/*
9** Leap second handling from Bradley White.
10** POSIX-style TZ environment variable handling from Guy Harris.
11*/
12
13/*LINTLIBRARY*/
14
Elliott Hughes9fb22a32015-10-07 17:13:40 -070015#define LOCALTIME_IMPLEMENTATION
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080016#include "private.h"
Elliott Hughes9fb22a32015-10-07 17:13:40 -070017
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080018#include "tzfile.h"
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000019#include <fcntl.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080020
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000021#if defined THREAD_SAFE && THREAD_SAFE
Elliott Hughes9fb22a32015-10-07 17:13:40 -070022# include <pthread.h>
23static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
24static int lock(void) { return pthread_mutex_lock(&locallock); }
25static void unlock(void) { pthread_mutex_unlock(&locallock); }
26#else
27static int lock(void) { return 0; }
28static void unlock(void) { }
29#endif
30
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080031#ifndef TZ_ABBR_MAX_LEN
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070032#define TZ_ABBR_MAX_LEN 16
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080033#endif /* !defined TZ_ABBR_MAX_LEN */
34
35#ifndef TZ_ABBR_CHAR_SET
36#define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070037 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#endif /* !defined TZ_ABBR_CHAR_SET */
39
40#ifndef TZ_ABBR_ERR_CHAR
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070041#define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080042#endif /* !defined TZ_ABBR_ERR_CHAR */
43
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044/*
45** SunOS 4.1.1 headers lack O_BINARY.
46*/
47
48#ifdef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070049#define OPEN_MODE (O_RDONLY | O_BINARY)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080050#endif /* defined O_BINARY */
51#ifndef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070052#define OPEN_MODE O_RDONLY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080053#endif /* !defined O_BINARY */
54
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055#ifndef WILDABBR
56/*
57** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070058** 1. They might reference tzname[0] before calling tzset (explicitly
59** or implicitly).
60** 2. They might reference tzname[1] before calling tzset (explicitly
61** or implicitly).
62** 3. They might reference tzname[1] after setting to a time zone
63** in which Daylight Saving Time is never observed.
64** 4. They might reference tzname[0] after setting to a time zone
65** in which Standard Time is never observed.
66** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080067** What's best to do in the above cases is open to debate;
68** for now, we just set things up so that in any of the five cases
69** WILDABBR is used. Another possibility: initialize tzname[0] to the
70** string "tzname[0] used before set", and similarly for the other cases.
71** And another: initialize tzname[0] to "ERA", with an explanation in the
72** manual page of what this "time zone abbreviation" means (doing this so
73** that tzname[0] has the "normal" length of three characters).
74*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070075#define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080076#endif /* !defined WILDABBR */
77
Elliott Hughes906eb992014-06-18 19:46:25 -070078static const char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080079
Calin Juravled8928922014-02-28 12:18:53 +000080static const char gmt[] = "GMT";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081
82/*
83** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000084** Default to US rules as of 2017-05-07.
85** POSIX does not specify the default DST rules;
86** for historical reasons, US rules are a common default.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087*/
88#ifndef TZDEFRULESTRING
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000089#define TZDEFRULESTRING ",M3.2.0,M11.1.0"
90#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091
Calin Juravled8928922014-02-28 12:18:53 +000092struct ttinfo { /* time type information */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000093 int_fast32_t tt_utoff; /* UT offset in seconds */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070094 bool tt_isdst; /* used to set tm_isdst */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000095 int tt_desigidx; /* abbreviation list index */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070096 bool tt_ttisstd; /* transition is std time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000097 bool tt_ttisut; /* transition is UT */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080098};
99
Calin Juravled8928922014-02-28 12:18:53 +0000100struct lsinfo { /* leap second information */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700101 time_t ls_trans; /* transition time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000102 int_fast32_t ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800103};
104
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700105#define SMALLEST(a, b) (((a) < (b)) ? (a) : (b))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700106#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800107
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000108/* This abbreviation means local time is unspecified. */
109static char const UNSPEC[] = "-00";
110
111/* How many extra bytes are needed at the end of struct state's chars array.
112 This needs to be at least 1 for null termination in case the input
113 data isn't properly terminated, and it also needs to be big enough
114 for ttunspecified to work without crashing. */
115enum { CHARS_EXTRA = BIGGEST(sizeof UNSPEC, 2) - 1 };
116
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117#ifdef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700118#define MY_TZNAME_MAX TZNAME_MAX
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119#endif /* defined TZNAME_MAX */
120#ifndef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700121#define MY_TZNAME_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800122#endif /* !defined TZNAME_MAX */
123
124struct state {
Calin Juravled8928922014-02-28 12:18:53 +0000125 int leapcnt;
126 int timecnt;
127 int typecnt;
128 int charcnt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700129 bool goback;
130 bool goahead;
Calin Juravled8928922014-02-28 12:18:53 +0000131 time_t ats[TZ_MAX_TIMES];
132 unsigned char types[TZ_MAX_TIMES];
133 struct ttinfo ttis[TZ_MAX_TYPES];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000134 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + CHARS_EXTRA,
135 sizeof gmt),
Calin Juravled8928922014-02-28 12:18:53 +0000136 (2 * (MY_TZNAME_MAX + 1)))];
137 struct lsinfo lsis[TZ_MAX_LEAPS];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000138 /* The time type to use for early times or if no transitions.
139 It is always zero for recent tzdb releases.
140 It might be nonzero for data from tzdb 2018e or earlier. */
141 int defaulttype;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800142};
143
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700144enum r_type {
145 JULIAN_DAY, /* Jn = Julian day */
146 DAY_OF_YEAR, /* n = day of year */
147 MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */
148};
149
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150struct rule {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700151 enum r_type r_type; /* type of rule */
Calin Juravled8928922014-02-28 12:18:53 +0000152 int r_day; /* day number of rule */
153 int r_week; /* week number of rule */
154 int r_mon; /* month number of rule */
155 int_fast32_t r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800156};
157
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700158static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
159 struct tm *);
160static bool increment_overflow(int *, int);
161static bool increment_overflow_time(time_t *, int_fast32_t);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000162static int_fast32_t leapcorr(struct state const *, time_t);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700163static bool normalize_overflow32(int_fast32_t *, int *, int);
164static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
165 struct tm *);
166static bool typesequiv(struct state const *, int, int);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000167static bool tzparse(char const *, struct state *, struct state *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168
169#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000170static struct state * lclptr;
171static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172#endif /* defined ALL_STATE */
173
174#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700175static struct state lclmem;
176static struct state gmtmem;
177#define lclptr (&lclmem)
178#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800179#endif /* State Farm */
180
181#ifndef TZ_STRLEN_MAX
182#define TZ_STRLEN_MAX 255
183#endif /* !defined TZ_STRLEN_MAX */
184
Calin Juravled8928922014-02-28 12:18:53 +0000185static char lcl_TZname[TZ_STRLEN_MAX + 1];
186static int lcl_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800187
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800188/*
189** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700190** Except for the strftime function, these functions [asctime,
191** ctime, gmtime, localtime] return values in one of two static
192** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800193** Thanks to Paul Eggert for noting this.
194*/
195
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700196static struct tm tm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800197
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000198#if 2 <= HAVE_TZNAME + TZ_TIME_T
Elliott Hughes0a610d02016-07-29 14:04:17 -0700199char * tzname[2] = {
200 (char *) wildabbr,
201 (char *) wildabbr
202};
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000203#endif
204#if 2 <= USG_COMPAT + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700205long timezone;
206int daylight;
Elliott Hughes0a610d02016-07-29 14:04:17 -0700207#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800208
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000209#if 2 <= ALTZONE + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700210long altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000211#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800212
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000213/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700214static void
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000215init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700216{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000217 s->tt_utoff = utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700218 s->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000219 s->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700220 s->tt_ttisstd = false;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000221 s->tt_ttisut = false;
222}
223
224/* Return true if SP's time type I does not specify local time. */
225static bool
226ttunspecified(struct state const *sp, int i)
227{
228 char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
229 /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */
230 return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700231}
232
Elliott Hughesce4783c2013-07-12 17:31:11 -0700233static int_fast32_t
234detzcode(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800235{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700236 register int_fast32_t result;
237 register int i;
238 int_fast32_t one = 1;
239 int_fast32_t halfmaxval = one << (32 - 2);
240 int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
241 int_fast32_t minval = -1 - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800242
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700243 result = codep[0] & 0x7f;
244 for (i = 1; i < 4; ++i)
245 result = (result << 8) | (codep[i] & 0xff);
246
247 if (codep[0] & 0x80) {
248 /* Do two's-complement negation even on non-two's-complement machines.
249 If the result would be minval - 1, return minval. */
250 result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
251 result += minval;
252 }
253 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800254}
255
Calin Juravle627d37c2014-02-28 11:46:03 +0000256static int_fast64_t
Elliott Hughesce4783c2013-07-12 17:31:11 -0700257detzcode64(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800258{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000259 register int_fast64_t result;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700260 register int i;
261 int_fast64_t one = 1;
262 int_fast64_t halfmaxval = one << (64 - 2);
263 int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
264 int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800265
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700266 result = codep[0] & 0x7f;
267 for (i = 1; i < 8; ++i)
268 result = (result << 8) | (codep[i] & 0xff);
269
270 if (codep[0] & 0x80) {
271 /* Do two's-complement negation even on non-two's-complement machines.
272 If the result would be minval - 1, return minval. */
273 result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
274 result += minval;
275 }
276 return result;
277}
278
279static void
280update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
281{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000282#if HAVE_TZNAME
283 tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
284#endif
285#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700286 if (!ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000287 timezone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700288#endif
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000289#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700290 if (ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000291 altzone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700292#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800293}
294
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000295/* If STDDST_MASK indicates that SP's TYPE provides useful info,
296 update tzname, timezone, and/or altzone and return STDDST_MASK,
297 diminished by the provided info if it is a specified local time.
298 Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */
299static int
300may_update_tzname_etc(int stddst_mask, struct state *sp, int type)
301{
302 struct ttinfo *ttisp = &sp->ttis[type];
303 int this_bit = 1 << ttisp->tt_isdst;
304 if (stddst_mask & this_bit) {
305 update_tzname_etc(sp, ttisp);
306 if (!ttunspecified(sp, type))
307 return stddst_mask & ~this_bit;
308 }
309 return stddst_mask;
310}
311
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800312static void
Elliott Hughesce4783c2013-07-12 17:31:11 -0700313settzname(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800314{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700315 register struct state * const sp = lclptr;
316 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800317
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000318 /* If STDDST_MASK & 1 we need info about a standard time.
319 If STDDST_MASK & 2 we need info about a daylight saving time.
320 When STDDST_MASK becomes zero we can stop looking. */
321 int stddst_mask = 0;
322
323#if HAVE_TZNAME
324 tzname[0] = tzname[1] = (char *) (sp ? wildabbr : gmt);
325 stddst_mask = 3;
326#endif
327#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700328 timezone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000329 stddst_mask = 3;
330#endif
331#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700332 altzone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000333 stddst_mask |= 2;
334#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700335 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000336 ** And to get the latest time zone abbreviations into tzname. . .
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700337 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000338 if (sp) {
339 for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
340 stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
341 for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
342 stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700343 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000344#if USG_COMPAT
345 daylight = stddst_mask >> 1 ^ 1;
346#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347}
348
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700349static void
350scrub_abbrs(struct state *sp)
351{
352 int i;
353 /*
354 ** First, replace bogus characters.
355 */
356 for (i = 0; i < sp->charcnt; ++i)
357 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
358 sp->chars[i] = TZ_ABBR_ERR_CHAR;
359 /*
360 ** Second, truncate long abbreviations.
361 */
362 for (i = 0; i < sp->typecnt; ++i) {
363 register const struct ttinfo * const ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000364 char *cp = &sp->chars[ttisp->tt_desigidx];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700365
366 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
367 strcmp(cp, GRANDPARENTED) != 0)
368 *(cp + TZ_ABBR_MAX_LEN) = '\0';
369 }
370}
371
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700372/* Input buffer for data read from a compiled tz file. */
373union input_buffer {
374 /* The first part of the buffer, interpreted as a header. */
375 struct tzhead tzhead;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800376
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700377 /* The entire buffer. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000378 char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
379 + 4 * TZ_MAX_TIMES];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800380};
381
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000382// Android-removed: There is no directory with file-per-time zone on Android.
383#ifndef __BIONIC__
384/* TZDIR with a trailing '/' rather than a trailing '\0'. */
385static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
386#endif
387
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700388/* Local storage needed for 'tzloadbody'. */
389union local_storage {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700390 /* The results of analyzing the file's contents after it is opened. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000391 struct file_analysis {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700392 /* The input buffer. */
393 union input_buffer u;
394
395 /* A temporary state used for parsing a TZ string in the file. */
396 struct state st;
397 } u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000398
399 // Android-removed: There is no directory with file-per-time zone on Android.
400 #ifndef __BIONIC__
401 /* The file name to be opened. */
402 char fullname[BIGGEST(sizeof(struct file_analysis),
403 sizeof tzdirslash + 1024)];
404 #endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700405};
406
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700407/* Load tz data from the file named NAME into *SP. Read extended
408 format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
409 success, an errno value on failure. */
410static int
411tzloadbody(char const *name, struct state *sp, bool doextend,
412 union local_storage *lsp)
413{
414 register int i;
415 register int fid;
416 register int stored;
417 register ssize_t nread;
Elliott Hughesa9209d72016-09-16 18:16:47 -0700418#if !defined(__BIONIC__)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700419 register bool doaccess;
420 register char *fullname = lsp->fullname;
421#endif
422 register union input_buffer *up = &lsp->u.u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000423 register int tzheadsize = sizeof(struct tzhead);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700424
425 sp->goback = sp->goahead = false;
426
427 if (! name) {
428 name = TZDEFAULT;
429 if (! name)
430 return EINVAL;
431 }
432
Elliott Hughesa9209d72016-09-16 18:16:47 -0700433#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -0700434 extern int __bionic_open_tzdata(const char*, int32_t*);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700435 int32_t entry_length;
436 fid = __bionic_open_tzdata(name, &entry_length);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700437#else
438 if (name[0] == ':')
439 ++name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000440#ifdef SUPPRESS_TZDIR
441 /* Do not prepend TZDIR. This is intended for specialized
442 applications only, due to its security implications. */
443 doaccess = true;
444#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700445 doaccess = name[0] == '/';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000446#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700447 if (!doaccess) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000448 char const *dot;
449 size_t namelen = strlen(name);
450 if (sizeof lsp->fullname - sizeof tzdirslash <= namelen)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700451 return ENAMETOOLONG;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000452
453 /* Create a string "TZDIR/NAME". Using sprintf here
454 would pull in stdio (and would fail if the
455 resulting string length exceeded INT_MAX!). */
456 memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
457 strcpy(lsp->fullname + sizeof tzdirslash, name);
458
459 /* Set doaccess if NAME contains a ".." file name
460 component, as such a name could read a file outside
461 the TZDIR virtual subtree. */
462 for (dot = name; (dot = strchr(dot, '.')); dot++)
463 if ((dot == name || dot[-1] == '/') && dot[1] == '.'
464 && (dot[2] == '/' || !dot[2])) {
465 doaccess = true;
466 break;
467 }
468
469 name = lsp->fullname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700470 }
471 if (doaccess && access(name, R_OK) != 0)
472 return errno;
473 fid = open(name, OPEN_MODE);
474#endif
475 if (fid < 0)
476 return errno;
477
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700478#if defined(__BIONIC__)
Elliott Hughes4edd6512016-10-03 16:46:33 -0700479 nread = TEMP_FAILURE_RETRY(read(fid, up->buf, entry_length));
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700480#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700481 nread = read(fid, up->buf, sizeof up->buf);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700482#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700483 if (nread < tzheadsize) {
484 int err = nread < 0 ? errno : EINVAL;
485 close(fid);
486 return err;
487 }
488 if (close(fid) < 0)
489 return errno;
490 for (stored = 4; stored <= 8; stored *= 2) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000491 char version = up->tzhead.tzh_version[0];
492 bool skip_datablock = stored == 4 && version;
493 int_fast32_t datablock_size;
494 int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
495 int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
496 int_fast64_t prevtr = -1;
497 int_fast32_t prevcorr;
498 int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
499 int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
500 int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
501 int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
502 char const *p = up->buf + tzheadsize;
503 /* Although tzfile(5) currently requires typecnt to be nonzero,
504 support future formats that may allow zero typecnt
505 in files that have a TZ string and no transitions. */
506 if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
507 && 0 <= typecnt && typecnt < TZ_MAX_TYPES
508 && 0 <= timecnt && timecnt < TZ_MAX_TIMES
509 && 0 <= charcnt && charcnt < TZ_MAX_CHARS
510 && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
511 && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
512 return EINVAL;
513 datablock_size
514 = (timecnt * stored /* ats */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700515 + timecnt /* types */
516 + typecnt * 6 /* ttinfos */
517 + charcnt /* chars */
518 + leapcnt * (stored + 4) /* lsinfos */
519 + ttisstdcnt /* ttisstds */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000520 + ttisutcnt); /* ttisuts */
521 if (nread < tzheadsize + datablock_size)
522 return EINVAL;
523 if (skip_datablock)
524 p += datablock_size;
525 else {
526 if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
527 && (ttisutcnt == typecnt || ttisutcnt == 0)))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700528 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000529
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700530 sp->leapcnt = leapcnt;
531 sp->timecnt = timecnt;
532 sp->typecnt = typecnt;
533 sp->charcnt = charcnt;
534
535 /* Read transitions, discarding those out of time_t range.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000536 But pretend the last transition before TIME_T_MIN
537 occurred at TIME_T_MIN. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700538 timecnt = 0;
539 for (i = 0; i < sp->timecnt; ++i) {
540 int_fast64_t at
541 = stored == 4 ? detzcode(p) : detzcode64(p);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000542 sp->types[i] = at <= TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700543 if (sp->types[i]) {
544 time_t attime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000545 = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
546 ? TIME_T_MIN : at);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700547 if (timecnt && attime <= sp->ats[timecnt - 1]) {
548 if (attime < sp->ats[timecnt - 1])
549 return EINVAL;
550 sp->types[i - 1] = 0;
551 timecnt--;
552 }
553 sp->ats[timecnt++] = attime;
554 }
555 p += stored;
556 }
557
558 timecnt = 0;
559 for (i = 0; i < sp->timecnt; ++i) {
560 unsigned char typ = *p++;
561 if (sp->typecnt <= typ)
562 return EINVAL;
563 if (sp->types[i])
564 sp->types[timecnt++] = typ;
565 }
566 sp->timecnt = timecnt;
567 for (i = 0; i < sp->typecnt; ++i) {
568 register struct ttinfo * ttisp;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000569 unsigned char isdst, desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700570
571 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000572 ttisp->tt_utoff = detzcode(p);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700573 p += 4;
574 isdst = *p++;
575 if (! (isdst < 2))
576 return EINVAL;
577 ttisp->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000578 desigidx = *p++;
579 if (! (desigidx < sp->charcnt))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700580 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000581 ttisp->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700582 }
583 for (i = 0; i < sp->charcnt; ++i)
584 sp->chars[i] = *p++;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000585 /* Ensure '\0'-terminated, and make it safe to call
586 ttunspecified later. */
587 memset(&sp->chars[i], 0, CHARS_EXTRA);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700588
589 /* Read leap seconds, discarding those out of time_t range. */
590 leapcnt = 0;
591 for (i = 0; i < sp->leapcnt; ++i) {
592 int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
593 int_fast32_t corr = detzcode(p + stored);
594 p += stored + 4;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000595
596 /* Leap seconds cannot occur before the Epoch,
597 or out of order. */
598 if (tr <= prevtr)
599 return EINVAL;
600
601 /* To avoid other botches in this code, each leap second's
602 correction must differ from the previous one's by 1
603 second or less, except that the first correction can be
604 any value; these requirements are more generous than
605 RFC 8536, to allow future RFC extensions. */
606 if (! (i == 0
607 || (prevcorr < corr
608 ? corr == prevcorr + 1
609 : (corr == prevcorr
610 || corr == prevcorr - 1))))
611 return EINVAL;
612 prevtr = tr;
613 prevcorr = corr;
614
615 if (tr <= TIME_T_MAX) {
616 sp->lsis[leapcnt].ls_trans = tr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700617 sp->lsis[leapcnt].ls_corr = corr;
618 leapcnt++;
619 }
620 }
621 sp->leapcnt = leapcnt;
622
623 for (i = 0; i < sp->typecnt; ++i) {
624 register struct ttinfo * ttisp;
625
626 ttisp = &sp->ttis[i];
627 if (ttisstdcnt == 0)
628 ttisp->tt_ttisstd = false;
629 else {
630 if (*p != true && *p != false)
631 return EINVAL;
632 ttisp->tt_ttisstd = *p++;
633 }
634 }
635 for (i = 0; i < sp->typecnt; ++i) {
636 register struct ttinfo * ttisp;
637
638 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000639 if (ttisutcnt == 0)
640 ttisp->tt_ttisut = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700641 else {
642 if (*p != true && *p != false)
643 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000644 ttisp->tt_ttisut = *p++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700645 }
646 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000647 }
648
649 nread -= p - up->buf;
650 memmove(up->buf, p, nread);
651
652 /* If this is an old file, we're done. */
653 if (!version)
654 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700655 }
656 if (doextend && nread > 2 &&
657 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
658 sp->typecnt + 2 <= TZ_MAX_TYPES) {
659 struct state *ts = &lsp->u.st;
660
661 up->buf[nread - 1] = '\0';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000662 if (tzparse(&up->buf[1], ts, sp)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700663
664 /* Attempt to reuse existing abbreviations.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000665 Without this, America/Anchorage would be right on
666 the edge after 2037 when TZ_MAX_CHARS is 50, as
667 sp->charcnt equals 40 (for LMT AST AWT APT AHST
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700668 AHDT YST AKDT AKST) and ts->charcnt equals 10
669 (for AKST AKDT). Reusing means sp->charcnt can
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000670 stay 40 in this example. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700671 int gotabbr = 0;
672 int charcnt = sp->charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000673 for (i = 0; i < ts->typecnt; i++) {
674 char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700675 int j;
676 for (j = 0; j < charcnt; j++)
677 if (strcmp(sp->chars + j, tsabbr) == 0) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000678 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700679 gotabbr++;
680 break;
681 }
682 if (! (j < charcnt)) {
683 int tsabbrlen = strlen(tsabbr);
684 if (j + tsabbrlen < TZ_MAX_CHARS) {
685 strcpy(sp->chars + j, tsabbr);
686 charcnt = j + tsabbrlen + 1;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000687 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700688 gotabbr++;
689 }
690 }
691 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000692 if (gotabbr == ts->typecnt) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700693 sp->charcnt = charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000694
695 /* Ignore any trailing, no-op transitions generated
696 by zic as they don't help here and can run afoul
697 of bugs in zic 2016j or earlier. */
698 while (1 < sp->timecnt
699 && (sp->types[sp->timecnt - 1]
700 == sp->types[sp->timecnt - 2]))
701 sp->timecnt--;
702
703 for (i = 0;
704 i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES;
705 i++) {
706 time_t t = ts->ats[i];
707 if (increment_overflow_time(&t, leapcorr(sp, t))
708 || (0 < sp->timecnt
709 && t <= sp->ats[sp->timecnt - 1]))
710 continue;
711 sp->ats[sp->timecnt] = t;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700712 sp->types[sp->timecnt] = (sp->typecnt
713 + ts->types[i]);
714 sp->timecnt++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700715 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000716 for (i = 0; i < ts->typecnt; i++)
717 sp->ttis[sp->typecnt++] = ts->ttis[i];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700718 }
719 }
720 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000721 if (sp->typecnt == 0)
722 return EINVAL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700723 if (sp->timecnt > 1) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000724 if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) {
725 time_t repeatat = sp->ats[0] + SECSPERREPEAT;
726 int repeattype = sp->types[0];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700727 for (i = 1; i < sp->timecnt; ++i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000728 if (sp->ats[i] == repeatat
729 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700730 sp->goback = true;
731 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000732 }
733 }
734 if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) {
735 time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT;
736 int repeattype = sp->types[sp->timecnt - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700737 for (i = sp->timecnt - 2; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000738 if (sp->ats[i] == repeatat
739 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700740 sp->goahead = true;
741 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000742 }
743 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700744 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000745
746 /* Infer sp->defaulttype from the data. Although this default
747 type is always zero for data from recent tzdb releases,
748 things are trickier for data from tzdb 2018e or earlier.
749
750 The first set of heuristics work around bugs in 32-bit data
751 generated by tzdb 2013c or earlier. The workaround is for
752 zones like Australia/Macquarie where timestamps before the
753 first transition have a time type that is not the earliest
754 standard-time type. See:
755 https://mm.icann.org/pipermail/tz/2013-May/019368.html */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700756 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000757 ** If type 0 does not specify local time, or is unused in transitions,
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700758 ** it's the type to use for early times.
759 */
760 for (i = 0; i < sp->timecnt; ++i)
761 if (sp->types[i] == 0)
762 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000763 i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700764 /*
765 ** Absent the above,
766 ** if there are transition times
767 ** and the first transition is to a daylight time
768 ** find the standard type less than and closest to
769 ** the type of the first transition.
770 */
771 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
772 i = sp->types[0];
773 while (--i >= 0)
774 if (!sp->ttis[i].tt_isdst)
775 break;
776 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000777 /* The next heuristics are for data generated by tzdb 2018e or
778 earlier, for zones like EST5EDT where the first transition
779 is to DST. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700780 /*
781 ** If no result yet, find the first standard type.
782 ** If there is none, punt to type zero.
783 */
784 if (i < 0) {
785 i = 0;
786 while (sp->ttis[i].tt_isdst)
787 if (++i >= sp->typecnt) {
788 i = 0;
789 break;
790 }
791 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000792 /* A simple 'sp->defaulttype = 0;' would suffice here if we
793 didn't have to worry about 2018e-or-earlier data. Even
794 simpler would be to remove the defaulttype member and just
795 use 0 in its place. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700796 sp->defaulttype = i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000797
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700798 return 0;
799}
800
801/* Load tz data from the file named NAME into *SP. Read extended
802 format if DOEXTEND. Return 0 on success, an errno value on failure. */
803static int
804tzload(char const *name, struct state *sp, bool doextend)
805{
806#ifdef ALL_STATE
807 union local_storage *lsp = malloc(sizeof *lsp);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000808 if (!lsp) {
809 return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
810 } else {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700811 int err = tzloadbody(name, sp, doextend, lsp);
812 free(lsp);
813 return err;
814 }
815#else
816 union local_storage ls;
817 return tzloadbody(name, sp, doextend, &ls);
818#endif
819}
820
821static bool
822typesequiv(const struct state *sp, int a, int b)
823{
824 register bool result;
825
826 if (sp == NULL ||
827 a < 0 || a >= sp->typecnt ||
828 b < 0 || b >= sp->typecnt)
829 result = false;
830 else {
831 register const struct ttinfo * ap = &sp->ttis[a];
832 register const struct ttinfo * bp = &sp->ttis[b];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000833 result = (ap->tt_utoff == bp->tt_utoff
834 && ap->tt_isdst == bp->tt_isdst
835 && ap->tt_ttisstd == bp->tt_ttisstd
836 && ap->tt_ttisut == bp->tt_ttisut
837 && (strcmp(&sp->chars[ap->tt_desigidx],
838 &sp->chars[bp->tt_desigidx])
839 == 0));
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700840 }
841 return result;
842}
843
844static const int mon_lengths[2][MONSPERYEAR] = {
845 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
846 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
847};
848
849static const int year_lengths[2] = {
850 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800851};
852
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000853/* Is C an ASCII digit? */
854static bool
855is_digit(char c)
856{
857 return '0' <= c && c <= '9';
858}
859
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800860/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000861** Given a pointer into a timezone string, scan until a character that is not
862** a valid character in a time zone abbreviation is found.
863** Return a pointer to that character.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800864*/
865
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000866static ATTRIBUTE_PURE const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700867getzname(register const char *strp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800868{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700869 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800870
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700871 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
872 c != '+')
873 ++strp;
874 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800875}
876
877/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000878** Given a pointer into an extended timezone string, scan until the ending
879** delimiter of the time zone abbreviation is located.
880** Return a pointer to the delimiter.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800881**
882** As with getzname above, the legal character set is actually quite
883** restricted, with other characters producing undefined results.
884** We don't do any checking here; checking is done later in common-case code.
885*/
886
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000887static ATTRIBUTE_PURE const char *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800888getqzname(register const char *strp, const int delim)
889{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700890 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800891
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700892 while ((c = *strp) != '\0' && c != delim)
893 ++strp;
894 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800895}
896
897/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000898** Given a pointer into a timezone string, extract a number from that string.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800899** Check that the number is within a specified range; if it is not, return
900** NULL.
901** Otherwise, return a pointer to the first character not part of the number.
902*/
903
904static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700905getnum(register const char *strp, int *const nump, const int min, const int max)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800906{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700907 register char c;
908 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800909
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700910 if (strp == NULL || !is_digit(c = *strp))
911 return NULL;
912 num = 0;
913 do {
914 num = num * 10 + (c - '0');
915 if (num > max)
916 return NULL; /* illegal value */
917 c = *++strp;
918 } while (is_digit(c));
919 if (num < min)
920 return NULL; /* illegal value */
921 *nump = num;
922 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800923}
924
925/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000926** Given a pointer into a timezone string, extract a number of seconds,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800927** in hh[:mm[:ss]] form, from the string.
928** If any error occurs, return NULL.
929** Otherwise, return a pointer to the first character not part of the number
930** of seconds.
931*/
932
933static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700934getsecs(register const char *strp, int_fast32_t *const secsp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800935{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700936 int num;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000937 int_fast32_t secsperhour = SECSPERHOUR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800938
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700939 /*
940 ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
941 ** "M10.4.6/26", which does not conform to Posix,
942 ** but which specifies the equivalent of
943 ** "02:00 on the first Sunday on or after 23 Oct".
944 */
945 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
946 if (strp == NULL)
947 return NULL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000948 *secsp = num * secsperhour;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700949 if (*strp == ':') {
950 ++strp;
951 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
952 if (strp == NULL)
953 return NULL;
954 *secsp += num * SECSPERMIN;
955 if (*strp == ':') {
956 ++strp;
957 /* 'SECSPERMIN' allows for leap seconds. */
958 strp = getnum(strp, &num, 0, SECSPERMIN);
959 if (strp == NULL)
960 return NULL;
961 *secsp += num;
962 }
963 }
964 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800965}
966
967/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000968** Given a pointer into a timezone string, extract an offset, in
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800969** [+-]hh[:mm[:ss]] form, from the string.
970** If any error occurs, return NULL.
971** Otherwise, return a pointer to the first character not part of the time.
972*/
973
974static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700975getoffset(register const char *strp, int_fast32_t *const offsetp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800976{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700977 register bool neg = false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800978
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700979 if (*strp == '-') {
980 neg = true;
981 ++strp;
982 } else if (*strp == '+')
983 ++strp;
984 strp = getsecs(strp, offsetp);
985 if (strp == NULL)
986 return NULL; /* illegal time */
987 if (neg)
988 *offsetp = -*offsetp;
989 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800990}
991
992/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000993** Given a pointer into a timezone string, extract a rule in the form
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800994** date[/time]. See POSIX section 8 for the format of "date" and "time".
995** If a valid rule is not found, return NULL.
996** Otherwise, return a pointer to the first character not part of the rule.
997*/
998
999static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001000getrule(const char *strp, register struct rule *const rulep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001001{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001002 if (*strp == 'J') {
1003 /*
1004 ** Julian day.
1005 */
1006 rulep->r_type = JULIAN_DAY;
1007 ++strp;
1008 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1009 } else if (*strp == 'M') {
1010 /*
1011 ** Month, week, day.
1012 */
1013 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
1014 ++strp;
1015 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1016 if (strp == NULL)
1017 return NULL;
1018 if (*strp++ != '.')
1019 return NULL;
1020 strp = getnum(strp, &rulep->r_week, 1, 5);
1021 if (strp == NULL)
1022 return NULL;
1023 if (*strp++ != '.')
1024 return NULL;
1025 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1026 } else if (is_digit(*strp)) {
1027 /*
1028 ** Day of year.
1029 */
1030 rulep->r_type = DAY_OF_YEAR;
1031 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1032 } else return NULL; /* invalid format */
1033 if (strp == NULL)
1034 return NULL;
1035 if (*strp == '/') {
1036 /*
1037 ** Time specified.
1038 */
1039 ++strp;
1040 strp = getoffset(strp, &rulep->r_time);
1041 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1042 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001043}
1044
1045/*
Calin Juravle627d37c2014-02-28 11:46:03 +00001046** Given a year, a rule, and the offset from UT at the time that rule takes
1047** effect, calculate the year-relative time that rule takes effect.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001048*/
1049
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001050static int_fast32_t
Calin Juravle627d37c2014-02-28 11:46:03 +00001051transtime(const int year, register const struct rule *const rulep,
Calin Juravled8928922014-02-28 12:18:53 +00001052 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001053{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001054 register bool leapyear;
Calin Juravled8928922014-02-28 12:18:53 +00001055 register int_fast32_t value;
1056 register int i;
1057 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001058
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001059 leapyear = isleap(year);
1060 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001061
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001062 case JULIAN_DAY:
1063 /*
1064 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1065 ** years.
1066 ** In non-leap years, or if the day number is 59 or less, just
1067 ** add SECSPERDAY times the day number-1 to the time of
1068 ** January 1, midnight, to get the day.
1069 */
Calin Juravled8928922014-02-28 12:18:53 +00001070 value = (rulep->r_day - 1) * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001071 if (leapyear && rulep->r_day >= 60)
1072 value += SECSPERDAY;
1073 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001074
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001075 case DAY_OF_YEAR:
1076 /*
1077 ** n - day of year.
1078 ** Just add SECSPERDAY times the day number to the time of
1079 ** January 1, midnight, to get the day.
1080 */
Calin Juravled8928922014-02-28 12:18:53 +00001081 value = rulep->r_day * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001082 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001083
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001084 case MONTH_NTH_DAY_OF_WEEK:
1085 /*
1086 ** Mm.n.d - nth "dth day" of month m.
1087 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001088
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001089 /*
1090 ** Use Zeller's Congruence to get day-of-week of first day of
1091 ** month.
1092 */
1093 m1 = (rulep->r_mon + 9) % 12 + 1;
1094 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1095 yy1 = yy0 / 100;
1096 yy2 = yy0 % 100;
1097 dow = ((26 * m1 - 2) / 10 +
1098 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1099 if (dow < 0)
1100 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001101
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001102 /*
1103 ** "dow" is the day-of-week of the first day of the month. Get
1104 ** the day-of-month (zero-origin) of the first "dow" day of the
1105 ** month.
1106 */
1107 d = rulep->r_day - dow;
1108 if (d < 0)
1109 d += DAYSPERWEEK;
1110 for (i = 1; i < rulep->r_week; ++i) {
1111 if (d + DAYSPERWEEK >=
1112 mon_lengths[leapyear][rulep->r_mon - 1])
1113 break;
1114 d += DAYSPERWEEK;
1115 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001116
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001117 /*
1118 ** "d" is the day-of-month (zero-origin) of the day we want.
1119 */
Calin Juravled8928922014-02-28 12:18:53 +00001120 value = d * SECSPERDAY;
1121 for (i = 0; i < rulep->r_mon - 1; ++i)
1122 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001123 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001124
1125 default: UNREACHABLE();
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001126 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001127
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001128 /*
Calin Juravled8928922014-02-28 12:18:53 +00001129 ** "value" is the year-relative time of 00:00:00 UT on the day in
1130 ** question. To get the year-relative time of the specified local
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001131 ** time on that day, add the transition time and the current offset
Elliott Hughese0d0b152013-09-27 00:04:30 -07001132 ** from UT.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001133 */
1134 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001135}
1136
1137/*
1138** Given a POSIX section 8-style TZ string, fill in the rule tables as
1139** appropriate.
1140*/
1141
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001142static bool
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001143tzparse(const char *name, struct state *sp, struct state *basep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001144{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001145 const char * stdname;
1146 const char * dstname;
1147 size_t stdlen;
1148 size_t dstlen;
1149 size_t charcnt;
1150 int_fast32_t stdoffset;
1151 int_fast32_t dstoffset;
1152 register char * cp;
1153 register bool load_ok;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001154 time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001155
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001156 stdname = name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001157 if (*name == '<') {
1158 name++;
1159 stdname = name;
1160 name = getqzname(name, '>');
1161 if (*name != '>')
1162 return false;
1163 stdlen = name - stdname;
1164 name++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001165 } else {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001166 name = getzname(name);
1167 stdlen = name - stdname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001168 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001169 if (!stdlen)
1170 return false;
1171 name = getoffset(name, &stdoffset);
1172 if (name == NULL)
1173 return false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001174 charcnt = stdlen + 1;
1175 if (sizeof sp->chars < charcnt)
1176 return false;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001177 if (basep) {
1178 if (0 < basep->timecnt)
1179 atlo = basep->ats[basep->timecnt - 1];
1180 load_ok = false;
1181 sp->leapcnt = basep->leapcnt;
1182 memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
1183 } else {
1184 load_ok = tzload(TZDEFRULES, sp, false) == 0;
1185 if (!load_ok)
1186 sp->leapcnt = 0; /* So, we're off a little. */
1187 }
1188 if (0 < sp->leapcnt)
1189 leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001190 if (*name != '\0') {
1191 if (*name == '<') {
1192 dstname = ++name;
1193 name = getqzname(name, '>');
1194 if (*name != '>')
1195 return false;
1196 dstlen = name - dstname;
1197 name++;
1198 } else {
1199 dstname = name;
1200 name = getzname(name);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001201 dstlen = name - dstname; /* length of DST abbr. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001202 }
1203 if (!dstlen)
1204 return false;
1205 charcnt += dstlen + 1;
1206 if (sizeof sp->chars < charcnt)
1207 return false;
1208 if (*name != '\0' && *name != ',' && *name != ';') {
1209 name = getoffset(name, &dstoffset);
1210 if (name == NULL)
1211 return false;
1212 } else dstoffset = stdoffset - SECSPERHOUR;
1213 if (*name == '\0' && !load_ok)
1214 name = TZDEFRULESTRING;
1215 if (*name == ',' || *name == ';') {
1216 struct rule start;
1217 struct rule end;
1218 register int year;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001219 register int timecnt;
1220 time_t janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001221 int_fast32_t janoffset = 0;
1222 int yearbeg, yearlim;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001223
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001224 ++name;
1225 if ((name = getrule(name, &start)) == NULL)
1226 return false;
1227 if (*name++ != ',')
1228 return false;
1229 if ((name = getrule(name, &end)) == NULL)
1230 return false;
1231 if (*name != '\0')
1232 return false;
1233 sp->typecnt = 2; /* standard time and DST */
1234 /*
1235 ** Two transitions per year, from EPOCH_YEAR forward.
1236 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001237 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1238 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001239 sp->defaulttype = 0;
1240 timecnt = 0;
1241 janfirst = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001242 yearbeg = EPOCH_YEAR;
1243
1244 do {
1245 int_fast32_t yearsecs
1246 = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
1247 yearbeg--;
1248 if (increment_overflow_time(&janfirst, -yearsecs)) {
1249 janoffset = -yearsecs;
1250 break;
1251 }
1252 } while (atlo < janfirst
1253 && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1254
1255 while (true) {
1256 int_fast32_t yearsecs
1257 = year_lengths[isleap(yearbeg)] * SECSPERDAY;
1258 int yearbeg1 = yearbeg;
1259 time_t janfirst1 = janfirst;
1260 if (increment_overflow_time(&janfirst1, yearsecs)
1261 || increment_overflow(&yearbeg1, 1)
1262 || atlo <= janfirst1)
1263 break;
1264 yearbeg = yearbeg1;
1265 janfirst = janfirst1;
1266 }
1267
1268 yearlim = yearbeg;
1269 if (increment_overflow(&yearlim, YEARSPERREPEAT + 1))
1270 yearlim = INT_MAX;
1271 for (year = yearbeg; year < yearlim; year++) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001272 int_fast32_t
1273 starttime = transtime(year, &start, stdoffset),
1274 endtime = transtime(year, &end, dstoffset);
1275 int_fast32_t
1276 yearsecs = (year_lengths[isleap(year)]
1277 * SECSPERDAY);
1278 bool reversed = endtime < starttime;
1279 if (reversed) {
1280 int_fast32_t swap = starttime;
1281 starttime = endtime;
1282 endtime = swap;
1283 }
1284 if (reversed
1285 || (starttime < endtime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001286 && endtime - starttime < yearsecs)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001287 if (TZ_MAX_TIMES - 2 < timecnt)
1288 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001289 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001290 if (! increment_overflow_time
1291 (&sp->ats[timecnt],
1292 janoffset + starttime)
1293 && atlo <= sp->ats[timecnt])
1294 sp->types[timecnt++] = !reversed;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001295 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001296 if (! increment_overflow_time
1297 (&sp->ats[timecnt],
1298 janoffset + endtime)
1299 && atlo <= sp->ats[timecnt]) {
1300 sp->types[timecnt++] = reversed;
1301 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001302 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001303 if (endtime < leaplo) {
1304 yearlim = year;
1305 if (increment_overflow(&yearlim,
1306 YEARSPERREPEAT + 1))
1307 yearlim = INT_MAX;
1308 }
1309 if (increment_overflow_time
1310 (&janfirst, janoffset + yearsecs))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001311 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001312 janoffset = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001313 }
1314 sp->timecnt = timecnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001315 if (! timecnt) {
1316 sp->ttis[0] = sp->ttis[1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001317 sp->typecnt = 1; /* Perpetual DST. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001318 } else if (YEARSPERREPEAT < year - yearbeg)
1319 sp->goback = sp->goahead = true;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001320 } else {
1321 register int_fast32_t theirstdoffset;
1322 register int_fast32_t theirdstoffset;
1323 register int_fast32_t theiroffset;
1324 register bool isdst;
1325 register int i;
1326 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001327
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001328 if (*name != '\0')
1329 return false;
1330 /*
1331 ** Initial values of theirstdoffset and theirdstoffset.
1332 */
1333 theirstdoffset = 0;
1334 for (i = 0; i < sp->timecnt; ++i) {
1335 j = sp->types[i];
1336 if (!sp->ttis[j].tt_isdst) {
1337 theirstdoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001338 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001339 break;
1340 }
1341 }
1342 theirdstoffset = 0;
1343 for (i = 0; i < sp->timecnt; ++i) {
1344 j = sp->types[i];
1345 if (sp->ttis[j].tt_isdst) {
1346 theirdstoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001347 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001348 break;
1349 }
1350 }
1351 /*
1352 ** Initially we're assumed to be in standard time.
1353 */
1354 isdst = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001355 /*
1356 ** Now juggle transition times and types
1357 ** tracking offsets as you do.
1358 */
1359 for (i = 0; i < sp->timecnt; ++i) {
1360 j = sp->types[i];
1361 sp->types[i] = sp->ttis[j].tt_isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001362 if (sp->ttis[j].tt_ttisut) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001363 /* No adjustment to transition time */
1364 } else {
1365 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001366 ** If daylight saving time is in
1367 ** effect, and the transition time was
1368 ** not specified as standard time, add
1369 ** the daylight saving time offset to
1370 ** the transition time; otherwise, add
1371 ** the standard time offset to the
1372 ** transition time.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001373 */
1374 /*
1375 ** Transitions from DST to DDST
1376 ** will effectively disappear since
1377 ** POSIX provides for only one DST
1378 ** offset.
1379 */
1380 if (isdst && !sp->ttis[j].tt_ttisstd) {
1381 sp->ats[i] += dstoffset -
1382 theirdstoffset;
1383 } else {
1384 sp->ats[i] += stdoffset -
1385 theirstdoffset;
1386 }
1387 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001388 theiroffset = -sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001389 if (sp->ttis[j].tt_isdst)
1390 theirdstoffset = theiroffset;
1391 else theirstdoffset = theiroffset;
1392 }
1393 /*
1394 ** Finally, fill in ttis.
1395 */
1396 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1397 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1398 sp->typecnt = 2;
1399 sp->defaulttype = 0;
1400 }
1401 } else {
1402 dstlen = 0;
1403 sp->typecnt = 1; /* only standard time */
1404 sp->timecnt = 0;
1405 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1406 sp->defaulttype = 0;
1407 }
1408 sp->charcnt = charcnt;
1409 cp = sp->chars;
1410 memcpy(cp, stdname, stdlen);
1411 cp += stdlen;
1412 *cp++ = '\0';
1413 if (dstlen != 0) {
1414 memcpy(cp, dstname, dstlen);
1415 *(cp + dstlen) = '\0';
1416 }
1417 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001418}
1419
1420static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001421gmtload(struct state *const sp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001422{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001423 if (tzload(gmt, sp, true) != 0)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001424 tzparse("GMT0", sp, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001425}
1426
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001427/* Initialize *SP to a value appropriate for the TZ setting NAME.
1428 Return 0 on success, an errno value on failure. */
1429static int
1430zoneinit(struct state *sp, char const *name)
1431{
1432 if (name && ! name[0]) {
1433 /*
1434 ** User wants it fast rather than right.
1435 */
1436 sp->leapcnt = 0; /* so, we're off a little */
1437 sp->timecnt = 0;
1438 sp->typecnt = 0;
1439 sp->charcnt = 0;
1440 sp->goback = sp->goahead = false;
1441 init_ttinfo(&sp->ttis[0], 0, false, 0);
1442 strcpy(sp->chars, gmt);
1443 sp->defaulttype = 0;
1444 return 0;
1445 } else {
1446 int err = tzload(name, sp, true);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001447 if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001448 err = 0;
1449 if (err == 0)
1450 scrub_abbrs(sp);
1451 return err;
1452 }
1453}
1454
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001455void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001456tzsetlcl(char const *name)
1457{
1458 struct state *sp = lclptr;
1459 int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1460 if (lcl < 0
1461 ? lcl_is_set < 0
1462 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1463 return;
1464#ifdef ALL_STATE
1465 if (! sp)
1466 lclptr = sp = malloc(sizeof *lclptr);
1467#endif /* defined ALL_STATE */
1468 if (sp) {
1469 if (zoneinit(sp, name) != 0)
1470 zoneinit(sp, "");
1471 if (0 < lcl)
1472 strcpy(lcl_TZname, name);
1473 }
1474 settzname();
1475 lcl_is_set = lcl;
1476}
1477
Elliott Hughesa9209d72016-09-16 18:16:47 -07001478#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001479extern void tzset_unlocked(void);
1480#else
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001481static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001482tzset_unlocked(void)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001483{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001484 tzsetlcl(getenv("TZ"));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001485}
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001486#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001487
1488void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001489tzset(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001490{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001491 if (lock() != 0)
1492 return;
1493 tzset_unlocked();
1494 unlock();
1495}
1496
1497static void
1498gmtcheck(void)
1499{
1500 static bool gmt_is_set;
1501 if (lock() != 0)
1502 return;
1503 if (! gmt_is_set) {
1504#ifdef ALL_STATE
1505 gmtptr = malloc(sizeof *gmtptr);
1506#endif
1507 if (gmtptr)
1508 gmtload(gmtptr);
1509 gmt_is_set = true;
1510 }
1511 unlock();
1512}
1513
1514#if NETBSD_INSPIRED
1515
1516timezone_t
1517tzalloc(char const *name)
1518{
1519 timezone_t sp = malloc(sizeof *sp);
1520 if (sp) {
1521 int err = zoneinit(sp, name);
1522 if (err != 0) {
1523 free(sp);
1524 errno = err;
1525 return NULL;
1526 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001527 } else if (!HAVE_MALLOC_ERRNO)
1528 errno = ENOMEM;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001529 return sp;
1530}
1531
1532void
1533tzfree(timezone_t sp)
1534{
1535 free(sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001536}
1537
1538/*
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001539** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
1540** ctime_r are obsolescent and have potential security problems that
1541** ctime_rz would share. Callers can instead use localtime_rz + strftime.
1542**
1543** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1544** in zones with three or more time zone abbreviations.
1545** Callers can instead use localtime_rz + strftime.
1546*/
1547
1548#endif
1549
1550/*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001551** The easy way to behave "as if no library function calls" localtime
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001552** is to not call it, so we drop its guts into "localsub", which can be
1553** freely called. (And no, the PANS doesn't require the above behavior,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001554** but it *is* desirable.)
1555**
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001556** If successful and SETNAME is nonzero,
1557** set the applicable parts of tzname, timezone and altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001558** however, it's OK to omit this step if the timezone is POSIX-compatible,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001559** since in that case tzset should have already done this step correctly.
1560** SETNAME's type is intfast32_t for compatibility with gmtsub,
1561** but it is actually a boolean and its value should be 0 or 1.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001562*/
1563
1564/*ARGSUSED*/
1565static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001566localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1567 struct tm *const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001568{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001569 register const struct ttinfo * ttisp;
1570 register int i;
1571 register struct tm * result;
1572 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001573
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001574 if (sp == NULL) {
1575 /* Don't bother to set tzname etc.; tzset has already done it. */
1576 return gmtsub(gmtptr, timep, 0, tmp);
1577 }
1578 if ((sp->goback && t < sp->ats[0]) ||
1579 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001580 time_t newt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001581 register time_t seconds;
1582 register time_t years;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001583
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001584 if (t < sp->ats[0])
1585 seconds = sp->ats[0] - t;
1586 else seconds = t - sp->ats[sp->timecnt - 1];
1587 --seconds;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001588
1589 /* Beware integer overflow, as SECONDS might
1590 be close to the maximum time_t. */
1591 years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001592 seconds = years * AVGSECSPERYEAR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001593 years += YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001594 if (t < sp->ats[0])
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001595 newt = t + seconds + SECSPERREPEAT;
1596 else
1597 newt = t - seconds - SECSPERREPEAT;
1598
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001599 if (newt < sp->ats[0] ||
1600 newt > sp->ats[sp->timecnt - 1])
1601 return NULL; /* "cannot happen" */
1602 result = localsub(sp, &newt, setname, tmp);
1603 if (result) {
1604 register int_fast64_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001605
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001606 newy = result->tm_year;
1607 if (t < sp->ats[0])
1608 newy -= years;
1609 else newy += years;
1610 if (! (INT_MIN <= newy && newy <= INT_MAX))
1611 return NULL;
1612 result->tm_year = newy;
1613 }
1614 return result;
1615 }
1616 if (sp->timecnt == 0 || t < sp->ats[0]) {
1617 i = sp->defaulttype;
1618 } else {
1619 register int lo = 1;
1620 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001621
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001622 while (lo < hi) {
1623 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001624
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001625 if (t < sp->ats[mid])
1626 hi = mid;
1627 else lo = mid + 1;
1628 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001629 i = sp->types[lo - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001630 }
1631 ttisp = &sp->ttis[i];
1632 /*
1633 ** To get (wrong) behavior that's compatible with System V Release 2.0
1634 ** you'd replace the statement below with
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001635 ** t += ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001636 ** timesub(&t, 0L, sp, tmp);
1637 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001638 result = timesub(&t, ttisp->tt_utoff, sp, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001639 if (result) {
1640 result->tm_isdst = ttisp->tt_isdst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001641#ifdef TM_ZONE
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001642 result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001643#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001644 if (setname)
1645 update_tzname_etc(sp, ttisp);
1646 }
1647 return result;
1648}
1649
1650#if NETBSD_INSPIRED
1651
1652struct tm *
1653localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
1654{
1655 return localsub(sp, timep, 0, tmp);
1656}
1657
1658#endif
1659
1660static struct tm *
Elliott Hughesea877162017-01-11 14:34:16 -08001661localtime_tzset(time_t const *timep, struct tm *tmp)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001662{
1663 int err = lock();
1664 if (err) {
1665 errno = err;
1666 return NULL;
1667 }
Elliott Hughesea877162017-01-11 14:34:16 -08001668
1669 // http://b/31339449: POSIX says localtime(3) acts as if it called tzset(3), but upstream
1670 // and glibc both think it's okay for localtime_r(3) to not do so (presumably because of
1671 // the "not required to set tzname" clause). It's unclear that POSIX actually intended this,
1672 // the BSDs disagree with glibc, and it's confusing to developers to have localtime_r(3)
1673 // behave differently than other time zone-sensitive functions in <time.h>.
1674 tzset_unlocked();
1675
1676 tmp = localsub(lclptr, timep, true, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001677 unlock();
1678 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001679}
1680
1681struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001682localtime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001683{
Elliott Hughesea877162017-01-11 14:34:16 -08001684 return localtime_tzset(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001685}
1686
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001687struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001688localtime_r(const time_t *timep, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001689{
Elliott Hughesea877162017-01-11 14:34:16 -08001690 return localtime_tzset(timep, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001691}
1692
1693/*
1694** gmtsub is to gmtime as localsub is to localtime.
1695*/
1696
1697static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001698gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
1699 struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001700{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001701 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001703 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001704#ifdef TM_ZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001705 /*
1706 ** Could get fancy here and deliver something such as
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001707 ** "+xx" or "-xx" if offset is non-zero,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001708 ** but this is no time for a treasure hunt.
1709 */
1710 tmp->TM_ZONE = ((char *)
1711 (offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001712#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001713 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001714}
1715
1716/*
1717* Re-entrant version of gmtime.
1718*/
1719
1720struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001721gmtime_r(const time_t *timep, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001722{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001723 gmtcheck();
1724 return gmtsub(gmtptr, timep, 0, tmp);
1725}
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001726
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001727struct tm *
1728gmtime(const time_t *timep)
1729{
1730 return gmtime_r(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001731}
1732
Elliott Hughes906eb992014-06-18 19:46:25 -07001733#ifdef STD_INSPIRED
1734
1735struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001736offtime(const time_t *timep, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07001737{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001738 gmtcheck();
1739 return gmtsub(gmtptr, timep, offset, &tm);
Elliott Hughes906eb992014-06-18 19:46:25 -07001740}
1741
1742#endif /* defined STD_INSPIRED */
1743
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001744/*
1745** Return the number of leap years through the end of the given year
1746** where, to make the math easy, the answer for year zero is defined as zero.
1747*/
1748
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001749static time_t
1750leaps_thru_end_of_nonneg(time_t y)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001751{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001752 return y / 4 - y / 100 + y / 400;
1753}
1754
1755static time_t
1756leaps_thru_end_of(time_t y)
1757{
1758 return (y < 0
1759 ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1760 : leaps_thru_end_of_nonneg(y));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001761}
1762
1763static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001764timesub(const time_t *timep, int_fast32_t offset,
1765 const struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001766{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001767 register const struct lsinfo * lp;
1768 register time_t tdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001769 register const int * ip;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001770 register int_fast32_t corr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001771 register int i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001772 int_fast32_t idays, rem, dayoff, dayrem;
1773 time_t y;
1774
1775 /* If less than SECSPERMIN, the number of seconds since the
1776 most recent positive leap second; otherwise, do not add 1
1777 to localtime tm_sec because of leap seconds. */
1778 time_t secs_since_posleap = SECSPERMIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001779
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001780 corr = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001781 i = (sp == NULL) ? 0 : sp->leapcnt;
1782 while (--i >= 0) {
1783 lp = &sp->lsis[i];
1784 if (*timep >= lp->ls_trans) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001785 corr = lp->ls_corr;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001786 if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
1787 secs_since_posleap = *timep - lp->ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001788 break;
1789 }
1790 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001791
1792 /* Calculate the year, avoiding integer overflow even if
1793 time_t is unsigned. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001794 tdays = *timep / SECSPERDAY;
1795 rem = *timep % SECSPERDAY;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001796 rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
1797 dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
1798 rem %= SECSPERDAY;
1799 /* y = (EPOCH_YEAR
1800 + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
1801 sans overflow. But calculate against 1570 (EPOCH_YEAR -
1802 YEARSPERREPEAT) instead of against 1970 so that things work
1803 for localtime values before 1970 when time_t is unsigned. */
1804 dayrem = tdays % DAYSPERREPEAT;
1805 dayrem += dayoff % DAYSPERREPEAT;
1806 y = (EPOCH_YEAR - YEARSPERREPEAT
1807 + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
1808 - ((dayrem % DAYSPERREPEAT) < 0)
1809 + tdays / DAYSPERREPEAT)
1810 * YEARSPERREPEAT));
1811 /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */
1812 idays = tdays % DAYSPERREPEAT;
1813 idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
1814 idays %= DAYSPERREPEAT;
1815 /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
1816 while (year_lengths[isleap(y)] <= idays) {
1817 int tdelta = idays / DAYSPERLYEAR;
1818 int_fast32_t ydelta = tdelta + !tdelta;
1819 time_t newy = y + ydelta;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001820 register int leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001821 leapdays = leaps_thru_end_of(newy - 1) -
1822 leaps_thru_end_of(y - 1);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001823 idays -= ydelta * DAYSPERNYEAR;
1824 idays -= leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001825 y = newy;
1826 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001827
1828 if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
1829 int signed_y = y;
1830 tmp->tm_year = signed_y - TM_YEAR_BASE;
1831 } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
1832 && y - TM_YEAR_BASE <= INT_MAX)
1833 tmp->tm_year = y - TM_YEAR_BASE;
1834 else {
1835 errno = EOVERFLOW;
1836 return NULL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001837 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001838 tmp->tm_yday = idays;
1839 /*
1840 ** The "extra" mods below avoid overflow problems.
1841 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001842 tmp->tm_wday = (TM_WDAY_BASE
1843 + ((tmp->tm_year % DAYSPERWEEK)
1844 * (DAYSPERNYEAR % DAYSPERWEEK))
1845 + leaps_thru_end_of(y - 1)
1846 - leaps_thru_end_of(TM_YEAR_BASE - 1)
1847 + idays);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001848 tmp->tm_wday %= DAYSPERWEEK;
1849 if (tmp->tm_wday < 0)
1850 tmp->tm_wday += DAYSPERWEEK;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001851 tmp->tm_hour = rem / SECSPERHOUR;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001852 rem %= SECSPERHOUR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001853 tmp->tm_min = rem / SECSPERMIN;
1854 tmp->tm_sec = rem % SECSPERMIN;
1855
1856 /* Use "... ??:??:60" at the end of the localtime minute containing
1857 the second just before the positive leap second. */
1858 tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
1859
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001860 ip = mon_lengths[isleap(y)];
1861 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1862 idays -= ip[tmp->tm_mon];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001863 tmp->tm_mday = idays + 1;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001864 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001865#ifdef TM_GMTOFF
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001866 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001867#endif /* defined TM_GMTOFF */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001868 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001869}
1870
1871char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001872ctime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001873{
1874/*
1875** Section 4.12.3.2 of X3.159-1989 requires that
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001876** The ctime function converts the calendar time pointed to by timer
1877** to local time in the form of a string. It is equivalent to
1878** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001879*/
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001880 struct tm *tmp = localtime(timep);
1881 return tmp ? asctime(tmp) : NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001882}
1883
1884char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001885ctime_r(const time_t *timep, char *buf)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001886{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001887 struct tm mytm;
1888 struct tm *tmp = localtime_r(timep, &mytm);
1889 return tmp ? asctime_r(tmp, buf) : NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001890}
1891
1892/*
1893** Adapted from code provided by Robert Elz, who writes:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001894** The "best" way to do mktime I think is based on an idea of Bob
1895** Kridle's (so its said...) from a long time ago.
1896** It does a binary search of the time_t space. Since time_t's are
1897** just 32 bits, its a max of 32 iterations (even at 64 bits it
1898** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001899*/
1900
1901#ifndef WRONG
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001902#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001903#endif /* !defined WRONG */
1904
1905/*
Elliott Hughesce4783c2013-07-12 17:31:11 -07001906** Normalize logic courtesy Paul Eggert.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001907*/
1908
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001909static bool
1910increment_overflow(int *ip, int j)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001911{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001912 register int const i = *ip;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001913
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001914 /*
1915 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1916 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1917 ** If i < 0 there can only be overflow if i + j < INT_MIN
1918 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1919 */
1920 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1921 return true;
1922 *ip += j;
1923 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001924}
1925
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001926static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001927increment_overflow32(int_fast32_t *const lp, int const m)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001928{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001929 register int_fast32_t const l = *lp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001930
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001931 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
1932 return true;
1933 *lp += m;
1934 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001935}
1936
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001937static bool
Calin Juravle627d37c2014-02-28 11:46:03 +00001938increment_overflow_time(time_t *tp, int_fast32_t j)
1939{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001940 /*
1941 ** This is like
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001942 ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001943 ** except that it does the right thing even if *tp + j would overflow.
1944 */
1945 if (! (j < 0
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001946 ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
1947 : *tp <= TIME_T_MAX - j))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001948 return true;
1949 *tp += j;
1950 return false;
Calin Juravle627d37c2014-02-28 11:46:03 +00001951}
1952
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001953static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001954normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001955{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001956 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001957
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001958 tensdelta = (*unitsptr >= 0) ?
1959 (*unitsptr / base) :
1960 (-1 - (-1 - *unitsptr) / base);
1961 *unitsptr -= tensdelta * base;
1962 return increment_overflow(tensptr, tensdelta);
1963}
1964
1965static bool
1966normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
1967{
1968 register int tensdelta;
1969
1970 tensdelta = (*unitsptr >= 0) ?
1971 (*unitsptr / base) :
1972 (-1 - (-1 - *unitsptr) / base);
1973 *unitsptr -= tensdelta * base;
1974 return increment_overflow32(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001975}
1976
1977static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001978tmcomp(register const struct tm *const atmp,
1979 register const struct tm *const btmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001980{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001981 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001982
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001983 if (atmp->tm_year != btmp->tm_year)
1984 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1985 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1986 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1987 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1988 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1989 result = atmp->tm_sec - btmp->tm_sec;
1990 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001991}
1992
1993static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001994time2sub(struct tm *const tmp,
1995 struct tm *(*funcp)(struct state const *, time_t const *,
1996 int_fast32_t, struct tm *),
1997 struct state const *sp,
1998 const int_fast32_t offset,
1999 bool *okayp,
2000 bool do_norm_secs)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002001{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002002 register int dir;
2003 register int i, j;
2004 register int saved_seconds;
2005 register int_fast32_t li;
2006 register time_t lo;
2007 register time_t hi;
2008 int_fast32_t y;
2009 time_t newt;
2010 time_t t;
2011 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002012
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002013 *okayp = false;
2014 yourtm = *tmp;
2015 if (do_norm_secs) {
2016 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2017 SECSPERMIN))
2018 return WRONG;
2019 }
2020 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2021 return WRONG;
2022 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2023 return WRONG;
2024 y = yourtm.tm_year;
2025 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
2026 return WRONG;
2027 /*
2028 ** Turn y into an actual year number for now.
2029 ** It is converted back to an offset from TM_YEAR_BASE later.
2030 */
2031 if (increment_overflow32(&y, TM_YEAR_BASE))
2032 return WRONG;
2033 while (yourtm.tm_mday <= 0) {
2034 if (increment_overflow32(&y, -1))
2035 return WRONG;
2036 li = y + (1 < yourtm.tm_mon);
2037 yourtm.tm_mday += year_lengths[isleap(li)];
2038 }
2039 while (yourtm.tm_mday > DAYSPERLYEAR) {
2040 li = y + (1 < yourtm.tm_mon);
2041 yourtm.tm_mday -= year_lengths[isleap(li)];
2042 if (increment_overflow32(&y, 1))
2043 return WRONG;
2044 }
2045 for ( ; ; ) {
2046 i = mon_lengths[isleap(y)][yourtm.tm_mon];
2047 if (yourtm.tm_mday <= i)
2048 break;
2049 yourtm.tm_mday -= i;
2050 if (++yourtm.tm_mon >= MONSPERYEAR) {
2051 yourtm.tm_mon = 0;
2052 if (increment_overflow32(&y, 1))
2053 return WRONG;
2054 }
2055 }
2056 if (increment_overflow32(&y, -TM_YEAR_BASE))
2057 return WRONG;
2058 if (! (INT_MIN <= y && y <= INT_MAX))
2059 return WRONG;
2060 yourtm.tm_year = y;
2061 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2062 saved_seconds = 0;
2063 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
2064 /*
2065 ** We can't set tm_sec to 0, because that might push the
2066 ** time below the minimum representable time.
2067 ** Set tm_sec to 59 instead.
2068 ** This assumes that the minimum representable time is
2069 ** not in the same minute that a leap second was deleted from,
2070 ** which is a safer assumption than using 58 would be.
2071 */
2072 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2073 return WRONG;
2074 saved_seconds = yourtm.tm_sec;
2075 yourtm.tm_sec = SECSPERMIN - 1;
2076 } else {
2077 saved_seconds = yourtm.tm_sec;
2078 yourtm.tm_sec = 0;
2079 }
2080 /*
2081 ** Do a binary search (this works whatever time_t's type is).
2082 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002083 lo = TIME_T_MIN;
2084 hi = TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002085 for ( ; ; ) {
2086 t = lo / 2 + hi / 2;
2087 if (t < lo)
2088 t = lo;
2089 else if (t > hi)
2090 t = hi;
2091 if (! funcp(sp, &t, offset, &mytm)) {
2092 /*
2093 ** Assume that t is too extreme to be represented in
2094 ** a struct tm; arrange things so that it is less
2095 ** extreme on the next pass.
2096 */
2097 dir = (t > 0) ? 1 : -1;
2098 } else dir = tmcomp(&mytm, &yourtm);
2099 if (dir != 0) {
2100 if (t == lo) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002101 if (t == TIME_T_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002102 return WRONG;
2103 ++t;
2104 ++lo;
2105 } else if (t == hi) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002106 if (t == TIME_T_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002107 return WRONG;
2108 --t;
2109 --hi;
2110 }
2111 if (lo > hi)
2112 return WRONG;
2113 if (dir > 0)
2114 hi = t;
2115 else lo = t;
2116 continue;
2117 }
2118#if defined TM_GMTOFF && ! UNINIT_TRAP
2119 if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
2120 && (yourtm.TM_GMTOFF < 0
2121 ? (-SECSPERDAY <= yourtm.TM_GMTOFF
2122 && (mytm.TM_GMTOFF <=
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002123 (SMALLEST(INT_FAST32_MAX, LONG_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002124 + yourtm.TM_GMTOFF)))
2125 : (yourtm.TM_GMTOFF <= SECSPERDAY
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002126 && ((BIGGEST(INT_FAST32_MIN, LONG_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002127 + yourtm.TM_GMTOFF)
2128 <= mytm.TM_GMTOFF)))) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002129 /* MYTM matches YOURTM except with the wrong UT offset.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002130 YOURTM.TM_GMTOFF is plausible, so try it instead.
2131 It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2132 since the guess gets checked. */
2133 time_t altt = t;
2134 int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2135 if (!increment_overflow_time(&altt, diff)) {
2136 struct tm alttm;
2137 if (funcp(sp, &altt, offset, &alttm)
2138 && alttm.tm_isdst == mytm.tm_isdst
2139 && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2140 && tmcomp(&alttm, &yourtm) == 0) {
2141 t = altt;
2142 mytm = alttm;
2143 }
2144 }
2145 }
2146#endif
2147 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2148 break;
2149 /*
2150 ** Right time, wrong type.
2151 ** Hunt for right time, right type.
2152 ** It's okay to guess wrong since the guess
2153 ** gets checked.
2154 */
2155 if (sp == NULL)
2156 return WRONG;
2157 for (i = sp->typecnt - 1; i >= 0; --i) {
2158 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2159 continue;
2160 for (j = sp->typecnt - 1; j >= 0; --j) {
2161 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2162 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002163 if (ttunspecified(sp, j))
2164 continue;
2165 newt = (t + sp->ttis[j].tt_utoff
2166 - sp->ttis[i].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002167 if (! funcp(sp, &newt, offset, &mytm))
2168 continue;
2169 if (tmcomp(&mytm, &yourtm) != 0)
2170 continue;
2171 if (mytm.tm_isdst != yourtm.tm_isdst)
2172 continue;
2173 /*
2174 ** We have a match.
2175 */
2176 t = newt;
2177 goto label;
2178 }
2179 }
2180 return WRONG;
2181 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002182label:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002183 newt = t + saved_seconds;
2184 if ((newt < t) != (saved_seconds < 0))
2185 return WRONG;
2186 t = newt;
2187 if (funcp(sp, &t, offset, tmp))
2188 *okayp = true;
2189 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002190}
2191
2192static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002193time2(struct tm * const tmp,
2194 struct tm *(*funcp)(struct state const *, time_t const *,
2195 int_fast32_t, struct tm *),
2196 struct state const *sp,
Elliott Hughesce4783c2013-07-12 17:31:11 -07002197 const int_fast32_t offset,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002198 bool *okayp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002199{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002200 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002201
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002202 /*
2203 ** First try without normalization of seconds
2204 ** (in case tm_sec contains a value associated with a leap second).
2205 ** If that fails, try with normalization of seconds.
2206 */
2207 t = time2sub(tmp, funcp, sp, offset, okayp, false);
2208 return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002209}
2210
2211static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002212time1(struct tm *const tmp,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002213 struct tm *(*funcp)(struct state const *, time_t const *,
2214 int_fast32_t, struct tm *),
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002215 struct state const *sp,
2216 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002217{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002218 register time_t t;
2219 register int samei, otheri;
2220 register int sameind, otherind;
2221 register int i;
2222 register int nseen;
2223 char seen[TZ_MAX_TYPES];
2224 unsigned char types[TZ_MAX_TYPES];
2225 bool okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002226
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002227 if (tmp == NULL) {
2228 errno = EINVAL;
2229 return WRONG;
2230 }
2231 if (tmp->tm_isdst > 1)
2232 tmp->tm_isdst = 1;
2233 t = time2(tmp, funcp, sp, offset, &okay);
2234 if (okay)
2235 return t;
2236 if (tmp->tm_isdst < 0)
Elliott Hughes906eb992014-06-18 19:46:25 -07002237#ifdef PCTS
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002238 /*
2239 ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2240 */
2241 tmp->tm_isdst = 0; /* reset to std and try again */
Elliott Hughes906eb992014-06-18 19:46:25 -07002242#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002243 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002244#endif /* !defined PCTS */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002245 /*
2246 ** We're supposed to assume that somebody took a time of one type
2247 ** and did some math on it that yielded a "struct tm" that's bad.
2248 ** We try to divine the type they started from and adjust to the
2249 ** type they need.
2250 */
2251 if (sp == NULL)
2252 return WRONG;
2253 for (i = 0; i < sp->typecnt; ++i)
2254 seen[i] = false;
2255 nseen = 0;
2256 for (i = sp->timecnt - 1; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002257 if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002258 seen[sp->types[i]] = true;
2259 types[nseen++] = sp->types[i];
2260 }
2261 for (sameind = 0; sameind < nseen; ++sameind) {
2262 samei = types[sameind];
2263 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2264 continue;
2265 for (otherind = 0; otherind < nseen; ++otherind) {
2266 otheri = types[otherind];
2267 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2268 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002269 tmp->tm_sec += (sp->ttis[otheri].tt_utoff
2270 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002271 tmp->tm_isdst = !tmp->tm_isdst;
2272 t = time2(tmp, funcp, sp, offset, &okay);
2273 if (okay)
2274 return t;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002275 tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
2276 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002277 tmp->tm_isdst = !tmp->tm_isdst;
2278 }
2279 }
2280 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002281}
2282
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002283static time_t
2284mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2285{
2286 if (sp)
2287 return time1(tmp, localsub, sp, setname);
2288 else {
2289 gmtcheck();
2290 return time1(tmp, gmtsub, gmtptr, 0);
2291 }
2292}
2293
2294#if NETBSD_INSPIRED
2295
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002296time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002297mktime_z(struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002298{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002299 return mktime_tzname(sp, tmp, false);
2300}
2301
2302#endif
2303
2304time_t
2305mktime(struct tm *tmp)
2306{
Elliott Hughesa9209d72016-09-16 18:16:47 -07002307#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002308 int saved_errno = errno;
2309#endif
2310
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002311 time_t t;
2312 int err = lock();
2313 if (err) {
2314 errno = err;
2315 return -1;
2316 }
2317 tzset_unlocked();
2318 t = mktime_tzname(lclptr, tmp, true);
2319 unlock();
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002320
Elliott Hughesa9209d72016-09-16 18:16:47 -07002321#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002322 errno = (t == -1) ? EOVERFLOW : saved_errno;
2323#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002324 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002325}
2326
2327#ifdef STD_INSPIRED
2328
2329time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002330timelocal(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002331{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002332 if (tmp != NULL)
2333 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2334 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002335}
2336
2337time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002338timegm(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002339{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002340 return timeoff(tmp, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002341}
2342
Elliott Hughes906eb992014-06-18 19:46:25 -07002343time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002344timeoff(struct tm *tmp, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07002345{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002346 if (tmp)
2347 tmp->tm_isdst = 0;
2348 gmtcheck();
2349 return time1(tmp, gmtsub, gmtptr, offset);
Elliott Hughes906eb992014-06-18 19:46:25 -07002350}
2351
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002352#endif /* defined STD_INSPIRED */
2353
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002354static int_fast32_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002355leapcorr(struct state const *sp, time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002356{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002357 register struct lsinfo const * lp;
2358 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002359
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002360 i = sp->leapcnt;
2361 while (--i >= 0) {
2362 lp = &sp->lsis[i];
2363 if (t >= lp->ls_trans)
2364 return lp->ls_corr;
2365 }
2366 return 0;
2367}
2368
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002369/*
2370** XXX--is the below the right way to conditionalize??
2371*/
2372
2373#ifdef STD_INSPIRED
2374
2375/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
2376 NETBSD_INSPIRED is defined, and are private otherwise. */
2377# if NETBSD_INSPIRED
2378# define NETBSD_INSPIRED_EXTERN
2379# else
2380# define NETBSD_INSPIRED_EXTERN static
2381# endif
2382
2383/*
2384** IEEE Std 1003.1 (POSIX) says that 536457599
2385** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2386** is not the case if we are accounting for leap seconds.
2387** So, we provide the following conversion routines for use
2388** when exchanging timestamps with POSIX conforming systems.
2389*/
2390
2391NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002392time2posix_z(struct state *sp, time_t t)
2393{
2394 return t - leapcorr(sp, t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002395}
2396
2397time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002398time2posix(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002399{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002400 int err = lock();
2401 if (err) {
2402 errno = err;
2403 return -1;
2404 }
2405 if (!lcl_is_set)
2406 tzset_unlocked();
2407 if (lclptr)
2408 t = time2posix_z(lclptr, t);
2409 unlock();
2410 return t;
2411}
2412
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002413NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002414posix2time_z(struct state *sp, time_t t)
2415{
2416 time_t x;
2417 time_t y;
2418 /*
2419 ** For a positive leap second hit, the result
2420 ** is not unique. For a negative leap second
2421 ** hit, the corresponding time doesn't exist,
2422 ** so we return an adjacent second.
2423 */
2424 x = t + leapcorr(sp, t);
2425 y = x - leapcorr(sp, x);
2426 if (y < t) {
2427 do {
2428 x++;
2429 y = x - leapcorr(sp, x);
2430 } while (y < t);
2431 x -= y != t;
2432 } else if (y > t) {
2433 do {
2434 --x;
2435 y = x - leapcorr(sp, x);
2436 } while (y > t);
2437 x += y != t;
2438 }
2439 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002440}
2441
2442time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002443posix2time(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002444{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002445 int err = lock();
2446 if (err) {
2447 errno = err;
2448 return -1;
2449 }
2450 if (!lcl_is_set)
2451 tzset_unlocked();
2452 if (lclptr)
2453 t = posix2time_z(lclptr, t);
2454 unlock();
2455 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002456}
2457
2458#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002459
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002460#if TZ_TIME_T
2461
2462# if !USG_COMPAT
2463# define daylight 0
2464# define timezone 0
2465# endif
2466# if !ALTZONE
2467# define altzone 0
2468# endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002469
2470/* Convert from the underlying system's time_t to the ersatz time_tz,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002471 which is called 'time_t' in this file. Typically, this merely
2472 converts the time's integer width. On some platforms, the system
2473 time is local time not UT, or uses some epoch other than the POSIX
2474 epoch.
2475
2476 Although this code appears to define a function named 'time' that
2477 returns time_t, the macros in private.h cause this code to actually
2478 define a function named 'tz_time' that returns tz_time_t. The call
2479 to sys_time invokes the underlying system's 'time' function. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002480
2481time_t
2482time(time_t *p)
2483{
2484 time_t r = sys_time(0);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002485 if (r != (time_t) -1) {
2486 int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
2487 if (increment_overflow32(&offset, -EPOCH_OFFSET)
2488 || increment_overflow_time(&r, offset)) {
2489 errno = EOVERFLOW;
2490 r = -1;
2491 }
2492 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002493 if (p)
2494 *p = r;
2495 return r;
2496}
2497
2498#endif