blob: 5e1181fe879bcf8d38e9b3ffabcf084fbbcdc063 [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_CHAR_SET
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010032# define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070033 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#endif /* !defined TZ_ABBR_CHAR_SET */
35
36#ifndef TZ_ABBR_ERR_CHAR
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010037# define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#endif /* !defined TZ_ABBR_ERR_CHAR */
39
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040/*
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010041+** Support non-POSIX platforms that distinguish between text and binary files.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080042*/
43
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#ifndef O_BINARY
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010045# define O_BINARY 0
46#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048#ifndef WILDABBR
49/*
50** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070051** 1. They might reference tzname[0] before calling tzset (explicitly
52** or implicitly).
53** 2. They might reference tzname[1] before calling tzset (explicitly
54** or implicitly).
55** 3. They might reference tzname[1] after setting to a time zone
56** in which Daylight Saving Time is never observed.
57** 4. They might reference tzname[0] after setting to a time zone
58** in which Standard Time is never observed.
59** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060** What's best to do in the above cases is open to debate;
61** for now, we just set things up so that in any of the five cases
62** WILDABBR is used. Another possibility: initialize tzname[0] to the
63** string "tzname[0] used before set", and similarly for the other cases.
64** And another: initialize tzname[0] to "ERA", with an explanation in the
65** manual page of what this "time zone abbreviation" means (doing this so
66** that tzname[0] has the "normal" length of three characters).
67*/
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010068# define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080069#endif /* !defined WILDABBR */
70
Elliott Hughes906eb992014-06-18 19:46:25 -070071static const char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010073static char const etc_utc[] = "Etc/UTC";
74static char const *utc = etc_utc + sizeof "Etc/" - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075
76/*
77** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000078** Default to US rules as of 2017-05-07.
79** POSIX does not specify the default DST rules;
80** for historical reasons, US rules are a common default.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081*/
82#ifndef TZDEFRULESTRING
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010083# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000084#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080085
Calin Juravled8928922014-02-28 12:18:53 +000086struct ttinfo { /* time type information */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000087 int_fast32_t tt_utoff; /* UT offset in seconds */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070088 bool tt_isdst; /* used to set tm_isdst */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000089 int tt_desigidx; /* abbreviation list index */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070090 bool tt_ttisstd; /* transition is std time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000091 bool tt_ttisut; /* transition is UT */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080092};
93
Calin Juravled8928922014-02-28 12:18:53 +000094struct lsinfo { /* leap second information */
Elliott Hughesce4783c2013-07-12 17:31:11 -070095 time_t ls_trans; /* transition time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000096 int_fast32_t ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080097};
98
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000099/* This abbreviation means local time is unspecified. */
100static char const UNSPEC[] = "-00";
101
102/* How many extra bytes are needed at the end of struct state's chars array.
103 This needs to be at least 1 for null termination in case the input
104 data isn't properly terminated, and it also needs to be big enough
105 for ttunspecified to work without crashing. */
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100106enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000107
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100108/* Limit to time zone abbreviation length in POSIX-style TZ strings.
109 This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
110#ifndef TZNAME_MAXIMUM
111# define TZNAME_MAXIMUM 255
112#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113
114struct state {
Calin Juravled8928922014-02-28 12:18:53 +0000115 int leapcnt;
116 int timecnt;
117 int typecnt;
118 int charcnt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700119 bool goback;
120 bool goahead;
Calin Juravled8928922014-02-28 12:18:53 +0000121 time_t ats[TZ_MAX_TIMES];
122 unsigned char types[TZ_MAX_TIMES];
123 struct ttinfo ttis[TZ_MAX_TYPES];
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100124 char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
125 2 * (TZNAME_MAXIMUM + 1))];
Calin Juravled8928922014-02-28 12:18:53 +0000126 struct lsinfo lsis[TZ_MAX_LEAPS];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000127 /* The time type to use for early times or if no transitions.
128 It is always zero for recent tzdb releases.
129 It might be nonzero for data from tzdb 2018e or earlier. */
130 int defaulttype;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800131};
132
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700133enum r_type {
134 JULIAN_DAY, /* Jn = Julian day */
135 DAY_OF_YEAR, /* n = day of year */
136 MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */
137};
138
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139struct rule {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700140 enum r_type r_type; /* type of rule */
Calin Juravled8928922014-02-28 12:18:53 +0000141 int r_day; /* day number of rule */
142 int r_week; /* week number of rule */
143 int r_mon; /* month number of rule */
144 int_fast32_t r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800145};
146
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700147static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
148 struct tm *);
149static bool increment_overflow(int *, int);
150static bool increment_overflow_time(time_t *, int_fast32_t);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000151static int_fast32_t leapcorr(struct state const *, time_t);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700152static bool normalize_overflow32(int_fast32_t *, int *, int);
153static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
154 struct tm *);
155static bool typesequiv(struct state const *, int, int);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000156static bool tzparse(char const *, struct state *, struct state *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157
158#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000159static struct state * lclptr;
160static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800161#endif /* defined ALL_STATE */
162
163#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700164static struct state lclmem;
165static struct state gmtmem;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100166static struct state *const lclptr = &lclmem;
167static struct state *const gmtptr = &gmtmem;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168#endif /* State Farm */
169
170#ifndef TZ_STRLEN_MAX
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100171# define TZ_STRLEN_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172#endif /* !defined TZ_STRLEN_MAX */
173
Calin Juravled8928922014-02-28 12:18:53 +0000174static char lcl_TZname[TZ_STRLEN_MAX + 1];
175static int lcl_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800176
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800177/*
178** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700179** Except for the strftime function, these functions [asctime,
180** ctime, gmtime, localtime] return values in one of two static
181** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800182** Thanks to Paul Eggert for noting this.
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100183**
184** This requirement was removed in C99, so support it only if requested,
185** as support is more likely to lead to bugs in badly written programs.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186*/
187
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100188#if SUPPORT_C89
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700189static struct tm tm;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100190#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000192#if 2 <= HAVE_TZNAME + TZ_TIME_T
Elliott Hughes0a610d02016-07-29 14:04:17 -0700193char * tzname[2] = {
194 (char *) wildabbr,
195 (char *) wildabbr
196};
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000197#endif
198#if 2 <= USG_COMPAT + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700199long timezone;
200int daylight;
Elliott Hughes0a610d02016-07-29 14:04:17 -0700201#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800202
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000203#if 2 <= ALTZONE + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700204long altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000205#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000207/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700208static void
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000209init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700210{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000211 s->tt_utoff = utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700212 s->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000213 s->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700214 s->tt_ttisstd = false;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000215 s->tt_ttisut = false;
216}
217
218/* Return true if SP's time type I does not specify local time. */
219static bool
220ttunspecified(struct state const *sp, int i)
221{
222 char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
223 /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */
224 return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700225}
226
Elliott Hughesce4783c2013-07-12 17:31:11 -0700227static int_fast32_t
228detzcode(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800229{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700230 register int_fast32_t result;
231 register int i;
232 int_fast32_t one = 1;
233 int_fast32_t halfmaxval = one << (32 - 2);
234 int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
235 int_fast32_t minval = -1 - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800236
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700237 result = codep[0] & 0x7f;
238 for (i = 1; i < 4; ++i)
239 result = (result << 8) | (codep[i] & 0xff);
240
241 if (codep[0] & 0x80) {
242 /* Do two's-complement negation even on non-two's-complement machines.
243 If the result would be minval - 1, return minval. */
244 result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
245 result += minval;
246 }
247 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248}
249
Calin Juravle627d37c2014-02-28 11:46:03 +0000250static int_fast64_t
Elliott Hughesce4783c2013-07-12 17:31:11 -0700251detzcode64(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000253 register int_fast64_t result;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700254 register int i;
255 int_fast64_t one = 1;
256 int_fast64_t halfmaxval = one << (64 - 2);
257 int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
258 int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700260 result = codep[0] & 0x7f;
261 for (i = 1; i < 8; ++i)
262 result = (result << 8) | (codep[i] & 0xff);
263
264 if (codep[0] & 0x80) {
265 /* Do two's-complement negation even on non-two's-complement machines.
266 If the result would be minval - 1, return minval. */
267 result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
268 result += minval;
269 }
270 return result;
271}
272
273static void
274update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
275{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000276#if HAVE_TZNAME
277 tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
278#endif
279#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700280 if (!ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000281 timezone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700282#endif
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000283#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700284 if (ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000285 altzone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700286#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287}
288
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000289/* If STDDST_MASK indicates that SP's TYPE provides useful info,
290 update tzname, timezone, and/or altzone and return STDDST_MASK,
291 diminished by the provided info if it is a specified local time.
292 Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */
293static int
294may_update_tzname_etc(int stddst_mask, struct state *sp, int type)
295{
296 struct ttinfo *ttisp = &sp->ttis[type];
297 int this_bit = 1 << ttisp->tt_isdst;
298 if (stddst_mask & this_bit) {
299 update_tzname_etc(sp, ttisp);
300 if (!ttunspecified(sp, type))
301 return stddst_mask & ~this_bit;
302 }
303 return stddst_mask;
304}
305
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800306static void
Elliott Hughesce4783c2013-07-12 17:31:11 -0700307settzname(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800308{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700309 register struct state * const sp = lclptr;
310 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800311
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000312 /* If STDDST_MASK & 1 we need info about a standard time.
313 If STDDST_MASK & 2 we need info about a daylight saving time.
314 When STDDST_MASK becomes zero we can stop looking. */
315 int stddst_mask = 0;
316
317#if HAVE_TZNAME
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100318 tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000319 stddst_mask = 3;
320#endif
321#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700322 timezone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000323 stddst_mask = 3;
324#endif
325#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700326 altzone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000327 stddst_mask |= 2;
328#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700329 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000330 ** And to get the latest time zone abbreviations into tzname. . .
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700331 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000332 if (sp) {
333 for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
334 stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
335 for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
336 stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700337 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000338#if USG_COMPAT
339 daylight = stddst_mask >> 1 ^ 1;
340#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800341}
342
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100343/* Replace bogus characters in time zone abbreviations.
344 Return 0 on success, an errno value if a time zone abbreviation is
345 too long. */
346static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700347scrub_abbrs(struct state *sp)
348{
349 int i;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100350
351 /* Reject overlong abbreviations. */
352 for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
353 int len = strlen(&sp->chars[i]);
354 if (TZNAME_MAXIMUM < len)
355 return EOVERFLOW;
356 i += len + 1;
357 }
358
359 /* Replace bogus characters. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700360 for (i = 0; i < sp->charcnt; ++i)
361 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
362 sp->chars[i] = TZ_ABBR_ERR_CHAR;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700363
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100364 return 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700365}
366
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700367/* Input buffer for data read from a compiled tz file. */
368union input_buffer {
369 /* The first part of the buffer, interpreted as a header. */
370 struct tzhead tzhead;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800371
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700372 /* The entire buffer. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000373 char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
374 + 4 * TZ_MAX_TIMES];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800375};
376
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000377// Android-removed: There is no directory with file-per-time zone on Android.
378#ifndef __BIONIC__
379/* TZDIR with a trailing '/' rather than a trailing '\0'. */
380static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
381#endif
382
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700383/* Local storage needed for 'tzloadbody'. */
384union local_storage {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700385 /* The results of analyzing the file's contents after it is opened. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000386 struct file_analysis {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700387 /* The input buffer. */
388 union input_buffer u;
389
390 /* A temporary state used for parsing a TZ string in the file. */
391 struct state st;
392 } u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000393
394 // Android-removed: There is no directory with file-per-time zone on Android.
395 #ifndef __BIONIC__
396 /* The file name to be opened. */
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100397 char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000398 #endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700399};
400
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700401/* Load tz data from the file named NAME into *SP. Read extended
402 format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
403 success, an errno value on failure. */
404static int
405tzloadbody(char const *name, struct state *sp, bool doextend,
406 union local_storage *lsp)
407{
408 register int i;
409 register int fid;
410 register int stored;
411 register ssize_t nread;
Elliott Hughesa9209d72016-09-16 18:16:47 -0700412#if !defined(__BIONIC__)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700413 register bool doaccess;
414 register char *fullname = lsp->fullname;
415#endif
416 register union input_buffer *up = &lsp->u.u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000417 register int tzheadsize = sizeof(struct tzhead);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700418
419 sp->goback = sp->goahead = false;
420
421 if (! name) {
422 name = TZDEFAULT;
423 if (! name)
424 return EINVAL;
425 }
426
Elliott Hughesa9209d72016-09-16 18:16:47 -0700427#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -0700428 extern int __bionic_open_tzdata(const char*, int32_t*);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700429 int32_t entry_length;
430 fid = __bionic_open_tzdata(name, &entry_length);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700431#else
432 if (name[0] == ':')
433 ++name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000434#ifdef SUPPRESS_TZDIR
435 /* Do not prepend TZDIR. This is intended for specialized
436 applications only, due to its security implications. */
437 doaccess = true;
438#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700439 doaccess = name[0] == '/';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000440#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700441 if (!doaccess) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000442 char const *dot;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100443 if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700444 return ENAMETOOLONG;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000445
446 /* Create a string "TZDIR/NAME". Using sprintf here
447 would pull in stdio (and would fail if the
448 resulting string length exceeded INT_MAX!). */
449 memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
450 strcpy(lsp->fullname + sizeof tzdirslash, name);
451
452 /* Set doaccess if NAME contains a ".." file name
453 component, as such a name could read a file outside
454 the TZDIR virtual subtree. */
455 for (dot = name; (dot = strchr(dot, '.')); dot++)
456 if ((dot == name || dot[-1] == '/') && dot[1] == '.'
457 && (dot[2] == '/' || !dot[2])) {
458 doaccess = true;
459 break;
460 }
461
462 name = lsp->fullname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700463 }
464 if (doaccess && access(name, R_OK) != 0)
465 return errno;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100466 fid = open(name, O_RDONLY | O_BINARY);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700467#endif
468 if (fid < 0)
469 return errno;
470
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700471#if defined(__BIONIC__)
Elliott Hughes4edd6512016-10-03 16:46:33 -0700472 nread = TEMP_FAILURE_RETRY(read(fid, up->buf, entry_length));
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700473#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700474 nread = read(fid, up->buf, sizeof up->buf);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700475#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700476 if (nread < tzheadsize) {
477 int err = nread < 0 ? errno : EINVAL;
478 close(fid);
479 return err;
480 }
481 if (close(fid) < 0)
482 return errno;
483 for (stored = 4; stored <= 8; stored *= 2) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000484 char version = up->tzhead.tzh_version[0];
485 bool skip_datablock = stored == 4 && version;
486 int_fast32_t datablock_size;
487 int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
488 int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
489 int_fast64_t prevtr = -1;
490 int_fast32_t prevcorr;
491 int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
492 int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
493 int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
494 int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
495 char const *p = up->buf + tzheadsize;
496 /* Although tzfile(5) currently requires typecnt to be nonzero,
497 support future formats that may allow zero typecnt
498 in files that have a TZ string and no transitions. */
499 if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
500 && 0 <= typecnt && typecnt < TZ_MAX_TYPES
501 && 0 <= timecnt && timecnt < TZ_MAX_TIMES
502 && 0 <= charcnt && charcnt < TZ_MAX_CHARS
503 && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
504 && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
505 return EINVAL;
506 datablock_size
507 = (timecnt * stored /* ats */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700508 + timecnt /* types */
509 + typecnt * 6 /* ttinfos */
510 + charcnt /* chars */
511 + leapcnt * (stored + 4) /* lsinfos */
512 + ttisstdcnt /* ttisstds */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000513 + ttisutcnt); /* ttisuts */
514 if (nread < tzheadsize + datablock_size)
515 return EINVAL;
516 if (skip_datablock)
517 p += datablock_size;
518 else {
519 if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
520 && (ttisutcnt == typecnt || ttisutcnt == 0)))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700521 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000522
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700523 sp->leapcnt = leapcnt;
524 sp->timecnt = timecnt;
525 sp->typecnt = typecnt;
526 sp->charcnt = charcnt;
527
528 /* Read transitions, discarding those out of time_t range.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000529 But pretend the last transition before TIME_T_MIN
530 occurred at TIME_T_MIN. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700531 timecnt = 0;
532 for (i = 0; i < sp->timecnt; ++i) {
533 int_fast64_t at
534 = stored == 4 ? detzcode(p) : detzcode64(p);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000535 sp->types[i] = at <= TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700536 if (sp->types[i]) {
537 time_t attime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000538 = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
539 ? TIME_T_MIN : at);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700540 if (timecnt && attime <= sp->ats[timecnt - 1]) {
541 if (attime < sp->ats[timecnt - 1])
542 return EINVAL;
543 sp->types[i - 1] = 0;
544 timecnt--;
545 }
546 sp->ats[timecnt++] = attime;
547 }
548 p += stored;
549 }
550
551 timecnt = 0;
552 for (i = 0; i < sp->timecnt; ++i) {
553 unsigned char typ = *p++;
554 if (sp->typecnt <= typ)
555 return EINVAL;
556 if (sp->types[i])
557 sp->types[timecnt++] = typ;
558 }
559 sp->timecnt = timecnt;
560 for (i = 0; i < sp->typecnt; ++i) {
561 register struct ttinfo * ttisp;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000562 unsigned char isdst, desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700563
564 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000565 ttisp->tt_utoff = detzcode(p);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700566 p += 4;
567 isdst = *p++;
568 if (! (isdst < 2))
569 return EINVAL;
570 ttisp->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000571 desigidx = *p++;
572 if (! (desigidx < sp->charcnt))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700573 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000574 ttisp->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700575 }
576 for (i = 0; i < sp->charcnt; ++i)
577 sp->chars[i] = *p++;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000578 /* Ensure '\0'-terminated, and make it safe to call
579 ttunspecified later. */
580 memset(&sp->chars[i], 0, CHARS_EXTRA);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700581
582 /* Read leap seconds, discarding those out of time_t range. */
583 leapcnt = 0;
584 for (i = 0; i < sp->leapcnt; ++i) {
585 int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
586 int_fast32_t corr = detzcode(p + stored);
587 p += stored + 4;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000588
589 /* Leap seconds cannot occur before the Epoch,
590 or out of order. */
591 if (tr <= prevtr)
592 return EINVAL;
593
594 /* To avoid other botches in this code, each leap second's
595 correction must differ from the previous one's by 1
596 second or less, except that the first correction can be
597 any value; these requirements are more generous than
598 RFC 8536, to allow future RFC extensions. */
599 if (! (i == 0
600 || (prevcorr < corr
601 ? corr == prevcorr + 1
602 : (corr == prevcorr
603 || corr == prevcorr - 1))))
604 return EINVAL;
605 prevtr = tr;
606 prevcorr = corr;
607
608 if (tr <= TIME_T_MAX) {
609 sp->lsis[leapcnt].ls_trans = tr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700610 sp->lsis[leapcnt].ls_corr = corr;
611 leapcnt++;
612 }
613 }
614 sp->leapcnt = leapcnt;
615
616 for (i = 0; i < sp->typecnt; ++i) {
617 register struct ttinfo * ttisp;
618
619 ttisp = &sp->ttis[i];
620 if (ttisstdcnt == 0)
621 ttisp->tt_ttisstd = false;
622 else {
623 if (*p != true && *p != false)
624 return EINVAL;
625 ttisp->tt_ttisstd = *p++;
626 }
627 }
628 for (i = 0; i < sp->typecnt; ++i) {
629 register struct ttinfo * ttisp;
630
631 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000632 if (ttisutcnt == 0)
633 ttisp->tt_ttisut = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700634 else {
635 if (*p != true && *p != false)
636 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000637 ttisp->tt_ttisut = *p++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700638 }
639 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000640 }
641
642 nread -= p - up->buf;
643 memmove(up->buf, p, nread);
644
645 /* If this is an old file, we're done. */
646 if (!version)
647 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700648 }
649 if (doextend && nread > 2 &&
650 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
651 sp->typecnt + 2 <= TZ_MAX_TYPES) {
652 struct state *ts = &lsp->u.st;
653
654 up->buf[nread - 1] = '\0';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000655 if (tzparse(&up->buf[1], ts, sp)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700656
657 /* Attempt to reuse existing abbreviations.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000658 Without this, America/Anchorage would be right on
659 the edge after 2037 when TZ_MAX_CHARS is 50, as
660 sp->charcnt equals 40 (for LMT AST AWT APT AHST
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700661 AHDT YST AKDT AKST) and ts->charcnt equals 10
662 (for AKST AKDT). Reusing means sp->charcnt can
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000663 stay 40 in this example. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700664 int gotabbr = 0;
665 int charcnt = sp->charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000666 for (i = 0; i < ts->typecnt; i++) {
667 char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700668 int j;
669 for (j = 0; j < charcnt; j++)
670 if (strcmp(sp->chars + j, tsabbr) == 0) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000671 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700672 gotabbr++;
673 break;
674 }
675 if (! (j < charcnt)) {
676 int tsabbrlen = strlen(tsabbr);
677 if (j + tsabbrlen < TZ_MAX_CHARS) {
678 strcpy(sp->chars + j, tsabbr);
679 charcnt = j + tsabbrlen + 1;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000680 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700681 gotabbr++;
682 }
683 }
684 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000685 if (gotabbr == ts->typecnt) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700686 sp->charcnt = charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000687
688 /* Ignore any trailing, no-op transitions generated
689 by zic as they don't help here and can run afoul
690 of bugs in zic 2016j or earlier. */
691 while (1 < sp->timecnt
692 && (sp->types[sp->timecnt - 1]
693 == sp->types[sp->timecnt - 2]))
694 sp->timecnt--;
695
696 for (i = 0;
697 i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES;
698 i++) {
699 time_t t = ts->ats[i];
700 if (increment_overflow_time(&t, leapcorr(sp, t))
701 || (0 < sp->timecnt
702 && t <= sp->ats[sp->timecnt - 1]))
703 continue;
704 sp->ats[sp->timecnt] = t;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700705 sp->types[sp->timecnt] = (sp->typecnt
706 + ts->types[i]);
707 sp->timecnt++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700708 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000709 for (i = 0; i < ts->typecnt; i++)
710 sp->ttis[sp->typecnt++] = ts->ttis[i];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700711 }
712 }
713 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000714 if (sp->typecnt == 0)
715 return EINVAL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700716 if (sp->timecnt > 1) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000717 if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) {
718 time_t repeatat = sp->ats[0] + SECSPERREPEAT;
719 int repeattype = sp->types[0];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700720 for (i = 1; i < sp->timecnt; ++i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000721 if (sp->ats[i] == repeatat
722 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700723 sp->goback = true;
724 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000725 }
726 }
727 if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) {
728 time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT;
729 int repeattype = sp->types[sp->timecnt - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700730 for (i = sp->timecnt - 2; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000731 if (sp->ats[i] == repeatat
732 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700733 sp->goahead = true;
734 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000735 }
736 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700737 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000738
739 /* Infer sp->defaulttype from the data. Although this default
740 type is always zero for data from recent tzdb releases,
741 things are trickier for data from tzdb 2018e or earlier.
742
743 The first set of heuristics work around bugs in 32-bit data
744 generated by tzdb 2013c or earlier. The workaround is for
745 zones like Australia/Macquarie where timestamps before the
746 first transition have a time type that is not the earliest
747 standard-time type. See:
748 https://mm.icann.org/pipermail/tz/2013-May/019368.html */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700749 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000750 ** If type 0 does not specify local time, or is unused in transitions,
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700751 ** it's the type to use for early times.
752 */
753 for (i = 0; i < sp->timecnt; ++i)
754 if (sp->types[i] == 0)
755 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000756 i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700757 /*
758 ** Absent the above,
759 ** if there are transition times
760 ** and the first transition is to a daylight time
761 ** find the standard type less than and closest to
762 ** the type of the first transition.
763 */
764 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
765 i = sp->types[0];
766 while (--i >= 0)
767 if (!sp->ttis[i].tt_isdst)
768 break;
769 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000770 /* The next heuristics are for data generated by tzdb 2018e or
771 earlier, for zones like EST5EDT where the first transition
772 is to DST. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700773 /*
774 ** If no result yet, find the first standard type.
775 ** If there is none, punt to type zero.
776 */
777 if (i < 0) {
778 i = 0;
779 while (sp->ttis[i].tt_isdst)
780 if (++i >= sp->typecnt) {
781 i = 0;
782 break;
783 }
784 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000785 /* A simple 'sp->defaulttype = 0;' would suffice here if we
786 didn't have to worry about 2018e-or-earlier data. Even
787 simpler would be to remove the defaulttype member and just
788 use 0 in its place. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700789 sp->defaulttype = i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000790
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700791 return 0;
792}
793
794/* Load tz data from the file named NAME into *SP. Read extended
795 format if DOEXTEND. Return 0 on success, an errno value on failure. */
796static int
797tzload(char const *name, struct state *sp, bool doextend)
798{
799#ifdef ALL_STATE
800 union local_storage *lsp = malloc(sizeof *lsp);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000801 if (!lsp) {
802 return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
803 } else {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700804 int err = tzloadbody(name, sp, doextend, lsp);
805 free(lsp);
806 return err;
807 }
808#else
809 union local_storage ls;
810 return tzloadbody(name, sp, doextend, &ls);
811#endif
812}
813
814static bool
815typesequiv(const struct state *sp, int a, int b)
816{
817 register bool result;
818
819 if (sp == NULL ||
820 a < 0 || a >= sp->typecnt ||
821 b < 0 || b >= sp->typecnt)
822 result = false;
823 else {
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100824 /* Compare the relevant members of *AP and *BP.
825 Ignore tt_ttisstd and tt_ttisut, as they are
826 irrelevant now and counting them could cause
827 sp->goahead to mistakenly remain false. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700828 register const struct ttinfo * ap = &sp->ttis[a];
829 register const struct ttinfo * bp = &sp->ttis[b];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000830 result = (ap->tt_utoff == bp->tt_utoff
831 && ap->tt_isdst == bp->tt_isdst
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000832 && (strcmp(&sp->chars[ap->tt_desigidx],
833 &sp->chars[bp->tt_desigidx])
834 == 0));
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700835 }
836 return result;
837}
838
839static const int mon_lengths[2][MONSPERYEAR] = {
840 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
841 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
842};
843
844static const int year_lengths[2] = {
845 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800846};
847
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000848/* Is C an ASCII digit? */
849static bool
850is_digit(char c)
851{
852 return '0' <= c && c <= '9';
853}
854
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800855/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000856** Given a pointer into a timezone string, scan until a character that is not
857** a valid character in a time zone abbreviation is found.
858** Return a pointer to that character.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800859*/
860
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100861ATTRIBUTE_REPRODUCIBLE static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700862getzname(register const char *strp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800863{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700864 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800865
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700866 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
867 c != '+')
868 ++strp;
869 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800870}
871
872/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000873** Given a pointer into an extended timezone string, scan until the ending
874** delimiter of the time zone abbreviation is located.
875** Return a pointer to the delimiter.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800876**
877** As with getzname above, the legal character set is actually quite
878** restricted, with other characters producing undefined results.
879** We don't do any checking here; checking is done later in common-case code.
880*/
881
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100882ATTRIBUTE_REPRODUCIBLE static const char *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800883getqzname(register const char *strp, const int delim)
884{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700885 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800886
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700887 while ((c = *strp) != '\0' && c != delim)
888 ++strp;
889 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800890}
891
892/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000893** Given a pointer into a timezone string, extract a number from that string.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800894** Check that the number is within a specified range; if it is not, return
895** NULL.
896** Otherwise, return a pointer to the first character not part of the number.
897*/
898
899static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700900getnum(register const char *strp, int *const nump, const int min, const int max)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800901{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700902 register char c;
903 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800904
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700905 if (strp == NULL || !is_digit(c = *strp))
906 return NULL;
907 num = 0;
908 do {
909 num = num * 10 + (c - '0');
910 if (num > max)
911 return NULL; /* illegal value */
912 c = *++strp;
913 } while (is_digit(c));
914 if (num < min)
915 return NULL; /* illegal value */
916 *nump = num;
917 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800918}
919
920/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000921** Given a pointer into a timezone string, extract a number of seconds,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800922** in hh[:mm[:ss]] form, from the string.
923** If any error occurs, return NULL.
924** Otherwise, return a pointer to the first character not part of the number
925** of seconds.
926*/
927
928static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700929getsecs(register const char *strp, int_fast32_t *const secsp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800930{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700931 int num;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000932 int_fast32_t secsperhour = SECSPERHOUR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800933
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700934 /*
935 ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
936 ** "M10.4.6/26", which does not conform to Posix,
937 ** but which specifies the equivalent of
938 ** "02:00 on the first Sunday on or after 23 Oct".
939 */
940 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
941 if (strp == NULL)
942 return NULL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000943 *secsp = num * secsperhour;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700944 if (*strp == ':') {
945 ++strp;
946 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
947 if (strp == NULL)
948 return NULL;
949 *secsp += num * SECSPERMIN;
950 if (*strp == ':') {
951 ++strp;
952 /* 'SECSPERMIN' allows for leap seconds. */
953 strp = getnum(strp, &num, 0, SECSPERMIN);
954 if (strp == NULL)
955 return NULL;
956 *secsp += num;
957 }
958 }
959 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800960}
961
962/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000963** Given a pointer into a timezone string, extract an offset, in
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800964** [+-]hh[:mm[:ss]] form, from the string.
965** If any error occurs, return NULL.
966** Otherwise, return a pointer to the first character not part of the time.
967*/
968
969static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700970getoffset(register const char *strp, int_fast32_t *const offsetp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800971{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700972 register bool neg = false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800973
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700974 if (*strp == '-') {
975 neg = true;
976 ++strp;
977 } else if (*strp == '+')
978 ++strp;
979 strp = getsecs(strp, offsetp);
980 if (strp == NULL)
981 return NULL; /* illegal time */
982 if (neg)
983 *offsetp = -*offsetp;
984 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800985}
986
987/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000988** Given a pointer into a timezone string, extract a rule in the form
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800989** date[/time]. See POSIX section 8 for the format of "date" and "time".
990** If a valid rule is not found, return NULL.
991** Otherwise, return a pointer to the first character not part of the rule.
992*/
993
994static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700995getrule(const char *strp, register struct rule *const rulep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800996{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700997 if (*strp == 'J') {
998 /*
999 ** Julian day.
1000 */
1001 rulep->r_type = JULIAN_DAY;
1002 ++strp;
1003 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1004 } else if (*strp == 'M') {
1005 /*
1006 ** Month, week, day.
1007 */
1008 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
1009 ++strp;
1010 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1011 if (strp == NULL)
1012 return NULL;
1013 if (*strp++ != '.')
1014 return NULL;
1015 strp = getnum(strp, &rulep->r_week, 1, 5);
1016 if (strp == NULL)
1017 return NULL;
1018 if (*strp++ != '.')
1019 return NULL;
1020 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1021 } else if (is_digit(*strp)) {
1022 /*
1023 ** Day of year.
1024 */
1025 rulep->r_type = DAY_OF_YEAR;
1026 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1027 } else return NULL; /* invalid format */
1028 if (strp == NULL)
1029 return NULL;
1030 if (*strp == '/') {
1031 /*
1032 ** Time specified.
1033 */
1034 ++strp;
1035 strp = getoffset(strp, &rulep->r_time);
1036 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1037 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001038}
1039
1040/*
Calin Juravle627d37c2014-02-28 11:46:03 +00001041** Given a year, a rule, and the offset from UT at the time that rule takes
1042** effect, calculate the year-relative time that rule takes effect.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001043*/
1044
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001045static int_fast32_t
Calin Juravle627d37c2014-02-28 11:46:03 +00001046transtime(const int year, register const struct rule *const rulep,
Calin Juravled8928922014-02-28 12:18:53 +00001047 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001048{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001049 register bool leapyear;
Calin Juravled8928922014-02-28 12:18:53 +00001050 register int_fast32_t value;
1051 register int i;
1052 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001053
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001054 leapyear = isleap(year);
1055 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001056
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001057 case JULIAN_DAY:
1058 /*
1059 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1060 ** years.
1061 ** In non-leap years, or if the day number is 59 or less, just
1062 ** add SECSPERDAY times the day number-1 to the time of
1063 ** January 1, midnight, to get the day.
1064 */
Calin Juravled8928922014-02-28 12:18:53 +00001065 value = (rulep->r_day - 1) * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001066 if (leapyear && rulep->r_day >= 60)
1067 value += SECSPERDAY;
1068 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001069
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001070 case DAY_OF_YEAR:
1071 /*
1072 ** n - day of year.
1073 ** Just add SECSPERDAY times the day number to the time of
1074 ** January 1, midnight, to get the day.
1075 */
Calin Juravled8928922014-02-28 12:18:53 +00001076 value = rulep->r_day * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001077 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001078
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001079 case MONTH_NTH_DAY_OF_WEEK:
1080 /*
1081 ** Mm.n.d - nth "dth day" of month m.
1082 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001083
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001084 /*
1085 ** Use Zeller's Congruence to get day-of-week of first day of
1086 ** month.
1087 */
1088 m1 = (rulep->r_mon + 9) % 12 + 1;
1089 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1090 yy1 = yy0 / 100;
1091 yy2 = yy0 % 100;
1092 dow = ((26 * m1 - 2) / 10 +
1093 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1094 if (dow < 0)
1095 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001096
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001097 /*
1098 ** "dow" is the day-of-week of the first day of the month. Get
1099 ** the day-of-month (zero-origin) of the first "dow" day of the
1100 ** month.
1101 */
1102 d = rulep->r_day - dow;
1103 if (d < 0)
1104 d += DAYSPERWEEK;
1105 for (i = 1; i < rulep->r_week; ++i) {
1106 if (d + DAYSPERWEEK >=
1107 mon_lengths[leapyear][rulep->r_mon - 1])
1108 break;
1109 d += DAYSPERWEEK;
1110 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001111
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001112 /*
1113 ** "d" is the day-of-month (zero-origin) of the day we want.
1114 */
Calin Juravled8928922014-02-28 12:18:53 +00001115 value = d * SECSPERDAY;
1116 for (i = 0; i < rulep->r_mon - 1; ++i)
1117 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001118 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001119
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001120 default: unreachable();
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001121 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001122
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001123 /*
Calin Juravled8928922014-02-28 12:18:53 +00001124 ** "value" is the year-relative time of 00:00:00 UT on the day in
1125 ** question. To get the year-relative time of the specified local
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001126 ** time on that day, add the transition time and the current offset
Elliott Hughese0d0b152013-09-27 00:04:30 -07001127 ** from UT.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001128 */
1129 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001130}
1131
1132/*
1133** Given a POSIX section 8-style TZ string, fill in the rule tables as
1134** appropriate.
1135*/
1136
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001137static bool
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001138tzparse(const char *name, struct state *sp, struct state *basep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001139{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001140 const char * stdname;
1141 const char * dstname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001142 int_fast32_t stdoffset;
1143 int_fast32_t dstoffset;
1144 register char * cp;
1145 register bool load_ok;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001146 ptrdiff_t stdlen, dstlen, charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001147 time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001148
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001149 stdname = name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001150 if (*name == '<') {
1151 name++;
1152 stdname = name;
1153 name = getqzname(name, '>');
1154 if (*name != '>')
1155 return false;
1156 stdlen = name - stdname;
1157 name++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001158 } else {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001159 name = getzname(name);
1160 stdlen = name - stdname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001161 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001162 if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001163 return false;
1164 name = getoffset(name, &stdoffset);
1165 if (name == NULL)
1166 return false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001167 charcnt = stdlen + 1;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001168 if (basep) {
1169 if (0 < basep->timecnt)
1170 atlo = basep->ats[basep->timecnt - 1];
1171 load_ok = false;
1172 sp->leapcnt = basep->leapcnt;
1173 memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
1174 } else {
1175 load_ok = tzload(TZDEFRULES, sp, false) == 0;
1176 if (!load_ok)
1177 sp->leapcnt = 0; /* So, we're off a little. */
1178 }
1179 if (0 < sp->leapcnt)
1180 leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001181 if (*name != '\0') {
1182 if (*name == '<') {
1183 dstname = ++name;
1184 name = getqzname(name, '>');
1185 if (*name != '>')
1186 return false;
1187 dstlen = name - dstname;
1188 name++;
1189 } else {
1190 dstname = name;
1191 name = getzname(name);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001192 dstlen = name - dstname; /* length of DST abbr. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001193 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001194 if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001195 return false;
1196 charcnt += dstlen + 1;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001197 if (*name != '\0' && *name != ',' && *name != ';') {
1198 name = getoffset(name, &dstoffset);
1199 if (name == NULL)
1200 return false;
1201 } else dstoffset = stdoffset - SECSPERHOUR;
1202 if (*name == '\0' && !load_ok)
1203 name = TZDEFRULESTRING;
1204 if (*name == ',' || *name == ';') {
1205 struct rule start;
1206 struct rule end;
1207 register int year;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001208 register int timecnt;
1209 time_t janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001210 int_fast32_t janoffset = 0;
1211 int yearbeg, yearlim;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001212
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001213 ++name;
1214 if ((name = getrule(name, &start)) == NULL)
1215 return false;
1216 if (*name++ != ',')
1217 return false;
1218 if ((name = getrule(name, &end)) == NULL)
1219 return false;
1220 if (*name != '\0')
1221 return false;
1222 sp->typecnt = 2; /* standard time and DST */
1223 /*
1224 ** Two transitions per year, from EPOCH_YEAR forward.
1225 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001226 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1227 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001228 sp->defaulttype = 0;
1229 timecnt = 0;
1230 janfirst = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001231 yearbeg = EPOCH_YEAR;
1232
1233 do {
1234 int_fast32_t yearsecs
1235 = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
1236 yearbeg--;
1237 if (increment_overflow_time(&janfirst, -yearsecs)) {
1238 janoffset = -yearsecs;
1239 break;
1240 }
1241 } while (atlo < janfirst
1242 && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1243
1244 while (true) {
1245 int_fast32_t yearsecs
1246 = year_lengths[isleap(yearbeg)] * SECSPERDAY;
1247 int yearbeg1 = yearbeg;
1248 time_t janfirst1 = janfirst;
1249 if (increment_overflow_time(&janfirst1, yearsecs)
1250 || increment_overflow(&yearbeg1, 1)
1251 || atlo <= janfirst1)
1252 break;
1253 yearbeg = yearbeg1;
1254 janfirst = janfirst1;
1255 }
1256
1257 yearlim = yearbeg;
1258 if (increment_overflow(&yearlim, YEARSPERREPEAT + 1))
1259 yearlim = INT_MAX;
1260 for (year = yearbeg; year < yearlim; year++) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001261 int_fast32_t
1262 starttime = transtime(year, &start, stdoffset),
1263 endtime = transtime(year, &end, dstoffset);
1264 int_fast32_t
1265 yearsecs = (year_lengths[isleap(year)]
1266 * SECSPERDAY);
1267 bool reversed = endtime < starttime;
1268 if (reversed) {
1269 int_fast32_t swap = starttime;
1270 starttime = endtime;
1271 endtime = swap;
1272 }
1273 if (reversed
1274 || (starttime < endtime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001275 && endtime - starttime < yearsecs)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001276 if (TZ_MAX_TIMES - 2 < timecnt)
1277 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001278 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001279 if (! increment_overflow_time
1280 (&sp->ats[timecnt],
1281 janoffset + starttime)
1282 && atlo <= sp->ats[timecnt])
1283 sp->types[timecnt++] = !reversed;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001284 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001285 if (! increment_overflow_time
1286 (&sp->ats[timecnt],
1287 janoffset + endtime)
1288 && atlo <= sp->ats[timecnt]) {
1289 sp->types[timecnt++] = reversed;
1290 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001291 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001292 if (endtime < leaplo) {
1293 yearlim = year;
1294 if (increment_overflow(&yearlim,
1295 YEARSPERREPEAT + 1))
1296 yearlim = INT_MAX;
1297 }
1298 if (increment_overflow_time
1299 (&janfirst, janoffset + yearsecs))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001300 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001301 janoffset = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001302 }
1303 sp->timecnt = timecnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001304 if (! timecnt) {
1305 sp->ttis[0] = sp->ttis[1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001306 sp->typecnt = 1; /* Perpetual DST. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001307 } else if (YEARSPERREPEAT < year - yearbeg)
1308 sp->goback = sp->goahead = true;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001309 } else {
1310 register int_fast32_t theirstdoffset;
1311 register int_fast32_t theirdstoffset;
1312 register int_fast32_t theiroffset;
1313 register bool isdst;
1314 register int i;
1315 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001316
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001317 if (*name != '\0')
1318 return false;
1319 /*
1320 ** Initial values of theirstdoffset and theirdstoffset.
1321 */
1322 theirstdoffset = 0;
1323 for (i = 0; i < sp->timecnt; ++i) {
1324 j = sp->types[i];
1325 if (!sp->ttis[j].tt_isdst) {
1326 theirstdoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001327 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001328 break;
1329 }
1330 }
1331 theirdstoffset = 0;
1332 for (i = 0; i < sp->timecnt; ++i) {
1333 j = sp->types[i];
1334 if (sp->ttis[j].tt_isdst) {
1335 theirdstoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001336 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001337 break;
1338 }
1339 }
1340 /*
1341 ** Initially we're assumed to be in standard time.
1342 */
1343 isdst = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001344 /*
1345 ** Now juggle transition times and types
1346 ** tracking offsets as you do.
1347 */
1348 for (i = 0; i < sp->timecnt; ++i) {
1349 j = sp->types[i];
1350 sp->types[i] = sp->ttis[j].tt_isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001351 if (sp->ttis[j].tt_ttisut) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001352 /* No adjustment to transition time */
1353 } else {
1354 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001355 ** If daylight saving time is in
1356 ** effect, and the transition time was
1357 ** not specified as standard time, add
1358 ** the daylight saving time offset to
1359 ** the transition time; otherwise, add
1360 ** the standard time offset to the
1361 ** transition time.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001362 */
1363 /*
1364 ** Transitions from DST to DDST
1365 ** will effectively disappear since
1366 ** POSIX provides for only one DST
1367 ** offset.
1368 */
1369 if (isdst && !sp->ttis[j].tt_ttisstd) {
1370 sp->ats[i] += dstoffset -
1371 theirdstoffset;
1372 } else {
1373 sp->ats[i] += stdoffset -
1374 theirstdoffset;
1375 }
1376 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001377 theiroffset = -sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001378 if (sp->ttis[j].tt_isdst)
1379 theirdstoffset = theiroffset;
1380 else theirstdoffset = theiroffset;
1381 }
1382 /*
1383 ** Finally, fill in ttis.
1384 */
1385 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1386 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1387 sp->typecnt = 2;
1388 sp->defaulttype = 0;
1389 }
1390 } else {
1391 dstlen = 0;
1392 sp->typecnt = 1; /* only standard time */
1393 sp->timecnt = 0;
1394 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1395 sp->defaulttype = 0;
1396 }
1397 sp->charcnt = charcnt;
1398 cp = sp->chars;
1399 memcpy(cp, stdname, stdlen);
1400 cp += stdlen;
1401 *cp++ = '\0';
1402 if (dstlen != 0) {
1403 memcpy(cp, dstname, dstlen);
1404 *(cp + dstlen) = '\0';
1405 }
1406 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001407}
1408
1409static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001410gmtload(struct state *const sp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001411{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001412 if (tzload(etc_utc, sp, true) != 0)
1413 tzparse("UTC0", sp, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001414}
1415
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001416/* Initialize *SP to a value appropriate for the TZ setting NAME.
1417 Return 0 on success, an errno value on failure. */
1418static int
1419zoneinit(struct state *sp, char const *name)
1420{
1421 if (name && ! name[0]) {
1422 /*
1423 ** User wants it fast rather than right.
1424 */
1425 sp->leapcnt = 0; /* so, we're off a little */
1426 sp->timecnt = 0;
1427 sp->typecnt = 0;
1428 sp->charcnt = 0;
1429 sp->goback = sp->goahead = false;
1430 init_ttinfo(&sp->ttis[0], 0, false, 0);
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001431 strcpy(sp->chars, utc);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001432 sp->defaulttype = 0;
1433 return 0;
1434 } else {
1435 int err = tzload(name, sp, true);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001436 if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001437 err = 0;
1438 if (err == 0)
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001439 err = scrub_abbrs(sp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001440 return err;
1441 }
1442}
1443
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001444void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001445tzsetlcl(char const *name)
1446{
1447 struct state *sp = lclptr;
1448 int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1449 if (lcl < 0
1450 ? lcl_is_set < 0
1451 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1452 return;
1453#ifdef ALL_STATE
1454 if (! sp)
1455 lclptr = sp = malloc(sizeof *lclptr);
1456#endif /* defined ALL_STATE */
1457 if (sp) {
1458 if (zoneinit(sp, name) != 0)
1459 zoneinit(sp, "");
1460 if (0 < lcl)
1461 strcpy(lcl_TZname, name);
1462 }
1463 settzname();
1464 lcl_is_set = lcl;
1465}
1466
Elliott Hughesa9209d72016-09-16 18:16:47 -07001467#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001468extern void tzset_unlocked(void);
1469#else
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001470static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001471tzset_unlocked(void)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001472{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001473 tzsetlcl(getenv("TZ"));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001474}
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001475#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001476
1477void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001478tzset(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001479{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001480 if (lock() != 0)
1481 return;
1482 tzset_unlocked();
1483 unlock();
1484}
1485
1486static void
1487gmtcheck(void)
1488{
1489 static bool gmt_is_set;
1490 if (lock() != 0)
1491 return;
1492 if (! gmt_is_set) {
1493#ifdef ALL_STATE
1494 gmtptr = malloc(sizeof *gmtptr);
1495#endif
1496 if (gmtptr)
1497 gmtload(gmtptr);
1498 gmt_is_set = true;
1499 }
1500 unlock();
1501}
1502
1503#if NETBSD_INSPIRED
1504
1505timezone_t
1506tzalloc(char const *name)
1507{
1508 timezone_t sp = malloc(sizeof *sp);
1509 if (sp) {
1510 int err = zoneinit(sp, name);
1511 if (err != 0) {
1512 free(sp);
1513 errno = err;
1514 return NULL;
1515 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001516 } else if (!HAVE_MALLOC_ERRNO)
1517 errno = ENOMEM;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001518 return sp;
1519}
1520
1521void
1522tzfree(timezone_t sp)
1523{
1524 free(sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001525}
1526
1527/*
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001528** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
1529** ctime_r are obsolescent and have potential security problems that
1530** ctime_rz would share. Callers can instead use localtime_rz + strftime.
1531**
1532** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1533** in zones with three or more time zone abbreviations.
1534** Callers can instead use localtime_rz + strftime.
1535*/
1536
1537#endif
1538
1539/*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001540** The easy way to behave "as if no library function calls" localtime
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001541** is to not call it, so we drop its guts into "localsub", which can be
1542** freely called. (And no, the PANS doesn't require the above behavior,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001543** but it *is* desirable.)
1544**
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001545** If successful and SETNAME is nonzero,
1546** set the applicable parts of tzname, timezone and altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001547** however, it's OK to omit this step if the timezone is POSIX-compatible,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001548** since in that case tzset should have already done this step correctly.
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001549** SETNAME's type is int_fast32_t for compatibility with gmtsub,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001550** but it is actually a boolean and its value should be 0 or 1.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001551*/
1552
1553/*ARGSUSED*/
1554static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001555localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1556 struct tm *const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001557{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001558 register const struct ttinfo * ttisp;
1559 register int i;
1560 register struct tm * result;
1561 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001562
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001563 if (sp == NULL) {
1564 /* Don't bother to set tzname etc.; tzset has already done it. */
1565 return gmtsub(gmtptr, timep, 0, tmp);
1566 }
1567 if ((sp->goback && t < sp->ats[0]) ||
1568 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001569 time_t newt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001570 register time_t seconds;
1571 register time_t years;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001572
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001573 if (t < sp->ats[0])
1574 seconds = sp->ats[0] - t;
1575 else seconds = t - sp->ats[sp->timecnt - 1];
1576 --seconds;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001577
1578 /* Beware integer overflow, as SECONDS might
1579 be close to the maximum time_t. */
1580 years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001581 seconds = years * AVGSECSPERYEAR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001582 years += YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001583 if (t < sp->ats[0])
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001584 newt = t + seconds + SECSPERREPEAT;
1585 else
1586 newt = t - seconds - SECSPERREPEAT;
1587
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001588 if (newt < sp->ats[0] ||
1589 newt > sp->ats[sp->timecnt - 1])
1590 return NULL; /* "cannot happen" */
1591 result = localsub(sp, &newt, setname, tmp);
1592 if (result) {
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001593#if defined ckd_add && defined ckd_sub
1594 if (t < sp->ats[0]
1595 ? ckd_sub(&result->tm_year,
1596 result->tm_year, years)
1597 : ckd_add(&result->tm_year,
1598 result->tm_year, years))
1599 return NULL;
1600#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001601 register int_fast64_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001602
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001603 newy = result->tm_year;
1604 if (t < sp->ats[0])
1605 newy -= years;
1606 else newy += years;
1607 if (! (INT_MIN <= newy && newy <= INT_MAX))
1608 return NULL;
1609 result->tm_year = newy;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001610#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001611 }
1612 return result;
1613 }
1614 if (sp->timecnt == 0 || t < sp->ats[0]) {
1615 i = sp->defaulttype;
1616 } else {
1617 register int lo = 1;
1618 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001619
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001620 while (lo < hi) {
1621 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001622
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001623 if (t < sp->ats[mid])
1624 hi = mid;
1625 else lo = mid + 1;
1626 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001627 i = sp->types[lo - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001628 }
1629 ttisp = &sp->ttis[i];
1630 /*
1631 ** To get (wrong) behavior that's compatible with System V Release 2.0
1632 ** you'd replace the statement below with
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001633 ** t += ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001634 ** timesub(&t, 0L, sp, tmp);
1635 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001636 result = timesub(&t, ttisp->tt_utoff, sp, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001637 if (result) {
1638 result->tm_isdst = ttisp->tt_isdst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001639#ifdef TM_ZONE
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001640 result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001641#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001642 if (setname)
1643 update_tzname_etc(sp, ttisp);
1644 }
1645 return result;
1646}
1647
1648#if NETBSD_INSPIRED
1649
1650struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001651localtime_rz(struct state *restrict sp, time_t const *restrict timep,
1652 struct tm *restrict tmp)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001653{
1654 return localsub(sp, timep, 0, tmp);
1655}
1656
1657#endif
1658
1659static struct tm *
Elliott Hughesea877162017-01-11 14:34:16 -08001660localtime_tzset(time_t const *timep, struct tm *tmp)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001661{
1662 int err = lock();
1663 if (err) {
1664 errno = err;
1665 return NULL;
1666 }
Elliott Hughesea877162017-01-11 14:34:16 -08001667
1668 // http://b/31339449: POSIX says localtime(3) acts as if it called tzset(3), but upstream
1669 // and glibc both think it's okay for localtime_r(3) to not do so (presumably because of
1670 // the "not required to set tzname" clause). It's unclear that POSIX actually intended this,
1671 // the BSDs disagree with glibc, and it's confusing to developers to have localtime_r(3)
1672 // behave differently than other time zone-sensitive functions in <time.h>.
1673 tzset_unlocked();
1674
1675 tmp = localsub(lclptr, timep, true, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001676 unlock();
1677 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001678}
1679
1680struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001681localtime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001682{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001683#if !SUPPORT_C89
1684 static struct tm tm;
1685#endif
Elliott Hughesea877162017-01-11 14:34:16 -08001686 return localtime_tzset(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001687}
1688
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001689struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001690localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001691{
Elliott Hughesea877162017-01-11 14:34:16 -08001692 return localtime_tzset(timep, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001693}
1694
1695/*
1696** gmtsub is to gmtime as localsub is to localtime.
1697*/
1698
1699static struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001700gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
1701 int_fast32_t offset, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001703 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001704
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001705 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001706#ifdef TM_ZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001707 /*
1708 ** Could get fancy here and deliver something such as
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001709 ** "+xx" or "-xx" if offset is non-zero,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001710 ** but this is no time for a treasure hunt.
1711 */
1712 tmp->TM_ZONE = ((char *)
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001713 (offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001714#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001715 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001716}
1717
1718/*
1719* Re-entrant version of gmtime.
1720*/
1721
1722struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001723gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001724{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001725 gmtcheck();
1726 return gmtsub(gmtptr, timep, 0, tmp);
1727}
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001728
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001729struct tm *
1730gmtime(const time_t *timep)
1731{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001732#if !SUPPORT_C89
1733 static struct tm tm;
1734#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001735 return gmtime_r(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001736}
1737
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001738#if STD_INSPIRED
Elliott Hughes906eb992014-06-18 19:46:25 -07001739
1740struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001741offtime(const time_t *timep, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07001742{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001743 gmtcheck();
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001744
1745#if !SUPPORT_C89
1746 static struct tm tm;
1747#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001748 return gmtsub(gmtptr, timep, offset, &tm);
Elliott Hughes906eb992014-06-18 19:46:25 -07001749}
1750
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001751#endif
Elliott Hughes906eb992014-06-18 19:46:25 -07001752
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001753/*
1754** Return the number of leap years through the end of the given year
1755** where, to make the math easy, the answer for year zero is defined as zero.
1756*/
1757
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001758static time_t
1759leaps_thru_end_of_nonneg(time_t y)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001760{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001761 return y / 4 - y / 100 + y / 400;
1762}
1763
1764static time_t
1765leaps_thru_end_of(time_t y)
1766{
1767 return (y < 0
1768 ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1769 : leaps_thru_end_of_nonneg(y));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001770}
1771
1772static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001773timesub(const time_t *timep, int_fast32_t offset,
1774 const struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001775{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001776 register const struct lsinfo * lp;
1777 register time_t tdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001778 register const int * ip;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001779 register int_fast32_t corr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001780 register int i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001781 int_fast32_t idays, rem, dayoff, dayrem;
1782 time_t y;
1783
1784 /* If less than SECSPERMIN, the number of seconds since the
1785 most recent positive leap second; otherwise, do not add 1
1786 to localtime tm_sec because of leap seconds. */
1787 time_t secs_since_posleap = SECSPERMIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001788
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001789 corr = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001790 i = (sp == NULL) ? 0 : sp->leapcnt;
1791 while (--i >= 0) {
1792 lp = &sp->lsis[i];
1793 if (*timep >= lp->ls_trans) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001794 corr = lp->ls_corr;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001795 if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
1796 secs_since_posleap = *timep - lp->ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001797 break;
1798 }
1799 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001800
1801 /* Calculate the year, avoiding integer overflow even if
1802 time_t is unsigned. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001803 tdays = *timep / SECSPERDAY;
1804 rem = *timep % SECSPERDAY;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001805 rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
1806 dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
1807 rem %= SECSPERDAY;
1808 /* y = (EPOCH_YEAR
1809 + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
1810 sans overflow. But calculate against 1570 (EPOCH_YEAR -
1811 YEARSPERREPEAT) instead of against 1970 so that things work
1812 for localtime values before 1970 when time_t is unsigned. */
1813 dayrem = tdays % DAYSPERREPEAT;
1814 dayrem += dayoff % DAYSPERREPEAT;
1815 y = (EPOCH_YEAR - YEARSPERREPEAT
1816 + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
1817 - ((dayrem % DAYSPERREPEAT) < 0)
1818 + tdays / DAYSPERREPEAT)
1819 * YEARSPERREPEAT));
1820 /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */
1821 idays = tdays % DAYSPERREPEAT;
1822 idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
1823 idays %= DAYSPERREPEAT;
1824 /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
1825 while (year_lengths[isleap(y)] <= idays) {
1826 int tdelta = idays / DAYSPERLYEAR;
1827 int_fast32_t ydelta = tdelta + !tdelta;
1828 time_t newy = y + ydelta;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001829 register int leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001830 leapdays = leaps_thru_end_of(newy - 1) -
1831 leaps_thru_end_of(y - 1);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001832 idays -= ydelta * DAYSPERNYEAR;
1833 idays -= leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001834 y = newy;
1835 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001836
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001837#ifdef ckd_add
1838 if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
1839 errno = EOVERFLOW;
1840 return NULL;
1841 }
1842#else
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001843 if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
1844 int signed_y = y;
1845 tmp->tm_year = signed_y - TM_YEAR_BASE;
1846 } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
1847 && y - TM_YEAR_BASE <= INT_MAX)
1848 tmp->tm_year = y - TM_YEAR_BASE;
1849 else {
1850 errno = EOVERFLOW;
1851 return NULL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001852 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001853#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001854 tmp->tm_yday = idays;
1855 /*
1856 ** The "extra" mods below avoid overflow problems.
1857 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001858 tmp->tm_wday = (TM_WDAY_BASE
1859 + ((tmp->tm_year % DAYSPERWEEK)
1860 * (DAYSPERNYEAR % DAYSPERWEEK))
1861 + leaps_thru_end_of(y - 1)
1862 - leaps_thru_end_of(TM_YEAR_BASE - 1)
1863 + idays);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001864 tmp->tm_wday %= DAYSPERWEEK;
1865 if (tmp->tm_wday < 0)
1866 tmp->tm_wday += DAYSPERWEEK;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001867 tmp->tm_hour = rem / SECSPERHOUR;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001868 rem %= SECSPERHOUR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001869 tmp->tm_min = rem / SECSPERMIN;
1870 tmp->tm_sec = rem % SECSPERMIN;
1871
1872 /* Use "... ??:??:60" at the end of the localtime minute containing
1873 the second just before the positive leap second. */
1874 tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
1875
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001876 ip = mon_lengths[isleap(y)];
1877 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1878 idays -= ip[tmp->tm_mon];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001879 tmp->tm_mday = idays + 1;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001880 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001881#ifdef TM_GMTOFF
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001882 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001883#endif /* defined TM_GMTOFF */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001884 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001885}
1886
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001887/*
1888** Adapted from code provided by Robert Elz, who writes:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001889** The "best" way to do mktime I think is based on an idea of Bob
1890** Kridle's (so its said...) from a long time ago.
1891** It does a binary search of the time_t space. Since time_t's are
1892** just 32 bits, its a max of 32 iterations (even at 64 bits it
1893** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001894*/
1895
1896#ifndef WRONG
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001897# define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001898#endif /* !defined WRONG */
1899
1900/*
Elliott Hughesce4783c2013-07-12 17:31:11 -07001901** Normalize logic courtesy Paul Eggert.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001902*/
1903
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001904static bool
1905increment_overflow(int *ip, int j)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001906{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001907#ifdef ckd_add
1908 return ckd_add(ip, *ip, j);
1909#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001910 register int const i = *ip;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001911
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001912 /*
1913 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1914 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1915 ** If i < 0 there can only be overflow if i + j < INT_MIN
1916 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1917 */
1918 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1919 return true;
1920 *ip += j;
1921 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001922#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001923}
1924
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001925static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001926increment_overflow32(int_fast32_t *const lp, int const m)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001927{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001928#ifdef ckd_add
1929 return ckd_add(lp, *lp, m);
1930#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001931 register int_fast32_t const l = *lp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001932
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001933 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
1934 return true;
1935 *lp += m;
1936 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001937#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001938}
1939
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001940static bool
Calin Juravle627d37c2014-02-28 11:46:03 +00001941increment_overflow_time(time_t *tp, int_fast32_t j)
1942{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001943#ifdef ckd_add
1944 return ckd_add(tp, *tp, j);
1945#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001946 /*
1947 ** This is like
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001948 ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001949 ** except that it does the right thing even if *tp + j would overflow.
1950 */
1951 if (! (j < 0
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001952 ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
1953 : *tp <= TIME_T_MAX - j))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001954 return true;
1955 *tp += j;
1956 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001957#endif
Calin Juravle627d37c2014-02-28 11:46:03 +00001958}
1959
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001960static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001961normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001962{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001963 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001964
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001965 tensdelta = (*unitsptr >= 0) ?
1966 (*unitsptr / base) :
1967 (-1 - (-1 - *unitsptr) / base);
1968 *unitsptr -= tensdelta * base;
1969 return increment_overflow(tensptr, tensdelta);
1970}
1971
1972static bool
1973normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
1974{
1975 register int tensdelta;
1976
1977 tensdelta = (*unitsptr >= 0) ?
1978 (*unitsptr / base) :
1979 (-1 - (-1 - *unitsptr) / base);
1980 *unitsptr -= tensdelta * base;
1981 return increment_overflow32(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001982}
1983
1984static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001985tmcomp(register const struct tm *const atmp,
1986 register const struct tm *const btmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001987{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001988 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001989
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001990 if (atmp->tm_year != btmp->tm_year)
1991 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1992 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1993 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1994 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1995 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1996 result = atmp->tm_sec - btmp->tm_sec;
1997 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001998}
1999
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002000/* Copy to *DEST from *SRC. Copy only the members needed for mktime,
2001 as other members might not be initialized. */
2002static void
2003mktmcpy(struct tm *dest, struct tm const *src)
2004{
2005 dest->tm_sec = src->tm_sec;
2006 dest->tm_min = src->tm_min;
2007 dest->tm_hour = src->tm_hour;
2008 dest->tm_mday = src->tm_mday;
2009 dest->tm_mon = src->tm_mon;
2010 dest->tm_year = src->tm_year;
2011 dest->tm_isdst = src->tm_isdst;
2012#if defined TM_GMTOFF && ! UNINIT_TRAP
2013 dest->TM_GMTOFF = src->TM_GMTOFF;
2014#endif
2015}
2016
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002017static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002018time2sub(struct tm *const tmp,
2019 struct tm *(*funcp)(struct state const *, time_t const *,
2020 int_fast32_t, struct tm *),
2021 struct state const *sp,
2022 const int_fast32_t offset,
2023 bool *okayp,
2024 bool do_norm_secs)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002025{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002026 register int dir;
2027 register int i, j;
2028 register int saved_seconds;
2029 register int_fast32_t li;
2030 register time_t lo;
2031 register time_t hi;
2032 int_fast32_t y;
2033 time_t newt;
2034 time_t t;
2035 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002036
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002037 *okayp = false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002038 mktmcpy(&yourtm, tmp);
2039
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002040 if (do_norm_secs) {
2041 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2042 SECSPERMIN))
2043 return WRONG;
2044 }
2045 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2046 return WRONG;
2047 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2048 return WRONG;
2049 y = yourtm.tm_year;
2050 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
2051 return WRONG;
2052 /*
2053 ** Turn y into an actual year number for now.
2054 ** It is converted back to an offset from TM_YEAR_BASE later.
2055 */
2056 if (increment_overflow32(&y, TM_YEAR_BASE))
2057 return WRONG;
2058 while (yourtm.tm_mday <= 0) {
2059 if (increment_overflow32(&y, -1))
2060 return WRONG;
2061 li = y + (1 < yourtm.tm_mon);
2062 yourtm.tm_mday += year_lengths[isleap(li)];
2063 }
2064 while (yourtm.tm_mday > DAYSPERLYEAR) {
2065 li = y + (1 < yourtm.tm_mon);
2066 yourtm.tm_mday -= year_lengths[isleap(li)];
2067 if (increment_overflow32(&y, 1))
2068 return WRONG;
2069 }
2070 for ( ; ; ) {
2071 i = mon_lengths[isleap(y)][yourtm.tm_mon];
2072 if (yourtm.tm_mday <= i)
2073 break;
2074 yourtm.tm_mday -= i;
2075 if (++yourtm.tm_mon >= MONSPERYEAR) {
2076 yourtm.tm_mon = 0;
2077 if (increment_overflow32(&y, 1))
2078 return WRONG;
2079 }
2080 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002081#ifdef ckd_add
2082 if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
2083 return WRONG;
2084#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002085 if (increment_overflow32(&y, -TM_YEAR_BASE))
2086 return WRONG;
2087 if (! (INT_MIN <= y && y <= INT_MAX))
2088 return WRONG;
2089 yourtm.tm_year = y;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002090#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002091 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2092 saved_seconds = 0;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002093 else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002094 /*
2095 ** We can't set tm_sec to 0, because that might push the
2096 ** time below the minimum representable time.
2097 ** Set tm_sec to 59 instead.
2098 ** This assumes that the minimum representable time is
2099 ** not in the same minute that a leap second was deleted from,
2100 ** which is a safer assumption than using 58 would be.
2101 */
2102 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2103 return WRONG;
2104 saved_seconds = yourtm.tm_sec;
2105 yourtm.tm_sec = SECSPERMIN - 1;
2106 } else {
2107 saved_seconds = yourtm.tm_sec;
2108 yourtm.tm_sec = 0;
2109 }
2110 /*
2111 ** Do a binary search (this works whatever time_t's type is).
2112 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002113 lo = TIME_T_MIN;
2114 hi = TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002115 for ( ; ; ) {
2116 t = lo / 2 + hi / 2;
2117 if (t < lo)
2118 t = lo;
2119 else if (t > hi)
2120 t = hi;
2121 if (! funcp(sp, &t, offset, &mytm)) {
2122 /*
2123 ** Assume that t is too extreme to be represented in
2124 ** a struct tm; arrange things so that it is less
2125 ** extreme on the next pass.
2126 */
2127 dir = (t > 0) ? 1 : -1;
2128 } else dir = tmcomp(&mytm, &yourtm);
2129 if (dir != 0) {
2130 if (t == lo) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002131 if (t == TIME_T_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002132 return WRONG;
2133 ++t;
2134 ++lo;
2135 } else if (t == hi) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002136 if (t == TIME_T_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002137 return WRONG;
2138 --t;
2139 --hi;
2140 }
2141 if (lo > hi)
2142 return WRONG;
2143 if (dir > 0)
2144 hi = t;
2145 else lo = t;
2146 continue;
2147 }
2148#if defined TM_GMTOFF && ! UNINIT_TRAP
2149 if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
2150 && (yourtm.TM_GMTOFF < 0
2151 ? (-SECSPERDAY <= yourtm.TM_GMTOFF
2152 && (mytm.TM_GMTOFF <=
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002153 (min(INT_FAST32_MAX, LONG_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002154 + yourtm.TM_GMTOFF)))
2155 : (yourtm.TM_GMTOFF <= SECSPERDAY
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002156 && ((max(INT_FAST32_MIN, LONG_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002157 + yourtm.TM_GMTOFF)
2158 <= mytm.TM_GMTOFF)))) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002159 /* MYTM matches YOURTM except with the wrong UT offset.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002160 YOURTM.TM_GMTOFF is plausible, so try it instead.
2161 It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2162 since the guess gets checked. */
2163 time_t altt = t;
2164 int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2165 if (!increment_overflow_time(&altt, diff)) {
2166 struct tm alttm;
2167 if (funcp(sp, &altt, offset, &alttm)
2168 && alttm.tm_isdst == mytm.tm_isdst
2169 && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2170 && tmcomp(&alttm, &yourtm) == 0) {
2171 t = altt;
2172 mytm = alttm;
2173 }
2174 }
2175 }
2176#endif
2177 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2178 break;
2179 /*
2180 ** Right time, wrong type.
2181 ** Hunt for right time, right type.
2182 ** It's okay to guess wrong since the guess
2183 ** gets checked.
2184 */
2185 if (sp == NULL)
2186 return WRONG;
2187 for (i = sp->typecnt - 1; i >= 0; --i) {
2188 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2189 continue;
2190 for (j = sp->typecnt - 1; j >= 0; --j) {
2191 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2192 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002193 if (ttunspecified(sp, j))
2194 continue;
2195 newt = (t + sp->ttis[j].tt_utoff
2196 - sp->ttis[i].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002197 if (! funcp(sp, &newt, offset, &mytm))
2198 continue;
2199 if (tmcomp(&mytm, &yourtm) != 0)
2200 continue;
2201 if (mytm.tm_isdst != yourtm.tm_isdst)
2202 continue;
2203 /*
2204 ** We have a match.
2205 */
2206 t = newt;
2207 goto label;
2208 }
2209 }
2210 return WRONG;
2211 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002212label:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002213 newt = t + saved_seconds;
2214 if ((newt < t) != (saved_seconds < 0))
2215 return WRONG;
2216 t = newt;
2217 if (funcp(sp, &t, offset, tmp))
2218 *okayp = true;
2219 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002220}
2221
2222static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002223time2(struct tm * const tmp,
2224 struct tm *(*funcp)(struct state const *, time_t const *,
2225 int_fast32_t, struct tm *),
2226 struct state const *sp,
Elliott Hughesce4783c2013-07-12 17:31:11 -07002227 const int_fast32_t offset,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002228 bool *okayp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002229{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002230 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002231
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002232 /*
2233 ** First try without normalization of seconds
2234 ** (in case tm_sec contains a value associated with a leap second).
2235 ** If that fails, try with normalization of seconds.
2236 */
2237 t = time2sub(tmp, funcp, sp, offset, okayp, false);
2238 return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002239}
2240
2241static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002242time1(struct tm *const tmp,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002243 struct tm *(*funcp)(struct state const *, time_t const *,
2244 int_fast32_t, struct tm *),
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002245 struct state const *sp,
2246 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002247{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002248 register time_t t;
2249 register int samei, otheri;
2250 register int sameind, otherind;
2251 register int i;
2252 register int nseen;
2253 char seen[TZ_MAX_TYPES];
2254 unsigned char types[TZ_MAX_TYPES];
2255 bool okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002256
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002257 if (tmp == NULL) {
2258 errno = EINVAL;
2259 return WRONG;
2260 }
2261 if (tmp->tm_isdst > 1)
2262 tmp->tm_isdst = 1;
2263 t = time2(tmp, funcp, sp, offset, &okay);
2264 if (okay)
2265 return t;
2266 if (tmp->tm_isdst < 0)
Elliott Hughes906eb992014-06-18 19:46:25 -07002267#ifdef PCTS
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002268 /*
2269 ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2270 */
2271 tmp->tm_isdst = 0; /* reset to std and try again */
Elliott Hughes906eb992014-06-18 19:46:25 -07002272#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002273 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002274#endif /* !defined PCTS */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002275 /*
2276 ** We're supposed to assume that somebody took a time of one type
2277 ** and did some math on it that yielded a "struct tm" that's bad.
2278 ** We try to divine the type they started from and adjust to the
2279 ** type they need.
2280 */
2281 if (sp == NULL)
2282 return WRONG;
2283 for (i = 0; i < sp->typecnt; ++i)
2284 seen[i] = false;
2285 nseen = 0;
2286 for (i = sp->timecnt - 1; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002287 if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002288 seen[sp->types[i]] = true;
2289 types[nseen++] = sp->types[i];
2290 }
2291 for (sameind = 0; sameind < nseen; ++sameind) {
2292 samei = types[sameind];
2293 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2294 continue;
2295 for (otherind = 0; otherind < nseen; ++otherind) {
2296 otheri = types[otherind];
2297 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2298 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002299 tmp->tm_sec += (sp->ttis[otheri].tt_utoff
2300 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002301 tmp->tm_isdst = !tmp->tm_isdst;
2302 t = time2(tmp, funcp, sp, offset, &okay);
2303 if (okay)
2304 return t;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002305 tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
2306 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002307 tmp->tm_isdst = !tmp->tm_isdst;
2308 }
2309 }
2310 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002311}
2312
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002313static time_t
2314mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2315{
2316 if (sp)
2317 return time1(tmp, localsub, sp, setname);
2318 else {
2319 gmtcheck();
2320 return time1(tmp, gmtsub, gmtptr, 0);
2321 }
2322}
2323
2324#if NETBSD_INSPIRED
2325
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002326time_t
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002327mktime_z(struct state *restrict sp, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002328{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002329 return mktime_tzname(sp, tmp, false);
2330}
2331
2332#endif
2333
2334time_t
2335mktime(struct tm *tmp)
2336{
Elliott Hughesa9209d72016-09-16 18:16:47 -07002337#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002338 int saved_errno = errno;
2339#endif
2340
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002341 time_t t;
2342 int err = lock();
2343 if (err) {
2344 errno = err;
2345 return -1;
2346 }
2347 tzset_unlocked();
2348 t = mktime_tzname(lclptr, tmp, true);
2349 unlock();
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002350
Elliott Hughesa9209d72016-09-16 18:16:47 -07002351#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002352 errno = (t == -1) ? EOVERFLOW : saved_errno;
2353#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002354 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002355}
2356
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002357#if STD_INSPIRED
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002358time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002359timelocal(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002360{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002361 if (tmp != NULL)
2362 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2363 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002364}
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002365#else
2366static
2367#endif
Elliott Hughes906eb992014-06-18 19:46:25 -07002368time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002369timeoff(struct tm *tmp, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07002370{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002371 if (tmp)
2372 tmp->tm_isdst = 0;
2373 gmtcheck();
2374 return time1(tmp, gmtsub, gmtptr, offset);
Elliott Hughes906eb992014-06-18 19:46:25 -07002375}
2376
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002377time_t
2378timegm(struct tm *tmp)
2379{
2380 time_t t;
2381 struct tm tmcpy;
2382 mktmcpy(&tmcpy, tmp);
2383 tmcpy.tm_wday = -1;
2384 t = timeoff(&tmcpy, 0);
2385 if (0 <= tmcpy.tm_wday)
2386 *tmp = tmcpy;
2387 return t;
2388}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002389
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002390static int_fast32_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002391leapcorr(struct state const *sp, time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002392{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002393 register struct lsinfo const * lp;
2394 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002395
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002396 i = sp->leapcnt;
2397 while (--i >= 0) {
2398 lp = &sp->lsis[i];
2399 if (t >= lp->ls_trans)
2400 return lp->ls_corr;
2401 }
2402 return 0;
2403}
2404
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002405/*
2406** XXX--is the below the right way to conditionalize??
2407*/
2408
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002409#if STD_INSPIRED
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002410
2411/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
2412 NETBSD_INSPIRED is defined, and are private otherwise. */
2413# if NETBSD_INSPIRED
2414# define NETBSD_INSPIRED_EXTERN
2415# else
2416# define NETBSD_INSPIRED_EXTERN static
2417# endif
2418
2419/*
2420** IEEE Std 1003.1 (POSIX) says that 536457599
2421** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2422** is not the case if we are accounting for leap seconds.
2423** So, we provide the following conversion routines for use
2424** when exchanging timestamps with POSIX conforming systems.
2425*/
2426
2427NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002428time2posix_z(struct state *sp, time_t t)
2429{
2430 return t - leapcorr(sp, t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002431}
2432
2433time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002434time2posix(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002435{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002436 int err = lock();
2437 if (err) {
2438 errno = err;
2439 return -1;
2440 }
2441 if (!lcl_is_set)
2442 tzset_unlocked();
2443 if (lclptr)
2444 t = time2posix_z(lclptr, t);
2445 unlock();
2446 return t;
2447}
2448
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002449NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002450posix2time_z(struct state *sp, time_t t)
2451{
2452 time_t x;
2453 time_t y;
2454 /*
2455 ** For a positive leap second hit, the result
2456 ** is not unique. For a negative leap second
2457 ** hit, the corresponding time doesn't exist,
2458 ** so we return an adjacent second.
2459 */
2460 x = t + leapcorr(sp, t);
2461 y = x - leapcorr(sp, x);
2462 if (y < t) {
2463 do {
2464 x++;
2465 y = x - leapcorr(sp, x);
2466 } while (y < t);
2467 x -= y != t;
2468 } else if (y > t) {
2469 do {
2470 --x;
2471 y = x - leapcorr(sp, x);
2472 } while (y > t);
2473 x += y != t;
2474 }
2475 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002476}
2477
2478time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002479posix2time(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002480{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002481 int err = lock();
2482 if (err) {
2483 errno = err;
2484 return -1;
2485 }
2486 if (!lcl_is_set)
2487 tzset_unlocked();
2488 if (lclptr)
2489 t = posix2time_z(lclptr, t);
2490 unlock();
2491 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002492}
2493
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002494#endif /* STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002495
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002496#if TZ_TIME_T
2497
2498# if !USG_COMPAT
2499# define daylight 0
2500# define timezone 0
2501# endif
2502# if !ALTZONE
2503# define altzone 0
2504# endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002505
2506/* Convert from the underlying system's time_t to the ersatz time_tz,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002507 which is called 'time_t' in this file. Typically, this merely
2508 converts the time's integer width. On some platforms, the system
2509 time is local time not UT, or uses some epoch other than the POSIX
2510 epoch.
2511
2512 Although this code appears to define a function named 'time' that
2513 returns time_t, the macros in private.h cause this code to actually
2514 define a function named 'tz_time' that returns tz_time_t. The call
2515 to sys_time invokes the underlying system's 'time' function. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002516
2517time_t
2518time(time_t *p)
2519{
2520 time_t r = sys_time(0);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002521 if (r != (time_t) -1) {
2522 int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
2523 if (increment_overflow32(&offset, -EPOCH_OFFSET)
2524 || increment_overflow_time(&r, offset)) {
2525 errno = EOVERFLOW;
2526 r = -1;
2527 }
2528 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002529 if (p)
2530 *p = r;
2531 return r;
2532}
2533
2534#endif