1bc421551SDag-Erling Smørgrav /* Convert timestamp from time_t to struct tm. */
2bc421551SDag-Erling Smørgrav
3bc421551SDag-Erling Smørgrav /*
4bc421551SDag-Erling Smørgrav ** This file is in the public domain, so clarified as of
5bc421551SDag-Erling Smørgrav ** 1996-06-05 by Arthur David Olson.
6bc421551SDag-Erling Smørgrav */
7bc421551SDag-Erling Smørgrav
8bc421551SDag-Erling Smørgrav /*
9bc421551SDag-Erling Smørgrav ** Leap second handling from Bradley White.
1046c59934SDag-Erling Smørgrav ** POSIX.1-1988 style TZ environment variable handling from Guy Harris.
11bc421551SDag-Erling Smørgrav */
12bc421551SDag-Erling Smørgrav
13bc421551SDag-Erling Smørgrav /*LINTLIBRARY*/
14bc421551SDag-Erling Smørgrav
15bc421551SDag-Erling Smørgrav #define LOCALTIME_IMPLEMENTATION
16bc421551SDag-Erling Smørgrav #include "namespace.h"
17bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES
18bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES_INTERVAL
19bc421551SDag-Erling Smørgrav #define DETECT_TZ_CHANGES_INTERVAL 61
20bc421551SDag-Erling Smørgrav #endif
21bc421551SDag-Erling Smørgrav #include <sys/stat.h>
22bc421551SDag-Erling Smørgrav #endif
23bc421551SDag-Erling Smørgrav #include <fcntl.h>
24bc421551SDag-Erling Smørgrav #if THREAD_SAFE
25bc421551SDag-Erling Smørgrav #include <pthread.h>
26bc421551SDag-Erling Smørgrav #endif
27bc421551SDag-Erling Smørgrav #include "private.h"
28bc421551SDag-Erling Smørgrav #include "un-namespace.h"
29bc421551SDag-Erling Smørgrav
3046c59934SDag-Erling Smørgrav #include "tzdir.h"
31bc421551SDag-Erling Smørgrav #include "tzfile.h"
32bc421551SDag-Erling Smørgrav
33bc421551SDag-Erling Smørgrav #include "libc_private.h"
34bc421551SDag-Erling Smørgrav
35bc421551SDag-Erling Smørgrav #if defined THREAD_SAFE && THREAD_SAFE
36bc421551SDag-Erling Smørgrav static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
lock(void)37bc421551SDag-Erling Smørgrav static int lock(void) {
38bc421551SDag-Erling Smørgrav if (__isthreaded)
39bc421551SDag-Erling Smørgrav return _pthread_mutex_lock(&locallock);
40bc421551SDag-Erling Smørgrav return 0;
41bc421551SDag-Erling Smørgrav }
unlock(void)42bc421551SDag-Erling Smørgrav static void unlock(void) {
43bc421551SDag-Erling Smørgrav if (__isthreaded)
44bc421551SDag-Erling Smørgrav _pthread_mutex_unlock(&locallock);
45bc421551SDag-Erling Smørgrav }
46bc421551SDag-Erling Smørgrav #else
lock(void)47bc421551SDag-Erling Smørgrav static int lock(void) { return 0; }
unlock(void)48bc421551SDag-Erling Smørgrav static void unlock(void) { }
49bc421551SDag-Erling Smørgrav #endif
50bc421551SDag-Erling Smørgrav
51bc421551SDag-Erling Smørgrav #ifndef TZ_ABBR_CHAR_SET
52bc421551SDag-Erling Smørgrav # define TZ_ABBR_CHAR_SET \
53bc421551SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
54bc421551SDag-Erling Smørgrav #endif /* !defined TZ_ABBR_CHAR_SET */
55bc421551SDag-Erling Smørgrav
56bc421551SDag-Erling Smørgrav #ifndef TZ_ABBR_ERR_CHAR
57bc421551SDag-Erling Smørgrav # define TZ_ABBR_ERR_CHAR '_'
58bc421551SDag-Erling Smørgrav #endif /* !defined TZ_ABBR_ERR_CHAR */
59bc421551SDag-Erling Smørgrav
60bc421551SDag-Erling Smørgrav /*
61bc421551SDag-Erling Smørgrav ** Support non-POSIX platforms that distinguish between text and binary files.
62bc421551SDag-Erling Smørgrav */
63bc421551SDag-Erling Smørgrav
64bc421551SDag-Erling Smørgrav #ifndef O_BINARY
65bc421551SDag-Erling Smørgrav # define O_BINARY 0
66bc421551SDag-Erling Smørgrav #endif
67bc421551SDag-Erling Smørgrav
68bc421551SDag-Erling Smørgrav #ifndef WILDABBR
69bc421551SDag-Erling Smørgrav /*
70bc421551SDag-Erling Smørgrav ** Someone might make incorrect use of a time zone abbreviation:
71bc421551SDag-Erling Smørgrav ** 1. They might reference tzname[0] before calling tzset (explicitly
72bc421551SDag-Erling Smørgrav ** or implicitly).
73bc421551SDag-Erling Smørgrav ** 2. They might reference tzname[1] before calling tzset (explicitly
74bc421551SDag-Erling Smørgrav ** or implicitly).
75bc421551SDag-Erling Smørgrav ** 3. They might reference tzname[1] after setting to a time zone
76bc421551SDag-Erling Smørgrav ** in which Daylight Saving Time is never observed.
77bc421551SDag-Erling Smørgrav ** 4. They might reference tzname[0] after setting to a time zone
78bc421551SDag-Erling Smørgrav ** in which Standard Time is never observed.
79bc421551SDag-Erling Smørgrav ** 5. They might reference tm.TM_ZONE after calling offtime.
80bc421551SDag-Erling Smørgrav ** What's best to do in the above cases is open to debate;
81bc421551SDag-Erling Smørgrav ** for now, we just set things up so that in any of the five cases
82bc421551SDag-Erling Smørgrav ** WILDABBR is used. Another possibility: initialize tzname[0] to the
83bc421551SDag-Erling Smørgrav ** string "tzname[0] used before set", and similarly for the other cases.
84bc421551SDag-Erling Smørgrav ** And another: initialize tzname[0] to "ERA", with an explanation in the
85bc421551SDag-Erling Smørgrav ** manual page of what this "time zone abbreviation" means (doing this so
86bc421551SDag-Erling Smørgrav ** that tzname[0] has the "normal" length of three characters).
87bc421551SDag-Erling Smørgrav */
88bc421551SDag-Erling Smørgrav # define WILDABBR " "
89bc421551SDag-Erling Smørgrav #endif /* !defined WILDABBR */
90bc421551SDag-Erling Smørgrav
91bc421551SDag-Erling Smørgrav static const char wildabbr[] = WILDABBR;
92bc421551SDag-Erling Smørgrav
93bc421551SDag-Erling Smørgrav static char const etc_utc[] = "Etc/UTC";
94bc421551SDag-Erling Smørgrav static char const *utc = etc_utc + sizeof "Etc/" - 1;
95bc421551SDag-Erling Smørgrav
96bc421551SDag-Erling Smørgrav /*
97bc421551SDag-Erling Smørgrav ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
98bc421551SDag-Erling Smørgrav ** Default to US rules as of 2017-05-07.
99bc421551SDag-Erling Smørgrav ** POSIX does not specify the default DST rules;
100bc421551SDag-Erling Smørgrav ** for historical reasons, US rules are a common default.
101bc421551SDag-Erling Smørgrav */
102bc421551SDag-Erling Smørgrav #ifndef TZDEFRULESTRING
103bc421551SDag-Erling Smørgrav # define TZDEFRULESTRING ",M3.2.0,M11.1.0"
104bc421551SDag-Erling Smørgrav #endif
105bc421551SDag-Erling Smørgrav
106bc421551SDag-Erling Smørgrav struct ttinfo { /* time type information */
107bc421551SDag-Erling Smørgrav int_fast32_t tt_utoff; /* UT offset in seconds */
108bc421551SDag-Erling Smørgrav bool tt_isdst; /* used to set tm_isdst */
109bc421551SDag-Erling Smørgrav int tt_desigidx; /* abbreviation list index */
110bc421551SDag-Erling Smørgrav bool tt_ttisstd; /* transition is std time */
111bc421551SDag-Erling Smørgrav bool tt_ttisut; /* transition is UT */
112bc421551SDag-Erling Smørgrav };
113bc421551SDag-Erling Smørgrav
114bc421551SDag-Erling Smørgrav struct lsinfo { /* leap second information */
115bc421551SDag-Erling Smørgrav time_t ls_trans; /* transition time */
116bc421551SDag-Erling Smørgrav int_fast32_t ls_corr; /* correction to apply */
117bc421551SDag-Erling Smørgrav };
118bc421551SDag-Erling Smørgrav
119bc421551SDag-Erling Smørgrav /* This abbreviation means local time is unspecified. */
120bc421551SDag-Erling Smørgrav static char const UNSPEC[] = "-00";
121bc421551SDag-Erling Smørgrav
122bc421551SDag-Erling Smørgrav /* How many extra bytes are needed at the end of struct state's chars array.
123bc421551SDag-Erling Smørgrav This needs to be at least 1 for null termination in case the input
124bc421551SDag-Erling Smørgrav data isn't properly terminated, and it also needs to be big enough
125bc421551SDag-Erling Smørgrav for ttunspecified to work without crashing. */
126bc421551SDag-Erling Smørgrav enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
127bc421551SDag-Erling Smørgrav
12846c59934SDag-Erling Smørgrav /* Limit to time zone abbreviation length in POSIX.1-2017-style TZ strings.
12975411d15SDag-Erling Smørgrav This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
13075411d15SDag-Erling Smørgrav #ifndef TZNAME_MAXIMUM
13175411d15SDag-Erling Smørgrav # define TZNAME_MAXIMUM 255
13275411d15SDag-Erling Smørgrav #endif
133bc421551SDag-Erling Smørgrav
13446c59934SDag-Erling Smørgrav /* A representation of the contents of a TZif file. Ideally this
13546c59934SDag-Erling Smørgrav would have no size limits; the following sizes should suffice for
13646c59934SDag-Erling Smørgrav practical use. This struct should not be too large, as instances
13746c59934SDag-Erling Smørgrav are put on the stack and stacks are relatively small on some platforms.
13846c59934SDag-Erling Smørgrav See tzfile.h for more about the sizes. */
139bc421551SDag-Erling Smørgrav struct state {
140bc421551SDag-Erling Smørgrav int leapcnt;
141bc421551SDag-Erling Smørgrav int timecnt;
142bc421551SDag-Erling Smørgrav int typecnt;
143bc421551SDag-Erling Smørgrav int charcnt;
144bc421551SDag-Erling Smørgrav bool goback;
145bc421551SDag-Erling Smørgrav bool goahead;
146bc421551SDag-Erling Smørgrav time_t ats[TZ_MAX_TIMES];
147bc421551SDag-Erling Smørgrav unsigned char types[TZ_MAX_TIMES];
148bc421551SDag-Erling Smørgrav struct ttinfo ttis[TZ_MAX_TYPES];
149bc421551SDag-Erling Smørgrav char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
15075411d15SDag-Erling Smørgrav 2 * (TZNAME_MAXIMUM + 1))];
151bc421551SDag-Erling Smørgrav struct lsinfo lsis[TZ_MAX_LEAPS];
152bc421551SDag-Erling Smørgrav
153bc421551SDag-Erling Smørgrav /* The time type to use for early times or if no transitions.
154bc421551SDag-Erling Smørgrav It is always zero for recent tzdb releases.
155bc421551SDag-Erling Smørgrav It might be nonzero for data from tzdb 2018e or earlier. */
156bc421551SDag-Erling Smørgrav int defaulttype;
157bc421551SDag-Erling Smørgrav };
158bc421551SDag-Erling Smørgrav
159bc421551SDag-Erling Smørgrav enum r_type {
160bc421551SDag-Erling Smørgrav JULIAN_DAY, /* Jn = Julian day */
161bc421551SDag-Erling Smørgrav DAY_OF_YEAR, /* n = day of year */
162bc421551SDag-Erling Smørgrav MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */
163bc421551SDag-Erling Smørgrav };
164bc421551SDag-Erling Smørgrav
165bc421551SDag-Erling Smørgrav struct rule {
166bc421551SDag-Erling Smørgrav enum r_type r_type; /* type of rule */
167bc421551SDag-Erling Smørgrav int r_day; /* day number of rule */
168bc421551SDag-Erling Smørgrav int r_week; /* week number of rule */
169bc421551SDag-Erling Smørgrav int r_mon; /* month number of rule */
170bc421551SDag-Erling Smørgrav int_fast32_t r_time; /* transition time of rule */
171bc421551SDag-Erling Smørgrav };
172bc421551SDag-Erling Smørgrav
173bc421551SDag-Erling Smørgrav static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
174bc421551SDag-Erling Smørgrav struct tm *);
175bc421551SDag-Erling Smørgrav static bool increment_overflow(int *, int);
176bc421551SDag-Erling Smørgrav static bool increment_overflow_time(time_t *, int_fast32_t);
177bc421551SDag-Erling Smørgrav static int_fast32_t leapcorr(struct state const *, time_t);
178bc421551SDag-Erling Smørgrav static bool normalize_overflow32(int_fast32_t *, int *, int);
179bc421551SDag-Erling Smørgrav static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
180bc421551SDag-Erling Smørgrav struct tm *);
18146c59934SDag-Erling Smørgrav static bool tzparse(char const *, struct state *, struct state const *);
182bc421551SDag-Erling Smørgrav
183bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
184bc421551SDag-Erling Smørgrav static struct state * lclptr;
185bc421551SDag-Erling Smørgrav static struct state * gmtptr;
186bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */
187bc421551SDag-Erling Smørgrav
188bc421551SDag-Erling Smørgrav #ifndef ALL_STATE
189bc421551SDag-Erling Smørgrav static struct state lclmem;
190bc421551SDag-Erling Smørgrav static struct state gmtmem;
191bc421551SDag-Erling Smørgrav static struct state *const lclptr = &lclmem;
192bc421551SDag-Erling Smørgrav static struct state *const gmtptr = &gmtmem;
193bc421551SDag-Erling Smørgrav #endif /* State Farm */
194bc421551SDag-Erling Smørgrav
195bc421551SDag-Erling Smørgrav #ifndef TZ_STRLEN_MAX
196bc421551SDag-Erling Smørgrav # define TZ_STRLEN_MAX 255
197bc421551SDag-Erling Smørgrav #endif /* !defined TZ_STRLEN_MAX */
198bc421551SDag-Erling Smørgrav
199bc421551SDag-Erling Smørgrav static char lcl_TZname[TZ_STRLEN_MAX + 1];
200bc421551SDag-Erling Smørgrav static int lcl_is_set;
201bc421551SDag-Erling Smørgrav
202bc421551SDag-Erling Smørgrav static pthread_once_t gmt_once = PTHREAD_ONCE_INIT;
203bc421551SDag-Erling Smørgrav static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT;
204bc421551SDag-Erling Smørgrav static pthread_key_t gmtime_key;
205bc421551SDag-Erling Smørgrav static int gmtime_key_error;
20675411d15SDag-Erling Smørgrav static pthread_once_t offtime_once = PTHREAD_ONCE_INIT;
20775411d15SDag-Erling Smørgrav static pthread_key_t offtime_key;
20875411d15SDag-Erling Smørgrav static int offtime_key_error;
209bc421551SDag-Erling Smørgrav static pthread_once_t localtime_once = PTHREAD_ONCE_INIT;
210bc421551SDag-Erling Smørgrav static pthread_key_t localtime_key;
211bc421551SDag-Erling Smørgrav static int localtime_key_error;
212bc421551SDag-Erling Smørgrav
213bc421551SDag-Erling Smørgrav /*
214bc421551SDag-Erling Smørgrav ** Section 4.12.3 of X3.159-1989 requires that
215bc421551SDag-Erling Smørgrav ** Except for the strftime function, these functions [asctime,
216bc421551SDag-Erling Smørgrav ** ctime, gmtime, localtime] return values in one of two static
217bc421551SDag-Erling Smørgrav ** objects: a broken-down time structure and an array of char.
218bc421551SDag-Erling Smørgrav ** Thanks to Paul Eggert for noting this.
21975411d15SDag-Erling Smørgrav **
22075411d15SDag-Erling Smørgrav ** This requirement was removed in C99, so support it only if requested,
22175411d15SDag-Erling Smørgrav ** as support is more likely to lead to bugs in badly written programs.
222bc421551SDag-Erling Smørgrav */
223bc421551SDag-Erling Smørgrav
22475411d15SDag-Erling Smørgrav #if SUPPORT_C89
225bc421551SDag-Erling Smørgrav static struct tm tm;
22675411d15SDag-Erling Smørgrav #endif
227bc421551SDag-Erling Smørgrav
228bc421551SDag-Erling Smørgrav #if 2 <= HAVE_TZNAME + TZ_TIME_T
229bc421551SDag-Erling Smørgrav char * tzname[2] = {
230bc421551SDag-Erling Smørgrav (char *) wildabbr,
231bc421551SDag-Erling Smørgrav (char *) wildabbr
232bc421551SDag-Erling Smørgrav };
233bc421551SDag-Erling Smørgrav #endif
234bc421551SDag-Erling Smørgrav #if 2 <= USG_COMPAT + TZ_TIME_T
235bc421551SDag-Erling Smørgrav long timezone;
236bc421551SDag-Erling Smørgrav int daylight;
237bc421551SDag-Erling Smørgrav #endif
238bc421551SDag-Erling Smørgrav #if 2 <= ALTZONE + TZ_TIME_T
239bc421551SDag-Erling Smørgrav long altzone;
240bc421551SDag-Erling Smørgrav #endif
241bc421551SDag-Erling Smørgrav
242bc421551SDag-Erling Smørgrav /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
243bc421551SDag-Erling Smørgrav static void
init_ttinfo(struct ttinfo * s,int_fast32_t utoff,bool isdst,int desigidx)244bc421551SDag-Erling Smørgrav init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
245bc421551SDag-Erling Smørgrav {
246bc421551SDag-Erling Smørgrav s->tt_utoff = utoff;
247bc421551SDag-Erling Smørgrav s->tt_isdst = isdst;
248bc421551SDag-Erling Smørgrav s->tt_desigidx = desigidx;
249bc421551SDag-Erling Smørgrav s->tt_ttisstd = false;
250bc421551SDag-Erling Smørgrav s->tt_ttisut = false;
251bc421551SDag-Erling Smørgrav }
252bc421551SDag-Erling Smørgrav
253bc421551SDag-Erling Smørgrav /* Return true if SP's time type I does not specify local time. */
254bc421551SDag-Erling Smørgrav static bool
ttunspecified(struct state const * sp,int i)255bc421551SDag-Erling Smørgrav ttunspecified(struct state const *sp, int i)
256bc421551SDag-Erling Smørgrav {
257bc421551SDag-Erling Smørgrav char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
258bc421551SDag-Erling Smørgrav /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */
259bc421551SDag-Erling Smørgrav return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
260bc421551SDag-Erling Smørgrav }
261bc421551SDag-Erling Smørgrav
262bc421551SDag-Erling Smørgrav static int_fast32_t
detzcode(const char * const codep)263bc421551SDag-Erling Smørgrav detzcode(const char *const codep)
264bc421551SDag-Erling Smørgrav {
265bc421551SDag-Erling Smørgrav register int_fast32_t result;
266bc421551SDag-Erling Smørgrav register int i;
267bc421551SDag-Erling Smørgrav int_fast32_t one = 1;
268bc421551SDag-Erling Smørgrav int_fast32_t halfmaxval = one << (32 - 2);
269bc421551SDag-Erling Smørgrav int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
270bc421551SDag-Erling Smørgrav int_fast32_t minval = -1 - maxval;
271bc421551SDag-Erling Smørgrav
272bc421551SDag-Erling Smørgrav result = codep[0] & 0x7f;
273bc421551SDag-Erling Smørgrav for (i = 1; i < 4; ++i)
274bc421551SDag-Erling Smørgrav result = (result << 8) | (codep[i] & 0xff);
275bc421551SDag-Erling Smørgrav
276bc421551SDag-Erling Smørgrav if (codep[0] & 0x80) {
277bc421551SDag-Erling Smørgrav /* Do two's-complement negation even on non-two's-complement machines.
278bc421551SDag-Erling Smørgrav If the result would be minval - 1, return minval. */
279bc421551SDag-Erling Smørgrav result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
280bc421551SDag-Erling Smørgrav result += minval;
281bc421551SDag-Erling Smørgrav }
282bc421551SDag-Erling Smørgrav return result;
283bc421551SDag-Erling Smørgrav }
284bc421551SDag-Erling Smørgrav
285bc421551SDag-Erling Smørgrav static int_fast64_t
detzcode64(const char * const codep)286bc421551SDag-Erling Smørgrav detzcode64(const char *const codep)
287bc421551SDag-Erling Smørgrav {
288bc421551SDag-Erling Smørgrav register int_fast64_t result;
289bc421551SDag-Erling Smørgrav register int i;
290bc421551SDag-Erling Smørgrav int_fast64_t one = 1;
291bc421551SDag-Erling Smørgrav int_fast64_t halfmaxval = one << (64 - 2);
292bc421551SDag-Erling Smørgrav int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
293bc421551SDag-Erling Smørgrav int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
294bc421551SDag-Erling Smørgrav
295bc421551SDag-Erling Smørgrav result = codep[0] & 0x7f;
296bc421551SDag-Erling Smørgrav for (i = 1; i < 8; ++i)
297bc421551SDag-Erling Smørgrav result = (result << 8) | (codep[i] & 0xff);
298bc421551SDag-Erling Smørgrav
299bc421551SDag-Erling Smørgrav if (codep[0] & 0x80) {
300bc421551SDag-Erling Smørgrav /* Do two's-complement negation even on non-two's-complement machines.
301bc421551SDag-Erling Smørgrav If the result would be minval - 1, return minval. */
302bc421551SDag-Erling Smørgrav result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
303bc421551SDag-Erling Smørgrav result += minval;
304bc421551SDag-Erling Smørgrav }
305bc421551SDag-Erling Smørgrav return result;
306bc421551SDag-Erling Smørgrav }
307bc421551SDag-Erling Smørgrav
308bc421551SDag-Erling Smørgrav static void
update_tzname_etc(struct state const * sp,struct ttinfo const * ttisp)309bc421551SDag-Erling Smørgrav update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
310bc421551SDag-Erling Smørgrav {
311bc421551SDag-Erling Smørgrav #if HAVE_TZNAME
312bc421551SDag-Erling Smørgrav tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
313bc421551SDag-Erling Smørgrav #endif
314bc421551SDag-Erling Smørgrav #if USG_COMPAT
315bc421551SDag-Erling Smørgrav if (!ttisp->tt_isdst)
316bc421551SDag-Erling Smørgrav timezone = - ttisp->tt_utoff;
317bc421551SDag-Erling Smørgrav #endif
318bc421551SDag-Erling Smørgrav #if ALTZONE
319bc421551SDag-Erling Smørgrav if (ttisp->tt_isdst)
320bc421551SDag-Erling Smørgrav altzone = - ttisp->tt_utoff;
321bc421551SDag-Erling Smørgrav #endif
322bc421551SDag-Erling Smørgrav }
323bc421551SDag-Erling Smørgrav
324bc421551SDag-Erling Smørgrav /* If STDDST_MASK indicates that SP's TYPE provides useful info,
325bc421551SDag-Erling Smørgrav update tzname, timezone, and/or altzone and return STDDST_MASK,
326bc421551SDag-Erling Smørgrav diminished by the provided info if it is a specified local time.
327bc421551SDag-Erling Smørgrav Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */
328bc421551SDag-Erling Smørgrav static int
may_update_tzname_etc(int stddst_mask,struct state * sp,int type)329bc421551SDag-Erling Smørgrav may_update_tzname_etc(int stddst_mask, struct state *sp, int type)
330bc421551SDag-Erling Smørgrav {
331bc421551SDag-Erling Smørgrav struct ttinfo *ttisp = &sp->ttis[type];
332bc421551SDag-Erling Smørgrav int this_bit = 1 << ttisp->tt_isdst;
333bc421551SDag-Erling Smørgrav if (stddst_mask & this_bit) {
334bc421551SDag-Erling Smørgrav update_tzname_etc(sp, ttisp);
335bc421551SDag-Erling Smørgrav if (!ttunspecified(sp, type))
336bc421551SDag-Erling Smørgrav return stddst_mask & ~this_bit;
337bc421551SDag-Erling Smørgrav }
338bc421551SDag-Erling Smørgrav return stddst_mask;
339bc421551SDag-Erling Smørgrav }
340bc421551SDag-Erling Smørgrav
341bc421551SDag-Erling Smørgrav static void
settzname(void)342bc421551SDag-Erling Smørgrav settzname(void)
343bc421551SDag-Erling Smørgrav {
344bc421551SDag-Erling Smørgrav register struct state * const sp = lclptr;
345bc421551SDag-Erling Smørgrav register int i;
346bc421551SDag-Erling Smørgrav
347bc421551SDag-Erling Smørgrav /* If STDDST_MASK & 1 we need info about a standard time.
348bc421551SDag-Erling Smørgrav If STDDST_MASK & 2 we need info about a daylight saving time.
349bc421551SDag-Erling Smørgrav When STDDST_MASK becomes zero we can stop looking. */
350bc421551SDag-Erling Smørgrav int stddst_mask = 0;
351bc421551SDag-Erling Smørgrav
352bc421551SDag-Erling Smørgrav #if HAVE_TZNAME
353bc421551SDag-Erling Smørgrav tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
354bc421551SDag-Erling Smørgrav stddst_mask = 3;
355bc421551SDag-Erling Smørgrav #endif
356bc421551SDag-Erling Smørgrav #if USG_COMPAT
357bc421551SDag-Erling Smørgrav timezone = 0;
358bc421551SDag-Erling Smørgrav stddst_mask = 3;
359bc421551SDag-Erling Smørgrav #endif
360bc421551SDag-Erling Smørgrav #if ALTZONE
361bc421551SDag-Erling Smørgrav altzone = 0;
362bc421551SDag-Erling Smørgrav stddst_mask |= 2;
363bc421551SDag-Erling Smørgrav #endif
364bc421551SDag-Erling Smørgrav /*
365bc421551SDag-Erling Smørgrav ** And to get the latest time zone abbreviations into tzname. . .
366bc421551SDag-Erling Smørgrav */
367bc421551SDag-Erling Smørgrav if (sp) {
368bc421551SDag-Erling Smørgrav for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
369bc421551SDag-Erling Smørgrav stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
370bc421551SDag-Erling Smørgrav for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
371bc421551SDag-Erling Smørgrav stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
372bc421551SDag-Erling Smørgrav }
373bc421551SDag-Erling Smørgrav #if USG_COMPAT
374bc421551SDag-Erling Smørgrav daylight = stddst_mask >> 1 ^ 1;
375bc421551SDag-Erling Smørgrav #endif
376bc421551SDag-Erling Smørgrav }
377bc421551SDag-Erling Smørgrav
37875411d15SDag-Erling Smørgrav /* Replace bogus characters in time zone abbreviations.
37975411d15SDag-Erling Smørgrav Return 0 on success, an errno value if a time zone abbreviation is
38075411d15SDag-Erling Smørgrav too long. */
38175411d15SDag-Erling Smørgrav static int
scrub_abbrs(struct state * sp)382bc421551SDag-Erling Smørgrav scrub_abbrs(struct state *sp)
383bc421551SDag-Erling Smørgrav {
384bc421551SDag-Erling Smørgrav int i;
38575411d15SDag-Erling Smørgrav
38675411d15SDag-Erling Smørgrav /* Reject overlong abbreviations. */
38775411d15SDag-Erling Smørgrav for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
38875411d15SDag-Erling Smørgrav int len = strlen(&sp->chars[i]);
38975411d15SDag-Erling Smørgrav if (TZNAME_MAXIMUM < len)
39075411d15SDag-Erling Smørgrav return EOVERFLOW;
39175411d15SDag-Erling Smørgrav i += len + 1;
39275411d15SDag-Erling Smørgrav }
39375411d15SDag-Erling Smørgrav
39475411d15SDag-Erling Smørgrav /* Replace bogus characters. */
395bc421551SDag-Erling Smørgrav for (i = 0; i < sp->charcnt; ++i)
396bc421551SDag-Erling Smørgrav if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
397bc421551SDag-Erling Smørgrav sp->chars[i] = TZ_ABBR_ERR_CHAR;
398bc421551SDag-Erling Smørgrav
39975411d15SDag-Erling Smørgrav return 0;
400bc421551SDag-Erling Smørgrav }
401bc421551SDag-Erling Smørgrav
402bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES
403bc421551SDag-Erling Smørgrav /*
404bc421551SDag-Erling Smørgrav * Determine if there's a change in the timezone since the last time we checked.
405bc421551SDag-Erling Smørgrav * Returns: -1 on error
406bc421551SDag-Erling Smørgrav * 0 if the timezone has not changed
407bc421551SDag-Erling Smørgrav * 1 if the timezone has changed
408bc421551SDag-Erling Smørgrav */
409bc421551SDag-Erling Smørgrav static int
change_in_tz(const char * name)410bc421551SDag-Erling Smørgrav change_in_tz(const char *name)
411bc421551SDag-Erling Smørgrav {
412bc421551SDag-Erling Smørgrav static char old_name[PATH_MAX];
413bc421551SDag-Erling Smørgrav static struct stat old_sb;
414bc421551SDag-Erling Smørgrav struct stat sb;
415bc421551SDag-Erling Smørgrav int error;
416bc421551SDag-Erling Smørgrav
417bc421551SDag-Erling Smørgrav error = stat(name, &sb);
418bc421551SDag-Erling Smørgrav if (error != 0)
419bc421551SDag-Erling Smørgrav return -1;
420bc421551SDag-Erling Smørgrav
421bc421551SDag-Erling Smørgrav if (strcmp(name, old_name) != 0) {
422bc421551SDag-Erling Smørgrav strlcpy(old_name, name, sizeof(old_name));
423bc421551SDag-Erling Smørgrav old_sb = sb;
424bc421551SDag-Erling Smørgrav return 1;
425bc421551SDag-Erling Smørgrav }
426bc421551SDag-Erling Smørgrav
427bc421551SDag-Erling Smørgrav if (sb.st_dev != old_sb.st_dev ||
428bc421551SDag-Erling Smørgrav sb.st_ino != old_sb.st_ino ||
429bc421551SDag-Erling Smørgrav sb.st_ctime != old_sb.st_ctime ||
430bc421551SDag-Erling Smørgrav sb.st_mtime != old_sb.st_mtime) {
431bc421551SDag-Erling Smørgrav old_sb = sb;
432bc421551SDag-Erling Smørgrav return 1;
433bc421551SDag-Erling Smørgrav }
434bc421551SDag-Erling Smørgrav
435bc421551SDag-Erling Smørgrav return 0;
436bc421551SDag-Erling Smørgrav }
437bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */
438bc421551SDag-Erling Smørgrav #define change_in_tz(X) 1
439bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */
440bc421551SDag-Erling Smørgrav
441bc421551SDag-Erling Smørgrav /* Input buffer for data read from a compiled tz file. */
442bc421551SDag-Erling Smørgrav union input_buffer {
443bc421551SDag-Erling Smørgrav /* The first part of the buffer, interpreted as a header. */
444bc421551SDag-Erling Smørgrav struct tzhead tzhead;
445bc421551SDag-Erling Smørgrav
44646c59934SDag-Erling Smørgrav /* The entire buffer. Ideally this would have no size limits;
44746c59934SDag-Erling Smørgrav the following should suffice for practical use. */
448bc421551SDag-Erling Smørgrav char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
449bc421551SDag-Erling Smørgrav + 4 * TZ_MAX_TIMES];
450bc421551SDag-Erling Smørgrav };
451bc421551SDag-Erling Smørgrav
452bc421551SDag-Erling Smørgrav /* TZDIR with a trailing '/' rather than a trailing '\0'. */
453bc421551SDag-Erling Smørgrav static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
454bc421551SDag-Erling Smørgrav
455bc421551SDag-Erling Smørgrav /* Local storage needed for 'tzloadbody'. */
456bc421551SDag-Erling Smørgrav union local_storage {
457bc421551SDag-Erling Smørgrav /* The results of analyzing the file's contents after it is opened. */
458bc421551SDag-Erling Smørgrav struct file_analysis {
459bc421551SDag-Erling Smørgrav /* The input buffer. */
460bc421551SDag-Erling Smørgrav union input_buffer u;
461bc421551SDag-Erling Smørgrav
462bc421551SDag-Erling Smørgrav /* A temporary state used for parsing a TZ string in the file. */
463bc421551SDag-Erling Smørgrav struct state st;
464bc421551SDag-Erling Smørgrav } u;
465bc421551SDag-Erling Smørgrav
46646c59934SDag-Erling Smørgrav /* The name of the file to be opened. Ideally this would have no
46746c59934SDag-Erling Smørgrav size limits, to support arbitrarily long Zone names.
46846c59934SDag-Erling Smørgrav Limiting Zone names to 1024 bytes should suffice for practical use.
46946c59934SDag-Erling Smørgrav However, there is no need for this to be smaller than struct
47046c59934SDag-Erling Smørgrav file_analysis as that struct is allocated anyway, as the other
47146c59934SDag-Erling Smørgrav union member. */
472bc421551SDag-Erling Smørgrav char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
473bc421551SDag-Erling Smørgrav };
474bc421551SDag-Erling Smørgrav
475bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP. Read extended
476bc421551SDag-Erling Smørgrav format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
477bc421551SDag-Erling Smørgrav success, an errno value on failure. */
478bc421551SDag-Erling Smørgrav static int
tzloadbody(char const * name,struct state * sp,bool doextend,union local_storage * lsp)479bc421551SDag-Erling Smørgrav tzloadbody(char const *name, struct state *sp, bool doextend,
480bc421551SDag-Erling Smørgrav union local_storage *lsp)
481bc421551SDag-Erling Smørgrav {
482bc421551SDag-Erling Smørgrav register int i;
483bc421551SDag-Erling Smørgrav register int fid;
484bc421551SDag-Erling Smørgrav register int stored;
485bc421551SDag-Erling Smørgrav register ssize_t nread;
486bc421551SDag-Erling Smørgrav register union input_buffer *up = &lsp->u.u;
487bc421551SDag-Erling Smørgrav register int tzheadsize = sizeof(struct tzhead);
488bc421551SDag-Erling Smørgrav
489bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = false;
490bc421551SDag-Erling Smørgrav
491bc421551SDag-Erling Smørgrav if (! name) {
492bc421551SDag-Erling Smørgrav name = TZDEFAULT;
493bc421551SDag-Erling Smørgrav if (! name)
494bc421551SDag-Erling Smørgrav return EINVAL;
495bc421551SDag-Erling Smørgrav }
496bc421551SDag-Erling Smørgrav
497bc421551SDag-Erling Smørgrav if (name[0] == ':')
498bc421551SDag-Erling Smørgrav ++name;
4993e2e5eebSDag-Erling Smørgrav if (name[0] != '/') {
500bc421551SDag-Erling Smørgrav if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
501bc421551SDag-Erling Smørgrav return ENAMETOOLONG;
502bc421551SDag-Erling Smørgrav
503bc421551SDag-Erling Smørgrav /* Create a string "TZDIR/NAME". Using sprintf here
504bc421551SDag-Erling Smørgrav would pull in stdio (and would fail if the
505bc421551SDag-Erling Smørgrav resulting string length exceeded INT_MAX!). */
506bc421551SDag-Erling Smørgrav memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
507bc421551SDag-Erling Smørgrav strcpy(lsp->fullname + sizeof tzdirslash, name);
508bc421551SDag-Erling Smørgrav
509bc421551SDag-Erling Smørgrav name = lsp->fullname;
510bc421551SDag-Erling Smørgrav }
511bc421551SDag-Erling Smørgrav if (doextend) {
512bc421551SDag-Erling Smørgrav /*
513bc421551SDag-Erling Smørgrav * Detect if the timezone file has changed. Check
514bc421551SDag-Erling Smørgrav * 'doextend' to ignore TZDEFRULES; the change_in_tz()
515bc421551SDag-Erling Smørgrav * function can only keep state for a single file.
516bc421551SDag-Erling Smørgrav */
517bc421551SDag-Erling Smørgrav int ret = change_in_tz(name);
518bc421551SDag-Erling Smørgrav if (ret <= 0) {
519bc421551SDag-Erling Smørgrav /*
520bc421551SDag-Erling Smørgrav * Returns an errno value if there was an error,
521bc421551SDag-Erling Smørgrav * and 0 if the timezone had not changed.
522bc421551SDag-Erling Smørgrav */
523bc421551SDag-Erling Smørgrav return errno;
524bc421551SDag-Erling Smørgrav }
525bc421551SDag-Erling Smørgrav }
526bc421551SDag-Erling Smørgrav fid = _open(name, O_RDONLY | O_BINARY);
527bc421551SDag-Erling Smørgrav if (fid < 0)
528bc421551SDag-Erling Smørgrav return errno;
529bc421551SDag-Erling Smørgrav
530bc421551SDag-Erling Smørgrav nread = _read(fid, up->buf, sizeof up->buf);
531bc421551SDag-Erling Smørgrav if (nread < tzheadsize) {
532bc421551SDag-Erling Smørgrav int err = nread < 0 ? errno : EINVAL;
533bc421551SDag-Erling Smørgrav _close(fid);
534bc421551SDag-Erling Smørgrav return err;
535bc421551SDag-Erling Smørgrav }
536bc421551SDag-Erling Smørgrav if (_close(fid) < 0)
537bc421551SDag-Erling Smørgrav return errno;
538bc421551SDag-Erling Smørgrav for (stored = 4; stored <= 8; stored *= 2) {
539bc421551SDag-Erling Smørgrav char version = up->tzhead.tzh_version[0];
540bc421551SDag-Erling Smørgrav bool skip_datablock = stored == 4 && version;
541bc421551SDag-Erling Smørgrav int_fast32_t datablock_size;
542bc421551SDag-Erling Smørgrav int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
543bc421551SDag-Erling Smørgrav int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
544bc421551SDag-Erling Smørgrav int_fast64_t prevtr = -1;
545bc421551SDag-Erling Smørgrav int_fast32_t prevcorr;
546bc421551SDag-Erling Smørgrav int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
547bc421551SDag-Erling Smørgrav int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
548bc421551SDag-Erling Smørgrav int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
549bc421551SDag-Erling Smørgrav int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
550bc421551SDag-Erling Smørgrav char const *p = up->buf + tzheadsize;
551bc421551SDag-Erling Smørgrav /* Although tzfile(5) currently requires typecnt to be nonzero,
552bc421551SDag-Erling Smørgrav support future formats that may allow zero typecnt
553bc421551SDag-Erling Smørgrav in files that have a TZ string and no transitions. */
554bc421551SDag-Erling Smørgrav if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
555bc421551SDag-Erling Smørgrav && 0 <= typecnt && typecnt < TZ_MAX_TYPES
556bc421551SDag-Erling Smørgrav && 0 <= timecnt && timecnt < TZ_MAX_TIMES
557bc421551SDag-Erling Smørgrav && 0 <= charcnt && charcnt < TZ_MAX_CHARS
558bc421551SDag-Erling Smørgrav && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
559bc421551SDag-Erling Smørgrav && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
560bc421551SDag-Erling Smørgrav return EINVAL;
561bc421551SDag-Erling Smørgrav datablock_size
562bc421551SDag-Erling Smørgrav = (timecnt * stored /* ats */
563bc421551SDag-Erling Smørgrav + timecnt /* types */
564bc421551SDag-Erling Smørgrav + typecnt * 6 /* ttinfos */
565bc421551SDag-Erling Smørgrav + charcnt /* chars */
566bc421551SDag-Erling Smørgrav + leapcnt * (stored + 4) /* lsinfos */
567bc421551SDag-Erling Smørgrav + ttisstdcnt /* ttisstds */
568bc421551SDag-Erling Smørgrav + ttisutcnt); /* ttisuts */
569bc421551SDag-Erling Smørgrav if (nread < tzheadsize + datablock_size)
570bc421551SDag-Erling Smørgrav return EINVAL;
571bc421551SDag-Erling Smørgrav if (skip_datablock)
572bc421551SDag-Erling Smørgrav p += datablock_size;
573bc421551SDag-Erling Smørgrav else {
574bc421551SDag-Erling Smørgrav if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
575bc421551SDag-Erling Smørgrav && (ttisutcnt == typecnt || ttisutcnt == 0)))
576bc421551SDag-Erling Smørgrav return EINVAL;
577bc421551SDag-Erling Smørgrav
578bc421551SDag-Erling Smørgrav sp->leapcnt = leapcnt;
579bc421551SDag-Erling Smørgrav sp->timecnt = timecnt;
580bc421551SDag-Erling Smørgrav sp->typecnt = typecnt;
581bc421551SDag-Erling Smørgrav sp->charcnt = charcnt;
582bc421551SDag-Erling Smørgrav
583bc421551SDag-Erling Smørgrav /* Read transitions, discarding those out of time_t range.
584bc421551SDag-Erling Smørgrav But pretend the last transition before TIME_T_MIN
585bc421551SDag-Erling Smørgrav occurred at TIME_T_MIN. */
586bc421551SDag-Erling Smørgrav timecnt = 0;
587bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) {
588bc421551SDag-Erling Smørgrav int_fast64_t at
589bc421551SDag-Erling Smørgrav = stored == 4 ? detzcode(p) : detzcode64(p);
590bc421551SDag-Erling Smørgrav sp->types[i] = at <= TIME_T_MAX;
591bc421551SDag-Erling Smørgrav if (sp->types[i]) {
592bc421551SDag-Erling Smørgrav time_t attime
593bc421551SDag-Erling Smørgrav = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
594bc421551SDag-Erling Smørgrav ? TIME_T_MIN : at);
595bc421551SDag-Erling Smørgrav if (timecnt && attime <= sp->ats[timecnt - 1]) {
596bc421551SDag-Erling Smørgrav if (attime < sp->ats[timecnt - 1])
597bc421551SDag-Erling Smørgrav return EINVAL;
598bc421551SDag-Erling Smørgrav sp->types[i - 1] = 0;
599bc421551SDag-Erling Smørgrav timecnt--;
600bc421551SDag-Erling Smørgrav }
601bc421551SDag-Erling Smørgrav sp->ats[timecnt++] = attime;
602bc421551SDag-Erling Smørgrav }
603bc421551SDag-Erling Smørgrav p += stored;
604bc421551SDag-Erling Smørgrav }
605bc421551SDag-Erling Smørgrav
606bc421551SDag-Erling Smørgrav timecnt = 0;
607bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) {
608bc421551SDag-Erling Smørgrav unsigned char typ = *p++;
609bc421551SDag-Erling Smørgrav if (sp->typecnt <= typ)
610bc421551SDag-Erling Smørgrav return EINVAL;
611bc421551SDag-Erling Smørgrav if (sp->types[i])
612bc421551SDag-Erling Smørgrav sp->types[timecnt++] = typ;
613bc421551SDag-Erling Smørgrav }
614bc421551SDag-Erling Smørgrav sp->timecnt = timecnt;
615bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) {
616bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp;
617bc421551SDag-Erling Smørgrav unsigned char isdst, desigidx;
618bc421551SDag-Erling Smørgrav
619bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i];
620bc421551SDag-Erling Smørgrav ttisp->tt_utoff = detzcode(p);
621bc421551SDag-Erling Smørgrav p += 4;
622bc421551SDag-Erling Smørgrav isdst = *p++;
623bc421551SDag-Erling Smørgrav if (! (isdst < 2))
624bc421551SDag-Erling Smørgrav return EINVAL;
625bc421551SDag-Erling Smørgrav ttisp->tt_isdst = isdst;
626bc421551SDag-Erling Smørgrav desigidx = *p++;
627bc421551SDag-Erling Smørgrav if (! (desigidx < sp->charcnt))
628bc421551SDag-Erling Smørgrav return EINVAL;
629bc421551SDag-Erling Smørgrav ttisp->tt_desigidx = desigidx;
630bc421551SDag-Erling Smørgrav }
631bc421551SDag-Erling Smørgrav for (i = 0; i < sp->charcnt; ++i)
632bc421551SDag-Erling Smørgrav sp->chars[i] = *p++;
633bc421551SDag-Erling Smørgrav /* Ensure '\0'-terminated, and make it safe to call
634bc421551SDag-Erling Smørgrav ttunspecified later. */
635bc421551SDag-Erling Smørgrav memset(&sp->chars[i], 0, CHARS_EXTRA);
636bc421551SDag-Erling Smørgrav
637bc421551SDag-Erling Smørgrav /* Read leap seconds, discarding those out of time_t range. */
638bc421551SDag-Erling Smørgrav leapcnt = 0;
639bc421551SDag-Erling Smørgrav for (i = 0; i < sp->leapcnt; ++i) {
640bc421551SDag-Erling Smørgrav int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
641bc421551SDag-Erling Smørgrav int_fast32_t corr = detzcode(p + stored);
642bc421551SDag-Erling Smørgrav p += stored + 4;
643bc421551SDag-Erling Smørgrav
644bc421551SDag-Erling Smørgrav /* Leap seconds cannot occur before the Epoch,
645bc421551SDag-Erling Smørgrav or out of order. */
646bc421551SDag-Erling Smørgrav if (tr <= prevtr)
647bc421551SDag-Erling Smørgrav return EINVAL;
648bc421551SDag-Erling Smørgrav
649bc421551SDag-Erling Smørgrav /* To avoid other botches in this code, each leap second's
650bc421551SDag-Erling Smørgrav correction must differ from the previous one's by 1
651bc421551SDag-Erling Smørgrav second or less, except that the first correction can be
652bc421551SDag-Erling Smørgrav any value; these requirements are more generous than
653bc421551SDag-Erling Smørgrav RFC 8536, to allow future RFC extensions. */
654bc421551SDag-Erling Smørgrav if (! (i == 0
655bc421551SDag-Erling Smørgrav || (prevcorr < corr
656bc421551SDag-Erling Smørgrav ? corr == prevcorr + 1
657bc421551SDag-Erling Smørgrav : (corr == prevcorr
658bc421551SDag-Erling Smørgrav || corr == prevcorr - 1))))
659bc421551SDag-Erling Smørgrav return EINVAL;
660bc421551SDag-Erling Smørgrav prevtr = tr;
661bc421551SDag-Erling Smørgrav prevcorr = corr;
662bc421551SDag-Erling Smørgrav
663bc421551SDag-Erling Smørgrav if (tr <= TIME_T_MAX) {
664bc421551SDag-Erling Smørgrav sp->lsis[leapcnt].ls_trans = tr;
665bc421551SDag-Erling Smørgrav sp->lsis[leapcnt].ls_corr = corr;
666bc421551SDag-Erling Smørgrav leapcnt++;
667bc421551SDag-Erling Smørgrav }
668bc421551SDag-Erling Smørgrav }
669bc421551SDag-Erling Smørgrav sp->leapcnt = leapcnt;
670bc421551SDag-Erling Smørgrav
671bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) {
672bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp;
673bc421551SDag-Erling Smørgrav
674bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i];
675bc421551SDag-Erling Smørgrav if (ttisstdcnt == 0)
676bc421551SDag-Erling Smørgrav ttisp->tt_ttisstd = false;
677bc421551SDag-Erling Smørgrav else {
678bc421551SDag-Erling Smørgrav if (*p != true && *p != false)
679bc421551SDag-Erling Smørgrav return EINVAL;
680bc421551SDag-Erling Smørgrav ttisp->tt_ttisstd = *p++;
681bc421551SDag-Erling Smørgrav }
682bc421551SDag-Erling Smørgrav }
683bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) {
684bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp;
685bc421551SDag-Erling Smørgrav
686bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i];
687bc421551SDag-Erling Smørgrav if (ttisutcnt == 0)
688bc421551SDag-Erling Smørgrav ttisp->tt_ttisut = false;
689bc421551SDag-Erling Smørgrav else {
690bc421551SDag-Erling Smørgrav if (*p != true && *p != false)
691bc421551SDag-Erling Smørgrav return EINVAL;
692bc421551SDag-Erling Smørgrav ttisp->tt_ttisut = *p++;
693bc421551SDag-Erling Smørgrav }
694bc421551SDag-Erling Smørgrav }
695bc421551SDag-Erling Smørgrav }
696bc421551SDag-Erling Smørgrav
697bc421551SDag-Erling Smørgrav nread -= p - up->buf;
698bc421551SDag-Erling Smørgrav memmove(up->buf, p, nread);
699bc421551SDag-Erling Smørgrav
700bc421551SDag-Erling Smørgrav /* If this is an old file, we're done. */
701bc421551SDag-Erling Smørgrav if (!version)
702bc421551SDag-Erling Smørgrav break;
703bc421551SDag-Erling Smørgrav }
704bc421551SDag-Erling Smørgrav if (doextend && nread > 2 &&
705bc421551SDag-Erling Smørgrav up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
706bc421551SDag-Erling Smørgrav sp->typecnt + 2 <= TZ_MAX_TYPES) {
707bc421551SDag-Erling Smørgrav struct state *ts = &lsp->u.st;
708bc421551SDag-Erling Smørgrav
709bc421551SDag-Erling Smørgrav up->buf[nread - 1] = '\0';
710bc421551SDag-Erling Smørgrav if (tzparse(&up->buf[1], ts, sp)) {
711bc421551SDag-Erling Smørgrav
712bc421551SDag-Erling Smørgrav /* Attempt to reuse existing abbreviations.
713bc421551SDag-Erling Smørgrav Without this, America/Anchorage would be right on
714bc421551SDag-Erling Smørgrav the edge after 2037 when TZ_MAX_CHARS is 50, as
715bc421551SDag-Erling Smørgrav sp->charcnt equals 40 (for LMT AST AWT APT AHST
716bc421551SDag-Erling Smørgrav AHDT YST AKDT AKST) and ts->charcnt equals 10
717bc421551SDag-Erling Smørgrav (for AKST AKDT). Reusing means sp->charcnt can
718bc421551SDag-Erling Smørgrav stay 40 in this example. */
719bc421551SDag-Erling Smørgrav int gotabbr = 0;
720bc421551SDag-Erling Smørgrav int charcnt = sp->charcnt;
721bc421551SDag-Erling Smørgrav for (i = 0; i < ts->typecnt; i++) {
722bc421551SDag-Erling Smørgrav char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
723bc421551SDag-Erling Smørgrav int j;
724bc421551SDag-Erling Smørgrav for (j = 0; j < charcnt; j++)
725bc421551SDag-Erling Smørgrav if (strcmp(sp->chars + j, tsabbr) == 0) {
726bc421551SDag-Erling Smørgrav ts->ttis[i].tt_desigidx = j;
727bc421551SDag-Erling Smørgrav gotabbr++;
728bc421551SDag-Erling Smørgrav break;
729bc421551SDag-Erling Smørgrav }
730bc421551SDag-Erling Smørgrav if (! (j < charcnt)) {
731bc421551SDag-Erling Smørgrav int tsabbrlen = strlen(tsabbr);
732bc421551SDag-Erling Smørgrav if (j + tsabbrlen < TZ_MAX_CHARS) {
733bc421551SDag-Erling Smørgrav strcpy(sp->chars + j, tsabbr);
734bc421551SDag-Erling Smørgrav charcnt = j + tsabbrlen + 1;
735bc421551SDag-Erling Smørgrav ts->ttis[i].tt_desigidx = j;
736bc421551SDag-Erling Smørgrav gotabbr++;
737bc421551SDag-Erling Smørgrav }
738bc421551SDag-Erling Smørgrav }
739bc421551SDag-Erling Smørgrav }
740bc421551SDag-Erling Smørgrav if (gotabbr == ts->typecnt) {
741bc421551SDag-Erling Smørgrav sp->charcnt = charcnt;
742bc421551SDag-Erling Smørgrav
743bc421551SDag-Erling Smørgrav /* Ignore any trailing, no-op transitions generated
744bc421551SDag-Erling Smørgrav by zic as they don't help here and can run afoul
745bc421551SDag-Erling Smørgrav of bugs in zic 2016j or earlier. */
746bc421551SDag-Erling Smørgrav while (1 < sp->timecnt
747bc421551SDag-Erling Smørgrav && (sp->types[sp->timecnt - 1]
748bc421551SDag-Erling Smørgrav == sp->types[sp->timecnt - 2]))
749bc421551SDag-Erling Smørgrav sp->timecnt--;
750bc421551SDag-Erling Smørgrav
75146c59934SDag-Erling Smørgrav sp->goahead = ts->goahead;
75246c59934SDag-Erling Smørgrav
75346c59934SDag-Erling Smørgrav for (i = 0; i < ts->timecnt; i++) {
754bc421551SDag-Erling Smørgrav time_t t = ts->ats[i];
755bc421551SDag-Erling Smørgrav if (increment_overflow_time(&t, leapcorr(sp, t))
756bc421551SDag-Erling Smørgrav || (0 < sp->timecnt
757bc421551SDag-Erling Smørgrav && t <= sp->ats[sp->timecnt - 1]))
758bc421551SDag-Erling Smørgrav continue;
75946c59934SDag-Erling Smørgrav if (TZ_MAX_TIMES <= sp->timecnt) {
76046c59934SDag-Erling Smørgrav sp->goahead = false;
76146c59934SDag-Erling Smørgrav break;
76246c59934SDag-Erling Smørgrav }
763bc421551SDag-Erling Smørgrav sp->ats[sp->timecnt] = t;
764bc421551SDag-Erling Smørgrav sp->types[sp->timecnt] = (sp->typecnt
765bc421551SDag-Erling Smørgrav + ts->types[i]);
766bc421551SDag-Erling Smørgrav sp->timecnt++;
767bc421551SDag-Erling Smørgrav }
768bc421551SDag-Erling Smørgrav for (i = 0; i < ts->typecnt; i++)
769bc421551SDag-Erling Smørgrav sp->ttis[sp->typecnt++] = ts->ttis[i];
770bc421551SDag-Erling Smørgrav }
771bc421551SDag-Erling Smørgrav }
772bc421551SDag-Erling Smørgrav }
773bc421551SDag-Erling Smørgrav if (sp->typecnt == 0)
774bc421551SDag-Erling Smørgrav return EINVAL;
775bc421551SDag-Erling Smørgrav
776bc421551SDag-Erling Smørgrav /* Infer sp->defaulttype from the data. Although this default
777bc421551SDag-Erling Smørgrav type is always zero for data from recent tzdb releases,
778bc421551SDag-Erling Smørgrav things are trickier for data from tzdb 2018e or earlier.
779bc421551SDag-Erling Smørgrav
780bc421551SDag-Erling Smørgrav The first set of heuristics work around bugs in 32-bit data
781bc421551SDag-Erling Smørgrav generated by tzdb 2013c or earlier. The workaround is for
782bc421551SDag-Erling Smørgrav zones like Australia/Macquarie where timestamps before the
783bc421551SDag-Erling Smørgrav first transition have a time type that is not the earliest
784bc421551SDag-Erling Smørgrav standard-time type. See:
785bc421551SDag-Erling Smørgrav https://mm.icann.org/pipermail/tz/2013-May/019368.html */
786bc421551SDag-Erling Smørgrav /*
787bc421551SDag-Erling Smørgrav ** If type 0 does not specify local time, or is unused in transitions,
788bc421551SDag-Erling Smørgrav ** it's the type to use for early times.
789bc421551SDag-Erling Smørgrav */
790bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i)
791bc421551SDag-Erling Smørgrav if (sp->types[i] == 0)
792bc421551SDag-Erling Smørgrav break;
793bc421551SDag-Erling Smørgrav i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
794bc421551SDag-Erling Smørgrav /*
795bc421551SDag-Erling Smørgrav ** Absent the above,
796bc421551SDag-Erling Smørgrav ** if there are transition times
797bc421551SDag-Erling Smørgrav ** and the first transition is to a daylight time
798bc421551SDag-Erling Smørgrav ** find the standard type less than and closest to
799bc421551SDag-Erling Smørgrav ** the type of the first transition.
800bc421551SDag-Erling Smørgrav */
801bc421551SDag-Erling Smørgrav if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
802bc421551SDag-Erling Smørgrav i = sp->types[0];
803bc421551SDag-Erling Smørgrav while (--i >= 0)
804bc421551SDag-Erling Smørgrav if (!sp->ttis[i].tt_isdst)
805bc421551SDag-Erling Smørgrav break;
806bc421551SDag-Erling Smørgrav }
807bc421551SDag-Erling Smørgrav /* The next heuristics are for data generated by tzdb 2018e or
808bc421551SDag-Erling Smørgrav earlier, for zones like EST5EDT where the first transition
809bc421551SDag-Erling Smørgrav is to DST. */
810bc421551SDag-Erling Smørgrav /*
811bc421551SDag-Erling Smørgrav ** If no result yet, find the first standard type.
812bc421551SDag-Erling Smørgrav ** If there is none, punt to type zero.
813bc421551SDag-Erling Smørgrav */
814bc421551SDag-Erling Smørgrav if (i < 0) {
815bc421551SDag-Erling Smørgrav i = 0;
816bc421551SDag-Erling Smørgrav while (sp->ttis[i].tt_isdst)
817bc421551SDag-Erling Smørgrav if (++i >= sp->typecnt) {
818bc421551SDag-Erling Smørgrav i = 0;
819bc421551SDag-Erling Smørgrav break;
820bc421551SDag-Erling Smørgrav }
821bc421551SDag-Erling Smørgrav }
822bc421551SDag-Erling Smørgrav /* A simple 'sp->defaulttype = 0;' would suffice here if we
823bc421551SDag-Erling Smørgrav didn't have to worry about 2018e-or-earlier data. Even
824bc421551SDag-Erling Smørgrav simpler would be to remove the defaulttype member and just
825bc421551SDag-Erling Smørgrav use 0 in its place. */
826bc421551SDag-Erling Smørgrav sp->defaulttype = i;
827bc421551SDag-Erling Smørgrav
828bc421551SDag-Erling Smørgrav return 0;
829bc421551SDag-Erling Smørgrav }
830bc421551SDag-Erling Smørgrav
831bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP. Read extended
832bc421551SDag-Erling Smørgrav format if DOEXTEND. Return 0 on success, an errno value on failure. */
833bc421551SDag-Erling Smørgrav static int
tzload(char const * name,struct state * sp,bool doextend)834bc421551SDag-Erling Smørgrav tzload(char const *name, struct state *sp, bool doextend)
835bc421551SDag-Erling Smørgrav {
836bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
837bc421551SDag-Erling Smørgrav union local_storage *lsp = malloc(sizeof *lsp);
838bc421551SDag-Erling Smørgrav if (!lsp) {
839bc421551SDag-Erling Smørgrav return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
840bc421551SDag-Erling Smørgrav } else {
841bc421551SDag-Erling Smørgrav int err = tzloadbody(name, sp, doextend, lsp);
842bc421551SDag-Erling Smørgrav free(lsp);
843bc421551SDag-Erling Smørgrav return err;
844bc421551SDag-Erling Smørgrav }
845bc421551SDag-Erling Smørgrav #else
846bc421551SDag-Erling Smørgrav union local_storage ls;
847bc421551SDag-Erling Smørgrav return tzloadbody(name, sp, doextend, &ls);
848bc421551SDag-Erling Smørgrav #endif
849bc421551SDag-Erling Smørgrav }
850bc421551SDag-Erling Smørgrav
851bc421551SDag-Erling Smørgrav static const int mon_lengths[2][MONSPERYEAR] = {
852bc421551SDag-Erling Smørgrav { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
853bc421551SDag-Erling Smørgrav { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
854bc421551SDag-Erling Smørgrav };
855bc421551SDag-Erling Smørgrav
856bc421551SDag-Erling Smørgrav static const int year_lengths[2] = {
857bc421551SDag-Erling Smørgrav DAYSPERNYEAR, DAYSPERLYEAR
858bc421551SDag-Erling Smørgrav };
859bc421551SDag-Erling Smørgrav
860bc421551SDag-Erling Smørgrav /* Is C an ASCII digit? */
861bc421551SDag-Erling Smørgrav static bool
is_digit(char c)862bc421551SDag-Erling Smørgrav is_digit(char c)
863bc421551SDag-Erling Smørgrav {
864bc421551SDag-Erling Smørgrav return '0' <= c && c <= '9';
865bc421551SDag-Erling Smørgrav }
866bc421551SDag-Erling Smørgrav
867bc421551SDag-Erling Smørgrav /*
868bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, scan until a character that is not
869bc421551SDag-Erling Smørgrav ** a valid character in a time zone abbreviation is found.
870bc421551SDag-Erling Smørgrav ** Return a pointer to that character.
871bc421551SDag-Erling Smørgrav */
872bc421551SDag-Erling Smørgrav
87375411d15SDag-Erling Smørgrav ATTRIBUTE_REPRODUCIBLE static const char *
getzname(register const char * strp)874bc421551SDag-Erling Smørgrav getzname(register const char *strp)
875bc421551SDag-Erling Smørgrav {
876bc421551SDag-Erling Smørgrav register char c;
877bc421551SDag-Erling Smørgrav
878bc421551SDag-Erling Smørgrav while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
879bc421551SDag-Erling Smørgrav c != '+')
880bc421551SDag-Erling Smørgrav ++strp;
881bc421551SDag-Erling Smørgrav return strp;
882bc421551SDag-Erling Smørgrav }
883bc421551SDag-Erling Smørgrav
884bc421551SDag-Erling Smørgrav /*
885bc421551SDag-Erling Smørgrav ** Given a pointer into an extended timezone string, scan until the ending
886bc421551SDag-Erling Smørgrav ** delimiter of the time zone abbreviation is located.
887bc421551SDag-Erling Smørgrav ** Return a pointer to the delimiter.
888bc421551SDag-Erling Smørgrav **
889bc421551SDag-Erling Smørgrav ** As with getzname above, the legal character set is actually quite
890bc421551SDag-Erling Smørgrav ** restricted, with other characters producing undefined results.
891bc421551SDag-Erling Smørgrav ** We don't do any checking here; checking is done later in common-case code.
892bc421551SDag-Erling Smørgrav */
893bc421551SDag-Erling Smørgrav
89475411d15SDag-Erling Smørgrav ATTRIBUTE_REPRODUCIBLE static const char *
getqzname(register const char * strp,const int delim)895bc421551SDag-Erling Smørgrav getqzname(register const char *strp, const int delim)
896bc421551SDag-Erling Smørgrav {
897bc421551SDag-Erling Smørgrav register int c;
898bc421551SDag-Erling Smørgrav
899bc421551SDag-Erling Smørgrav while ((c = *strp) != '\0' && c != delim)
900bc421551SDag-Erling Smørgrav ++strp;
901bc421551SDag-Erling Smørgrav return strp;
902bc421551SDag-Erling Smørgrav }
903bc421551SDag-Erling Smørgrav
904bc421551SDag-Erling Smørgrav /*
905bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number from that string.
906bc421551SDag-Erling Smørgrav ** Check that the number is within a specified range; if it is not, return
907bc421551SDag-Erling Smørgrav ** NULL.
908bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number.
909bc421551SDag-Erling Smørgrav */
910bc421551SDag-Erling Smørgrav
911bc421551SDag-Erling Smørgrav static const char *
getnum(register const char * strp,int * const nump,const int min,const int max)912bc421551SDag-Erling Smørgrav getnum(register const char *strp, int *const nump, const int min, const int max)
913bc421551SDag-Erling Smørgrav {
914bc421551SDag-Erling Smørgrav register char c;
915bc421551SDag-Erling Smørgrav register int num;
916bc421551SDag-Erling Smørgrav
917bc421551SDag-Erling Smørgrav if (strp == NULL || !is_digit(c = *strp))
918bc421551SDag-Erling Smørgrav return NULL;
919bc421551SDag-Erling Smørgrav num = 0;
920bc421551SDag-Erling Smørgrav do {
921bc421551SDag-Erling Smørgrav num = num * 10 + (c - '0');
922bc421551SDag-Erling Smørgrav if (num > max)
923bc421551SDag-Erling Smørgrav return NULL; /* illegal value */
924bc421551SDag-Erling Smørgrav c = *++strp;
925bc421551SDag-Erling Smørgrav } while (is_digit(c));
926bc421551SDag-Erling Smørgrav if (num < min)
927bc421551SDag-Erling Smørgrav return NULL; /* illegal value */
928bc421551SDag-Erling Smørgrav *nump = num;
929bc421551SDag-Erling Smørgrav return strp;
930bc421551SDag-Erling Smørgrav }
931bc421551SDag-Erling Smørgrav
932bc421551SDag-Erling Smørgrav /*
933bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number of seconds,
934bc421551SDag-Erling Smørgrav ** in hh[:mm[:ss]] form, from the string.
935bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL.
936bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number
937bc421551SDag-Erling Smørgrav ** of seconds.
938bc421551SDag-Erling Smørgrav */
939bc421551SDag-Erling Smørgrav
940bc421551SDag-Erling Smørgrav static const char *
getsecs(register const char * strp,int_fast32_t * const secsp)941bc421551SDag-Erling Smørgrav getsecs(register const char *strp, int_fast32_t *const secsp)
942bc421551SDag-Erling Smørgrav {
943bc421551SDag-Erling Smørgrav int num;
944bc421551SDag-Erling Smørgrav int_fast32_t secsperhour = SECSPERHOUR;
945bc421551SDag-Erling Smørgrav
946bc421551SDag-Erling Smørgrav /*
94746c59934SDag-Erling Smørgrav ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like
94846c59934SDag-Erling Smørgrav ** "M10.4.6/26", which does not conform to POSIX,
949bc421551SDag-Erling Smørgrav ** but which specifies the equivalent of
950bc421551SDag-Erling Smørgrav ** "02:00 on the first Sunday on or after 23 Oct".
951bc421551SDag-Erling Smørgrav */
952bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
953bc421551SDag-Erling Smørgrav if (strp == NULL)
954bc421551SDag-Erling Smørgrav return NULL;
955bc421551SDag-Erling Smørgrav *secsp = num * secsperhour;
956bc421551SDag-Erling Smørgrav if (*strp == ':') {
957bc421551SDag-Erling Smørgrav ++strp;
958bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
959bc421551SDag-Erling Smørgrav if (strp == NULL)
960bc421551SDag-Erling Smørgrav return NULL;
961bc421551SDag-Erling Smørgrav *secsp += num * SECSPERMIN;
962bc421551SDag-Erling Smørgrav if (*strp == ':') {
963bc421551SDag-Erling Smørgrav ++strp;
964bc421551SDag-Erling Smørgrav /* 'SECSPERMIN' allows for leap seconds. */
965bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, SECSPERMIN);
966bc421551SDag-Erling Smørgrav if (strp == NULL)
967bc421551SDag-Erling Smørgrav return NULL;
968bc421551SDag-Erling Smørgrav *secsp += num;
969bc421551SDag-Erling Smørgrav }
970bc421551SDag-Erling Smørgrav }
971bc421551SDag-Erling Smørgrav return strp;
972bc421551SDag-Erling Smørgrav }
973bc421551SDag-Erling Smørgrav
974bc421551SDag-Erling Smørgrav /*
975bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract an offset, in
976bc421551SDag-Erling Smørgrav ** [+-]hh[:mm[:ss]] form, from the string.
977bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL.
978bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the time.
979bc421551SDag-Erling Smørgrav */
980bc421551SDag-Erling Smørgrav
981bc421551SDag-Erling Smørgrav static const char *
getoffset(register const char * strp,int_fast32_t * const offsetp)982bc421551SDag-Erling Smørgrav getoffset(register const char *strp, int_fast32_t *const offsetp)
983bc421551SDag-Erling Smørgrav {
984bc421551SDag-Erling Smørgrav register bool neg = false;
985bc421551SDag-Erling Smørgrav
986bc421551SDag-Erling Smørgrav if (*strp == '-') {
987bc421551SDag-Erling Smørgrav neg = true;
988bc421551SDag-Erling Smørgrav ++strp;
989bc421551SDag-Erling Smørgrav } else if (*strp == '+')
990bc421551SDag-Erling Smørgrav ++strp;
991bc421551SDag-Erling Smørgrav strp = getsecs(strp, offsetp);
992bc421551SDag-Erling Smørgrav if (strp == NULL)
993bc421551SDag-Erling Smørgrav return NULL; /* illegal time */
994bc421551SDag-Erling Smørgrav if (neg)
995bc421551SDag-Erling Smørgrav *offsetp = -*offsetp;
996bc421551SDag-Erling Smørgrav return strp;
997bc421551SDag-Erling Smørgrav }
998bc421551SDag-Erling Smørgrav
999bc421551SDag-Erling Smørgrav /*
1000bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a rule in the form
100146c59934SDag-Erling Smørgrav ** date[/time]. See POSIX Base Definitions section 8.3 variable TZ
100246c59934SDag-Erling Smørgrav ** for the format of "date" and "time".
1003bc421551SDag-Erling Smørgrav ** If a valid rule is not found, return NULL.
1004bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the rule.
1005bc421551SDag-Erling Smørgrav */
1006bc421551SDag-Erling Smørgrav
1007bc421551SDag-Erling Smørgrav static const char *
getrule(const char * strp,register struct rule * const rulep)1008bc421551SDag-Erling Smørgrav getrule(const char *strp, register struct rule *const rulep)
1009bc421551SDag-Erling Smørgrav {
1010bc421551SDag-Erling Smørgrav if (*strp == 'J') {
1011bc421551SDag-Erling Smørgrav /*
1012bc421551SDag-Erling Smørgrav ** Julian day.
1013bc421551SDag-Erling Smørgrav */
1014bc421551SDag-Erling Smørgrav rulep->r_type = JULIAN_DAY;
1015bc421551SDag-Erling Smørgrav ++strp;
1016bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1017bc421551SDag-Erling Smørgrav } else if (*strp == 'M') {
1018bc421551SDag-Erling Smørgrav /*
1019bc421551SDag-Erling Smørgrav ** Month, week, day.
1020bc421551SDag-Erling Smørgrav */
1021bc421551SDag-Erling Smørgrav rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
1022bc421551SDag-Erling Smørgrav ++strp;
1023bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1024bc421551SDag-Erling Smørgrav if (strp == NULL)
1025bc421551SDag-Erling Smørgrav return NULL;
1026bc421551SDag-Erling Smørgrav if (*strp++ != '.')
1027bc421551SDag-Erling Smørgrav return NULL;
1028bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_week, 1, 5);
1029bc421551SDag-Erling Smørgrav if (strp == NULL)
1030bc421551SDag-Erling Smørgrav return NULL;
1031bc421551SDag-Erling Smørgrav if (*strp++ != '.')
1032bc421551SDag-Erling Smørgrav return NULL;
1033bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1034bc421551SDag-Erling Smørgrav } else if (is_digit(*strp)) {
1035bc421551SDag-Erling Smørgrav /*
1036bc421551SDag-Erling Smørgrav ** Day of year.
1037bc421551SDag-Erling Smørgrav */
1038bc421551SDag-Erling Smørgrav rulep->r_type = DAY_OF_YEAR;
1039bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1040bc421551SDag-Erling Smørgrav } else return NULL; /* invalid format */
1041bc421551SDag-Erling Smørgrav if (strp == NULL)
1042bc421551SDag-Erling Smørgrav return NULL;
1043bc421551SDag-Erling Smørgrav if (*strp == '/') {
1044bc421551SDag-Erling Smørgrav /*
1045bc421551SDag-Erling Smørgrav ** Time specified.
1046bc421551SDag-Erling Smørgrav */
1047bc421551SDag-Erling Smørgrav ++strp;
1048bc421551SDag-Erling Smørgrav strp = getoffset(strp, &rulep->r_time);
1049bc421551SDag-Erling Smørgrav } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1050bc421551SDag-Erling Smørgrav return strp;
1051bc421551SDag-Erling Smørgrav }
1052bc421551SDag-Erling Smørgrav
1053bc421551SDag-Erling Smørgrav /*
1054bc421551SDag-Erling Smørgrav ** Given a year, a rule, and the offset from UT at the time that rule takes
1055bc421551SDag-Erling Smørgrav ** effect, calculate the year-relative time that rule takes effect.
1056bc421551SDag-Erling Smørgrav */
1057bc421551SDag-Erling Smørgrav
1058bc421551SDag-Erling Smørgrav static int_fast32_t
transtime(const int year,register const struct rule * const rulep,const int_fast32_t offset)1059bc421551SDag-Erling Smørgrav transtime(const int year, register const struct rule *const rulep,
1060bc421551SDag-Erling Smørgrav const int_fast32_t offset)
1061bc421551SDag-Erling Smørgrav {
1062bc421551SDag-Erling Smørgrav register bool leapyear;
1063bc421551SDag-Erling Smørgrav register int_fast32_t value;
1064bc421551SDag-Erling Smørgrav register int i;
1065bc421551SDag-Erling Smørgrav int d, m1, yy0, yy1, yy2, dow;
1066bc421551SDag-Erling Smørgrav
1067bc421551SDag-Erling Smørgrav leapyear = isleap(year);
1068bc421551SDag-Erling Smørgrav switch (rulep->r_type) {
1069bc421551SDag-Erling Smørgrav
1070bc421551SDag-Erling Smørgrav case JULIAN_DAY:
1071bc421551SDag-Erling Smørgrav /*
1072bc421551SDag-Erling Smørgrav ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1073bc421551SDag-Erling Smørgrav ** years.
1074bc421551SDag-Erling Smørgrav ** In non-leap years, or if the day number is 59 or less, just
1075bc421551SDag-Erling Smørgrav ** add SECSPERDAY times the day number-1 to the time of
1076bc421551SDag-Erling Smørgrav ** January 1, midnight, to get the day.
1077bc421551SDag-Erling Smørgrav */
1078bc421551SDag-Erling Smørgrav value = (rulep->r_day - 1) * SECSPERDAY;
1079bc421551SDag-Erling Smørgrav if (leapyear && rulep->r_day >= 60)
1080bc421551SDag-Erling Smørgrav value += SECSPERDAY;
1081bc421551SDag-Erling Smørgrav break;
1082bc421551SDag-Erling Smørgrav
1083bc421551SDag-Erling Smørgrav case DAY_OF_YEAR:
1084bc421551SDag-Erling Smørgrav /*
1085bc421551SDag-Erling Smørgrav ** n - day of year.
1086bc421551SDag-Erling Smørgrav ** Just add SECSPERDAY times the day number to the time of
1087bc421551SDag-Erling Smørgrav ** January 1, midnight, to get the day.
1088bc421551SDag-Erling Smørgrav */
1089bc421551SDag-Erling Smørgrav value = rulep->r_day * SECSPERDAY;
1090bc421551SDag-Erling Smørgrav break;
1091bc421551SDag-Erling Smørgrav
1092bc421551SDag-Erling Smørgrav case MONTH_NTH_DAY_OF_WEEK:
1093bc421551SDag-Erling Smørgrav /*
1094bc421551SDag-Erling Smørgrav ** Mm.n.d - nth "dth day" of month m.
1095bc421551SDag-Erling Smørgrav */
1096bc421551SDag-Erling Smørgrav
1097bc421551SDag-Erling Smørgrav /*
1098bc421551SDag-Erling Smørgrav ** Use Zeller's Congruence to get day-of-week of first day of
1099bc421551SDag-Erling Smørgrav ** month.
1100bc421551SDag-Erling Smørgrav */
1101bc421551SDag-Erling Smørgrav m1 = (rulep->r_mon + 9) % 12 + 1;
1102bc421551SDag-Erling Smørgrav yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1103bc421551SDag-Erling Smørgrav yy1 = yy0 / 100;
1104bc421551SDag-Erling Smørgrav yy2 = yy0 % 100;
1105bc421551SDag-Erling Smørgrav dow = ((26 * m1 - 2) / 10 +
1106bc421551SDag-Erling Smørgrav 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1107bc421551SDag-Erling Smørgrav if (dow < 0)
1108bc421551SDag-Erling Smørgrav dow += DAYSPERWEEK;
1109bc421551SDag-Erling Smørgrav
1110bc421551SDag-Erling Smørgrav /*
1111bc421551SDag-Erling Smørgrav ** "dow" is the day-of-week of the first day of the month. Get
1112bc421551SDag-Erling Smørgrav ** the day-of-month (zero-origin) of the first "dow" day of the
1113bc421551SDag-Erling Smørgrav ** month.
1114bc421551SDag-Erling Smørgrav */
1115bc421551SDag-Erling Smørgrav d = rulep->r_day - dow;
1116bc421551SDag-Erling Smørgrav if (d < 0)
1117bc421551SDag-Erling Smørgrav d += DAYSPERWEEK;
1118bc421551SDag-Erling Smørgrav for (i = 1; i < rulep->r_week; ++i) {
1119bc421551SDag-Erling Smørgrav if (d + DAYSPERWEEK >=
1120bc421551SDag-Erling Smørgrav mon_lengths[leapyear][rulep->r_mon - 1])
1121bc421551SDag-Erling Smørgrav break;
1122bc421551SDag-Erling Smørgrav d += DAYSPERWEEK;
1123bc421551SDag-Erling Smørgrav }
1124bc421551SDag-Erling Smørgrav
1125bc421551SDag-Erling Smørgrav /*
1126bc421551SDag-Erling Smørgrav ** "d" is the day-of-month (zero-origin) of the day we want.
1127bc421551SDag-Erling Smørgrav */
1128bc421551SDag-Erling Smørgrav value = d * SECSPERDAY;
1129bc421551SDag-Erling Smørgrav for (i = 0; i < rulep->r_mon - 1; ++i)
1130bc421551SDag-Erling Smørgrav value += mon_lengths[leapyear][i] * SECSPERDAY;
1131bc421551SDag-Erling Smørgrav break;
1132bc421551SDag-Erling Smørgrav
1133bc421551SDag-Erling Smørgrav default: unreachable();
1134bc421551SDag-Erling Smørgrav }
1135bc421551SDag-Erling Smørgrav
1136bc421551SDag-Erling Smørgrav /*
1137bc421551SDag-Erling Smørgrav ** "value" is the year-relative time of 00:00:00 UT on the day in
1138bc421551SDag-Erling Smørgrav ** question. To get the year-relative time of the specified local
1139bc421551SDag-Erling Smørgrav ** time on that day, add the transition time and the current offset
1140bc421551SDag-Erling Smørgrav ** from UT.
1141bc421551SDag-Erling Smørgrav */
1142bc421551SDag-Erling Smørgrav return value + rulep->r_time + offset;
1143bc421551SDag-Erling Smørgrav }
1144bc421551SDag-Erling Smørgrav
1145bc421551SDag-Erling Smørgrav /*
114646c59934SDag-Erling Smørgrav ** Given a POSIX.1-2017-style TZ string, fill in the rule tables as
1147bc421551SDag-Erling Smørgrav ** appropriate.
1148bc421551SDag-Erling Smørgrav */
1149bc421551SDag-Erling Smørgrav
1150bc421551SDag-Erling Smørgrav static bool
tzparse(const char * name,struct state * sp,struct state const * basep)115146c59934SDag-Erling Smørgrav tzparse(const char *name, struct state *sp, struct state const *basep)
1152bc421551SDag-Erling Smørgrav {
1153bc421551SDag-Erling Smørgrav const char * stdname;
1154bc421551SDag-Erling Smørgrav const char * dstname;
1155bc421551SDag-Erling Smørgrav int_fast32_t stdoffset;
1156bc421551SDag-Erling Smørgrav int_fast32_t dstoffset;
1157bc421551SDag-Erling Smørgrav register char * cp;
1158bc421551SDag-Erling Smørgrav register bool load_ok;
1159bc421551SDag-Erling Smørgrav ptrdiff_t stdlen, dstlen, charcnt;
1160bc421551SDag-Erling Smørgrav time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
1161bc421551SDag-Erling Smørgrav
1162bc421551SDag-Erling Smørgrav stdname = name;
1163bc421551SDag-Erling Smørgrav if (*name == '<') {
1164bc421551SDag-Erling Smørgrav name++;
1165bc421551SDag-Erling Smørgrav stdname = name;
1166bc421551SDag-Erling Smørgrav name = getqzname(name, '>');
1167bc421551SDag-Erling Smørgrav if (*name != '>')
1168bc421551SDag-Erling Smørgrav return false;
1169bc421551SDag-Erling Smørgrav stdlen = name - stdname;
1170bc421551SDag-Erling Smørgrav name++;
1171bc421551SDag-Erling Smørgrav } else {
1172bc421551SDag-Erling Smørgrav name = getzname(name);
1173bc421551SDag-Erling Smørgrav stdlen = name - stdname;
1174bc421551SDag-Erling Smørgrav }
117575411d15SDag-Erling Smørgrav if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
1176bc421551SDag-Erling Smørgrav return false;
1177bc421551SDag-Erling Smørgrav name = getoffset(name, &stdoffset);
1178bc421551SDag-Erling Smørgrav if (name == NULL)
1179bc421551SDag-Erling Smørgrav return false;
1180bc421551SDag-Erling Smørgrav charcnt = stdlen + 1;
1181bc421551SDag-Erling Smørgrav if (basep) {
1182bc421551SDag-Erling Smørgrav if (0 < basep->timecnt)
1183bc421551SDag-Erling Smørgrav atlo = basep->ats[basep->timecnt - 1];
1184bc421551SDag-Erling Smørgrav load_ok = false;
1185bc421551SDag-Erling Smørgrav sp->leapcnt = basep->leapcnt;
1186bc421551SDag-Erling Smørgrav memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
1187bc421551SDag-Erling Smørgrav } else {
1188bc421551SDag-Erling Smørgrav load_ok = tzload(TZDEFRULES, sp, false) == 0;
1189bc421551SDag-Erling Smørgrav if (!load_ok)
1190bc421551SDag-Erling Smørgrav sp->leapcnt = 0; /* So, we're off a little. */
1191bc421551SDag-Erling Smørgrav }
1192bc421551SDag-Erling Smørgrav if (0 < sp->leapcnt)
1193bc421551SDag-Erling Smørgrav leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
119446c59934SDag-Erling Smørgrav sp->goback = sp->goahead = false;
1195bc421551SDag-Erling Smørgrav if (*name != '\0') {
1196bc421551SDag-Erling Smørgrav if (*name == '<') {
1197bc421551SDag-Erling Smørgrav dstname = ++name;
1198bc421551SDag-Erling Smørgrav name = getqzname(name, '>');
1199bc421551SDag-Erling Smørgrav if (*name != '>')
1200bc421551SDag-Erling Smørgrav return false;
1201bc421551SDag-Erling Smørgrav dstlen = name - dstname;
1202bc421551SDag-Erling Smørgrav name++;
1203bc421551SDag-Erling Smørgrav } else {
1204bc421551SDag-Erling Smørgrav dstname = name;
1205bc421551SDag-Erling Smørgrav name = getzname(name);
1206bc421551SDag-Erling Smørgrav dstlen = name - dstname; /* length of DST abbr. */
1207bc421551SDag-Erling Smørgrav }
120875411d15SDag-Erling Smørgrav if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
1209bc421551SDag-Erling Smørgrav return false;
1210bc421551SDag-Erling Smørgrav charcnt += dstlen + 1;
1211bc421551SDag-Erling Smørgrav if (*name != '\0' && *name != ',' && *name != ';') {
1212bc421551SDag-Erling Smørgrav name = getoffset(name, &dstoffset);
1213bc421551SDag-Erling Smørgrav if (name == NULL)
1214bc421551SDag-Erling Smørgrav return false;
1215bc421551SDag-Erling Smørgrav } else dstoffset = stdoffset - SECSPERHOUR;
1216bc421551SDag-Erling Smørgrav if (*name == '\0' && !load_ok)
1217bc421551SDag-Erling Smørgrav name = TZDEFRULESTRING;
1218bc421551SDag-Erling Smørgrav if (*name == ',' || *name == ';') {
1219bc421551SDag-Erling Smørgrav struct rule start;
1220bc421551SDag-Erling Smørgrav struct rule end;
1221bc421551SDag-Erling Smørgrav register int year;
1222bc421551SDag-Erling Smørgrav register int timecnt;
1223bc421551SDag-Erling Smørgrav time_t janfirst;
1224bc421551SDag-Erling Smørgrav int_fast32_t janoffset = 0;
1225bc421551SDag-Erling Smørgrav int yearbeg, yearlim;
1226bc421551SDag-Erling Smørgrav
1227bc421551SDag-Erling Smørgrav ++name;
1228bc421551SDag-Erling Smørgrav if ((name = getrule(name, &start)) == NULL)
1229bc421551SDag-Erling Smørgrav return false;
1230bc421551SDag-Erling Smørgrav if (*name++ != ',')
1231bc421551SDag-Erling Smørgrav return false;
1232bc421551SDag-Erling Smørgrav if ((name = getrule(name, &end)) == NULL)
1233bc421551SDag-Erling Smørgrav return false;
1234bc421551SDag-Erling Smørgrav if (*name != '\0')
1235bc421551SDag-Erling Smørgrav return false;
1236bc421551SDag-Erling Smørgrav sp->typecnt = 2; /* standard time and DST */
1237bc421551SDag-Erling Smørgrav /*
1238bc421551SDag-Erling Smørgrav ** Two transitions per year, from EPOCH_YEAR forward.
1239bc421551SDag-Erling Smørgrav */
1240bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1241bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1242bc421551SDag-Erling Smørgrav timecnt = 0;
1243bc421551SDag-Erling Smørgrav janfirst = 0;
1244bc421551SDag-Erling Smørgrav yearbeg = EPOCH_YEAR;
1245bc421551SDag-Erling Smørgrav
1246bc421551SDag-Erling Smørgrav do {
1247bc421551SDag-Erling Smørgrav int_fast32_t yearsecs
1248bc421551SDag-Erling Smørgrav = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
12491365bb72SDag-Erling Smørgrav time_t janfirst1 = janfirst;
1250bc421551SDag-Erling Smørgrav yearbeg--;
12511365bb72SDag-Erling Smørgrav if (increment_overflow_time(&janfirst1, -yearsecs)) {
1252bc421551SDag-Erling Smørgrav janoffset = -yearsecs;
1253bc421551SDag-Erling Smørgrav break;
1254bc421551SDag-Erling Smørgrav }
12551365bb72SDag-Erling Smørgrav janfirst = janfirst1;
1256bc421551SDag-Erling Smørgrav } while (atlo < janfirst
1257bc421551SDag-Erling Smørgrav && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1258bc421551SDag-Erling Smørgrav
1259bc421551SDag-Erling Smørgrav while (true) {
1260bc421551SDag-Erling Smørgrav int_fast32_t yearsecs
1261bc421551SDag-Erling Smørgrav = year_lengths[isleap(yearbeg)] * SECSPERDAY;
1262bc421551SDag-Erling Smørgrav int yearbeg1 = yearbeg;
1263bc421551SDag-Erling Smørgrav time_t janfirst1 = janfirst;
1264bc421551SDag-Erling Smørgrav if (increment_overflow_time(&janfirst1, yearsecs)
1265bc421551SDag-Erling Smørgrav || increment_overflow(&yearbeg1, 1)
1266bc421551SDag-Erling Smørgrav || atlo <= janfirst1)
1267bc421551SDag-Erling Smørgrav break;
1268bc421551SDag-Erling Smørgrav yearbeg = yearbeg1;
1269bc421551SDag-Erling Smørgrav janfirst = janfirst1;
1270bc421551SDag-Erling Smørgrav }
1271bc421551SDag-Erling Smørgrav
1272bc421551SDag-Erling Smørgrav yearlim = yearbeg;
127346c59934SDag-Erling Smørgrav if (increment_overflow(&yearlim, years_of_observations))
1274bc421551SDag-Erling Smørgrav yearlim = INT_MAX;
1275bc421551SDag-Erling Smørgrav for (year = yearbeg; year < yearlim; year++) {
1276bc421551SDag-Erling Smørgrav int_fast32_t
1277bc421551SDag-Erling Smørgrav starttime = transtime(year, &start, stdoffset),
1278bc421551SDag-Erling Smørgrav endtime = transtime(year, &end, dstoffset);
1279bc421551SDag-Erling Smørgrav int_fast32_t
1280bc421551SDag-Erling Smørgrav yearsecs = (year_lengths[isleap(year)]
1281bc421551SDag-Erling Smørgrav * SECSPERDAY);
1282bc421551SDag-Erling Smørgrav bool reversed = endtime < starttime;
1283bc421551SDag-Erling Smørgrav if (reversed) {
1284bc421551SDag-Erling Smørgrav int_fast32_t swap = starttime;
1285bc421551SDag-Erling Smørgrav starttime = endtime;
1286bc421551SDag-Erling Smørgrav endtime = swap;
1287bc421551SDag-Erling Smørgrav }
1288bc421551SDag-Erling Smørgrav if (reversed
1289bc421551SDag-Erling Smørgrav || (starttime < endtime
1290bc421551SDag-Erling Smørgrav && endtime - starttime < yearsecs)) {
1291bc421551SDag-Erling Smørgrav if (TZ_MAX_TIMES - 2 < timecnt)
1292bc421551SDag-Erling Smørgrav break;
1293bc421551SDag-Erling Smørgrav sp->ats[timecnt] = janfirst;
1294bc421551SDag-Erling Smørgrav if (! increment_overflow_time
1295bc421551SDag-Erling Smørgrav (&sp->ats[timecnt],
1296bc421551SDag-Erling Smørgrav janoffset + starttime)
1297bc421551SDag-Erling Smørgrav && atlo <= sp->ats[timecnt])
1298bc421551SDag-Erling Smørgrav sp->types[timecnt++] = !reversed;
1299bc421551SDag-Erling Smørgrav sp->ats[timecnt] = janfirst;
1300bc421551SDag-Erling Smørgrav if (! increment_overflow_time
1301bc421551SDag-Erling Smørgrav (&sp->ats[timecnt],
1302bc421551SDag-Erling Smørgrav janoffset + endtime)
1303bc421551SDag-Erling Smørgrav && atlo <= sp->ats[timecnt]) {
1304bc421551SDag-Erling Smørgrav sp->types[timecnt++] = reversed;
1305bc421551SDag-Erling Smørgrav }
1306bc421551SDag-Erling Smørgrav }
1307bc421551SDag-Erling Smørgrav if (endtime < leaplo) {
1308bc421551SDag-Erling Smørgrav yearlim = year;
1309bc421551SDag-Erling Smørgrav if (increment_overflow(&yearlim,
131046c59934SDag-Erling Smørgrav years_of_observations))
1311bc421551SDag-Erling Smørgrav yearlim = INT_MAX;
1312bc421551SDag-Erling Smørgrav }
1313bc421551SDag-Erling Smørgrav if (increment_overflow_time
1314bc421551SDag-Erling Smørgrav (&janfirst, janoffset + yearsecs))
1315bc421551SDag-Erling Smørgrav break;
1316bc421551SDag-Erling Smørgrav janoffset = 0;
1317bc421551SDag-Erling Smørgrav }
1318bc421551SDag-Erling Smørgrav sp->timecnt = timecnt;
1319bc421551SDag-Erling Smørgrav if (! timecnt) {
1320bc421551SDag-Erling Smørgrav sp->ttis[0] = sp->ttis[1];
1321bc421551SDag-Erling Smørgrav sp->typecnt = 1; /* Perpetual DST. */
132246c59934SDag-Erling Smørgrav } else if (years_of_observations <= year - yearbeg)
1323bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = true;
1324bc421551SDag-Erling Smørgrav } else {
1325bc421551SDag-Erling Smørgrav register int_fast32_t theirstdoffset;
1326bc421551SDag-Erling Smørgrav register int_fast32_t theirdstoffset;
1327bc421551SDag-Erling Smørgrav register int_fast32_t theiroffset;
1328bc421551SDag-Erling Smørgrav register bool isdst;
1329bc421551SDag-Erling Smørgrav register int i;
1330bc421551SDag-Erling Smørgrav register int j;
1331bc421551SDag-Erling Smørgrav
1332bc421551SDag-Erling Smørgrav if (*name != '\0')
1333bc421551SDag-Erling Smørgrav return false;
1334bc421551SDag-Erling Smørgrav /*
1335bc421551SDag-Erling Smørgrav ** Initial values of theirstdoffset and theirdstoffset.
1336bc421551SDag-Erling Smørgrav */
1337bc421551SDag-Erling Smørgrav theirstdoffset = 0;
1338bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) {
1339bc421551SDag-Erling Smørgrav j = sp->types[i];
1340bc421551SDag-Erling Smørgrav if (!sp->ttis[j].tt_isdst) {
1341bc421551SDag-Erling Smørgrav theirstdoffset =
1342bc421551SDag-Erling Smørgrav - sp->ttis[j].tt_utoff;
1343bc421551SDag-Erling Smørgrav break;
1344bc421551SDag-Erling Smørgrav }
1345bc421551SDag-Erling Smørgrav }
1346bc421551SDag-Erling Smørgrav theirdstoffset = 0;
1347bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) {
1348bc421551SDag-Erling Smørgrav j = sp->types[i];
1349bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst) {
1350bc421551SDag-Erling Smørgrav theirdstoffset =
1351bc421551SDag-Erling Smørgrav - sp->ttis[j].tt_utoff;
1352bc421551SDag-Erling Smørgrav break;
1353bc421551SDag-Erling Smørgrav }
1354bc421551SDag-Erling Smørgrav }
1355bc421551SDag-Erling Smørgrav /*
1356bc421551SDag-Erling Smørgrav ** Initially we're assumed to be in standard time.
1357bc421551SDag-Erling Smørgrav */
1358bc421551SDag-Erling Smørgrav isdst = false;
1359bc421551SDag-Erling Smørgrav /*
1360bc421551SDag-Erling Smørgrav ** Now juggle transition times and types
1361bc421551SDag-Erling Smørgrav ** tracking offsets as you do.
1362bc421551SDag-Erling Smørgrav */
1363bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) {
1364bc421551SDag-Erling Smørgrav j = sp->types[i];
1365bc421551SDag-Erling Smørgrav sp->types[i] = sp->ttis[j].tt_isdst;
1366bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_ttisut) {
1367bc421551SDag-Erling Smørgrav /* No adjustment to transition time */
1368bc421551SDag-Erling Smørgrav } else {
1369bc421551SDag-Erling Smørgrav /*
1370bc421551SDag-Erling Smørgrav ** If daylight saving time is in
1371bc421551SDag-Erling Smørgrav ** effect, and the transition time was
1372bc421551SDag-Erling Smørgrav ** not specified as standard time, add
1373bc421551SDag-Erling Smørgrav ** the daylight saving time offset to
1374bc421551SDag-Erling Smørgrav ** the transition time; otherwise, add
1375bc421551SDag-Erling Smørgrav ** the standard time offset to the
1376bc421551SDag-Erling Smørgrav ** transition time.
1377bc421551SDag-Erling Smørgrav */
1378bc421551SDag-Erling Smørgrav /*
1379bc421551SDag-Erling Smørgrav ** Transitions from DST to DDST
1380bc421551SDag-Erling Smørgrav ** will effectively disappear since
138146c59934SDag-Erling Smørgrav ** POSIX.1-2017 provides for only one
138246c59934SDag-Erling Smørgrav ** DST offset.
1383bc421551SDag-Erling Smørgrav */
1384bc421551SDag-Erling Smørgrav if (isdst && !sp->ttis[j].tt_ttisstd) {
1385bc421551SDag-Erling Smørgrav sp->ats[i] += dstoffset -
1386bc421551SDag-Erling Smørgrav theirdstoffset;
1387bc421551SDag-Erling Smørgrav } else {
1388bc421551SDag-Erling Smørgrav sp->ats[i] += stdoffset -
1389bc421551SDag-Erling Smørgrav theirstdoffset;
1390bc421551SDag-Erling Smørgrav }
1391bc421551SDag-Erling Smørgrav }
1392bc421551SDag-Erling Smørgrav theiroffset = -sp->ttis[j].tt_utoff;
1393bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst)
1394bc421551SDag-Erling Smørgrav theirdstoffset = theiroffset;
1395bc421551SDag-Erling Smørgrav else theirstdoffset = theiroffset;
1396bc421551SDag-Erling Smørgrav }
1397bc421551SDag-Erling Smørgrav /*
1398bc421551SDag-Erling Smørgrav ** Finally, fill in ttis.
1399bc421551SDag-Erling Smørgrav */
1400bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1401bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1402bc421551SDag-Erling Smørgrav sp->typecnt = 2;
1403bc421551SDag-Erling Smørgrav }
1404bc421551SDag-Erling Smørgrav } else {
1405bc421551SDag-Erling Smørgrav dstlen = 0;
1406bc421551SDag-Erling Smørgrav sp->typecnt = 1; /* only standard time */
1407bc421551SDag-Erling Smørgrav sp->timecnt = 0;
1408bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1409bc421551SDag-Erling Smørgrav }
141046c59934SDag-Erling Smørgrav sp->defaulttype = 0;
1411bc421551SDag-Erling Smørgrav sp->charcnt = charcnt;
1412bc421551SDag-Erling Smørgrav cp = sp->chars;
1413bc421551SDag-Erling Smørgrav memcpy(cp, stdname, stdlen);
1414bc421551SDag-Erling Smørgrav cp += stdlen;
1415bc421551SDag-Erling Smørgrav *cp++ = '\0';
1416bc421551SDag-Erling Smørgrav if (dstlen != 0) {
1417bc421551SDag-Erling Smørgrav memcpy(cp, dstname, dstlen);
1418bc421551SDag-Erling Smørgrav *(cp + dstlen) = '\0';
1419bc421551SDag-Erling Smørgrav }
1420bc421551SDag-Erling Smørgrav return true;
1421bc421551SDag-Erling Smørgrav }
1422bc421551SDag-Erling Smørgrav
1423bc421551SDag-Erling Smørgrav static void
gmtload(struct state * const sp)1424bc421551SDag-Erling Smørgrav gmtload(struct state *const sp)
1425bc421551SDag-Erling Smørgrav {
1426bc421551SDag-Erling Smørgrav if (tzload(etc_utc, sp, true) != 0)
1427bc421551SDag-Erling Smørgrav tzparse("UTC0", sp, NULL);
1428bc421551SDag-Erling Smørgrav }
1429bc421551SDag-Erling Smørgrav
1430bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES
1431bc421551SDag-Erling Smørgrav static int
recheck_tzdata()1432bc421551SDag-Erling Smørgrav recheck_tzdata()
1433bc421551SDag-Erling Smørgrav {
1434bc421551SDag-Erling Smørgrav static time_t last_checked;
1435bc421551SDag-Erling Smørgrav struct timespec now;
1436bc421551SDag-Erling Smørgrav time_t current_time;
1437bc421551SDag-Erling Smørgrav int error;
1438bc421551SDag-Erling Smørgrav
1439bc421551SDag-Erling Smørgrav /*
1440bc421551SDag-Erling Smørgrav * We want to recheck the timezone file every 61 sec.
1441bc421551SDag-Erling Smørgrav */
1442bc421551SDag-Erling Smørgrav error = clock_gettime(CLOCK_MONOTONIC, &now);
1443bc421551SDag-Erling Smørgrav if (error < 0) {
1444bc421551SDag-Erling Smørgrav /* XXX: Can we somehow report this? */
1445bc421551SDag-Erling Smørgrav return 0;
1446bc421551SDag-Erling Smørgrav }
1447bc421551SDag-Erling Smørgrav
1448bc421551SDag-Erling Smørgrav current_time = now.tv_sec;
1449bc421551SDag-Erling Smørgrav if ((current_time - last_checked > DETECT_TZ_CHANGES_INTERVAL) ||
1450bc421551SDag-Erling Smørgrav (last_checked > current_time)) {
1451bc421551SDag-Erling Smørgrav last_checked = current_time;
1452bc421551SDag-Erling Smørgrav return 1;
1453bc421551SDag-Erling Smørgrav }
1454bc421551SDag-Erling Smørgrav
1455bc421551SDag-Erling Smørgrav return 0;
1456bc421551SDag-Erling Smørgrav }
1457bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */
1458bc421551SDag-Erling Smørgrav #define recheck_tzdata() 0
1459bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */
1460bc421551SDag-Erling Smørgrav
1461bc421551SDag-Erling Smørgrav /* Initialize *SP to a value appropriate for the TZ setting NAME.
1462bc421551SDag-Erling Smørgrav Return 0 on success, an errno value on failure. */
1463bc421551SDag-Erling Smørgrav static int
zoneinit(struct state * sp,char const * name)1464bc421551SDag-Erling Smørgrav zoneinit(struct state *sp, char const *name)
1465bc421551SDag-Erling Smørgrav {
1466bc421551SDag-Erling Smørgrav if (name && ! name[0]) {
1467bc421551SDag-Erling Smørgrav /*
1468bc421551SDag-Erling Smørgrav ** User wants it fast rather than right.
1469bc421551SDag-Erling Smørgrav */
1470bc421551SDag-Erling Smørgrav sp->leapcnt = 0; /* so, we're off a little */
1471bc421551SDag-Erling Smørgrav sp->timecnt = 0;
1472bc421551SDag-Erling Smørgrav sp->typecnt = 0;
1473bc421551SDag-Erling Smørgrav sp->charcnt = 0;
1474bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = false;
1475bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], 0, false, 0);
1476bc421551SDag-Erling Smørgrav strcpy(sp->chars, utc);
1477bc421551SDag-Erling Smørgrav sp->defaulttype = 0;
1478bc421551SDag-Erling Smørgrav return 0;
1479bc421551SDag-Erling Smørgrav } else {
1480bc421551SDag-Erling Smørgrav int err = tzload(name, sp, true);
1481bc421551SDag-Erling Smørgrav if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
1482bc421551SDag-Erling Smørgrav err = 0;
1483bc421551SDag-Erling Smørgrav if (err == 0)
148475411d15SDag-Erling Smørgrav err = scrub_abbrs(sp);
1485bc421551SDag-Erling Smørgrav return err;
1486bc421551SDag-Erling Smørgrav }
1487bc421551SDag-Erling Smørgrav }
1488bc421551SDag-Erling Smørgrav
1489bc421551SDag-Erling Smørgrav static void
tzset_unlocked_name(char const * name)149071e0c890SDag-Erling Smørgrav tzset_unlocked_name(char const *name)
1491bc421551SDag-Erling Smørgrav {
1492bc421551SDag-Erling Smørgrav struct state *sp = lclptr;
1493bc421551SDag-Erling Smørgrav int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1494bc421551SDag-Erling Smørgrav if (lcl < 0
1495bc421551SDag-Erling Smørgrav ? lcl_is_set < 0
1496bc421551SDag-Erling Smørgrav : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1497bc421551SDag-Erling Smørgrav if (recheck_tzdata() == 0)
1498bc421551SDag-Erling Smørgrav return;
1499bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
1500bc421551SDag-Erling Smørgrav if (! sp)
1501bc421551SDag-Erling Smørgrav lclptr = sp = malloc(sizeof *lclptr);
1502bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */
1503bc421551SDag-Erling Smørgrav if (sp) {
1504bc421551SDag-Erling Smørgrav if (zoneinit(sp, name) != 0)
1505bc421551SDag-Erling Smørgrav zoneinit(sp, "");
1506bc421551SDag-Erling Smørgrav if (0 < lcl)
1507bc421551SDag-Erling Smørgrav strcpy(lcl_TZname, name);
1508bc421551SDag-Erling Smørgrav }
1509bc421551SDag-Erling Smørgrav settzname();
1510bc421551SDag-Erling Smørgrav lcl_is_set = lcl;
1511bc421551SDag-Erling Smørgrav }
1512bc421551SDag-Erling Smørgrav
151371e0c890SDag-Erling Smørgrav static void
tzset_unlocked(void)151471e0c890SDag-Erling Smørgrav tzset_unlocked(void)
151571e0c890SDag-Erling Smørgrav {
151671e0c890SDag-Erling Smørgrav tzset_unlocked_name(getenv("TZ"));
151771e0c890SDag-Erling Smørgrav }
151871e0c890SDag-Erling Smørgrav
1519bc421551SDag-Erling Smørgrav void
tzset(void)1520bc421551SDag-Erling Smørgrav tzset(void)
1521bc421551SDag-Erling Smørgrav {
1522bc421551SDag-Erling Smørgrav if (lock() != 0)
1523bc421551SDag-Erling Smørgrav return;
1524bc421551SDag-Erling Smørgrav tzset_unlocked();
1525bc421551SDag-Erling Smørgrav unlock();
1526bc421551SDag-Erling Smørgrav }
1527bc421551SDag-Erling Smørgrav
152871e0c890SDag-Erling Smørgrav void
freebsd13_tzsetwall(void)152971e0c890SDag-Erling Smørgrav freebsd13_tzsetwall(void)
153071e0c890SDag-Erling Smørgrav {
153171e0c890SDag-Erling Smørgrav if (lock() != 0)
153271e0c890SDag-Erling Smørgrav return;
153371e0c890SDag-Erling Smørgrav tzset_unlocked_name(NULL);
153471e0c890SDag-Erling Smørgrav unlock();
153571e0c890SDag-Erling Smørgrav }
153671e0c890SDag-Erling Smørgrav __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
153771e0c890SDag-Erling Smørgrav __warn_references(tzsetwall,
153871e0c890SDag-Erling Smørgrav "warning: tzsetwall() is deprecated, use tzset() instead.");
153971e0c890SDag-Erling Smørgrav
1540bc421551SDag-Erling Smørgrav static void
gmtcheck(void)1541bc421551SDag-Erling Smørgrav gmtcheck(void)
1542bc421551SDag-Erling Smørgrav {
1543bc421551SDag-Erling Smørgrav static bool gmt_is_set;
1544bc421551SDag-Erling Smørgrav if (lock() != 0)
1545bc421551SDag-Erling Smørgrav return;
1546bc421551SDag-Erling Smørgrav if (! gmt_is_set) {
1547bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
1548bc421551SDag-Erling Smørgrav gmtptr = malloc(sizeof *gmtptr);
1549bc421551SDag-Erling Smørgrav #endif
1550bc421551SDag-Erling Smørgrav if (gmtptr)
1551bc421551SDag-Erling Smørgrav gmtload(gmtptr);
1552bc421551SDag-Erling Smørgrav gmt_is_set = true;
1553bc421551SDag-Erling Smørgrav }
1554bc421551SDag-Erling Smørgrav unlock();
1555bc421551SDag-Erling Smørgrav }
1556bc421551SDag-Erling Smørgrav
1557bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
1558bc421551SDag-Erling Smørgrav
1559bc421551SDag-Erling Smørgrav timezone_t
tzalloc(char const * name)1560bc421551SDag-Erling Smørgrav tzalloc(char const *name)
1561bc421551SDag-Erling Smørgrav {
1562bc421551SDag-Erling Smørgrav timezone_t sp = malloc(sizeof *sp);
1563bc421551SDag-Erling Smørgrav if (sp) {
1564bc421551SDag-Erling Smørgrav int err = zoneinit(sp, name);
1565bc421551SDag-Erling Smørgrav if (err != 0) {
1566bc421551SDag-Erling Smørgrav free(sp);
1567bc421551SDag-Erling Smørgrav errno = err;
1568bc421551SDag-Erling Smørgrav return NULL;
1569bc421551SDag-Erling Smørgrav }
1570bc421551SDag-Erling Smørgrav } else if (!HAVE_MALLOC_ERRNO)
1571bc421551SDag-Erling Smørgrav errno = ENOMEM;
1572bc421551SDag-Erling Smørgrav return sp;
1573bc421551SDag-Erling Smørgrav }
1574bc421551SDag-Erling Smørgrav
1575bc421551SDag-Erling Smørgrav void
tzfree(timezone_t sp)1576bc421551SDag-Erling Smørgrav tzfree(timezone_t sp)
1577bc421551SDag-Erling Smørgrav {
1578bc421551SDag-Erling Smørgrav free(sp);
1579bc421551SDag-Erling Smørgrav }
1580bc421551SDag-Erling Smørgrav
1581bc421551SDag-Erling Smørgrav /*
1582bc421551SDag-Erling Smørgrav ** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
1583bc421551SDag-Erling Smørgrav ** ctime_r are obsolescent and have potential security problems that
1584bc421551SDag-Erling Smørgrav ** ctime_rz would share. Callers can instead use localtime_rz + strftime.
1585bc421551SDag-Erling Smørgrav **
1586bc421551SDag-Erling Smørgrav ** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1587bc421551SDag-Erling Smørgrav ** in zones with three or more time zone abbreviations.
1588bc421551SDag-Erling Smørgrav ** Callers can instead use localtime_rz + strftime.
1589bc421551SDag-Erling Smørgrav */
1590bc421551SDag-Erling Smørgrav
1591bc421551SDag-Erling Smørgrav #endif
1592bc421551SDag-Erling Smørgrav
1593bc421551SDag-Erling Smørgrav /*
1594bc421551SDag-Erling Smørgrav ** The easy way to behave "as if no library function calls" localtime
1595bc421551SDag-Erling Smørgrav ** is to not call it, so we drop its guts into "localsub", which can be
1596bc421551SDag-Erling Smørgrav ** freely called. (And no, the PANS doesn't require the above behavior,
1597bc421551SDag-Erling Smørgrav ** but it *is* desirable.)
1598bc421551SDag-Erling Smørgrav **
1599bc421551SDag-Erling Smørgrav ** If successful and SETNAME is nonzero,
1600bc421551SDag-Erling Smørgrav ** set the applicable parts of tzname, timezone and altzone;
160146c59934SDag-Erling Smørgrav ** however, it's OK to omit this step
160246c59934SDag-Erling Smørgrav ** if the timezone is compatible with POSIX.1-2017
1603bc421551SDag-Erling Smørgrav ** since in that case tzset should have already done this step correctly.
1604bc421551SDag-Erling Smørgrav ** SETNAME's type is int_fast32_t for compatibility with gmtsub,
1605bc421551SDag-Erling Smørgrav ** but it is actually a boolean and its value should be 0 or 1.
1606bc421551SDag-Erling Smørgrav */
1607bc421551SDag-Erling Smørgrav
1608bc421551SDag-Erling Smørgrav /*ARGSUSED*/
1609bc421551SDag-Erling Smørgrav static struct tm *
localsub(struct state const * sp,time_t const * timep,int_fast32_t setname,struct tm * const tmp)1610bc421551SDag-Erling Smørgrav localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1611bc421551SDag-Erling Smørgrav struct tm *const tmp)
1612bc421551SDag-Erling Smørgrav {
1613bc421551SDag-Erling Smørgrav register const struct ttinfo * ttisp;
1614bc421551SDag-Erling Smørgrav register int i;
1615bc421551SDag-Erling Smørgrav register struct tm * result;
1616bc421551SDag-Erling Smørgrav const time_t t = *timep;
1617bc421551SDag-Erling Smørgrav
1618bc421551SDag-Erling Smørgrav if (sp == NULL) {
1619bc421551SDag-Erling Smørgrav /* Don't bother to set tzname etc.; tzset has already done it. */
1620bc421551SDag-Erling Smørgrav return gmtsub(gmtptr, timep, 0, tmp);
1621bc421551SDag-Erling Smørgrav }
1622bc421551SDag-Erling Smørgrav if ((sp->goback && t < sp->ats[0]) ||
1623bc421551SDag-Erling Smørgrav (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1624bc421551SDag-Erling Smørgrav time_t newt;
1625bc421551SDag-Erling Smørgrav register time_t seconds;
1626bc421551SDag-Erling Smørgrav register time_t years;
1627bc421551SDag-Erling Smørgrav
1628bc421551SDag-Erling Smørgrav if (t < sp->ats[0])
1629bc421551SDag-Erling Smørgrav seconds = sp->ats[0] - t;
1630bc421551SDag-Erling Smørgrav else seconds = t - sp->ats[sp->timecnt - 1];
1631bc421551SDag-Erling Smørgrav --seconds;
1632bc421551SDag-Erling Smørgrav
1633bc421551SDag-Erling Smørgrav /* Beware integer overflow, as SECONDS might
1634bc421551SDag-Erling Smørgrav be close to the maximum time_t. */
1635bc421551SDag-Erling Smørgrav years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
1636bc421551SDag-Erling Smørgrav seconds = years * AVGSECSPERYEAR;
1637bc421551SDag-Erling Smørgrav years += YEARSPERREPEAT;
1638bc421551SDag-Erling Smørgrav if (t < sp->ats[0])
1639bc421551SDag-Erling Smørgrav newt = t + seconds + SECSPERREPEAT;
1640bc421551SDag-Erling Smørgrav else
1641bc421551SDag-Erling Smørgrav newt = t - seconds - SECSPERREPEAT;
1642bc421551SDag-Erling Smørgrav
1643bc421551SDag-Erling Smørgrav if (newt < sp->ats[0] ||
1644bc421551SDag-Erling Smørgrav newt > sp->ats[sp->timecnt - 1])
1645bc421551SDag-Erling Smørgrav return NULL; /* "cannot happen" */
1646bc421551SDag-Erling Smørgrav result = localsub(sp, &newt, setname, tmp);
1647bc421551SDag-Erling Smørgrav if (result) {
1648bc421551SDag-Erling Smørgrav #if defined ckd_add && defined ckd_sub
1649bc421551SDag-Erling Smørgrav if (t < sp->ats[0]
1650bc421551SDag-Erling Smørgrav ? ckd_sub(&result->tm_year,
1651bc421551SDag-Erling Smørgrav result->tm_year, years)
1652bc421551SDag-Erling Smørgrav : ckd_add(&result->tm_year,
1653bc421551SDag-Erling Smørgrav result->tm_year, years))
1654bc421551SDag-Erling Smørgrav return NULL;
1655bc421551SDag-Erling Smørgrav #else
1656bc421551SDag-Erling Smørgrav register int_fast64_t newy;
1657bc421551SDag-Erling Smørgrav
1658bc421551SDag-Erling Smørgrav newy = result->tm_year;
1659bc421551SDag-Erling Smørgrav if (t < sp->ats[0])
1660bc421551SDag-Erling Smørgrav newy -= years;
1661bc421551SDag-Erling Smørgrav else newy += years;
1662bc421551SDag-Erling Smørgrav if (! (INT_MIN <= newy && newy <= INT_MAX))
1663bc421551SDag-Erling Smørgrav return NULL;
1664bc421551SDag-Erling Smørgrav result->tm_year = newy;
1665bc421551SDag-Erling Smørgrav #endif
1666bc421551SDag-Erling Smørgrav }
1667bc421551SDag-Erling Smørgrav return result;
1668bc421551SDag-Erling Smørgrav }
1669bc421551SDag-Erling Smørgrav if (sp->timecnt == 0 || t < sp->ats[0]) {
1670bc421551SDag-Erling Smørgrav i = sp->defaulttype;
1671bc421551SDag-Erling Smørgrav } else {
1672bc421551SDag-Erling Smørgrav register int lo = 1;
1673bc421551SDag-Erling Smørgrav register int hi = sp->timecnt;
1674bc421551SDag-Erling Smørgrav
1675bc421551SDag-Erling Smørgrav while (lo < hi) {
1676bc421551SDag-Erling Smørgrav register int mid = (lo + hi) >> 1;
1677bc421551SDag-Erling Smørgrav
1678bc421551SDag-Erling Smørgrav if (t < sp->ats[mid])
1679bc421551SDag-Erling Smørgrav hi = mid;
1680bc421551SDag-Erling Smørgrav else lo = mid + 1;
1681bc421551SDag-Erling Smørgrav }
1682bc421551SDag-Erling Smørgrav i = sp->types[lo - 1];
1683bc421551SDag-Erling Smørgrav }
1684bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i];
1685bc421551SDag-Erling Smørgrav /*
1686bc421551SDag-Erling Smørgrav ** To get (wrong) behavior that's compatible with System V Release 2.0
1687bc421551SDag-Erling Smørgrav ** you'd replace the statement below with
1688bc421551SDag-Erling Smørgrav ** t += ttisp->tt_utoff;
1689bc421551SDag-Erling Smørgrav ** timesub(&t, 0L, sp, tmp);
1690bc421551SDag-Erling Smørgrav */
1691bc421551SDag-Erling Smørgrav result = timesub(&t, ttisp->tt_utoff, sp, tmp);
1692bc421551SDag-Erling Smørgrav if (result) {
1693bc421551SDag-Erling Smørgrav result->tm_isdst = ttisp->tt_isdst;
1694bc421551SDag-Erling Smørgrav #ifdef TM_ZONE
1695bc421551SDag-Erling Smørgrav result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
1696bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */
1697bc421551SDag-Erling Smørgrav if (setname)
1698bc421551SDag-Erling Smørgrav update_tzname_etc(sp, ttisp);
1699bc421551SDag-Erling Smørgrav }
1700bc421551SDag-Erling Smørgrav return result;
1701bc421551SDag-Erling Smørgrav }
1702bc421551SDag-Erling Smørgrav
1703bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
1704bc421551SDag-Erling Smørgrav
1705bc421551SDag-Erling Smørgrav struct tm *
localtime_rz(struct state * restrict sp,time_t const * restrict timep,struct tm * restrict tmp)170675411d15SDag-Erling Smørgrav localtime_rz(struct state *restrict sp, time_t const *restrict timep,
170775411d15SDag-Erling Smørgrav struct tm *restrict tmp)
1708bc421551SDag-Erling Smørgrav {
1709bc421551SDag-Erling Smørgrav return localsub(sp, timep, 0, tmp);
1710bc421551SDag-Erling Smørgrav }
1711bc421551SDag-Erling Smørgrav
1712bc421551SDag-Erling Smørgrav #endif
1713bc421551SDag-Erling Smørgrav
1714bc421551SDag-Erling Smørgrav static struct tm *
localtime_tzset(time_t const * timep,struct tm * tmp,bool setname)1715bc421551SDag-Erling Smørgrav localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
1716bc421551SDag-Erling Smørgrav {
1717bc421551SDag-Erling Smørgrav int err = lock();
1718bc421551SDag-Erling Smørgrav if (err) {
1719bc421551SDag-Erling Smørgrav errno = err;
1720bc421551SDag-Erling Smørgrav return NULL;
1721bc421551SDag-Erling Smørgrav }
1722bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
1723bc421551SDag-Erling Smørgrav if (setname || !lcl_is_set)
1724bc421551SDag-Erling Smørgrav #endif
1725bc421551SDag-Erling Smørgrav tzset_unlocked();
1726bc421551SDag-Erling Smørgrav tmp = localsub(lclptr, timep, setname, tmp);
1727bc421551SDag-Erling Smørgrav unlock();
1728bc421551SDag-Erling Smørgrav return tmp;
1729bc421551SDag-Erling Smørgrav }
1730bc421551SDag-Erling Smørgrav
1731bc421551SDag-Erling Smørgrav static void
localtime_key_init(void)1732bc421551SDag-Erling Smørgrav localtime_key_init(void)
1733bc421551SDag-Erling Smørgrav {
1734bc421551SDag-Erling Smørgrav
1735bc421551SDag-Erling Smørgrav localtime_key_error = _pthread_key_create(&localtime_key, free);
1736bc421551SDag-Erling Smørgrav }
1737bc421551SDag-Erling Smørgrav
1738bc421551SDag-Erling Smørgrav struct tm *
localtime(const time_t * timep)1739bc421551SDag-Erling Smørgrav localtime(const time_t *timep)
1740bc421551SDag-Erling Smørgrav {
174175411d15SDag-Erling Smørgrav #if !SUPPORT_C89
174275411d15SDag-Erling Smørgrav static struct tm tm;
174375411d15SDag-Erling Smørgrav #endif
1744bc421551SDag-Erling Smørgrav struct tm *p_tm = &tm;
1745bc421551SDag-Erling Smørgrav
1746bc421551SDag-Erling Smørgrav if (__isthreaded != 0) {
1747bc421551SDag-Erling Smørgrav _pthread_once(&localtime_once, localtime_key_init);
1748bc421551SDag-Erling Smørgrav if (localtime_key_error != 0) {
1749bc421551SDag-Erling Smørgrav errno = localtime_key_error;
1750bc421551SDag-Erling Smørgrav return (NULL);
1751bc421551SDag-Erling Smørgrav }
1752bc421551SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
1753bc421551SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
1754bc421551SDag-Erling Smørgrav return (NULL);
1755bc421551SDag-Erling Smørgrav }
175696e68c39SDag-Erling Smørgrav if (_pthread_setspecific(localtime_key, p_tm) != 0) {
175796e68c39SDag-Erling Smørgrav free(p_tm);
175896e68c39SDag-Erling Smørgrav return (NULL);
175996e68c39SDag-Erling Smørgrav }
1760bc421551SDag-Erling Smørgrav }
1761bc421551SDag-Erling Smørgrav }
1762bc421551SDag-Erling Smørgrav return localtime_tzset(timep, p_tm, true);
1763bc421551SDag-Erling Smørgrav }
1764bc421551SDag-Erling Smørgrav
1765bc421551SDag-Erling Smørgrav struct tm *
localtime_r(const time_t * restrict timep,struct tm * restrict tmp)176675411d15SDag-Erling Smørgrav localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
1767bc421551SDag-Erling Smørgrav {
1768bc421551SDag-Erling Smørgrav return localtime_tzset(timep, tmp, false);
1769bc421551SDag-Erling Smørgrav }
1770bc421551SDag-Erling Smørgrav
1771bc421551SDag-Erling Smørgrav /*
1772bc421551SDag-Erling Smørgrav ** gmtsub is to gmtime as localsub is to localtime.
1773bc421551SDag-Erling Smørgrav */
1774bc421551SDag-Erling Smørgrav
1775bc421551SDag-Erling Smørgrav static struct tm *
gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const * sp,time_t const * timep,int_fast32_t offset,struct tm * tmp)1776bc421551SDag-Erling Smørgrav gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
1777bc421551SDag-Erling Smørgrav int_fast32_t offset, struct tm *tmp)
1778bc421551SDag-Erling Smørgrav {
1779bc421551SDag-Erling Smørgrav register struct tm * result;
1780bc421551SDag-Erling Smørgrav
1781bc421551SDag-Erling Smørgrav result = timesub(timep, offset, gmtptr, tmp);
1782bc421551SDag-Erling Smørgrav #ifdef TM_ZONE
1783bc421551SDag-Erling Smørgrav /*
1784bc421551SDag-Erling Smørgrav ** Could get fancy here and deliver something such as
1785bc421551SDag-Erling Smørgrav ** "+xx" or "-xx" if offset is non-zero,
1786bc421551SDag-Erling Smørgrav ** but this is no time for a treasure hunt.
1787bc421551SDag-Erling Smørgrav */
1788bc421551SDag-Erling Smørgrav tmp->TM_ZONE = ((char *)
1789bc421551SDag-Erling Smørgrav (offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
1790bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */
1791bc421551SDag-Erling Smørgrav return result;
1792bc421551SDag-Erling Smørgrav }
1793bc421551SDag-Erling Smørgrav
1794bc421551SDag-Erling Smørgrav /*
1795bc421551SDag-Erling Smørgrav * Re-entrant version of gmtime.
1796bc421551SDag-Erling Smørgrav */
1797bc421551SDag-Erling Smørgrav
1798bc421551SDag-Erling Smørgrav struct tm *
gmtime_r(time_t const * restrict timep,struct tm * restrict tmp)179975411d15SDag-Erling Smørgrav gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
1800bc421551SDag-Erling Smørgrav {
1801bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck);
1802bc421551SDag-Erling Smørgrav return gmtsub(gmtptr, timep, 0, tmp);
1803bc421551SDag-Erling Smørgrav }
1804bc421551SDag-Erling Smørgrav
1805bc421551SDag-Erling Smørgrav static void
gmtime_key_init(void)1806bc421551SDag-Erling Smørgrav gmtime_key_init(void)
1807bc421551SDag-Erling Smørgrav {
1808bc421551SDag-Erling Smørgrav
1809bc421551SDag-Erling Smørgrav gmtime_key_error = _pthread_key_create(&gmtime_key, free);
1810bc421551SDag-Erling Smørgrav }
1811bc421551SDag-Erling Smørgrav
1812bc421551SDag-Erling Smørgrav struct tm *
gmtime(const time_t * timep)1813bc421551SDag-Erling Smørgrav gmtime(const time_t *timep)
1814bc421551SDag-Erling Smørgrav {
181575411d15SDag-Erling Smørgrav #if !SUPPORT_C89
181675411d15SDag-Erling Smørgrav static struct tm tm;
181775411d15SDag-Erling Smørgrav #endif
1818bc421551SDag-Erling Smørgrav struct tm *p_tm = &tm;
1819bc421551SDag-Erling Smørgrav
1820bc421551SDag-Erling Smørgrav if (__isthreaded != 0) {
1821bc421551SDag-Erling Smørgrav _pthread_once(&gmtime_once, gmtime_key_init);
1822bc421551SDag-Erling Smørgrav if (gmtime_key_error != 0) {
1823bc421551SDag-Erling Smørgrav errno = gmtime_key_error;
1824bc421551SDag-Erling Smørgrav return (NULL);
1825bc421551SDag-Erling Smørgrav }
1826bc421551SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
1827bc421551SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
1828bc421551SDag-Erling Smørgrav return (NULL);
1829bc421551SDag-Erling Smørgrav }
183096e68c39SDag-Erling Smørgrav if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
183196e68c39SDag-Erling Smørgrav free(p_tm);
183296e68c39SDag-Erling Smørgrav return (NULL);
183396e68c39SDag-Erling Smørgrav }
1834bc421551SDag-Erling Smørgrav }
1835bc421551SDag-Erling Smørgrav }
1836bc421551SDag-Erling Smørgrav return gmtime_r(timep, p_tm);
1837bc421551SDag-Erling Smørgrav }
1838bc421551SDag-Erling Smørgrav
183975411d15SDag-Erling Smørgrav #if STD_INSPIRED
184075411d15SDag-Erling Smørgrav
184146c59934SDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases.
184246c59934SDag-Erling Smørgrav Callers can instead use localtime_rz with a fixed-offset zone. */
184346c59934SDag-Erling Smørgrav
184475411d15SDag-Erling Smørgrav struct tm *
offtime_r(time_t const * restrict timep,long offset,struct tm * restrict tmp)184575411d15SDag-Erling Smørgrav offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
184675411d15SDag-Erling Smørgrav {
184775411d15SDag-Erling Smørgrav _once(&gmt_once, gmtcheck);
184875411d15SDag-Erling Smørgrav return gmtsub(gmtptr, timep, offset, tmp);
184975411d15SDag-Erling Smørgrav }
185075411d15SDag-Erling Smørgrav
185175411d15SDag-Erling Smørgrav static void
offtime_key_init(void)185275411d15SDag-Erling Smørgrav offtime_key_init(void)
185375411d15SDag-Erling Smørgrav {
185475411d15SDag-Erling Smørgrav
185575411d15SDag-Erling Smørgrav offtime_key_error = _pthread_key_create(&offtime_key, free);
185675411d15SDag-Erling Smørgrav }
1857bc421551SDag-Erling Smørgrav
1858bc421551SDag-Erling Smørgrav struct tm *
offtime(const time_t * timep,long offset)1859bc421551SDag-Erling Smørgrav offtime(const time_t *timep, long offset)
1860bc421551SDag-Erling Smørgrav {
186175411d15SDag-Erling Smørgrav #if !SUPPORT_C89
186275411d15SDag-Erling Smørgrav static struct tm tm;
186375411d15SDag-Erling Smørgrav #endif
186475411d15SDag-Erling Smørgrav struct tm *p_tm = &tm;
186575411d15SDag-Erling Smørgrav
186675411d15SDag-Erling Smørgrav if (__isthreaded != 0) {
186775411d15SDag-Erling Smørgrav _pthread_once(&offtime_once, offtime_key_init);
186875411d15SDag-Erling Smørgrav if (offtime_key_error != 0) {
186975411d15SDag-Erling Smørgrav errno = offtime_key_error;
187075411d15SDag-Erling Smørgrav return (NULL);
187175411d15SDag-Erling Smørgrav }
187275411d15SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
187375411d15SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
187475411d15SDag-Erling Smørgrav return (NULL);
187575411d15SDag-Erling Smørgrav }
187675411d15SDag-Erling Smørgrav if (_pthread_setspecific(offtime_key, p_tm) != 0) {
187775411d15SDag-Erling Smørgrav free(p_tm);
187875411d15SDag-Erling Smørgrav return (NULL);
187975411d15SDag-Erling Smørgrav }
188075411d15SDag-Erling Smørgrav }
188175411d15SDag-Erling Smørgrav }
188275411d15SDag-Erling Smørgrav return offtime_r(timep, offset, p_tm);
1883bc421551SDag-Erling Smørgrav }
1884bc421551SDag-Erling Smørgrav
188575411d15SDag-Erling Smørgrav #endif
1886bc421551SDag-Erling Smørgrav
1887bc421551SDag-Erling Smørgrav /*
1888bc421551SDag-Erling Smørgrav ** Return the number of leap years through the end of the given year
1889bc421551SDag-Erling Smørgrav ** where, to make the math easy, the answer for year zero is defined as zero.
1890bc421551SDag-Erling Smørgrav */
1891bc421551SDag-Erling Smørgrav
1892bc421551SDag-Erling Smørgrav static time_t
leaps_thru_end_of_nonneg(time_t y)1893bc421551SDag-Erling Smørgrav leaps_thru_end_of_nonneg(time_t y)
1894bc421551SDag-Erling Smørgrav {
1895bc421551SDag-Erling Smørgrav return y / 4 - y / 100 + y / 400;
1896bc421551SDag-Erling Smørgrav }
1897bc421551SDag-Erling Smørgrav
1898bc421551SDag-Erling Smørgrav static time_t
leaps_thru_end_of(time_t y)1899bc421551SDag-Erling Smørgrav leaps_thru_end_of(time_t y)
1900bc421551SDag-Erling Smørgrav {
1901bc421551SDag-Erling Smørgrav return (y < 0
1902bc421551SDag-Erling Smørgrav ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1903bc421551SDag-Erling Smørgrav : leaps_thru_end_of_nonneg(y));
1904bc421551SDag-Erling Smørgrav }
1905bc421551SDag-Erling Smørgrav
1906bc421551SDag-Erling Smørgrav static struct tm *
timesub(const time_t * timep,int_fast32_t offset,const struct state * sp,struct tm * tmp)1907bc421551SDag-Erling Smørgrav timesub(const time_t *timep, int_fast32_t offset,
1908bc421551SDag-Erling Smørgrav const struct state *sp, struct tm *tmp)
1909bc421551SDag-Erling Smørgrav {
1910bc421551SDag-Erling Smørgrav register const struct lsinfo * lp;
1911bc421551SDag-Erling Smørgrav register time_t tdays;
1912bc421551SDag-Erling Smørgrav register const int * ip;
1913bc421551SDag-Erling Smørgrav register int_fast32_t corr;
1914bc421551SDag-Erling Smørgrav register int i;
1915bc421551SDag-Erling Smørgrav int_fast32_t idays, rem, dayoff, dayrem;
1916bc421551SDag-Erling Smørgrav time_t y;
1917bc421551SDag-Erling Smørgrav
1918bc421551SDag-Erling Smørgrav /* If less than SECSPERMIN, the number of seconds since the
1919bc421551SDag-Erling Smørgrav most recent positive leap second; otherwise, do not add 1
1920bc421551SDag-Erling Smørgrav to localtime tm_sec because of leap seconds. */
1921bc421551SDag-Erling Smørgrav time_t secs_since_posleap = SECSPERMIN;
1922bc421551SDag-Erling Smørgrav
1923bc421551SDag-Erling Smørgrav corr = 0;
1924bc421551SDag-Erling Smørgrav i = (sp == NULL) ? 0 : sp->leapcnt;
1925bc421551SDag-Erling Smørgrav while (--i >= 0) {
1926bc421551SDag-Erling Smørgrav lp = &sp->lsis[i];
1927bc421551SDag-Erling Smørgrav if (*timep >= lp->ls_trans) {
1928bc421551SDag-Erling Smørgrav corr = lp->ls_corr;
1929bc421551SDag-Erling Smørgrav if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
1930bc421551SDag-Erling Smørgrav secs_since_posleap = *timep - lp->ls_trans;
1931bc421551SDag-Erling Smørgrav break;
1932bc421551SDag-Erling Smørgrav }
1933bc421551SDag-Erling Smørgrav }
1934bc421551SDag-Erling Smørgrav
1935bc421551SDag-Erling Smørgrav /* Calculate the year, avoiding integer overflow even if
1936bc421551SDag-Erling Smørgrav time_t is unsigned. */
1937bc421551SDag-Erling Smørgrav tdays = *timep / SECSPERDAY;
1938bc421551SDag-Erling Smørgrav rem = *timep % SECSPERDAY;
1939bc421551SDag-Erling Smørgrav rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
1940bc421551SDag-Erling Smørgrav dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
1941bc421551SDag-Erling Smørgrav rem %= SECSPERDAY;
1942bc421551SDag-Erling Smørgrav /* y = (EPOCH_YEAR
1943bc421551SDag-Erling Smørgrav + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
1944bc421551SDag-Erling Smørgrav sans overflow. But calculate against 1570 (EPOCH_YEAR -
1945bc421551SDag-Erling Smørgrav YEARSPERREPEAT) instead of against 1970 so that things work
1946bc421551SDag-Erling Smørgrav for localtime values before 1970 when time_t is unsigned. */
1947bc421551SDag-Erling Smørgrav dayrem = tdays % DAYSPERREPEAT;
1948bc421551SDag-Erling Smørgrav dayrem += dayoff % DAYSPERREPEAT;
1949bc421551SDag-Erling Smørgrav y = (EPOCH_YEAR - YEARSPERREPEAT
1950bc421551SDag-Erling Smørgrav + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
1951bc421551SDag-Erling Smørgrav - ((dayrem % DAYSPERREPEAT) < 0)
1952bc421551SDag-Erling Smørgrav + tdays / DAYSPERREPEAT)
1953bc421551SDag-Erling Smørgrav * YEARSPERREPEAT));
1954bc421551SDag-Erling Smørgrav /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */
1955bc421551SDag-Erling Smørgrav idays = tdays % DAYSPERREPEAT;
1956bc421551SDag-Erling Smørgrav idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
1957bc421551SDag-Erling Smørgrav idays %= DAYSPERREPEAT;
1958bc421551SDag-Erling Smørgrav /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
1959bc421551SDag-Erling Smørgrav while (year_lengths[isleap(y)] <= idays) {
1960bc421551SDag-Erling Smørgrav int tdelta = idays / DAYSPERLYEAR;
1961bc421551SDag-Erling Smørgrav int_fast32_t ydelta = tdelta + !tdelta;
1962bc421551SDag-Erling Smørgrav time_t newy = y + ydelta;
1963bc421551SDag-Erling Smørgrav register int leapdays;
1964bc421551SDag-Erling Smørgrav leapdays = leaps_thru_end_of(newy - 1) -
1965bc421551SDag-Erling Smørgrav leaps_thru_end_of(y - 1);
1966bc421551SDag-Erling Smørgrav idays -= ydelta * DAYSPERNYEAR;
1967bc421551SDag-Erling Smørgrav idays -= leapdays;
1968bc421551SDag-Erling Smørgrav y = newy;
1969bc421551SDag-Erling Smørgrav }
1970bc421551SDag-Erling Smørgrav
1971bc421551SDag-Erling Smørgrav #ifdef ckd_add
1972bc421551SDag-Erling Smørgrav if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
1973bc421551SDag-Erling Smørgrav errno = EOVERFLOW;
1974bc421551SDag-Erling Smørgrav return NULL;
1975bc421551SDag-Erling Smørgrav }
1976bc421551SDag-Erling Smørgrav #else
1977bc421551SDag-Erling Smørgrav if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
1978bc421551SDag-Erling Smørgrav int signed_y = y;
1979bc421551SDag-Erling Smørgrav tmp->tm_year = signed_y - TM_YEAR_BASE;
1980bc421551SDag-Erling Smørgrav } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
1981bc421551SDag-Erling Smørgrav && y - TM_YEAR_BASE <= INT_MAX)
1982bc421551SDag-Erling Smørgrav tmp->tm_year = y - TM_YEAR_BASE;
1983bc421551SDag-Erling Smørgrav else {
1984bc421551SDag-Erling Smørgrav errno = EOVERFLOW;
1985bc421551SDag-Erling Smørgrav return NULL;
1986bc421551SDag-Erling Smørgrav }
1987bc421551SDag-Erling Smørgrav #endif
1988bc421551SDag-Erling Smørgrav tmp->tm_yday = idays;
1989bc421551SDag-Erling Smørgrav /*
1990bc421551SDag-Erling Smørgrav ** The "extra" mods below avoid overflow problems.
1991bc421551SDag-Erling Smørgrav */
1992bc421551SDag-Erling Smørgrav tmp->tm_wday = (TM_WDAY_BASE
1993bc421551SDag-Erling Smørgrav + ((tmp->tm_year % DAYSPERWEEK)
1994bc421551SDag-Erling Smørgrav * (DAYSPERNYEAR % DAYSPERWEEK))
1995bc421551SDag-Erling Smørgrav + leaps_thru_end_of(y - 1)
1996bc421551SDag-Erling Smørgrav - leaps_thru_end_of(TM_YEAR_BASE - 1)
1997bc421551SDag-Erling Smørgrav + idays);
1998bc421551SDag-Erling Smørgrav tmp->tm_wday %= DAYSPERWEEK;
1999bc421551SDag-Erling Smørgrav if (tmp->tm_wday < 0)
2000bc421551SDag-Erling Smørgrav tmp->tm_wday += DAYSPERWEEK;
2001bc421551SDag-Erling Smørgrav tmp->tm_hour = rem / SECSPERHOUR;
2002bc421551SDag-Erling Smørgrav rem %= SECSPERHOUR;
2003bc421551SDag-Erling Smørgrav tmp->tm_min = rem / SECSPERMIN;
2004bc421551SDag-Erling Smørgrav tmp->tm_sec = rem % SECSPERMIN;
2005bc421551SDag-Erling Smørgrav
2006bc421551SDag-Erling Smørgrav /* Use "... ??:??:60" at the end of the localtime minute containing
2007bc421551SDag-Erling Smørgrav the second just before the positive leap second. */
2008bc421551SDag-Erling Smørgrav tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
2009bc421551SDag-Erling Smørgrav
2010bc421551SDag-Erling Smørgrav ip = mon_lengths[isleap(y)];
2011bc421551SDag-Erling Smørgrav for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
2012bc421551SDag-Erling Smørgrav idays -= ip[tmp->tm_mon];
2013bc421551SDag-Erling Smørgrav tmp->tm_mday = idays + 1;
2014bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0;
2015bc421551SDag-Erling Smørgrav #ifdef TM_GMTOFF
2016bc421551SDag-Erling Smørgrav tmp->TM_GMTOFF = offset;
2017bc421551SDag-Erling Smørgrav #endif /* defined TM_GMTOFF */
2018bc421551SDag-Erling Smørgrav return tmp;
2019bc421551SDag-Erling Smørgrav }
2020bc421551SDag-Erling Smørgrav
2021bc421551SDag-Erling Smørgrav /*
2022bc421551SDag-Erling Smørgrav ** Adapted from code provided by Robert Elz, who writes:
2023bc421551SDag-Erling Smørgrav ** The "best" way to do mktime I think is based on an idea of Bob
2024bc421551SDag-Erling Smørgrav ** Kridle's (so its said...) from a long time ago.
2025bc421551SDag-Erling Smørgrav ** It does a binary search of the time_t space. Since time_t's are
2026bc421551SDag-Erling Smørgrav ** just 32 bits, its a max of 32 iterations (even at 64 bits it
2027bc421551SDag-Erling Smørgrav ** would still be very reasonable).
2028bc421551SDag-Erling Smørgrav */
2029bc421551SDag-Erling Smørgrav
2030bc421551SDag-Erling Smørgrav #ifndef WRONG
2031bc421551SDag-Erling Smørgrav # define WRONG (-1)
2032bc421551SDag-Erling Smørgrav #endif /* !defined WRONG */
2033bc421551SDag-Erling Smørgrav
2034bc421551SDag-Erling Smørgrav /*
2035bc421551SDag-Erling Smørgrav ** Normalize logic courtesy Paul Eggert.
2036bc421551SDag-Erling Smørgrav */
2037bc421551SDag-Erling Smørgrav
2038bc421551SDag-Erling Smørgrav static bool
increment_overflow(int * ip,int j)2039bc421551SDag-Erling Smørgrav increment_overflow(int *ip, int j)
2040bc421551SDag-Erling Smørgrav {
2041bc421551SDag-Erling Smørgrav #ifdef ckd_add
2042bc421551SDag-Erling Smørgrav return ckd_add(ip, *ip, j);
2043bc421551SDag-Erling Smørgrav #else
2044bc421551SDag-Erling Smørgrav register int const i = *ip;
2045bc421551SDag-Erling Smørgrav
2046bc421551SDag-Erling Smørgrav /*
2047bc421551SDag-Erling Smørgrav ** If i >= 0 there can only be overflow if i + j > INT_MAX
2048bc421551SDag-Erling Smørgrav ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
2049bc421551SDag-Erling Smørgrav ** If i < 0 there can only be overflow if i + j < INT_MIN
2050bc421551SDag-Erling Smørgrav ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
2051bc421551SDag-Erling Smørgrav */
2052bc421551SDag-Erling Smørgrav if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
2053bc421551SDag-Erling Smørgrav return true;
2054bc421551SDag-Erling Smørgrav *ip += j;
2055bc421551SDag-Erling Smørgrav return false;
2056bc421551SDag-Erling Smørgrav #endif
2057bc421551SDag-Erling Smørgrav }
2058bc421551SDag-Erling Smørgrav
2059bc421551SDag-Erling Smørgrav static bool
increment_overflow32(int_fast32_t * const lp,int const m)2060bc421551SDag-Erling Smørgrav increment_overflow32(int_fast32_t *const lp, int const m)
2061bc421551SDag-Erling Smørgrav {
2062bc421551SDag-Erling Smørgrav #ifdef ckd_add
2063bc421551SDag-Erling Smørgrav return ckd_add(lp, *lp, m);
2064bc421551SDag-Erling Smørgrav #else
2065bc421551SDag-Erling Smørgrav register int_fast32_t const l = *lp;
2066bc421551SDag-Erling Smørgrav
2067bc421551SDag-Erling Smørgrav if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
2068bc421551SDag-Erling Smørgrav return true;
2069bc421551SDag-Erling Smørgrav *lp += m;
2070bc421551SDag-Erling Smørgrav return false;
2071bc421551SDag-Erling Smørgrav #endif
2072bc421551SDag-Erling Smørgrav }
2073bc421551SDag-Erling Smørgrav
2074bc421551SDag-Erling Smørgrav static bool
increment_overflow_time(time_t * tp,int_fast32_t j)2075bc421551SDag-Erling Smørgrav increment_overflow_time(time_t *tp, int_fast32_t j)
2076bc421551SDag-Erling Smørgrav {
2077bc421551SDag-Erling Smørgrav #ifdef ckd_add
2078bc421551SDag-Erling Smørgrav return ckd_add(tp, *tp, j);
2079bc421551SDag-Erling Smørgrav #else
2080bc421551SDag-Erling Smørgrav /*
2081bc421551SDag-Erling Smørgrav ** This is like
2082bc421551SDag-Erling Smørgrav ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
2083bc421551SDag-Erling Smørgrav ** except that it does the right thing even if *tp + j would overflow.
2084bc421551SDag-Erling Smørgrav */
2085bc421551SDag-Erling Smørgrav if (! (j < 0
2086bc421551SDag-Erling Smørgrav ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
2087bc421551SDag-Erling Smørgrav : *tp <= TIME_T_MAX - j))
2088bc421551SDag-Erling Smørgrav return true;
2089bc421551SDag-Erling Smørgrav *tp += j;
2090bc421551SDag-Erling Smørgrav return false;
2091bc421551SDag-Erling Smørgrav #endif
2092bc421551SDag-Erling Smørgrav }
2093bc421551SDag-Erling Smørgrav
2094bc421551SDag-Erling Smørgrav static bool
normalize_overflow(int * const tensptr,int * const unitsptr,const int base)2095bc421551SDag-Erling Smørgrav normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
2096bc421551SDag-Erling Smørgrav {
2097bc421551SDag-Erling Smørgrav register int tensdelta;
2098bc421551SDag-Erling Smørgrav
2099bc421551SDag-Erling Smørgrav tensdelta = (*unitsptr >= 0) ?
2100bc421551SDag-Erling Smørgrav (*unitsptr / base) :
2101bc421551SDag-Erling Smørgrav (-1 - (-1 - *unitsptr) / base);
2102bc421551SDag-Erling Smørgrav *unitsptr -= tensdelta * base;
2103bc421551SDag-Erling Smørgrav return increment_overflow(tensptr, tensdelta);
2104bc421551SDag-Erling Smørgrav }
2105bc421551SDag-Erling Smørgrav
2106bc421551SDag-Erling Smørgrav static bool
normalize_overflow32(int_fast32_t * tensptr,int * unitsptr,int base)2107bc421551SDag-Erling Smørgrav normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
2108bc421551SDag-Erling Smørgrav {
2109bc421551SDag-Erling Smørgrav register int tensdelta;
2110bc421551SDag-Erling Smørgrav
2111bc421551SDag-Erling Smørgrav tensdelta = (*unitsptr >= 0) ?
2112bc421551SDag-Erling Smørgrav (*unitsptr / base) :
2113bc421551SDag-Erling Smørgrav (-1 - (-1 - *unitsptr) / base);
2114bc421551SDag-Erling Smørgrav *unitsptr -= tensdelta * base;
2115bc421551SDag-Erling Smørgrav return increment_overflow32(tensptr, tensdelta);
2116bc421551SDag-Erling Smørgrav }
2117bc421551SDag-Erling Smørgrav
2118bc421551SDag-Erling Smørgrav static int
tmcomp(register const struct tm * const atmp,register const struct tm * const btmp)2119bc421551SDag-Erling Smørgrav tmcomp(register const struct tm *const atmp,
2120bc421551SDag-Erling Smørgrav register const struct tm *const btmp)
2121bc421551SDag-Erling Smørgrav {
2122bc421551SDag-Erling Smørgrav register int result;
2123bc421551SDag-Erling Smørgrav
2124bc421551SDag-Erling Smørgrav if (atmp->tm_year != btmp->tm_year)
2125bc421551SDag-Erling Smørgrav return atmp->tm_year < btmp->tm_year ? -1 : 1;
2126bc421551SDag-Erling Smørgrav if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
2127bc421551SDag-Erling Smørgrav (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
2128bc421551SDag-Erling Smørgrav (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
2129bc421551SDag-Erling Smørgrav (result = (atmp->tm_min - btmp->tm_min)) == 0)
2130bc421551SDag-Erling Smørgrav result = atmp->tm_sec - btmp->tm_sec;
2131bc421551SDag-Erling Smørgrav return result;
2132bc421551SDag-Erling Smørgrav }
2133bc421551SDag-Erling Smørgrav
2134bc421551SDag-Erling Smørgrav /* Copy to *DEST from *SRC. Copy only the members needed for mktime,
2135bc421551SDag-Erling Smørgrav as other members might not be initialized. */
2136bc421551SDag-Erling Smørgrav static void
mktmcpy(struct tm * dest,struct tm const * src)2137bc421551SDag-Erling Smørgrav mktmcpy(struct tm *dest, struct tm const *src)
2138bc421551SDag-Erling Smørgrav {
2139bc421551SDag-Erling Smørgrav dest->tm_sec = src->tm_sec;
2140bc421551SDag-Erling Smørgrav dest->tm_min = src->tm_min;
2141bc421551SDag-Erling Smørgrav dest->tm_hour = src->tm_hour;
2142bc421551SDag-Erling Smørgrav dest->tm_mday = src->tm_mday;
2143bc421551SDag-Erling Smørgrav dest->tm_mon = src->tm_mon;
2144bc421551SDag-Erling Smørgrav dest->tm_year = src->tm_year;
2145bc421551SDag-Erling Smørgrav dest->tm_isdst = src->tm_isdst;
2146bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP
2147bc421551SDag-Erling Smørgrav dest->TM_GMTOFF = src->TM_GMTOFF;
2148bc421551SDag-Erling Smørgrav #endif
2149bc421551SDag-Erling Smørgrav }
2150bc421551SDag-Erling Smørgrav
2151bc421551SDag-Erling Smørgrav static time_t
time2sub(struct tm * const tmp,struct tm * (* funcp)(struct state const *,time_t const *,int_fast32_t,struct tm *),struct state const * sp,const int_fast32_t offset,bool * okayp,bool do_norm_secs)2152bc421551SDag-Erling Smørgrav time2sub(struct tm *const tmp,
2153bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *,
2154bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *),
2155bc421551SDag-Erling Smørgrav struct state const *sp,
2156bc421551SDag-Erling Smørgrav const int_fast32_t offset,
2157bc421551SDag-Erling Smørgrav bool *okayp,
2158bc421551SDag-Erling Smørgrav bool do_norm_secs)
2159bc421551SDag-Erling Smørgrav {
2160bc421551SDag-Erling Smørgrav register int dir;
2161bc421551SDag-Erling Smørgrav register int i, j;
2162bc421551SDag-Erling Smørgrav register int saved_seconds;
2163bc421551SDag-Erling Smørgrav register int_fast32_t li;
2164bc421551SDag-Erling Smørgrav register time_t lo;
2165bc421551SDag-Erling Smørgrav register time_t hi;
2166bc421551SDag-Erling Smørgrav int_fast32_t y;
2167bc421551SDag-Erling Smørgrav time_t newt;
2168bc421551SDag-Erling Smørgrav time_t t;
2169bc421551SDag-Erling Smørgrav struct tm yourtm, mytm;
2170bc421551SDag-Erling Smørgrav
2171bc421551SDag-Erling Smørgrav *okayp = false;
2172bc421551SDag-Erling Smørgrav mktmcpy(&yourtm, tmp);
2173bc421551SDag-Erling Smørgrav
2174bc421551SDag-Erling Smørgrav if (do_norm_secs) {
2175bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2176bc421551SDag-Erling Smørgrav SECSPERMIN))
2177bc421551SDag-Erling Smørgrav return WRONG;
2178bc421551SDag-Erling Smørgrav }
2179bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2180bc421551SDag-Erling Smørgrav return WRONG;
2181bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2182bc421551SDag-Erling Smørgrav return WRONG;
2183bc421551SDag-Erling Smørgrav y = yourtm.tm_year;
2184bc421551SDag-Erling Smørgrav if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
2185bc421551SDag-Erling Smørgrav return WRONG;
2186bc421551SDag-Erling Smørgrav /*
2187bc421551SDag-Erling Smørgrav ** Turn y into an actual year number for now.
2188bc421551SDag-Erling Smørgrav ** It is converted back to an offset from TM_YEAR_BASE later.
2189bc421551SDag-Erling Smørgrav */
2190bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, TM_YEAR_BASE))
2191bc421551SDag-Erling Smørgrav return WRONG;
2192bc421551SDag-Erling Smørgrav while (yourtm.tm_mday <= 0) {
2193bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, -1))
2194bc421551SDag-Erling Smørgrav return WRONG;
2195bc421551SDag-Erling Smørgrav li = y + (1 < yourtm.tm_mon);
2196bc421551SDag-Erling Smørgrav yourtm.tm_mday += year_lengths[isleap(li)];
2197bc421551SDag-Erling Smørgrav }
2198bc421551SDag-Erling Smørgrav while (yourtm.tm_mday > DAYSPERLYEAR) {
2199bc421551SDag-Erling Smørgrav li = y + (1 < yourtm.tm_mon);
2200bc421551SDag-Erling Smørgrav yourtm.tm_mday -= year_lengths[isleap(li)];
2201bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, 1))
2202bc421551SDag-Erling Smørgrav return WRONG;
2203bc421551SDag-Erling Smørgrav }
2204bc421551SDag-Erling Smørgrav for ( ; ; ) {
2205bc421551SDag-Erling Smørgrav i = mon_lengths[isleap(y)][yourtm.tm_mon];
2206bc421551SDag-Erling Smørgrav if (yourtm.tm_mday <= i)
2207bc421551SDag-Erling Smørgrav break;
2208bc421551SDag-Erling Smørgrav yourtm.tm_mday -= i;
2209bc421551SDag-Erling Smørgrav if (++yourtm.tm_mon >= MONSPERYEAR) {
2210bc421551SDag-Erling Smørgrav yourtm.tm_mon = 0;
2211bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, 1))
2212bc421551SDag-Erling Smørgrav return WRONG;
2213bc421551SDag-Erling Smørgrav }
2214bc421551SDag-Erling Smørgrav }
2215bc421551SDag-Erling Smørgrav #ifdef ckd_add
2216bc421551SDag-Erling Smørgrav if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
2217bc421551SDag-Erling Smørgrav return WRONG;
2218bc421551SDag-Erling Smørgrav #else
2219bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, -TM_YEAR_BASE))
2220bc421551SDag-Erling Smørgrav return WRONG;
2221bc421551SDag-Erling Smørgrav if (! (INT_MIN <= y && y <= INT_MAX))
2222bc421551SDag-Erling Smørgrav return WRONG;
2223bc421551SDag-Erling Smørgrav yourtm.tm_year = y;
2224bc421551SDag-Erling Smørgrav #endif
2225bc421551SDag-Erling Smørgrav if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2226bc421551SDag-Erling Smørgrav saved_seconds = 0;
2227bc421551SDag-Erling Smørgrav else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
2228bc421551SDag-Erling Smørgrav /*
2229bc421551SDag-Erling Smørgrav ** We can't set tm_sec to 0, because that might push the
2230bc421551SDag-Erling Smørgrav ** time below the minimum representable time.
2231bc421551SDag-Erling Smørgrav ** Set tm_sec to 59 instead.
2232bc421551SDag-Erling Smørgrav ** This assumes that the minimum representable time is
2233bc421551SDag-Erling Smørgrav ** not in the same minute that a leap second was deleted from,
2234bc421551SDag-Erling Smørgrav ** which is a safer assumption than using 58 would be.
2235bc421551SDag-Erling Smørgrav */
2236bc421551SDag-Erling Smørgrav if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2237bc421551SDag-Erling Smørgrav return WRONG;
2238bc421551SDag-Erling Smørgrav saved_seconds = yourtm.tm_sec;
2239bc421551SDag-Erling Smørgrav yourtm.tm_sec = SECSPERMIN - 1;
2240bc421551SDag-Erling Smørgrav } else {
2241bc421551SDag-Erling Smørgrav saved_seconds = yourtm.tm_sec;
2242bc421551SDag-Erling Smørgrav yourtm.tm_sec = 0;
2243bc421551SDag-Erling Smørgrav }
2244bc421551SDag-Erling Smørgrav /*
2245bc421551SDag-Erling Smørgrav ** Do a binary search (this works whatever time_t's type is).
2246bc421551SDag-Erling Smørgrav */
2247bc421551SDag-Erling Smørgrav lo = TIME_T_MIN;
2248bc421551SDag-Erling Smørgrav hi = TIME_T_MAX;
2249bc421551SDag-Erling Smørgrav for ( ; ; ) {
2250bc421551SDag-Erling Smørgrav t = lo / 2 + hi / 2;
2251bc421551SDag-Erling Smørgrav if (t < lo)
2252bc421551SDag-Erling Smørgrav t = lo;
2253bc421551SDag-Erling Smørgrav else if (t > hi)
2254bc421551SDag-Erling Smørgrav t = hi;
2255bc421551SDag-Erling Smørgrav if (! funcp(sp, &t, offset, &mytm)) {
2256bc421551SDag-Erling Smørgrav /*
2257bc421551SDag-Erling Smørgrav ** Assume that t is too extreme to be represented in
2258bc421551SDag-Erling Smørgrav ** a struct tm; arrange things so that it is less
2259bc421551SDag-Erling Smørgrav ** extreme on the next pass.
2260bc421551SDag-Erling Smørgrav */
2261bc421551SDag-Erling Smørgrav dir = (t > 0) ? 1 : -1;
2262bc421551SDag-Erling Smørgrav } else dir = tmcomp(&mytm, &yourtm);
2263bc421551SDag-Erling Smørgrav if (dir != 0) {
2264bc421551SDag-Erling Smørgrav if (t == lo) {
2265bc421551SDag-Erling Smørgrav if (t == TIME_T_MAX)
2266bc421551SDag-Erling Smørgrav return WRONG;
2267bc421551SDag-Erling Smørgrav ++t;
2268bc421551SDag-Erling Smørgrav ++lo;
2269bc421551SDag-Erling Smørgrav } else if (t == hi) {
2270bc421551SDag-Erling Smørgrav if (t == TIME_T_MIN)
2271bc421551SDag-Erling Smørgrav return WRONG;
2272bc421551SDag-Erling Smørgrav --t;
2273bc421551SDag-Erling Smørgrav --hi;
2274bc421551SDag-Erling Smørgrav }
2275bc421551SDag-Erling Smørgrav if (lo > hi)
2276bc421551SDag-Erling Smørgrav return WRONG;
2277bc421551SDag-Erling Smørgrav if (dir > 0)
2278bc421551SDag-Erling Smørgrav hi = t;
2279bc421551SDag-Erling Smørgrav else lo = t;
2280bc421551SDag-Erling Smørgrav continue;
2281bc421551SDag-Erling Smørgrav }
2282bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP
2283bc421551SDag-Erling Smørgrav if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
2284bc421551SDag-Erling Smørgrav && (yourtm.TM_GMTOFF < 0
2285bc421551SDag-Erling Smørgrav ? (-SECSPERDAY <= yourtm.TM_GMTOFF
2286bc421551SDag-Erling Smørgrav && (mytm.TM_GMTOFF <=
2287bc421551SDag-Erling Smørgrav (min(INT_FAST32_MAX, LONG_MAX)
2288bc421551SDag-Erling Smørgrav + yourtm.TM_GMTOFF)))
2289bc421551SDag-Erling Smørgrav : (yourtm.TM_GMTOFF <= SECSPERDAY
2290bc421551SDag-Erling Smørgrav && ((max(INT_FAST32_MIN, LONG_MIN)
2291bc421551SDag-Erling Smørgrav + yourtm.TM_GMTOFF)
2292bc421551SDag-Erling Smørgrav <= mytm.TM_GMTOFF)))) {
2293bc421551SDag-Erling Smørgrav /* MYTM matches YOURTM except with the wrong UT offset.
2294bc421551SDag-Erling Smørgrav YOURTM.TM_GMTOFF is plausible, so try it instead.
2295bc421551SDag-Erling Smørgrav It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2296bc421551SDag-Erling Smørgrav since the guess gets checked. */
2297bc421551SDag-Erling Smørgrav time_t altt = t;
2298bc421551SDag-Erling Smørgrav int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2299bc421551SDag-Erling Smørgrav if (!increment_overflow_time(&altt, diff)) {
2300bc421551SDag-Erling Smørgrav struct tm alttm;
2301bc421551SDag-Erling Smørgrav if (funcp(sp, &altt, offset, &alttm)
2302bc421551SDag-Erling Smørgrav && alttm.tm_isdst == mytm.tm_isdst
2303bc421551SDag-Erling Smørgrav && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2304bc421551SDag-Erling Smørgrav && tmcomp(&alttm, &yourtm) == 0) {
2305bc421551SDag-Erling Smørgrav t = altt;
2306bc421551SDag-Erling Smørgrav mytm = alttm;
2307bc421551SDag-Erling Smørgrav }
2308bc421551SDag-Erling Smørgrav }
2309bc421551SDag-Erling Smørgrav }
2310bc421551SDag-Erling Smørgrav #endif
2311bc421551SDag-Erling Smørgrav if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2312bc421551SDag-Erling Smørgrav break;
2313bc421551SDag-Erling Smørgrav /*
2314bc421551SDag-Erling Smørgrav ** Right time, wrong type.
2315bc421551SDag-Erling Smørgrav ** Hunt for right time, right type.
2316bc421551SDag-Erling Smørgrav ** It's okay to guess wrong since the guess
2317bc421551SDag-Erling Smørgrav ** gets checked.
2318bc421551SDag-Erling Smørgrav */
2319bc421551SDag-Erling Smørgrav if (sp == NULL)
2320bc421551SDag-Erling Smørgrav return WRONG;
2321bc421551SDag-Erling Smørgrav for (i = sp->typecnt - 1; i >= 0; --i) {
2322bc421551SDag-Erling Smørgrav if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2323bc421551SDag-Erling Smørgrav continue;
2324bc421551SDag-Erling Smørgrav for (j = sp->typecnt - 1; j >= 0; --j) {
2325bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2326bc421551SDag-Erling Smørgrav continue;
2327bc421551SDag-Erling Smørgrav if (ttunspecified(sp, j))
2328bc421551SDag-Erling Smørgrav continue;
2329bc421551SDag-Erling Smørgrav newt = (t + sp->ttis[j].tt_utoff
2330bc421551SDag-Erling Smørgrav - sp->ttis[i].tt_utoff);
2331bc421551SDag-Erling Smørgrav if (! funcp(sp, &newt, offset, &mytm))
2332bc421551SDag-Erling Smørgrav continue;
2333bc421551SDag-Erling Smørgrav if (tmcomp(&mytm, &yourtm) != 0)
2334bc421551SDag-Erling Smørgrav continue;
2335bc421551SDag-Erling Smørgrav if (mytm.tm_isdst != yourtm.tm_isdst)
2336bc421551SDag-Erling Smørgrav continue;
2337bc421551SDag-Erling Smørgrav /*
2338bc421551SDag-Erling Smørgrav ** We have a match.
2339bc421551SDag-Erling Smørgrav */
2340bc421551SDag-Erling Smørgrav t = newt;
2341bc421551SDag-Erling Smørgrav goto label;
2342bc421551SDag-Erling Smørgrav }
2343bc421551SDag-Erling Smørgrav }
2344bc421551SDag-Erling Smørgrav return WRONG;
2345bc421551SDag-Erling Smørgrav }
2346bc421551SDag-Erling Smørgrav label:
2347bc421551SDag-Erling Smørgrav newt = t + saved_seconds;
2348bc421551SDag-Erling Smørgrav if ((newt < t) != (saved_seconds < 0))
2349bc421551SDag-Erling Smørgrav return WRONG;
2350bc421551SDag-Erling Smørgrav t = newt;
2351bc421551SDag-Erling Smørgrav if (funcp(sp, &t, offset, tmp))
2352bc421551SDag-Erling Smørgrav *okayp = true;
2353bc421551SDag-Erling Smørgrav return t;
2354bc421551SDag-Erling Smørgrav }
2355bc421551SDag-Erling Smørgrav
2356bc421551SDag-Erling Smørgrav static time_t
time2(struct tm * const tmp,struct tm * (* funcp)(struct state const *,time_t const *,int_fast32_t,struct tm *),struct state const * sp,const int_fast32_t offset,bool * okayp)2357bc421551SDag-Erling Smørgrav time2(struct tm * const tmp,
2358bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *,
2359bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *),
2360bc421551SDag-Erling Smørgrav struct state const *sp,
2361bc421551SDag-Erling Smørgrav const int_fast32_t offset,
2362bc421551SDag-Erling Smørgrav bool *okayp)
2363bc421551SDag-Erling Smørgrav {
2364bc421551SDag-Erling Smørgrav time_t t;
2365bc421551SDag-Erling Smørgrav
2366bc421551SDag-Erling Smørgrav /*
2367bc421551SDag-Erling Smørgrav ** First try without normalization of seconds
2368bc421551SDag-Erling Smørgrav ** (in case tm_sec contains a value associated with a leap second).
2369bc421551SDag-Erling Smørgrav ** If that fails, try with normalization of seconds.
2370bc421551SDag-Erling Smørgrav */
2371bc421551SDag-Erling Smørgrav t = time2sub(tmp, funcp, sp, offset, okayp, false);
2372bc421551SDag-Erling Smørgrav return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
2373bc421551SDag-Erling Smørgrav }
2374bc421551SDag-Erling Smørgrav
2375bc421551SDag-Erling Smørgrav static time_t
time1(struct tm * const tmp,struct tm * (* funcp)(struct state const *,time_t const *,int_fast32_t,struct tm *),struct state const * sp,const int_fast32_t offset)2376bc421551SDag-Erling Smørgrav time1(struct tm *const tmp,
2377bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *,
2378bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *),
2379bc421551SDag-Erling Smørgrav struct state const *sp,
2380bc421551SDag-Erling Smørgrav const int_fast32_t offset)
2381bc421551SDag-Erling Smørgrav {
2382bc421551SDag-Erling Smørgrav register time_t t;
2383bc421551SDag-Erling Smørgrav register int samei, otheri;
2384bc421551SDag-Erling Smørgrav register int sameind, otherind;
2385bc421551SDag-Erling Smørgrav register int i;
2386bc421551SDag-Erling Smørgrav register int nseen;
2387bc421551SDag-Erling Smørgrav char seen[TZ_MAX_TYPES];
2388bc421551SDag-Erling Smørgrav unsigned char types[TZ_MAX_TYPES];
2389bc421551SDag-Erling Smørgrav bool okay;
2390bc421551SDag-Erling Smørgrav
2391bc421551SDag-Erling Smørgrav if (tmp == NULL) {
2392bc421551SDag-Erling Smørgrav errno = EINVAL;
2393bc421551SDag-Erling Smørgrav return WRONG;
2394bc421551SDag-Erling Smørgrav }
2395bc421551SDag-Erling Smørgrav
2396bc421551SDag-Erling Smørgrav if (tmp->tm_isdst > 1)
2397bc421551SDag-Erling Smørgrav tmp->tm_isdst = 1;
2398bc421551SDag-Erling Smørgrav t = time2(tmp, funcp, sp, offset, &okay);
2399bc421551SDag-Erling Smørgrav if (okay)
2400bc421551SDag-Erling Smørgrav return t;
2401bc421551SDag-Erling Smørgrav if (tmp->tm_isdst < 0)
2402bc421551SDag-Erling Smørgrav #ifdef PCTS
2403bc421551SDag-Erling Smørgrav /*
2404bc421551SDag-Erling Smørgrav ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2405bc421551SDag-Erling Smørgrav */
2406bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0; /* reset to std and try again */
2407bc421551SDag-Erling Smørgrav #else
2408bc421551SDag-Erling Smørgrav return t;
2409bc421551SDag-Erling Smørgrav #endif /* !defined PCTS */
2410bc421551SDag-Erling Smørgrav /*
2411bc421551SDag-Erling Smørgrav ** We're supposed to assume that somebody took a time of one type
2412bc421551SDag-Erling Smørgrav ** and did some math on it that yielded a "struct tm" that's bad.
2413bc421551SDag-Erling Smørgrav ** We try to divine the type they started from and adjust to the
2414bc421551SDag-Erling Smørgrav ** type they need.
2415bc421551SDag-Erling Smørgrav */
2416bc421551SDag-Erling Smørgrav if (sp == NULL)
2417bc421551SDag-Erling Smørgrav return WRONG;
2418bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i)
2419bc421551SDag-Erling Smørgrav seen[i] = false;
2420bc421551SDag-Erling Smørgrav nseen = 0;
2421bc421551SDag-Erling Smørgrav for (i = sp->timecnt - 1; i >= 0; --i)
2422bc421551SDag-Erling Smørgrav if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
2423bc421551SDag-Erling Smørgrav seen[sp->types[i]] = true;
2424bc421551SDag-Erling Smørgrav types[nseen++] = sp->types[i];
2425bc421551SDag-Erling Smørgrav }
2426bc421551SDag-Erling Smørgrav for (sameind = 0; sameind < nseen; ++sameind) {
2427bc421551SDag-Erling Smørgrav samei = types[sameind];
2428bc421551SDag-Erling Smørgrav if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2429bc421551SDag-Erling Smørgrav continue;
2430bc421551SDag-Erling Smørgrav for (otherind = 0; otherind < nseen; ++otherind) {
2431bc421551SDag-Erling Smørgrav otheri = types[otherind];
2432bc421551SDag-Erling Smørgrav if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2433bc421551SDag-Erling Smørgrav continue;
2434bc421551SDag-Erling Smørgrav tmp->tm_sec += (sp->ttis[otheri].tt_utoff
2435bc421551SDag-Erling Smørgrav - sp->ttis[samei].tt_utoff);
2436bc421551SDag-Erling Smørgrav tmp->tm_isdst = !tmp->tm_isdst;
2437bc421551SDag-Erling Smørgrav t = time2(tmp, funcp, sp, offset, &okay);
2438bc421551SDag-Erling Smørgrav if (okay)
2439bc421551SDag-Erling Smørgrav return t;
2440bc421551SDag-Erling Smørgrav tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
2441bc421551SDag-Erling Smørgrav - sp->ttis[samei].tt_utoff);
2442bc421551SDag-Erling Smørgrav tmp->tm_isdst = !tmp->tm_isdst;
2443bc421551SDag-Erling Smørgrav }
2444bc421551SDag-Erling Smørgrav }
2445bc421551SDag-Erling Smørgrav return WRONG;
2446bc421551SDag-Erling Smørgrav }
2447bc421551SDag-Erling Smørgrav
2448bc421551SDag-Erling Smørgrav static time_t
mktime_tzname(struct state * sp,struct tm * tmp,bool setname)2449bc421551SDag-Erling Smørgrav mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2450bc421551SDag-Erling Smørgrav {
2451bc421551SDag-Erling Smørgrav if (sp)
2452bc421551SDag-Erling Smørgrav return time1(tmp, localsub, sp, setname);
2453bc421551SDag-Erling Smørgrav else {
2454bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck);
2455bc421551SDag-Erling Smørgrav return time1(tmp, gmtsub, gmtptr, 0);
2456bc421551SDag-Erling Smørgrav }
2457bc421551SDag-Erling Smørgrav }
2458bc421551SDag-Erling Smørgrav
2459bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
2460bc421551SDag-Erling Smørgrav
2461bc421551SDag-Erling Smørgrav time_t
mktime_z(struct state * restrict sp,struct tm * restrict tmp)246275411d15SDag-Erling Smørgrav mktime_z(struct state *restrict sp, struct tm *restrict tmp)
2463bc421551SDag-Erling Smørgrav {
2464bc421551SDag-Erling Smørgrav return mktime_tzname(sp, tmp, false);
2465bc421551SDag-Erling Smørgrav }
2466bc421551SDag-Erling Smørgrav
2467bc421551SDag-Erling Smørgrav #endif
2468bc421551SDag-Erling Smørgrav
2469bc421551SDag-Erling Smørgrav time_t
mktime(struct tm * tmp)2470bc421551SDag-Erling Smørgrav mktime(struct tm *tmp)
2471bc421551SDag-Erling Smørgrav {
2472bc421551SDag-Erling Smørgrav time_t t;
2473bc421551SDag-Erling Smørgrav int err = lock();
2474bc421551SDag-Erling Smørgrav if (err) {
2475bc421551SDag-Erling Smørgrav errno = err;
2476bc421551SDag-Erling Smørgrav return -1;
2477bc421551SDag-Erling Smørgrav }
2478bc421551SDag-Erling Smørgrav tzset_unlocked();
2479bc421551SDag-Erling Smørgrav t = mktime_tzname(lclptr, tmp, true);
2480bc421551SDag-Erling Smørgrav unlock();
2481bc421551SDag-Erling Smørgrav return t;
2482bc421551SDag-Erling Smørgrav }
2483bc421551SDag-Erling Smørgrav
248475411d15SDag-Erling Smørgrav #if STD_INSPIRED
248546c59934SDag-Erling Smørgrav /* This function is obsolescent and may disapper in future releases.
248646c59934SDag-Erling Smørgrav Callers can instead use mktime. */
2487bc421551SDag-Erling Smørgrav time_t
timelocal(struct tm * tmp)2488bc421551SDag-Erling Smørgrav timelocal(struct tm *tmp)
2489bc421551SDag-Erling Smørgrav {
2490bc421551SDag-Erling Smørgrav if (tmp != NULL)
2491bc421551SDag-Erling Smørgrav tmp->tm_isdst = -1; /* in case it wasn't initialized */
2492bc421551SDag-Erling Smørgrav return mktime(tmp);
2493bc421551SDag-Erling Smørgrav }
2494bc421551SDag-Erling Smørgrav #endif
249546c59934SDag-Erling Smørgrav
249646c59934SDag-Erling Smørgrav #ifndef EXTERN_TIMEOFF
249746c59934SDag-Erling Smørgrav # ifndef timeoff
249846c59934SDag-Erling Smørgrav # define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */
249946c59934SDag-Erling Smørgrav # endif
250046c59934SDag-Erling Smørgrav # define EXTERN_TIMEOFF static
250146c59934SDag-Erling Smørgrav #endif
250246c59934SDag-Erling Smørgrav
250346c59934SDag-Erling Smørgrav /* This function is obsolescent and may disapper in future releases.
250446c59934SDag-Erling Smørgrav Callers can instead use mktime_z with a fixed-offset zone. */
250546c59934SDag-Erling Smørgrav EXTERN_TIMEOFF time_t
timeoff(struct tm * tmp,long offset)2506bc421551SDag-Erling Smørgrav timeoff(struct tm *tmp, long offset)
2507bc421551SDag-Erling Smørgrav {
2508bc421551SDag-Erling Smørgrav if (tmp)
2509bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0;
2510bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck);
2511bc421551SDag-Erling Smørgrav return time1(tmp, gmtsub, gmtptr, offset);
2512bc421551SDag-Erling Smørgrav }
2513bc421551SDag-Erling Smørgrav
2514bc421551SDag-Erling Smørgrav time_t
timegm(struct tm * tmp)2515bc421551SDag-Erling Smørgrav timegm(struct tm *tmp)
2516bc421551SDag-Erling Smørgrav {
2517bc421551SDag-Erling Smørgrav time_t t;
2518bc421551SDag-Erling Smørgrav struct tm tmcpy;
2519bc421551SDag-Erling Smørgrav mktmcpy(&tmcpy, tmp);
2520bc421551SDag-Erling Smørgrav tmcpy.tm_wday = -1;
2521bc421551SDag-Erling Smørgrav t = timeoff(&tmcpy, 0);
2522bc421551SDag-Erling Smørgrav if (0 <= tmcpy.tm_wday)
2523bc421551SDag-Erling Smørgrav *tmp = tmcpy;
2524bc421551SDag-Erling Smørgrav return t;
2525bc421551SDag-Erling Smørgrav }
2526bc421551SDag-Erling Smørgrav
2527bc421551SDag-Erling Smørgrav static int_fast32_t
leapcorr(struct state const * sp,time_t t)2528bc421551SDag-Erling Smørgrav leapcorr(struct state const *sp, time_t t)
2529bc421551SDag-Erling Smørgrav {
2530bc421551SDag-Erling Smørgrav register struct lsinfo const * lp;
2531bc421551SDag-Erling Smørgrav register int i;
2532bc421551SDag-Erling Smørgrav
2533bc421551SDag-Erling Smørgrav i = sp->leapcnt;
2534bc421551SDag-Erling Smørgrav while (--i >= 0) {
2535bc421551SDag-Erling Smørgrav lp = &sp->lsis[i];
2536bc421551SDag-Erling Smørgrav if (t >= lp->ls_trans)
2537bc421551SDag-Erling Smørgrav return lp->ls_corr;
2538bc421551SDag-Erling Smørgrav }
2539bc421551SDag-Erling Smørgrav return 0;
2540bc421551SDag-Erling Smørgrav }
2541bc421551SDag-Erling Smørgrav
2542bc421551SDag-Erling Smørgrav /*
2543bc421551SDag-Erling Smørgrav ** XXX--is the below the right way to conditionalize??
2544bc421551SDag-Erling Smørgrav */
2545bc421551SDag-Erling Smørgrav
254675411d15SDag-Erling Smørgrav #if STD_INSPIRED
2547bc421551SDag-Erling Smørgrav
2548bc421551SDag-Erling Smørgrav /* NETBSD_INSPIRED_EXTERN functions are exported to callers if
2549bc421551SDag-Erling Smørgrav NETBSD_INSPIRED is defined, and are private otherwise. */
2550bc421551SDag-Erling Smørgrav # if NETBSD_INSPIRED
2551bc421551SDag-Erling Smørgrav # define NETBSD_INSPIRED_EXTERN
2552bc421551SDag-Erling Smørgrav # else
2553bc421551SDag-Erling Smørgrav # define NETBSD_INSPIRED_EXTERN static
2554bc421551SDag-Erling Smørgrav # endif
2555bc421551SDag-Erling Smørgrav
2556bc421551SDag-Erling Smørgrav /*
2557bc421551SDag-Erling Smørgrav ** IEEE Std 1003.1 (POSIX) says that 536457599
2558bc421551SDag-Erling Smørgrav ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2559bc421551SDag-Erling Smørgrav ** is not the case if we are accounting for leap seconds.
2560bc421551SDag-Erling Smørgrav ** So, we provide the following conversion routines for use
2561bc421551SDag-Erling Smørgrav ** when exchanging timestamps with POSIX conforming systems.
2562bc421551SDag-Erling Smørgrav */
2563bc421551SDag-Erling Smørgrav
2564bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t
time2posix_z(struct state * sp,time_t t)2565bc421551SDag-Erling Smørgrav time2posix_z(struct state *sp, time_t t)
2566bc421551SDag-Erling Smørgrav {
2567bc421551SDag-Erling Smørgrav return t - leapcorr(sp, t);
2568bc421551SDag-Erling Smørgrav }
2569bc421551SDag-Erling Smørgrav
2570bc421551SDag-Erling Smørgrav time_t
time2posix(time_t t)2571bc421551SDag-Erling Smørgrav time2posix(time_t t)
2572bc421551SDag-Erling Smørgrav {
2573bc421551SDag-Erling Smørgrav int err = lock();
2574bc421551SDag-Erling Smørgrav if (err) {
2575bc421551SDag-Erling Smørgrav errno = err;
2576bc421551SDag-Erling Smørgrav return -1;
2577bc421551SDag-Erling Smørgrav }
2578bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
2579bc421551SDag-Erling Smørgrav if (!lcl_is_set)
2580bc421551SDag-Erling Smørgrav #endif
2581bc421551SDag-Erling Smørgrav tzset_unlocked();
2582bc421551SDag-Erling Smørgrav if (lclptr)
2583bc421551SDag-Erling Smørgrav t = time2posix_z(lclptr, t);
2584bc421551SDag-Erling Smørgrav unlock();
2585bc421551SDag-Erling Smørgrav return t;
2586bc421551SDag-Erling Smørgrav }
2587bc421551SDag-Erling Smørgrav
2588bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t
posix2time_z(struct state * sp,time_t t)2589bc421551SDag-Erling Smørgrav posix2time_z(struct state *sp, time_t t)
2590bc421551SDag-Erling Smørgrav {
2591bc421551SDag-Erling Smørgrav time_t x;
2592bc421551SDag-Erling Smørgrav time_t y;
2593bc421551SDag-Erling Smørgrav /*
2594bc421551SDag-Erling Smørgrav ** For a positive leap second hit, the result
2595bc421551SDag-Erling Smørgrav ** is not unique. For a negative leap second
2596bc421551SDag-Erling Smørgrav ** hit, the corresponding time doesn't exist,
2597bc421551SDag-Erling Smørgrav ** so we return an adjacent second.
2598bc421551SDag-Erling Smørgrav */
2599bc421551SDag-Erling Smørgrav x = t + leapcorr(sp, t);
2600bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x);
2601bc421551SDag-Erling Smørgrav if (y < t) {
2602bc421551SDag-Erling Smørgrav do {
2603bc421551SDag-Erling Smørgrav x++;
2604bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x);
2605bc421551SDag-Erling Smørgrav } while (y < t);
2606bc421551SDag-Erling Smørgrav x -= y != t;
2607bc421551SDag-Erling Smørgrav } else if (y > t) {
2608bc421551SDag-Erling Smørgrav do {
2609bc421551SDag-Erling Smørgrav --x;
2610bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x);
2611bc421551SDag-Erling Smørgrav } while (y > t);
2612bc421551SDag-Erling Smørgrav x += y != t;
2613bc421551SDag-Erling Smørgrav }
2614bc421551SDag-Erling Smørgrav return x;
2615bc421551SDag-Erling Smørgrav }
2616bc421551SDag-Erling Smørgrav
2617bc421551SDag-Erling Smørgrav time_t
posix2time(time_t t)2618bc421551SDag-Erling Smørgrav posix2time(time_t t)
2619bc421551SDag-Erling Smørgrav {
2620bc421551SDag-Erling Smørgrav int err = lock();
2621bc421551SDag-Erling Smørgrav if (err) {
2622bc421551SDag-Erling Smørgrav errno = err;
2623bc421551SDag-Erling Smørgrav return -1;
2624bc421551SDag-Erling Smørgrav }
2625bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
2626bc421551SDag-Erling Smørgrav if (!lcl_is_set)
2627bc421551SDag-Erling Smørgrav #endif
2628bc421551SDag-Erling Smørgrav tzset_unlocked();
2629bc421551SDag-Erling Smørgrav if (lclptr)
2630bc421551SDag-Erling Smørgrav t = posix2time_z(lclptr, t);
2631bc421551SDag-Erling Smørgrav unlock();
2632bc421551SDag-Erling Smørgrav return t;
2633bc421551SDag-Erling Smørgrav }
2634bc421551SDag-Erling Smørgrav
263575411d15SDag-Erling Smørgrav #endif /* STD_INSPIRED */
2636bc421551SDag-Erling Smørgrav
2637bc421551SDag-Erling Smørgrav #if TZ_TIME_T
2638bc421551SDag-Erling Smørgrav
2639bc421551SDag-Erling Smørgrav # if !USG_COMPAT
2640bc421551SDag-Erling Smørgrav # define daylight 0
2641bc421551SDag-Erling Smørgrav # define timezone 0
2642bc421551SDag-Erling Smørgrav # endif
2643bc421551SDag-Erling Smørgrav # if !ALTZONE
2644bc421551SDag-Erling Smørgrav # define altzone 0
2645bc421551SDag-Erling Smørgrav # endif
2646bc421551SDag-Erling Smørgrav
2647bc421551SDag-Erling Smørgrav /* Convert from the underlying system's time_t to the ersatz time_tz,
2648bc421551SDag-Erling Smørgrav which is called 'time_t' in this file. Typically, this merely
2649bc421551SDag-Erling Smørgrav converts the time's integer width. On some platforms, the system
2650bc421551SDag-Erling Smørgrav time is local time not UT, or uses some epoch other than the POSIX
2651bc421551SDag-Erling Smørgrav epoch.
2652bc421551SDag-Erling Smørgrav
2653bc421551SDag-Erling Smørgrav Although this code appears to define a function named 'time' that
2654bc421551SDag-Erling Smørgrav returns time_t, the macros in private.h cause this code to actually
2655bc421551SDag-Erling Smørgrav define a function named 'tz_time' that returns tz_time_t. The call
2656bc421551SDag-Erling Smørgrav to sys_time invokes the underlying system's 'time' function. */
2657bc421551SDag-Erling Smørgrav
2658bc421551SDag-Erling Smørgrav time_t
time(time_t * p)2659bc421551SDag-Erling Smørgrav time(time_t *p)
2660bc421551SDag-Erling Smørgrav {
2661bc421551SDag-Erling Smørgrav time_t r = sys_time(0);
2662bc421551SDag-Erling Smørgrav if (r != (time_t) -1) {
2663bc421551SDag-Erling Smørgrav int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
2664bc421551SDag-Erling Smørgrav if (increment_overflow32(&offset, -EPOCH_OFFSET)
2665bc421551SDag-Erling Smørgrav || increment_overflow_time(&r, offset)) {
2666bc421551SDag-Erling Smørgrav errno = EOVERFLOW;
2667bc421551SDag-Erling Smørgrav r = -1;
2668bc421551SDag-Erling Smørgrav }
2669bc421551SDag-Erling Smørgrav }
2670bc421551SDag-Erling Smørgrav if (p)
2671bc421551SDag-Erling Smørgrav *p = r;
2672bc421551SDag-Erling Smørgrav return r;
2673bc421551SDag-Erling Smørgrav }
2674bc421551SDag-Erling Smørgrav
2675bc421551SDag-Erling Smørgrav #endif
2676