xref: /freebsd/contrib/tzcode/localtime.c (revision a979394afeb5c20fc58c5f5b005d51eb8f92f666)
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;
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 }
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
47bc421551SDag-Erling Smørgrav static int lock(void) { return 0; }
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 
128*a979394aSDag-Erling Smørgrav /* Limit to time zone abbreviation length in proleptic 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 
154bc421551SDag-Erling Smørgrav enum r_type {
155bc421551SDag-Erling Smørgrav   JULIAN_DAY,		/* Jn = Julian day */
156bc421551SDag-Erling Smørgrav   DAY_OF_YEAR,		/* n = day of year */
157bc421551SDag-Erling Smørgrav   MONTH_NTH_DAY_OF_WEEK	/* Mm.n.d = month, week, day of week */
158bc421551SDag-Erling Smørgrav };
159bc421551SDag-Erling Smørgrav 
160bc421551SDag-Erling Smørgrav struct rule {
161bc421551SDag-Erling Smørgrav 	enum r_type	r_type;		/* type of rule */
162bc421551SDag-Erling Smørgrav 	int		r_day;		/* day number of rule */
163bc421551SDag-Erling Smørgrav 	int		r_week;		/* week number of rule */
164bc421551SDag-Erling Smørgrav 	int		r_mon;		/* month number of rule */
165bc421551SDag-Erling Smørgrav 	int_fast32_t	r_time;		/* transition time of rule */
166bc421551SDag-Erling Smørgrav };
167bc421551SDag-Erling Smørgrav 
168bc421551SDag-Erling Smørgrav static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
169bc421551SDag-Erling Smørgrav 			 struct tm *);
170bc421551SDag-Erling Smørgrav static bool increment_overflow(int *, int);
171bc421551SDag-Erling Smørgrav static bool increment_overflow_time(time_t *, int_fast32_t);
172bc421551SDag-Erling Smørgrav static int_fast32_t leapcorr(struct state const *, time_t);
173bc421551SDag-Erling Smørgrav static bool normalize_overflow32(int_fast32_t *, int *, int);
174bc421551SDag-Erling Smørgrav static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
175bc421551SDag-Erling Smørgrav 			  struct tm *);
17646c59934SDag-Erling Smørgrav static bool tzparse(char const *, struct state *, struct state const *);
177bc421551SDag-Erling Smørgrav 
178bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
179bc421551SDag-Erling Smørgrav static struct state *	lclptr;
180bc421551SDag-Erling Smørgrav static struct state *	gmtptr;
181bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */
182bc421551SDag-Erling Smørgrav 
183bc421551SDag-Erling Smørgrav #ifndef ALL_STATE
184bc421551SDag-Erling Smørgrav static struct state	lclmem;
185bc421551SDag-Erling Smørgrav static struct state	gmtmem;
186bc421551SDag-Erling Smørgrav static struct state *const lclptr = &lclmem;
187bc421551SDag-Erling Smørgrav static struct state *const gmtptr = &gmtmem;
188bc421551SDag-Erling Smørgrav #endif /* State Farm */
189bc421551SDag-Erling Smørgrav 
190bc421551SDag-Erling Smørgrav #ifndef TZ_STRLEN_MAX
191bc421551SDag-Erling Smørgrav # define TZ_STRLEN_MAX 255
192bc421551SDag-Erling Smørgrav #endif /* !defined TZ_STRLEN_MAX */
193bc421551SDag-Erling Smørgrav 
194bc421551SDag-Erling Smørgrav static char		lcl_TZname[TZ_STRLEN_MAX + 1];
195bc421551SDag-Erling Smørgrav static int		lcl_is_set;
196bc421551SDag-Erling Smørgrav 
197bc421551SDag-Erling Smørgrav static pthread_once_t	gmt_once = PTHREAD_ONCE_INIT;
198bc421551SDag-Erling Smørgrav static pthread_once_t	gmtime_once = PTHREAD_ONCE_INIT;
199bc421551SDag-Erling Smørgrav static pthread_key_t	gmtime_key;
200bc421551SDag-Erling Smørgrav static int		gmtime_key_error;
20175411d15SDag-Erling Smørgrav static pthread_once_t	offtime_once = PTHREAD_ONCE_INIT;
20275411d15SDag-Erling Smørgrav static pthread_key_t	offtime_key;
20375411d15SDag-Erling Smørgrav static int		offtime_key_error;
204bc421551SDag-Erling Smørgrav static pthread_once_t	localtime_once = PTHREAD_ONCE_INIT;
205bc421551SDag-Erling Smørgrav static pthread_key_t	localtime_key;
206bc421551SDag-Erling Smørgrav static int		localtime_key_error;
207bc421551SDag-Erling Smørgrav 
208bc421551SDag-Erling Smørgrav /*
209bc421551SDag-Erling Smørgrav ** Section 4.12.3 of X3.159-1989 requires that
210bc421551SDag-Erling Smørgrav **	Except for the strftime function, these functions [asctime,
211bc421551SDag-Erling Smørgrav **	ctime, gmtime, localtime] return values in one of two static
212bc421551SDag-Erling Smørgrav **	objects: a broken-down time structure and an array of char.
213bc421551SDag-Erling Smørgrav ** Thanks to Paul Eggert for noting this.
21475411d15SDag-Erling Smørgrav **
215*a979394aSDag-Erling Smørgrav ** Although this requirement was removed in C99 it is still present in POSIX.
216*a979394aSDag-Erling Smørgrav ** Follow the requirement if SUPPORT_C89, even though this is more likely to
217*a979394aSDag-Erling Smørgrav ** trigger latent bugs in programs.
218bc421551SDag-Erling Smørgrav */
219bc421551SDag-Erling Smørgrav 
22075411d15SDag-Erling Smørgrav #if SUPPORT_C89
221bc421551SDag-Erling Smørgrav static struct tm	tm;
22275411d15SDag-Erling Smørgrav #endif
223bc421551SDag-Erling Smørgrav 
224bc421551SDag-Erling Smørgrav #if 2 <= HAVE_TZNAME + TZ_TIME_T
225bc421551SDag-Erling Smørgrav char *			tzname[2] = {
226bc421551SDag-Erling Smørgrav 	(char *) wildabbr,
227bc421551SDag-Erling Smørgrav 	(char *) wildabbr
228bc421551SDag-Erling Smørgrav };
229bc421551SDag-Erling Smørgrav #endif
230bc421551SDag-Erling Smørgrav #if 2 <= USG_COMPAT + TZ_TIME_T
231bc421551SDag-Erling Smørgrav long			timezone;
232bc421551SDag-Erling Smørgrav int			daylight;
233bc421551SDag-Erling Smørgrav #endif
234bc421551SDag-Erling Smørgrav #if 2 <= ALTZONE + TZ_TIME_T
235bc421551SDag-Erling Smørgrav long			altzone;
236bc421551SDag-Erling Smørgrav #endif
237bc421551SDag-Erling Smørgrav 
238bc421551SDag-Erling Smørgrav /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX.  */
239bc421551SDag-Erling Smørgrav static void
240bc421551SDag-Erling Smørgrav init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
241bc421551SDag-Erling Smørgrav {
242bc421551SDag-Erling Smørgrav   s->tt_utoff = utoff;
243bc421551SDag-Erling Smørgrav   s->tt_isdst = isdst;
244bc421551SDag-Erling Smørgrav   s->tt_desigidx = desigidx;
245bc421551SDag-Erling Smørgrav   s->tt_ttisstd = false;
246bc421551SDag-Erling Smørgrav   s->tt_ttisut = false;
247bc421551SDag-Erling Smørgrav }
248bc421551SDag-Erling Smørgrav 
249bc421551SDag-Erling Smørgrav /* Return true if SP's time type I does not specify local time.  */
250bc421551SDag-Erling Smørgrav static bool
251bc421551SDag-Erling Smørgrav ttunspecified(struct state const *sp, int i)
252bc421551SDag-Erling Smørgrav {
253bc421551SDag-Erling Smørgrav   char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
254bc421551SDag-Erling Smørgrav   /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA.  */
255bc421551SDag-Erling Smørgrav   return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
256bc421551SDag-Erling Smørgrav }
257bc421551SDag-Erling Smørgrav 
258bc421551SDag-Erling Smørgrav static int_fast32_t
259bc421551SDag-Erling Smørgrav detzcode(const char *const codep)
260bc421551SDag-Erling Smørgrav {
261bc421551SDag-Erling Smørgrav 	register int_fast32_t	result;
262bc421551SDag-Erling Smørgrav 	register int		i;
263bc421551SDag-Erling Smørgrav 	int_fast32_t one = 1;
264bc421551SDag-Erling Smørgrav 	int_fast32_t halfmaxval = one << (32 - 2);
265bc421551SDag-Erling Smørgrav 	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
266bc421551SDag-Erling Smørgrav 	int_fast32_t minval = -1 - maxval;
267bc421551SDag-Erling Smørgrav 
268bc421551SDag-Erling Smørgrav 	result = codep[0] & 0x7f;
269bc421551SDag-Erling Smørgrav 	for (i = 1; i < 4; ++i)
270bc421551SDag-Erling Smørgrav 		result = (result << 8) | (codep[i] & 0xff);
271bc421551SDag-Erling Smørgrav 
272bc421551SDag-Erling Smørgrav 	if (codep[0] & 0x80) {
273bc421551SDag-Erling Smørgrav 	  /* Do two's-complement negation even on non-two's-complement machines.
274bc421551SDag-Erling Smørgrav 	     If the result would be minval - 1, return minval.  */
275bc421551SDag-Erling Smørgrav 	  result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
276bc421551SDag-Erling Smørgrav 	  result += minval;
277bc421551SDag-Erling Smørgrav 	}
278bc421551SDag-Erling Smørgrav 	return result;
279bc421551SDag-Erling Smørgrav }
280bc421551SDag-Erling Smørgrav 
281bc421551SDag-Erling Smørgrav static int_fast64_t
282bc421551SDag-Erling Smørgrav detzcode64(const char *const codep)
283bc421551SDag-Erling Smørgrav {
284bc421551SDag-Erling Smørgrav 	register int_fast64_t result;
285bc421551SDag-Erling Smørgrav 	register int	i;
286bc421551SDag-Erling Smørgrav 	int_fast64_t one = 1;
287bc421551SDag-Erling Smørgrav 	int_fast64_t halfmaxval = one << (64 - 2);
288bc421551SDag-Erling Smørgrav 	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
289bc421551SDag-Erling Smørgrav 	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
290bc421551SDag-Erling Smørgrav 
291bc421551SDag-Erling Smørgrav 	result = codep[0] & 0x7f;
292bc421551SDag-Erling Smørgrav 	for (i = 1; i < 8; ++i)
293bc421551SDag-Erling Smørgrav 		result = (result << 8) | (codep[i] & 0xff);
294bc421551SDag-Erling Smørgrav 
295bc421551SDag-Erling Smørgrav 	if (codep[0] & 0x80) {
296bc421551SDag-Erling Smørgrav 	  /* Do two's-complement negation even on non-two's-complement machines.
297bc421551SDag-Erling Smørgrav 	     If the result would be minval - 1, return minval.  */
298bc421551SDag-Erling Smørgrav 	  result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
299bc421551SDag-Erling Smørgrav 	  result += minval;
300bc421551SDag-Erling Smørgrav 	}
301bc421551SDag-Erling Smørgrav 	return result;
302bc421551SDag-Erling Smørgrav }
303bc421551SDag-Erling Smørgrav 
304bc421551SDag-Erling Smørgrav static void
305bc421551SDag-Erling Smørgrav update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
306bc421551SDag-Erling Smørgrav {
307bc421551SDag-Erling Smørgrav #if HAVE_TZNAME
308bc421551SDag-Erling Smørgrav   tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
309bc421551SDag-Erling Smørgrav #endif
310bc421551SDag-Erling Smørgrav #if USG_COMPAT
311bc421551SDag-Erling Smørgrav   if (!ttisp->tt_isdst)
312bc421551SDag-Erling Smørgrav     timezone = - ttisp->tt_utoff;
313bc421551SDag-Erling Smørgrav #endif
314bc421551SDag-Erling Smørgrav #if ALTZONE
315bc421551SDag-Erling Smørgrav   if (ttisp->tt_isdst)
316bc421551SDag-Erling Smørgrav     altzone = - ttisp->tt_utoff;
317bc421551SDag-Erling Smørgrav #endif
318bc421551SDag-Erling Smørgrav }
319bc421551SDag-Erling Smørgrav 
320bc421551SDag-Erling Smørgrav /* If STDDST_MASK indicates that SP's TYPE provides useful info,
321bc421551SDag-Erling Smørgrav    update tzname, timezone, and/or altzone and return STDDST_MASK,
322bc421551SDag-Erling Smørgrav    diminished by the provided info if it is a specified local time.
323bc421551SDag-Erling Smørgrav    Otherwise, return STDDST_MASK.  See settzname for STDDST_MASK.  */
324bc421551SDag-Erling Smørgrav static int
325bc421551SDag-Erling Smørgrav may_update_tzname_etc(int stddst_mask, struct state *sp, int type)
326bc421551SDag-Erling Smørgrav {
327bc421551SDag-Erling Smørgrav   struct ttinfo *ttisp = &sp->ttis[type];
328bc421551SDag-Erling Smørgrav   int this_bit = 1 << ttisp->tt_isdst;
329bc421551SDag-Erling Smørgrav   if (stddst_mask & this_bit) {
330bc421551SDag-Erling Smørgrav     update_tzname_etc(sp, ttisp);
331bc421551SDag-Erling Smørgrav     if (!ttunspecified(sp, type))
332bc421551SDag-Erling Smørgrav       return stddst_mask & ~this_bit;
333bc421551SDag-Erling Smørgrav   }
334bc421551SDag-Erling Smørgrav   return stddst_mask;
335bc421551SDag-Erling Smørgrav }
336bc421551SDag-Erling Smørgrav 
337bc421551SDag-Erling Smørgrav static void
338bc421551SDag-Erling Smørgrav settzname(void)
339bc421551SDag-Erling Smørgrav {
340bc421551SDag-Erling Smørgrav 	register struct state * const	sp = lclptr;
341bc421551SDag-Erling Smørgrav 	register int			i;
342bc421551SDag-Erling Smørgrav 
343bc421551SDag-Erling Smørgrav 	/* If STDDST_MASK & 1 we need info about a standard time.
344bc421551SDag-Erling Smørgrav 	   If STDDST_MASK & 2 we need info about a daylight saving time.
345bc421551SDag-Erling Smørgrav 	   When STDDST_MASK becomes zero we can stop looking.  */
346bc421551SDag-Erling Smørgrav 	int stddst_mask = 0;
347bc421551SDag-Erling Smørgrav 
348bc421551SDag-Erling Smørgrav #if HAVE_TZNAME
349bc421551SDag-Erling Smørgrav 	tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
350bc421551SDag-Erling Smørgrav 	stddst_mask = 3;
351bc421551SDag-Erling Smørgrav #endif
352bc421551SDag-Erling Smørgrav #if USG_COMPAT
353bc421551SDag-Erling Smørgrav 	timezone = 0;
354bc421551SDag-Erling Smørgrav 	stddst_mask = 3;
355bc421551SDag-Erling Smørgrav #endif
356bc421551SDag-Erling Smørgrav #if ALTZONE
357bc421551SDag-Erling Smørgrav 	altzone = 0;
358bc421551SDag-Erling Smørgrav 	stddst_mask |= 2;
359bc421551SDag-Erling Smørgrav #endif
360bc421551SDag-Erling Smørgrav 	/*
361bc421551SDag-Erling Smørgrav 	** And to get the latest time zone abbreviations into tzname. . .
362bc421551SDag-Erling Smørgrav 	*/
363bc421551SDag-Erling Smørgrav 	if (sp) {
364bc421551SDag-Erling Smørgrav 	  for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
365bc421551SDag-Erling Smørgrav 	    stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
366bc421551SDag-Erling Smørgrav 	  for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
367bc421551SDag-Erling Smørgrav 	    stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
368bc421551SDag-Erling Smørgrav 	}
369bc421551SDag-Erling Smørgrav #if USG_COMPAT
370bc421551SDag-Erling Smørgrav 	daylight = stddst_mask >> 1 ^ 1;
371bc421551SDag-Erling Smørgrav #endif
372bc421551SDag-Erling Smørgrav }
373bc421551SDag-Erling Smørgrav 
37475411d15SDag-Erling Smørgrav /* Replace bogus characters in time zone abbreviations.
37575411d15SDag-Erling Smørgrav    Return 0 on success, an errno value if a time zone abbreviation is
37675411d15SDag-Erling Smørgrav    too long.  */
37775411d15SDag-Erling Smørgrav static int
378bc421551SDag-Erling Smørgrav scrub_abbrs(struct state *sp)
379bc421551SDag-Erling Smørgrav {
380bc421551SDag-Erling Smørgrav 	int i;
38175411d15SDag-Erling Smørgrav 
38275411d15SDag-Erling Smørgrav 	/* Reject overlong abbreviations.  */
38375411d15SDag-Erling Smørgrav 	for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
38475411d15SDag-Erling Smørgrav 	  int len = strlen(&sp->chars[i]);
38575411d15SDag-Erling Smørgrav 	  if (TZNAME_MAXIMUM < len)
38675411d15SDag-Erling Smørgrav 	    return EOVERFLOW;
38775411d15SDag-Erling Smørgrav 	  i += len + 1;
38875411d15SDag-Erling Smørgrav 	}
38975411d15SDag-Erling Smørgrav 
39075411d15SDag-Erling Smørgrav 	/* Replace bogus characters.  */
391bc421551SDag-Erling Smørgrav 	for (i = 0; i < sp->charcnt; ++i)
392bc421551SDag-Erling Smørgrav 		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
393bc421551SDag-Erling Smørgrav 			sp->chars[i] = TZ_ABBR_ERR_CHAR;
394bc421551SDag-Erling Smørgrav 
39575411d15SDag-Erling Smørgrav 	return 0;
396bc421551SDag-Erling Smørgrav }
397bc421551SDag-Erling Smørgrav 
398bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES
399bc421551SDag-Erling Smørgrav /*
400bc421551SDag-Erling Smørgrav  * Determine if there's a change in the timezone since the last time we checked.
401bc421551SDag-Erling Smørgrav  * Returns: -1 on error
402bc421551SDag-Erling Smørgrav  * 	     0 if the timezone has not changed
403bc421551SDag-Erling Smørgrav  *	     1 if the timezone has changed
404bc421551SDag-Erling Smørgrav  */
405bc421551SDag-Erling Smørgrav static int
406bc421551SDag-Erling Smørgrav change_in_tz(const char *name)
407bc421551SDag-Erling Smørgrav {
408bc421551SDag-Erling Smørgrav 	static char old_name[PATH_MAX];
409bc421551SDag-Erling Smørgrav 	static struct stat old_sb;
410bc421551SDag-Erling Smørgrav 	struct stat sb;
411bc421551SDag-Erling Smørgrav 	int error;
412bc421551SDag-Erling Smørgrav 
413bc421551SDag-Erling Smørgrav 	error = stat(name, &sb);
414bc421551SDag-Erling Smørgrav 	if (error != 0)
415bc421551SDag-Erling Smørgrav 		return -1;
416bc421551SDag-Erling Smørgrav 
417bc421551SDag-Erling Smørgrav 	if (strcmp(name, old_name) != 0) {
418bc421551SDag-Erling Smørgrav 		strlcpy(old_name, name, sizeof(old_name));
419bc421551SDag-Erling Smørgrav 		old_sb = sb;
420bc421551SDag-Erling Smørgrav 		return 1;
421bc421551SDag-Erling Smørgrav 	}
422bc421551SDag-Erling Smørgrav 
423bc421551SDag-Erling Smørgrav 	if (sb.st_dev != old_sb.st_dev ||
424bc421551SDag-Erling Smørgrav 	    sb.st_ino != old_sb.st_ino ||
425bc421551SDag-Erling Smørgrav 	    sb.st_ctime != old_sb.st_ctime ||
426bc421551SDag-Erling Smørgrav 	    sb.st_mtime != old_sb.st_mtime) {
427bc421551SDag-Erling Smørgrav 		old_sb = sb;
428bc421551SDag-Erling Smørgrav 		return 1;
429bc421551SDag-Erling Smørgrav 	}
430bc421551SDag-Erling Smørgrav 
431bc421551SDag-Erling Smørgrav 	return 0;
432bc421551SDag-Erling Smørgrav }
433bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */
434bc421551SDag-Erling Smørgrav #define	change_in_tz(X)	1
435bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */
436bc421551SDag-Erling Smørgrav 
437bc421551SDag-Erling Smørgrav /* Input buffer for data read from a compiled tz file.  */
438bc421551SDag-Erling Smørgrav union input_buffer {
439bc421551SDag-Erling Smørgrav   /* The first part of the buffer, interpreted as a header.  */
440bc421551SDag-Erling Smørgrav   struct tzhead tzhead;
441bc421551SDag-Erling Smørgrav 
44246c59934SDag-Erling Smørgrav   /* The entire buffer.  Ideally this would have no size limits;
44346c59934SDag-Erling Smørgrav      the following should suffice for practical use.  */
444bc421551SDag-Erling Smørgrav   char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
445bc421551SDag-Erling Smørgrav 	   + 4 * TZ_MAX_TIMES];
446bc421551SDag-Erling Smørgrav };
447bc421551SDag-Erling Smørgrav 
448bc421551SDag-Erling Smørgrav /* TZDIR with a trailing '/' rather than a trailing '\0'.  */
449bc421551SDag-Erling Smørgrav static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
450bc421551SDag-Erling Smørgrav 
451bc421551SDag-Erling Smørgrav /* Local storage needed for 'tzloadbody'.  */
452bc421551SDag-Erling Smørgrav union local_storage {
453bc421551SDag-Erling Smørgrav   /* The results of analyzing the file's contents after it is opened.  */
454bc421551SDag-Erling Smørgrav   struct file_analysis {
455bc421551SDag-Erling Smørgrav     /* The input buffer.  */
456bc421551SDag-Erling Smørgrav     union input_buffer u;
457bc421551SDag-Erling Smørgrav 
458bc421551SDag-Erling Smørgrav     /* A temporary state used for parsing a TZ string in the file.  */
459bc421551SDag-Erling Smørgrav     struct state st;
460bc421551SDag-Erling Smørgrav   } u;
461bc421551SDag-Erling Smørgrav 
46246c59934SDag-Erling Smørgrav   /* The name of the file to be opened.  Ideally this would have no
46346c59934SDag-Erling Smørgrav      size limits, to support arbitrarily long Zone names.
46446c59934SDag-Erling Smørgrav      Limiting Zone names to 1024 bytes should suffice for practical use.
46546c59934SDag-Erling Smørgrav      However, there is no need for this to be smaller than struct
46646c59934SDag-Erling Smørgrav      file_analysis as that struct is allocated anyway, as the other
46746c59934SDag-Erling Smørgrav      union member.  */
468bc421551SDag-Erling Smørgrav   char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
469bc421551SDag-Erling Smørgrav };
470bc421551SDag-Erling Smørgrav 
471bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP.  Read extended
472bc421551SDag-Erling Smørgrav    format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
473bc421551SDag-Erling Smørgrav    success, an errno value on failure.  */
474bc421551SDag-Erling Smørgrav static int
475bc421551SDag-Erling Smørgrav tzloadbody(char const *name, struct state *sp, bool doextend,
476bc421551SDag-Erling Smørgrav 	   union local_storage *lsp)
477bc421551SDag-Erling Smørgrav {
478bc421551SDag-Erling Smørgrav 	register int			i;
479bc421551SDag-Erling Smørgrav 	register int			fid;
480bc421551SDag-Erling Smørgrav 	register int			stored;
481bc421551SDag-Erling Smørgrav 	register ssize_t		nread;
482bc421551SDag-Erling Smørgrav 	register union input_buffer *up = &lsp->u.u;
483bc421551SDag-Erling Smørgrav 	register int tzheadsize = sizeof(struct tzhead);
484bc421551SDag-Erling Smørgrav 
485bc421551SDag-Erling Smørgrav 	sp->goback = sp->goahead = false;
486bc421551SDag-Erling Smørgrav 
487bc421551SDag-Erling Smørgrav 	if (! name) {
488bc421551SDag-Erling Smørgrav 		name = TZDEFAULT;
489bc421551SDag-Erling Smørgrav 		if (! name)
490bc421551SDag-Erling Smørgrav 		  return EINVAL;
491bc421551SDag-Erling Smørgrav 	}
492bc421551SDag-Erling Smørgrav 
493bc421551SDag-Erling Smørgrav 	if (name[0] == ':')
494bc421551SDag-Erling Smørgrav 		++name;
4953e2e5eebSDag-Erling Smørgrav 	if (name[0] != '/') {
496bc421551SDag-Erling Smørgrav 		if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
497bc421551SDag-Erling Smørgrav 		  return ENAMETOOLONG;
498bc421551SDag-Erling Smørgrav 
499bc421551SDag-Erling Smørgrav 		/* Create a string "TZDIR/NAME".  Using sprintf here
500bc421551SDag-Erling Smørgrav 		   would pull in stdio (and would fail if the
501bc421551SDag-Erling Smørgrav 		   resulting string length exceeded INT_MAX!).  */
502bc421551SDag-Erling Smørgrav 		memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
503bc421551SDag-Erling Smørgrav 		strcpy(lsp->fullname + sizeof tzdirslash, name);
504bc421551SDag-Erling Smørgrav 
505bc421551SDag-Erling Smørgrav 		name = lsp->fullname;
506bc421551SDag-Erling Smørgrav 	}
507bc421551SDag-Erling Smørgrav 	if (doextend) {
508bc421551SDag-Erling Smørgrav 		/*
509bc421551SDag-Erling Smørgrav 		 * Detect if the timezone file has changed.  Check
510bc421551SDag-Erling Smørgrav 		 * 'doextend' to ignore TZDEFRULES; the change_in_tz()
511bc421551SDag-Erling Smørgrav 		 * function can only keep state for a single file.
512bc421551SDag-Erling Smørgrav 		 */
513bc421551SDag-Erling Smørgrav 		int ret = change_in_tz(name);
514bc421551SDag-Erling Smørgrav 		if (ret <= 0) {
515bc421551SDag-Erling Smørgrav 			/*
516bc421551SDag-Erling Smørgrav 			 * Returns an errno value if there was an error,
517bc421551SDag-Erling Smørgrav 			 * and 0 if the timezone had not changed.
518bc421551SDag-Erling Smørgrav 			 */
519bc421551SDag-Erling Smørgrav 			return errno;
520bc421551SDag-Erling Smørgrav 		}
521bc421551SDag-Erling Smørgrav 	}
522bc421551SDag-Erling Smørgrav 	fid = _open(name, O_RDONLY | O_BINARY);
523bc421551SDag-Erling Smørgrav 	if (fid < 0)
524bc421551SDag-Erling Smørgrav 	  return errno;
525bc421551SDag-Erling Smørgrav 
526bc421551SDag-Erling Smørgrav 	nread = _read(fid, up->buf, sizeof up->buf);
527bc421551SDag-Erling Smørgrav 	if (nread < tzheadsize) {
528bc421551SDag-Erling Smørgrav 	  int err = nread < 0 ? errno : EINVAL;
529bc421551SDag-Erling Smørgrav 	  _close(fid);
530bc421551SDag-Erling Smørgrav 	  return err;
531bc421551SDag-Erling Smørgrav 	}
532bc421551SDag-Erling Smørgrav 	if (_close(fid) < 0)
533bc421551SDag-Erling Smørgrav 	  return errno;
534bc421551SDag-Erling Smørgrav 	for (stored = 4; stored <= 8; stored *= 2) {
535bc421551SDag-Erling Smørgrav 	    char version = up->tzhead.tzh_version[0];
536bc421551SDag-Erling Smørgrav 	    bool skip_datablock = stored == 4 && version;
537bc421551SDag-Erling Smørgrav 	    int_fast32_t datablock_size;
538bc421551SDag-Erling Smørgrav 	    int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
539bc421551SDag-Erling Smørgrav 	    int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
540bc421551SDag-Erling Smørgrav 	    int_fast64_t prevtr = -1;
541bc421551SDag-Erling Smørgrav 	    int_fast32_t prevcorr;
542bc421551SDag-Erling Smørgrav 	    int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
543bc421551SDag-Erling Smørgrav 	    int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
544bc421551SDag-Erling Smørgrav 	    int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
545bc421551SDag-Erling Smørgrav 	    int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
546bc421551SDag-Erling Smørgrav 	    char const *p = up->buf + tzheadsize;
547bc421551SDag-Erling Smørgrav 	    /* Although tzfile(5) currently requires typecnt to be nonzero,
548bc421551SDag-Erling Smørgrav 	       support future formats that may allow zero typecnt
549bc421551SDag-Erling Smørgrav 	       in files that have a TZ string and no transitions.  */
550bc421551SDag-Erling Smørgrav 	    if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
551bc421551SDag-Erling Smørgrav 		   && 0 <= typecnt && typecnt < TZ_MAX_TYPES
552bc421551SDag-Erling Smørgrav 		   && 0 <= timecnt && timecnt < TZ_MAX_TIMES
553bc421551SDag-Erling Smørgrav 		   && 0 <= charcnt && charcnt < TZ_MAX_CHARS
554bc421551SDag-Erling Smørgrav 		   && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
555bc421551SDag-Erling Smørgrav 		   && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
556bc421551SDag-Erling Smørgrav 	      return EINVAL;
557bc421551SDag-Erling Smørgrav 	    datablock_size
558bc421551SDag-Erling Smørgrav 		    = (timecnt * stored		/* ats */
559bc421551SDag-Erling Smørgrav 		       + timecnt		/* types */
560bc421551SDag-Erling Smørgrav 		       + typecnt * 6		/* ttinfos */
561bc421551SDag-Erling Smørgrav 		       + charcnt		/* chars */
562bc421551SDag-Erling Smørgrav 		       + leapcnt * (stored + 4)	/* lsinfos */
563bc421551SDag-Erling Smørgrav 		       + ttisstdcnt		/* ttisstds */
564bc421551SDag-Erling Smørgrav 		       + ttisutcnt);		/* ttisuts */
565bc421551SDag-Erling Smørgrav 	    if (nread < tzheadsize + datablock_size)
566bc421551SDag-Erling Smørgrav 	      return EINVAL;
567bc421551SDag-Erling Smørgrav 	    if (skip_datablock)
568bc421551SDag-Erling Smørgrav 		p += datablock_size;
569bc421551SDag-Erling Smørgrav 	    else {
570bc421551SDag-Erling Smørgrav 		if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
571bc421551SDag-Erling Smørgrav 		       && (ttisutcnt == typecnt || ttisutcnt == 0)))
572bc421551SDag-Erling Smørgrav 		  return EINVAL;
573bc421551SDag-Erling Smørgrav 
574bc421551SDag-Erling Smørgrav 		sp->leapcnt = leapcnt;
575bc421551SDag-Erling Smørgrav 		sp->timecnt = timecnt;
576bc421551SDag-Erling Smørgrav 		sp->typecnt = typecnt;
577bc421551SDag-Erling Smørgrav 		sp->charcnt = charcnt;
578bc421551SDag-Erling Smørgrav 
579bc421551SDag-Erling Smørgrav 		/* Read transitions, discarding those out of time_t range.
580bc421551SDag-Erling Smørgrav 		   But pretend the last transition before TIME_T_MIN
581bc421551SDag-Erling Smørgrav 		   occurred at TIME_T_MIN.  */
582bc421551SDag-Erling Smørgrav 		timecnt = 0;
583bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->timecnt; ++i) {
584bc421551SDag-Erling Smørgrav 			int_fast64_t at
585bc421551SDag-Erling Smørgrav 			  = stored == 4 ? detzcode(p) : detzcode64(p);
586bc421551SDag-Erling Smørgrav 			sp->types[i] = at <= TIME_T_MAX;
587bc421551SDag-Erling Smørgrav 			if (sp->types[i]) {
588bc421551SDag-Erling Smørgrav 			  time_t attime
589bc421551SDag-Erling Smørgrav 			    = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
590bc421551SDag-Erling Smørgrav 			       ? TIME_T_MIN : at);
591bc421551SDag-Erling Smørgrav 			  if (timecnt && attime <= sp->ats[timecnt - 1]) {
592bc421551SDag-Erling Smørgrav 			    if (attime < sp->ats[timecnt - 1])
593bc421551SDag-Erling Smørgrav 			      return EINVAL;
594bc421551SDag-Erling Smørgrav 			    sp->types[i - 1] = 0;
595bc421551SDag-Erling Smørgrav 			    timecnt--;
596bc421551SDag-Erling Smørgrav 			  }
597bc421551SDag-Erling Smørgrav 			  sp->ats[timecnt++] = attime;
598bc421551SDag-Erling Smørgrav 			}
599bc421551SDag-Erling Smørgrav 			p += stored;
600bc421551SDag-Erling Smørgrav 		}
601bc421551SDag-Erling Smørgrav 
602bc421551SDag-Erling Smørgrav 		timecnt = 0;
603bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->timecnt; ++i) {
604bc421551SDag-Erling Smørgrav 			unsigned char typ = *p++;
605bc421551SDag-Erling Smørgrav 			if (sp->typecnt <= typ)
606bc421551SDag-Erling Smørgrav 			  return EINVAL;
607bc421551SDag-Erling Smørgrav 			if (sp->types[i])
608bc421551SDag-Erling Smørgrav 				sp->types[timecnt++] = typ;
609bc421551SDag-Erling Smørgrav 		}
610bc421551SDag-Erling Smørgrav 		sp->timecnt = timecnt;
611bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->typecnt; ++i) {
612bc421551SDag-Erling Smørgrav 			register struct ttinfo *	ttisp;
613bc421551SDag-Erling Smørgrav 			unsigned char isdst, desigidx;
614bc421551SDag-Erling Smørgrav 
615bc421551SDag-Erling Smørgrav 			ttisp = &sp->ttis[i];
616bc421551SDag-Erling Smørgrav 			ttisp->tt_utoff = detzcode(p);
617bc421551SDag-Erling Smørgrav 			p += 4;
618bc421551SDag-Erling Smørgrav 			isdst = *p++;
619bc421551SDag-Erling Smørgrav 			if (! (isdst < 2))
620bc421551SDag-Erling Smørgrav 			  return EINVAL;
621bc421551SDag-Erling Smørgrav 			ttisp->tt_isdst = isdst;
622bc421551SDag-Erling Smørgrav 			desigidx = *p++;
623bc421551SDag-Erling Smørgrav 			if (! (desigidx < sp->charcnt))
624bc421551SDag-Erling Smørgrav 			  return EINVAL;
625bc421551SDag-Erling Smørgrav 			ttisp->tt_desigidx = desigidx;
626bc421551SDag-Erling Smørgrav 		}
627bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->charcnt; ++i)
628bc421551SDag-Erling Smørgrav 			sp->chars[i] = *p++;
629bc421551SDag-Erling Smørgrav 		/* Ensure '\0'-terminated, and make it safe to call
630bc421551SDag-Erling Smørgrav 		   ttunspecified later.  */
631bc421551SDag-Erling Smørgrav 		memset(&sp->chars[i], 0, CHARS_EXTRA);
632bc421551SDag-Erling Smørgrav 
633bc421551SDag-Erling Smørgrav 		/* Read leap seconds, discarding those out of time_t range.  */
634bc421551SDag-Erling Smørgrav 		leapcnt = 0;
635bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->leapcnt; ++i) {
636bc421551SDag-Erling Smørgrav 		  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
637bc421551SDag-Erling Smørgrav 		  int_fast32_t corr = detzcode(p + stored);
638bc421551SDag-Erling Smørgrav 		  p += stored + 4;
639bc421551SDag-Erling Smørgrav 
640bc421551SDag-Erling Smørgrav 		  /* Leap seconds cannot occur before the Epoch,
641bc421551SDag-Erling Smørgrav 		     or out of order.  */
642bc421551SDag-Erling Smørgrav 		  if (tr <= prevtr)
643bc421551SDag-Erling Smørgrav 		    return EINVAL;
644bc421551SDag-Erling Smørgrav 
645bc421551SDag-Erling Smørgrav 		  /* To avoid other botches in this code, each leap second's
646bc421551SDag-Erling Smørgrav 		     correction must differ from the previous one's by 1
647bc421551SDag-Erling Smørgrav 		     second or less, except that the first correction can be
648bc421551SDag-Erling Smørgrav 		     any value; these requirements are more generous than
649bc421551SDag-Erling Smørgrav 		     RFC 8536, to allow future RFC extensions.  */
650bc421551SDag-Erling Smørgrav 		  if (! (i == 0
651bc421551SDag-Erling Smørgrav 			 || (prevcorr < corr
652bc421551SDag-Erling Smørgrav 			     ? corr == prevcorr + 1
653bc421551SDag-Erling Smørgrav 			     : (corr == prevcorr
654bc421551SDag-Erling Smørgrav 				|| corr == prevcorr - 1))))
655bc421551SDag-Erling Smørgrav 		    return EINVAL;
656bc421551SDag-Erling Smørgrav 		  prevtr = tr;
657bc421551SDag-Erling Smørgrav 		  prevcorr = corr;
658bc421551SDag-Erling Smørgrav 
659bc421551SDag-Erling Smørgrav 		  if (tr <= TIME_T_MAX) {
660bc421551SDag-Erling Smørgrav 		    sp->lsis[leapcnt].ls_trans = tr;
661bc421551SDag-Erling Smørgrav 		    sp->lsis[leapcnt].ls_corr = corr;
662bc421551SDag-Erling Smørgrav 		    leapcnt++;
663bc421551SDag-Erling Smørgrav 		  }
664bc421551SDag-Erling Smørgrav 		}
665bc421551SDag-Erling Smørgrav 		sp->leapcnt = leapcnt;
666bc421551SDag-Erling Smørgrav 
667bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->typecnt; ++i) {
668bc421551SDag-Erling Smørgrav 			register struct ttinfo *	ttisp;
669bc421551SDag-Erling Smørgrav 
670bc421551SDag-Erling Smørgrav 			ttisp = &sp->ttis[i];
671bc421551SDag-Erling Smørgrav 			if (ttisstdcnt == 0)
672bc421551SDag-Erling Smørgrav 				ttisp->tt_ttisstd = false;
673bc421551SDag-Erling Smørgrav 			else {
674bc421551SDag-Erling Smørgrav 				if (*p != true && *p != false)
675bc421551SDag-Erling Smørgrav 				  return EINVAL;
676bc421551SDag-Erling Smørgrav 				ttisp->tt_ttisstd = *p++;
677bc421551SDag-Erling Smørgrav 			}
678bc421551SDag-Erling Smørgrav 		}
679bc421551SDag-Erling Smørgrav 		for (i = 0; i < sp->typecnt; ++i) {
680bc421551SDag-Erling Smørgrav 			register struct ttinfo *	ttisp;
681bc421551SDag-Erling Smørgrav 
682bc421551SDag-Erling Smørgrav 			ttisp = &sp->ttis[i];
683bc421551SDag-Erling Smørgrav 			if (ttisutcnt == 0)
684bc421551SDag-Erling Smørgrav 				ttisp->tt_ttisut = false;
685bc421551SDag-Erling Smørgrav 			else {
686bc421551SDag-Erling Smørgrav 				if (*p != true && *p != false)
687bc421551SDag-Erling Smørgrav 						return EINVAL;
688bc421551SDag-Erling Smørgrav 				ttisp->tt_ttisut = *p++;
689bc421551SDag-Erling Smørgrav 			}
690bc421551SDag-Erling Smørgrav 		}
691bc421551SDag-Erling Smørgrav 	    }
692bc421551SDag-Erling Smørgrav 
693bc421551SDag-Erling Smørgrav 	    nread -= p - up->buf;
694bc421551SDag-Erling Smørgrav 	    memmove(up->buf, p, nread);
695bc421551SDag-Erling Smørgrav 
696bc421551SDag-Erling Smørgrav 	    /* If this is an old file, we're done.  */
697bc421551SDag-Erling Smørgrav 	    if (!version)
698bc421551SDag-Erling Smørgrav 	      break;
699bc421551SDag-Erling Smørgrav 	}
700bc421551SDag-Erling Smørgrav 	if (doextend && nread > 2 &&
701bc421551SDag-Erling Smørgrav 		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
702bc421551SDag-Erling Smørgrav 		sp->typecnt + 2 <= TZ_MAX_TYPES) {
703bc421551SDag-Erling Smørgrav 			struct state	*ts = &lsp->u.st;
704bc421551SDag-Erling Smørgrav 
705bc421551SDag-Erling Smørgrav 			up->buf[nread - 1] = '\0';
706bc421551SDag-Erling Smørgrav 			if (tzparse(&up->buf[1], ts, sp)) {
707bc421551SDag-Erling Smørgrav 
708bc421551SDag-Erling Smørgrav 			  /* Attempt to reuse existing abbreviations.
709bc421551SDag-Erling Smørgrav 			     Without this, America/Anchorage would be right on
710bc421551SDag-Erling Smørgrav 			     the edge after 2037 when TZ_MAX_CHARS is 50, as
711bc421551SDag-Erling Smørgrav 			     sp->charcnt equals 40 (for LMT AST AWT APT AHST
712bc421551SDag-Erling Smørgrav 			     AHDT YST AKDT AKST) and ts->charcnt equals 10
713bc421551SDag-Erling Smørgrav 			     (for AKST AKDT).  Reusing means sp->charcnt can
714bc421551SDag-Erling Smørgrav 			     stay 40 in this example.  */
715bc421551SDag-Erling Smørgrav 			  int gotabbr = 0;
716bc421551SDag-Erling Smørgrav 			  int charcnt = sp->charcnt;
717bc421551SDag-Erling Smørgrav 			  for (i = 0; i < ts->typecnt; i++) {
718bc421551SDag-Erling Smørgrav 			    char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
719bc421551SDag-Erling Smørgrav 			    int j;
720bc421551SDag-Erling Smørgrav 			    for (j = 0; j < charcnt; j++)
721bc421551SDag-Erling Smørgrav 			      if (strcmp(sp->chars + j, tsabbr) == 0) {
722bc421551SDag-Erling Smørgrav 				ts->ttis[i].tt_desigidx = j;
723bc421551SDag-Erling Smørgrav 				gotabbr++;
724bc421551SDag-Erling Smørgrav 				break;
725bc421551SDag-Erling Smørgrav 			      }
726bc421551SDag-Erling Smørgrav 			    if (! (j < charcnt)) {
727bc421551SDag-Erling Smørgrav 			      int tsabbrlen = strlen(tsabbr);
728bc421551SDag-Erling Smørgrav 			      if (j + tsabbrlen < TZ_MAX_CHARS) {
729bc421551SDag-Erling Smørgrav 				strcpy(sp->chars + j, tsabbr);
730bc421551SDag-Erling Smørgrav 				charcnt = j + tsabbrlen + 1;
731bc421551SDag-Erling Smørgrav 				ts->ttis[i].tt_desigidx = j;
732bc421551SDag-Erling Smørgrav 				gotabbr++;
733bc421551SDag-Erling Smørgrav 			      }
734bc421551SDag-Erling Smørgrav 			    }
735bc421551SDag-Erling Smørgrav 			  }
736bc421551SDag-Erling Smørgrav 			  if (gotabbr == ts->typecnt) {
737bc421551SDag-Erling Smørgrav 			    sp->charcnt = charcnt;
738bc421551SDag-Erling Smørgrav 
739bc421551SDag-Erling Smørgrav 			    /* Ignore any trailing, no-op transitions generated
740bc421551SDag-Erling Smørgrav 			       by zic as they don't help here and can run afoul
741bc421551SDag-Erling Smørgrav 			       of bugs in zic 2016j or earlier.  */
742bc421551SDag-Erling Smørgrav 			    while (1 < sp->timecnt
743bc421551SDag-Erling Smørgrav 				   && (sp->types[sp->timecnt - 1]
744bc421551SDag-Erling Smørgrav 				       == sp->types[sp->timecnt - 2]))
745bc421551SDag-Erling Smørgrav 			      sp->timecnt--;
746bc421551SDag-Erling Smørgrav 
74746c59934SDag-Erling Smørgrav 			    sp->goahead = ts->goahead;
74846c59934SDag-Erling Smørgrav 
74946c59934SDag-Erling Smørgrav 			    for (i = 0; i < ts->timecnt; i++) {
750bc421551SDag-Erling Smørgrav 			      time_t t = ts->ats[i];
751bc421551SDag-Erling Smørgrav 			      if (increment_overflow_time(&t, leapcorr(sp, t))
752bc421551SDag-Erling Smørgrav 				  || (0 < sp->timecnt
753bc421551SDag-Erling Smørgrav 				      && t <= sp->ats[sp->timecnt - 1]))
754bc421551SDag-Erling Smørgrav 				continue;
75546c59934SDag-Erling Smørgrav 			      if (TZ_MAX_TIMES <= sp->timecnt) {
75646c59934SDag-Erling Smørgrav 				sp->goahead = false;
75746c59934SDag-Erling Smørgrav 				break;
75846c59934SDag-Erling Smørgrav 			      }
759bc421551SDag-Erling Smørgrav 			      sp->ats[sp->timecnt] = t;
760bc421551SDag-Erling Smørgrav 			      sp->types[sp->timecnt] = (sp->typecnt
761bc421551SDag-Erling Smørgrav 							+ ts->types[i]);
762bc421551SDag-Erling Smørgrav 			      sp->timecnt++;
763bc421551SDag-Erling Smørgrav 			    }
764bc421551SDag-Erling Smørgrav 			    for (i = 0; i < ts->typecnt; i++)
765bc421551SDag-Erling Smørgrav 			      sp->ttis[sp->typecnt++] = ts->ttis[i];
766bc421551SDag-Erling Smørgrav 			  }
767bc421551SDag-Erling Smørgrav 			}
768bc421551SDag-Erling Smørgrav 	}
769bc421551SDag-Erling Smørgrav 	if (sp->typecnt == 0)
770bc421551SDag-Erling Smørgrav 	  return EINVAL;
771bc421551SDag-Erling Smørgrav 
772bc421551SDag-Erling Smørgrav 	return 0;
773bc421551SDag-Erling Smørgrav }
774bc421551SDag-Erling Smørgrav 
775bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP.  Read extended
776bc421551SDag-Erling Smørgrav    format if DOEXTEND.  Return 0 on success, an errno value on failure.  */
777bc421551SDag-Erling Smørgrav static int
778bc421551SDag-Erling Smørgrav tzload(char const *name, struct state *sp, bool doextend)
779bc421551SDag-Erling Smørgrav {
780bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
781bc421551SDag-Erling Smørgrav   union local_storage *lsp = malloc(sizeof *lsp);
782bc421551SDag-Erling Smørgrav   if (!lsp) {
783bc421551SDag-Erling Smørgrav     return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
784bc421551SDag-Erling Smørgrav   } else {
785bc421551SDag-Erling Smørgrav     int err = tzloadbody(name, sp, doextend, lsp);
786bc421551SDag-Erling Smørgrav     free(lsp);
787bc421551SDag-Erling Smørgrav     return err;
788bc421551SDag-Erling Smørgrav   }
789bc421551SDag-Erling Smørgrav #else
790bc421551SDag-Erling Smørgrav   union local_storage ls;
791bc421551SDag-Erling Smørgrav   return tzloadbody(name, sp, doextend, &ls);
792bc421551SDag-Erling Smørgrav #endif
793bc421551SDag-Erling Smørgrav }
794bc421551SDag-Erling Smørgrav 
795bc421551SDag-Erling Smørgrav static const int	mon_lengths[2][MONSPERYEAR] = {
796bc421551SDag-Erling Smørgrav 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
797bc421551SDag-Erling Smørgrav 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
798bc421551SDag-Erling Smørgrav };
799bc421551SDag-Erling Smørgrav 
800bc421551SDag-Erling Smørgrav static const int	year_lengths[2] = {
801bc421551SDag-Erling Smørgrav 	DAYSPERNYEAR, DAYSPERLYEAR
802bc421551SDag-Erling Smørgrav };
803bc421551SDag-Erling Smørgrav 
804bc421551SDag-Erling Smørgrav /* Is C an ASCII digit?  */
805bc421551SDag-Erling Smørgrav static bool
806bc421551SDag-Erling Smørgrav is_digit(char c)
807bc421551SDag-Erling Smørgrav {
808bc421551SDag-Erling Smørgrav   return '0' <= c && c <= '9';
809bc421551SDag-Erling Smørgrav }
810bc421551SDag-Erling Smørgrav 
811bc421551SDag-Erling Smørgrav /*
812bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, scan until a character that is not
813bc421551SDag-Erling Smørgrav ** a valid character in a time zone abbreviation is found.
814bc421551SDag-Erling Smørgrav ** Return a pointer to that character.
815bc421551SDag-Erling Smørgrav */
816bc421551SDag-Erling Smørgrav 
817*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static const char *
818bc421551SDag-Erling Smørgrav getzname(register const char *strp)
819bc421551SDag-Erling Smørgrav {
820bc421551SDag-Erling Smørgrav 	register char	c;
821bc421551SDag-Erling Smørgrav 
822bc421551SDag-Erling Smørgrav 	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
823bc421551SDag-Erling Smørgrav 		c != '+')
824bc421551SDag-Erling Smørgrav 			++strp;
825bc421551SDag-Erling Smørgrav 	return strp;
826bc421551SDag-Erling Smørgrav }
827bc421551SDag-Erling Smørgrav 
828bc421551SDag-Erling Smørgrav /*
829bc421551SDag-Erling Smørgrav ** Given a pointer into an extended timezone string, scan until the ending
830bc421551SDag-Erling Smørgrav ** delimiter of the time zone abbreviation is located.
831bc421551SDag-Erling Smørgrav ** Return a pointer to the delimiter.
832bc421551SDag-Erling Smørgrav **
833bc421551SDag-Erling Smørgrav ** As with getzname above, the legal character set is actually quite
834bc421551SDag-Erling Smørgrav ** restricted, with other characters producing undefined results.
835bc421551SDag-Erling Smørgrav ** We don't do any checking here; checking is done later in common-case code.
836bc421551SDag-Erling Smørgrav */
837bc421551SDag-Erling Smørgrav 
838*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static const char *
839bc421551SDag-Erling Smørgrav getqzname(register const char *strp, const int delim)
840bc421551SDag-Erling Smørgrav {
841bc421551SDag-Erling Smørgrav 	register int	c;
842bc421551SDag-Erling Smørgrav 
843bc421551SDag-Erling Smørgrav 	while ((c = *strp) != '\0' && c != delim)
844bc421551SDag-Erling Smørgrav 		++strp;
845bc421551SDag-Erling Smørgrav 	return strp;
846bc421551SDag-Erling Smørgrav }
847bc421551SDag-Erling Smørgrav 
848bc421551SDag-Erling Smørgrav /*
849bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number from that string.
850bc421551SDag-Erling Smørgrav ** Check that the number is within a specified range; if it is not, return
851bc421551SDag-Erling Smørgrav ** NULL.
852bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number.
853bc421551SDag-Erling Smørgrav */
854bc421551SDag-Erling Smørgrav 
855bc421551SDag-Erling Smørgrav static const char *
856bc421551SDag-Erling Smørgrav getnum(register const char *strp, int *const nump, const int min, const int max)
857bc421551SDag-Erling Smørgrav {
858bc421551SDag-Erling Smørgrav 	register char	c;
859bc421551SDag-Erling Smørgrav 	register int	num;
860bc421551SDag-Erling Smørgrav 
861bc421551SDag-Erling Smørgrav 	if (strp == NULL || !is_digit(c = *strp))
862bc421551SDag-Erling Smørgrav 		return NULL;
863bc421551SDag-Erling Smørgrav 	num = 0;
864bc421551SDag-Erling Smørgrav 	do {
865bc421551SDag-Erling Smørgrav 		num = num * 10 + (c - '0');
866bc421551SDag-Erling Smørgrav 		if (num > max)
867bc421551SDag-Erling Smørgrav 			return NULL;	/* illegal value */
868bc421551SDag-Erling Smørgrav 		c = *++strp;
869bc421551SDag-Erling Smørgrav 	} while (is_digit(c));
870bc421551SDag-Erling Smørgrav 	if (num < min)
871bc421551SDag-Erling Smørgrav 		return NULL;		/* illegal value */
872bc421551SDag-Erling Smørgrav 	*nump = num;
873bc421551SDag-Erling Smørgrav 	return strp;
874bc421551SDag-Erling Smørgrav }
875bc421551SDag-Erling Smørgrav 
876bc421551SDag-Erling Smørgrav /*
877bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number of seconds,
878bc421551SDag-Erling Smørgrav ** in hh[:mm[:ss]] form, from the string.
879bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL.
880bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number
881bc421551SDag-Erling Smørgrav ** of seconds.
882bc421551SDag-Erling Smørgrav */
883bc421551SDag-Erling Smørgrav 
884bc421551SDag-Erling Smørgrav static const char *
885bc421551SDag-Erling Smørgrav getsecs(register const char *strp, int_fast32_t *const secsp)
886bc421551SDag-Erling Smørgrav {
887bc421551SDag-Erling Smørgrav 	int	num;
888bc421551SDag-Erling Smørgrav 	int_fast32_t secsperhour = SECSPERHOUR;
889bc421551SDag-Erling Smørgrav 
890bc421551SDag-Erling Smørgrav 	/*
89146c59934SDag-Erling Smørgrav 	** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like
89246c59934SDag-Erling Smørgrav 	** "M10.4.6/26", which does not conform to POSIX,
893bc421551SDag-Erling Smørgrav 	** but which specifies the equivalent of
894bc421551SDag-Erling Smørgrav 	** "02:00 on the first Sunday on or after 23 Oct".
895bc421551SDag-Erling Smørgrav 	*/
896bc421551SDag-Erling Smørgrav 	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
897bc421551SDag-Erling Smørgrav 	if (strp == NULL)
898bc421551SDag-Erling Smørgrav 		return NULL;
899bc421551SDag-Erling Smørgrav 	*secsp = num * secsperhour;
900bc421551SDag-Erling Smørgrav 	if (*strp == ':') {
901bc421551SDag-Erling Smørgrav 		++strp;
902bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
903bc421551SDag-Erling Smørgrav 		if (strp == NULL)
904bc421551SDag-Erling Smørgrav 			return NULL;
905bc421551SDag-Erling Smørgrav 		*secsp += num * SECSPERMIN;
906bc421551SDag-Erling Smørgrav 		if (*strp == ':') {
907bc421551SDag-Erling Smørgrav 			++strp;
908bc421551SDag-Erling Smørgrav 			/* 'SECSPERMIN' allows for leap seconds.  */
909bc421551SDag-Erling Smørgrav 			strp = getnum(strp, &num, 0, SECSPERMIN);
910bc421551SDag-Erling Smørgrav 			if (strp == NULL)
911bc421551SDag-Erling Smørgrav 				return NULL;
912bc421551SDag-Erling Smørgrav 			*secsp += num;
913bc421551SDag-Erling Smørgrav 		}
914bc421551SDag-Erling Smørgrav 	}
915bc421551SDag-Erling Smørgrav 	return strp;
916bc421551SDag-Erling Smørgrav }
917bc421551SDag-Erling Smørgrav 
918bc421551SDag-Erling Smørgrav /*
919bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract an offset, in
920bc421551SDag-Erling Smørgrav ** [+-]hh[:mm[:ss]] form, from the string.
921bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL.
922bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the time.
923bc421551SDag-Erling Smørgrav */
924bc421551SDag-Erling Smørgrav 
925bc421551SDag-Erling Smørgrav static const char *
926bc421551SDag-Erling Smørgrav getoffset(register const char *strp, int_fast32_t *const offsetp)
927bc421551SDag-Erling Smørgrav {
928bc421551SDag-Erling Smørgrav 	register bool neg = false;
929bc421551SDag-Erling Smørgrav 
930bc421551SDag-Erling Smørgrav 	if (*strp == '-') {
931bc421551SDag-Erling Smørgrav 		neg = true;
932bc421551SDag-Erling Smørgrav 		++strp;
933bc421551SDag-Erling Smørgrav 	} else if (*strp == '+')
934bc421551SDag-Erling Smørgrav 		++strp;
935bc421551SDag-Erling Smørgrav 	strp = getsecs(strp, offsetp);
936bc421551SDag-Erling Smørgrav 	if (strp == NULL)
937bc421551SDag-Erling Smørgrav 		return NULL;		/* illegal time */
938bc421551SDag-Erling Smørgrav 	if (neg)
939bc421551SDag-Erling Smørgrav 		*offsetp = -*offsetp;
940bc421551SDag-Erling Smørgrav 	return strp;
941bc421551SDag-Erling Smørgrav }
942bc421551SDag-Erling Smørgrav 
943bc421551SDag-Erling Smørgrav /*
944bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a rule in the form
94546c59934SDag-Erling Smørgrav ** date[/time]. See POSIX Base Definitions section 8.3 variable TZ
94646c59934SDag-Erling Smørgrav ** for the format of "date" and "time".
947bc421551SDag-Erling Smørgrav ** If a valid rule is not found, return NULL.
948bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the rule.
949bc421551SDag-Erling Smørgrav */
950bc421551SDag-Erling Smørgrav 
951bc421551SDag-Erling Smørgrav static const char *
952bc421551SDag-Erling Smørgrav getrule(const char *strp, register struct rule *const rulep)
953bc421551SDag-Erling Smørgrav {
954bc421551SDag-Erling Smørgrav 	if (*strp == 'J') {
955bc421551SDag-Erling Smørgrav 		/*
956bc421551SDag-Erling Smørgrav 		** Julian day.
957bc421551SDag-Erling Smørgrav 		*/
958bc421551SDag-Erling Smørgrav 		rulep->r_type = JULIAN_DAY;
959bc421551SDag-Erling Smørgrav 		++strp;
960bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
961bc421551SDag-Erling Smørgrav 	} else if (*strp == 'M') {
962bc421551SDag-Erling Smørgrav 		/*
963bc421551SDag-Erling Smørgrav 		** Month, week, day.
964bc421551SDag-Erling Smørgrav 		*/
965bc421551SDag-Erling Smørgrav 		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
966bc421551SDag-Erling Smørgrav 		++strp;
967bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
968bc421551SDag-Erling Smørgrav 		if (strp == NULL)
969bc421551SDag-Erling Smørgrav 			return NULL;
970bc421551SDag-Erling Smørgrav 		if (*strp++ != '.')
971bc421551SDag-Erling Smørgrav 			return NULL;
972bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &rulep->r_week, 1, 5);
973bc421551SDag-Erling Smørgrav 		if (strp == NULL)
974bc421551SDag-Erling Smørgrav 			return NULL;
975bc421551SDag-Erling Smørgrav 		if (*strp++ != '.')
976bc421551SDag-Erling Smørgrav 			return NULL;
977bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
978bc421551SDag-Erling Smørgrav 	} else if (is_digit(*strp)) {
979bc421551SDag-Erling Smørgrav 		/*
980bc421551SDag-Erling Smørgrav 		** Day of year.
981bc421551SDag-Erling Smørgrav 		*/
982bc421551SDag-Erling Smørgrav 		rulep->r_type = DAY_OF_YEAR;
983bc421551SDag-Erling Smørgrav 		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
984bc421551SDag-Erling Smørgrav 	} else	return NULL;		/* invalid format */
985bc421551SDag-Erling Smørgrav 	if (strp == NULL)
986bc421551SDag-Erling Smørgrav 		return NULL;
987bc421551SDag-Erling Smørgrav 	if (*strp == '/') {
988bc421551SDag-Erling Smørgrav 		/*
989bc421551SDag-Erling Smørgrav 		** Time specified.
990bc421551SDag-Erling Smørgrav 		*/
991bc421551SDag-Erling Smørgrav 		++strp;
992bc421551SDag-Erling Smørgrav 		strp = getoffset(strp, &rulep->r_time);
993bc421551SDag-Erling Smørgrav 	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
994bc421551SDag-Erling Smørgrav 	return strp;
995bc421551SDag-Erling Smørgrav }
996bc421551SDag-Erling Smørgrav 
997bc421551SDag-Erling Smørgrav /*
998bc421551SDag-Erling Smørgrav ** Given a year, a rule, and the offset from UT at the time that rule takes
999bc421551SDag-Erling Smørgrav ** effect, calculate the year-relative time that rule takes effect.
1000bc421551SDag-Erling Smørgrav */
1001bc421551SDag-Erling Smørgrav 
1002bc421551SDag-Erling Smørgrav static int_fast32_t
1003bc421551SDag-Erling Smørgrav transtime(const int year, register const struct rule *const rulep,
1004bc421551SDag-Erling Smørgrav 	  const int_fast32_t offset)
1005bc421551SDag-Erling Smørgrav {
1006bc421551SDag-Erling Smørgrav 	register bool	leapyear;
1007bc421551SDag-Erling Smørgrav 	register int_fast32_t value;
1008bc421551SDag-Erling Smørgrav 	register int	i;
1009bc421551SDag-Erling Smørgrav 	int		d, m1, yy0, yy1, yy2, dow;
1010bc421551SDag-Erling Smørgrav 
1011bc421551SDag-Erling Smørgrav 	leapyear = isleap(year);
1012bc421551SDag-Erling Smørgrav 	switch (rulep->r_type) {
1013bc421551SDag-Erling Smørgrav 
1014bc421551SDag-Erling Smørgrav 	case JULIAN_DAY:
1015bc421551SDag-Erling Smørgrav 		/*
1016bc421551SDag-Erling Smørgrav 		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1017bc421551SDag-Erling Smørgrav 		** years.
1018bc421551SDag-Erling Smørgrav 		** In non-leap years, or if the day number is 59 or less, just
1019bc421551SDag-Erling Smørgrav 		** add SECSPERDAY times the day number-1 to the time of
1020bc421551SDag-Erling Smørgrav 		** January 1, midnight, to get the day.
1021bc421551SDag-Erling Smørgrav 		*/
1022bc421551SDag-Erling Smørgrav 		value = (rulep->r_day - 1) * SECSPERDAY;
1023bc421551SDag-Erling Smørgrav 		if (leapyear && rulep->r_day >= 60)
1024bc421551SDag-Erling Smørgrav 			value += SECSPERDAY;
1025bc421551SDag-Erling Smørgrav 		break;
1026bc421551SDag-Erling Smørgrav 
1027bc421551SDag-Erling Smørgrav 	case DAY_OF_YEAR:
1028bc421551SDag-Erling Smørgrav 		/*
1029bc421551SDag-Erling Smørgrav 		** n - day of year.
1030bc421551SDag-Erling Smørgrav 		** Just add SECSPERDAY times the day number to the time of
1031bc421551SDag-Erling Smørgrav 		** January 1, midnight, to get the day.
1032bc421551SDag-Erling Smørgrav 		*/
1033bc421551SDag-Erling Smørgrav 		value = rulep->r_day * SECSPERDAY;
1034bc421551SDag-Erling Smørgrav 		break;
1035bc421551SDag-Erling Smørgrav 
1036bc421551SDag-Erling Smørgrav 	case MONTH_NTH_DAY_OF_WEEK:
1037bc421551SDag-Erling Smørgrav 		/*
1038bc421551SDag-Erling Smørgrav 		** Mm.n.d - nth "dth day" of month m.
1039bc421551SDag-Erling Smørgrav 		*/
1040bc421551SDag-Erling Smørgrav 
1041bc421551SDag-Erling Smørgrav 		/*
1042bc421551SDag-Erling Smørgrav 		** Use Zeller's Congruence to get day-of-week of first day of
1043bc421551SDag-Erling Smørgrav 		** month.
1044bc421551SDag-Erling Smørgrav 		*/
1045bc421551SDag-Erling Smørgrav 		m1 = (rulep->r_mon + 9) % 12 + 1;
1046bc421551SDag-Erling Smørgrav 		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1047bc421551SDag-Erling Smørgrav 		yy1 = yy0 / 100;
1048bc421551SDag-Erling Smørgrav 		yy2 = yy0 % 100;
1049bc421551SDag-Erling Smørgrav 		dow = ((26 * m1 - 2) / 10 +
1050bc421551SDag-Erling Smørgrav 			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1051bc421551SDag-Erling Smørgrav 		if (dow < 0)
1052bc421551SDag-Erling Smørgrav 			dow += DAYSPERWEEK;
1053bc421551SDag-Erling Smørgrav 
1054bc421551SDag-Erling Smørgrav 		/*
1055bc421551SDag-Erling Smørgrav 		** "dow" is the day-of-week of the first day of the month. Get
1056bc421551SDag-Erling Smørgrav 		** the day-of-month (zero-origin) of the first "dow" day of the
1057bc421551SDag-Erling Smørgrav 		** month.
1058bc421551SDag-Erling Smørgrav 		*/
1059bc421551SDag-Erling Smørgrav 		d = rulep->r_day - dow;
1060bc421551SDag-Erling Smørgrav 		if (d < 0)
1061bc421551SDag-Erling Smørgrav 			d += DAYSPERWEEK;
1062bc421551SDag-Erling Smørgrav 		for (i = 1; i < rulep->r_week; ++i) {
1063bc421551SDag-Erling Smørgrav 			if (d + DAYSPERWEEK >=
1064bc421551SDag-Erling Smørgrav 				mon_lengths[leapyear][rulep->r_mon - 1])
1065bc421551SDag-Erling Smørgrav 					break;
1066bc421551SDag-Erling Smørgrav 			d += DAYSPERWEEK;
1067bc421551SDag-Erling Smørgrav 		}
1068bc421551SDag-Erling Smørgrav 
1069bc421551SDag-Erling Smørgrav 		/*
1070bc421551SDag-Erling Smørgrav 		** "d" is the day-of-month (zero-origin) of the day we want.
1071bc421551SDag-Erling Smørgrav 		*/
1072bc421551SDag-Erling Smørgrav 		value = d * SECSPERDAY;
1073bc421551SDag-Erling Smørgrav 		for (i = 0; i < rulep->r_mon - 1; ++i)
1074bc421551SDag-Erling Smørgrav 			value += mon_lengths[leapyear][i] * SECSPERDAY;
1075bc421551SDag-Erling Smørgrav 		break;
1076bc421551SDag-Erling Smørgrav 
1077bc421551SDag-Erling Smørgrav 	default: unreachable();
1078bc421551SDag-Erling Smørgrav 	}
1079bc421551SDag-Erling Smørgrav 
1080bc421551SDag-Erling Smørgrav 	/*
1081bc421551SDag-Erling Smørgrav 	** "value" is the year-relative time of 00:00:00 UT on the day in
1082bc421551SDag-Erling Smørgrav 	** question. To get the year-relative time of the specified local
1083bc421551SDag-Erling Smørgrav 	** time on that day, add the transition time and the current offset
1084bc421551SDag-Erling Smørgrav 	** from UT.
1085bc421551SDag-Erling Smørgrav 	*/
1086bc421551SDag-Erling Smørgrav 	return value + rulep->r_time + offset;
1087bc421551SDag-Erling Smørgrav }
1088bc421551SDag-Erling Smørgrav 
1089bc421551SDag-Erling Smørgrav /*
1090*a979394aSDag-Erling Smørgrav ** Given a POSIX.1 proleptic TZ string, fill in the rule tables as
1091bc421551SDag-Erling Smørgrav ** appropriate.
1092bc421551SDag-Erling Smørgrav */
1093bc421551SDag-Erling Smørgrav 
1094bc421551SDag-Erling Smørgrav static bool
109546c59934SDag-Erling Smørgrav tzparse(const char *name, struct state *sp, struct state const *basep)
1096bc421551SDag-Erling Smørgrav {
1097bc421551SDag-Erling Smørgrav 	const char *			stdname;
1098bc421551SDag-Erling Smørgrav 	const char *			dstname;
1099bc421551SDag-Erling Smørgrav 	int_fast32_t			stdoffset;
1100bc421551SDag-Erling Smørgrav 	int_fast32_t			dstoffset;
1101bc421551SDag-Erling Smørgrav 	register char *			cp;
1102bc421551SDag-Erling Smørgrav 	register bool			load_ok;
1103bc421551SDag-Erling Smørgrav 	ptrdiff_t stdlen, dstlen, charcnt;
1104bc421551SDag-Erling Smørgrav 	time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
1105bc421551SDag-Erling Smørgrav 
1106bc421551SDag-Erling Smørgrav 	stdname = name;
1107bc421551SDag-Erling Smørgrav 	if (*name == '<') {
1108bc421551SDag-Erling Smørgrav 	  name++;
1109bc421551SDag-Erling Smørgrav 	  stdname = name;
1110bc421551SDag-Erling Smørgrav 	  name = getqzname(name, '>');
1111bc421551SDag-Erling Smørgrav 	  if (*name != '>')
1112bc421551SDag-Erling Smørgrav 	    return false;
1113bc421551SDag-Erling Smørgrav 	  stdlen = name - stdname;
1114bc421551SDag-Erling Smørgrav 	  name++;
1115bc421551SDag-Erling Smørgrav 	} else {
1116bc421551SDag-Erling Smørgrav 	  name = getzname(name);
1117bc421551SDag-Erling Smørgrav 	  stdlen = name - stdname;
1118bc421551SDag-Erling Smørgrav 	}
111975411d15SDag-Erling Smørgrav 	if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
1120bc421551SDag-Erling Smørgrav 	  return false;
1121bc421551SDag-Erling Smørgrav 	name = getoffset(name, &stdoffset);
1122bc421551SDag-Erling Smørgrav 	if (name == NULL)
1123bc421551SDag-Erling Smørgrav 	  return false;
1124bc421551SDag-Erling Smørgrav 	charcnt = stdlen + 1;
1125bc421551SDag-Erling Smørgrav 	if (basep) {
1126bc421551SDag-Erling Smørgrav 	  if (0 < basep->timecnt)
1127bc421551SDag-Erling Smørgrav 	    atlo = basep->ats[basep->timecnt - 1];
1128bc421551SDag-Erling Smørgrav 	  load_ok = false;
1129bc421551SDag-Erling Smørgrav 	  sp->leapcnt = basep->leapcnt;
1130bc421551SDag-Erling Smørgrav 	  memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
1131bc421551SDag-Erling Smørgrav 	} else {
1132bc421551SDag-Erling Smørgrav 	  load_ok = tzload(TZDEFRULES, sp, false) == 0;
1133bc421551SDag-Erling Smørgrav 	  if (!load_ok)
1134bc421551SDag-Erling Smørgrav 	    sp->leapcnt = 0;	/* So, we're off a little.  */
1135bc421551SDag-Erling Smørgrav 	}
1136bc421551SDag-Erling Smørgrav 	if (0 < sp->leapcnt)
1137bc421551SDag-Erling Smørgrav 	  leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
113846c59934SDag-Erling Smørgrav 	sp->goback = sp->goahead = false;
1139bc421551SDag-Erling Smørgrav 	if (*name != '\0') {
1140bc421551SDag-Erling Smørgrav 		if (*name == '<') {
1141bc421551SDag-Erling Smørgrav 			dstname = ++name;
1142bc421551SDag-Erling Smørgrav 			name = getqzname(name, '>');
1143bc421551SDag-Erling Smørgrav 			if (*name != '>')
1144bc421551SDag-Erling Smørgrav 			  return false;
1145bc421551SDag-Erling Smørgrav 			dstlen = name - dstname;
1146bc421551SDag-Erling Smørgrav 			name++;
1147bc421551SDag-Erling Smørgrav 		} else {
1148bc421551SDag-Erling Smørgrav 			dstname = name;
1149bc421551SDag-Erling Smørgrav 			name = getzname(name);
1150bc421551SDag-Erling Smørgrav 			dstlen = name - dstname; /* length of DST abbr. */
1151bc421551SDag-Erling Smørgrav 		}
115275411d15SDag-Erling Smørgrav 		if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
1153bc421551SDag-Erling Smørgrav 		  return false;
1154bc421551SDag-Erling Smørgrav 		charcnt += dstlen + 1;
1155bc421551SDag-Erling Smørgrav 		if (*name != '\0' && *name != ',' && *name != ';') {
1156bc421551SDag-Erling Smørgrav 			name = getoffset(name, &dstoffset);
1157bc421551SDag-Erling Smørgrav 			if (name == NULL)
1158bc421551SDag-Erling Smørgrav 			  return false;
1159bc421551SDag-Erling Smørgrav 		} else	dstoffset = stdoffset - SECSPERHOUR;
1160bc421551SDag-Erling Smørgrav 		if (*name == '\0' && !load_ok)
1161bc421551SDag-Erling Smørgrav 			name = TZDEFRULESTRING;
1162bc421551SDag-Erling Smørgrav 		if (*name == ',' || *name == ';') {
1163bc421551SDag-Erling Smørgrav 			struct rule	start;
1164bc421551SDag-Erling Smørgrav 			struct rule	end;
1165bc421551SDag-Erling Smørgrav 			register int	year;
1166bc421551SDag-Erling Smørgrav 			register int	timecnt;
1167bc421551SDag-Erling Smørgrav 			time_t		janfirst;
1168bc421551SDag-Erling Smørgrav 			int_fast32_t janoffset = 0;
1169bc421551SDag-Erling Smørgrav 			int yearbeg, yearlim;
1170bc421551SDag-Erling Smørgrav 
1171bc421551SDag-Erling Smørgrav 			++name;
1172bc421551SDag-Erling Smørgrav 			if ((name = getrule(name, &start)) == NULL)
1173bc421551SDag-Erling Smørgrav 			  return false;
1174bc421551SDag-Erling Smørgrav 			if (*name++ != ',')
1175bc421551SDag-Erling Smørgrav 			  return false;
1176bc421551SDag-Erling Smørgrav 			if ((name = getrule(name, &end)) == NULL)
1177bc421551SDag-Erling Smørgrav 			  return false;
1178bc421551SDag-Erling Smørgrav 			if (*name != '\0')
1179bc421551SDag-Erling Smørgrav 			  return false;
1180bc421551SDag-Erling Smørgrav 			sp->typecnt = 2;	/* standard time and DST */
1181bc421551SDag-Erling Smørgrav 			/*
1182bc421551SDag-Erling Smørgrav 			** Two transitions per year, from EPOCH_YEAR forward.
1183bc421551SDag-Erling Smørgrav 			*/
1184bc421551SDag-Erling Smørgrav 			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1185bc421551SDag-Erling Smørgrav 			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1186bc421551SDag-Erling Smørgrav 			timecnt = 0;
1187bc421551SDag-Erling Smørgrav 			janfirst = 0;
1188bc421551SDag-Erling Smørgrav 			yearbeg = EPOCH_YEAR;
1189bc421551SDag-Erling Smørgrav 
1190bc421551SDag-Erling Smørgrav 			do {
1191bc421551SDag-Erling Smørgrav 			  int_fast32_t yearsecs
1192bc421551SDag-Erling Smørgrav 			    = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
11931365bb72SDag-Erling Smørgrav 			  time_t janfirst1 = janfirst;
1194bc421551SDag-Erling Smørgrav 			  yearbeg--;
11951365bb72SDag-Erling Smørgrav 			  if (increment_overflow_time(&janfirst1, -yearsecs)) {
1196bc421551SDag-Erling Smørgrav 			    janoffset = -yearsecs;
1197bc421551SDag-Erling Smørgrav 			    break;
1198bc421551SDag-Erling Smørgrav 			  }
11991365bb72SDag-Erling Smørgrav 			  janfirst = janfirst1;
1200bc421551SDag-Erling Smørgrav 			} while (atlo < janfirst
1201bc421551SDag-Erling Smørgrav 				 && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1202bc421551SDag-Erling Smørgrav 
1203bc421551SDag-Erling Smørgrav 			while (true) {
1204bc421551SDag-Erling Smørgrav 			  int_fast32_t yearsecs
1205bc421551SDag-Erling Smørgrav 			    = year_lengths[isleap(yearbeg)] * SECSPERDAY;
1206bc421551SDag-Erling Smørgrav 			  int yearbeg1 = yearbeg;
1207bc421551SDag-Erling Smørgrav 			  time_t janfirst1 = janfirst;
1208bc421551SDag-Erling Smørgrav 			  if (increment_overflow_time(&janfirst1, yearsecs)
1209bc421551SDag-Erling Smørgrav 			      || increment_overflow(&yearbeg1, 1)
1210bc421551SDag-Erling Smørgrav 			      || atlo <= janfirst1)
1211bc421551SDag-Erling Smørgrav 			    break;
1212bc421551SDag-Erling Smørgrav 			  yearbeg = yearbeg1;
1213bc421551SDag-Erling Smørgrav 			  janfirst = janfirst1;
1214bc421551SDag-Erling Smørgrav 			}
1215bc421551SDag-Erling Smørgrav 
1216bc421551SDag-Erling Smørgrav 			yearlim = yearbeg;
121746c59934SDag-Erling Smørgrav 			if (increment_overflow(&yearlim, years_of_observations))
1218bc421551SDag-Erling Smørgrav 			  yearlim = INT_MAX;
1219bc421551SDag-Erling Smørgrav 			for (year = yearbeg; year < yearlim; year++) {
1220bc421551SDag-Erling Smørgrav 				int_fast32_t
1221bc421551SDag-Erling Smørgrav 				  starttime = transtime(year, &start, stdoffset),
1222bc421551SDag-Erling Smørgrav 				  endtime = transtime(year, &end, dstoffset);
1223bc421551SDag-Erling Smørgrav 				int_fast32_t
1224bc421551SDag-Erling Smørgrav 				  yearsecs = (year_lengths[isleap(year)]
1225bc421551SDag-Erling Smørgrav 					      * SECSPERDAY);
1226bc421551SDag-Erling Smørgrav 				bool reversed = endtime < starttime;
1227bc421551SDag-Erling Smørgrav 				if (reversed) {
1228bc421551SDag-Erling Smørgrav 					int_fast32_t swap = starttime;
1229bc421551SDag-Erling Smørgrav 					starttime = endtime;
1230bc421551SDag-Erling Smørgrav 					endtime = swap;
1231bc421551SDag-Erling Smørgrav 				}
1232bc421551SDag-Erling Smørgrav 				if (reversed
1233bc421551SDag-Erling Smørgrav 				    || (starttime < endtime
1234bc421551SDag-Erling Smørgrav 					&& endtime - starttime < yearsecs)) {
1235bc421551SDag-Erling Smørgrav 					if (TZ_MAX_TIMES - 2 < timecnt)
1236bc421551SDag-Erling Smørgrav 						break;
1237bc421551SDag-Erling Smørgrav 					sp->ats[timecnt] = janfirst;
1238bc421551SDag-Erling Smørgrav 					if (! increment_overflow_time
1239bc421551SDag-Erling Smørgrav 					    (&sp->ats[timecnt],
1240bc421551SDag-Erling Smørgrav 					     janoffset + starttime)
1241bc421551SDag-Erling Smørgrav 					    && atlo <= sp->ats[timecnt])
1242bc421551SDag-Erling Smørgrav 					  sp->types[timecnt++] = !reversed;
1243bc421551SDag-Erling Smørgrav 					sp->ats[timecnt] = janfirst;
1244bc421551SDag-Erling Smørgrav 					if (! increment_overflow_time
1245bc421551SDag-Erling Smørgrav 					    (&sp->ats[timecnt],
1246bc421551SDag-Erling Smørgrav 					     janoffset + endtime)
1247bc421551SDag-Erling Smørgrav 					    && atlo <= sp->ats[timecnt]) {
1248bc421551SDag-Erling Smørgrav 					  sp->types[timecnt++] = reversed;
1249bc421551SDag-Erling Smørgrav 					}
1250bc421551SDag-Erling Smørgrav 				}
1251bc421551SDag-Erling Smørgrav 				if (endtime < leaplo) {
1252bc421551SDag-Erling Smørgrav 				  yearlim = year;
1253bc421551SDag-Erling Smørgrav 				  if (increment_overflow(&yearlim,
125446c59934SDag-Erling Smørgrav 							 years_of_observations))
1255bc421551SDag-Erling Smørgrav 				    yearlim = INT_MAX;
1256bc421551SDag-Erling Smørgrav 				}
1257bc421551SDag-Erling Smørgrav 				if (increment_overflow_time
1258bc421551SDag-Erling Smørgrav 				    (&janfirst, janoffset + yearsecs))
1259bc421551SDag-Erling Smørgrav 					break;
1260bc421551SDag-Erling Smørgrav 				janoffset = 0;
1261bc421551SDag-Erling Smørgrav 			}
1262bc421551SDag-Erling Smørgrav 			sp->timecnt = timecnt;
1263bc421551SDag-Erling Smørgrav 			if (! timecnt) {
1264bc421551SDag-Erling Smørgrav 				sp->ttis[0] = sp->ttis[1];
1265bc421551SDag-Erling Smørgrav 				sp->typecnt = 1;	/* Perpetual DST.  */
126646c59934SDag-Erling Smørgrav 			} else if (years_of_observations <= year - yearbeg)
1267bc421551SDag-Erling Smørgrav 				sp->goback = sp->goahead = true;
1268bc421551SDag-Erling Smørgrav 		} else {
1269bc421551SDag-Erling Smørgrav 			register int_fast32_t	theirstdoffset;
1270bc421551SDag-Erling Smørgrav 			register int_fast32_t	theirdstoffset;
1271bc421551SDag-Erling Smørgrav 			register int_fast32_t	theiroffset;
1272bc421551SDag-Erling Smørgrav 			register bool		isdst;
1273bc421551SDag-Erling Smørgrav 			register int		i;
1274bc421551SDag-Erling Smørgrav 			register int		j;
1275bc421551SDag-Erling Smørgrav 
1276bc421551SDag-Erling Smørgrav 			if (*name != '\0')
1277bc421551SDag-Erling Smørgrav 			  return false;
1278bc421551SDag-Erling Smørgrav 			/*
1279bc421551SDag-Erling Smørgrav 			** Initial values of theirstdoffset and theirdstoffset.
1280bc421551SDag-Erling Smørgrav 			*/
1281bc421551SDag-Erling Smørgrav 			theirstdoffset = 0;
1282bc421551SDag-Erling Smørgrav 			for (i = 0; i < sp->timecnt; ++i) {
1283bc421551SDag-Erling Smørgrav 				j = sp->types[i];
1284bc421551SDag-Erling Smørgrav 				if (!sp->ttis[j].tt_isdst) {
1285bc421551SDag-Erling Smørgrav 					theirstdoffset =
1286bc421551SDag-Erling Smørgrav 						- sp->ttis[j].tt_utoff;
1287bc421551SDag-Erling Smørgrav 					break;
1288bc421551SDag-Erling Smørgrav 				}
1289bc421551SDag-Erling Smørgrav 			}
1290bc421551SDag-Erling Smørgrav 			theirdstoffset = 0;
1291bc421551SDag-Erling Smørgrav 			for (i = 0; i < sp->timecnt; ++i) {
1292bc421551SDag-Erling Smørgrav 				j = sp->types[i];
1293bc421551SDag-Erling Smørgrav 				if (sp->ttis[j].tt_isdst) {
1294bc421551SDag-Erling Smørgrav 					theirdstoffset =
1295bc421551SDag-Erling Smørgrav 						- sp->ttis[j].tt_utoff;
1296bc421551SDag-Erling Smørgrav 					break;
1297bc421551SDag-Erling Smørgrav 				}
1298bc421551SDag-Erling Smørgrav 			}
1299bc421551SDag-Erling Smørgrav 			/*
1300bc421551SDag-Erling Smørgrav 			** Initially we're assumed to be in standard time.
1301bc421551SDag-Erling Smørgrav 			*/
1302bc421551SDag-Erling Smørgrav 			isdst = false;
1303bc421551SDag-Erling Smørgrav 			/*
1304bc421551SDag-Erling Smørgrav 			** Now juggle transition times and types
1305bc421551SDag-Erling Smørgrav 			** tracking offsets as you do.
1306bc421551SDag-Erling Smørgrav 			*/
1307bc421551SDag-Erling Smørgrav 			for (i = 0; i < sp->timecnt; ++i) {
1308bc421551SDag-Erling Smørgrav 				j = sp->types[i];
1309bc421551SDag-Erling Smørgrav 				sp->types[i] = sp->ttis[j].tt_isdst;
1310bc421551SDag-Erling Smørgrav 				if (sp->ttis[j].tt_ttisut) {
1311bc421551SDag-Erling Smørgrav 					/* No adjustment to transition time */
1312bc421551SDag-Erling Smørgrav 				} else {
1313bc421551SDag-Erling Smørgrav 					/*
1314bc421551SDag-Erling Smørgrav 					** If daylight saving time is in
1315bc421551SDag-Erling Smørgrav 					** effect, and the transition time was
1316bc421551SDag-Erling Smørgrav 					** not specified as standard time, add
1317bc421551SDag-Erling Smørgrav 					** the daylight saving time offset to
1318bc421551SDag-Erling Smørgrav 					** the transition time; otherwise, add
1319bc421551SDag-Erling Smørgrav 					** the standard time offset to the
1320bc421551SDag-Erling Smørgrav 					** transition time.
1321bc421551SDag-Erling Smørgrav 					*/
1322bc421551SDag-Erling Smørgrav 					/*
1323bc421551SDag-Erling Smørgrav 					** Transitions from DST to DDST
1324bc421551SDag-Erling Smørgrav 					** will effectively disappear since
1325*a979394aSDag-Erling Smørgrav 					** proleptic TZ strings have only one
132646c59934SDag-Erling Smørgrav 					** DST offset.
1327bc421551SDag-Erling Smørgrav 					*/
1328bc421551SDag-Erling Smørgrav 					if (isdst && !sp->ttis[j].tt_ttisstd) {
1329bc421551SDag-Erling Smørgrav 						sp->ats[i] += dstoffset -
1330bc421551SDag-Erling Smørgrav 							theirdstoffset;
1331bc421551SDag-Erling Smørgrav 					} else {
1332bc421551SDag-Erling Smørgrav 						sp->ats[i] += stdoffset -
1333bc421551SDag-Erling Smørgrav 							theirstdoffset;
1334bc421551SDag-Erling Smørgrav 					}
1335bc421551SDag-Erling Smørgrav 				}
1336bc421551SDag-Erling Smørgrav 				theiroffset = -sp->ttis[j].tt_utoff;
1337bc421551SDag-Erling Smørgrav 				if (sp->ttis[j].tt_isdst)
1338bc421551SDag-Erling Smørgrav 					theirdstoffset = theiroffset;
1339bc421551SDag-Erling Smørgrav 				else	theirstdoffset = theiroffset;
1340bc421551SDag-Erling Smørgrav 			}
1341bc421551SDag-Erling Smørgrav 			/*
1342bc421551SDag-Erling Smørgrav 			** Finally, fill in ttis.
1343bc421551SDag-Erling Smørgrav 			*/
1344bc421551SDag-Erling Smørgrav 			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1345bc421551SDag-Erling Smørgrav 			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1346bc421551SDag-Erling Smørgrav 			sp->typecnt = 2;
1347bc421551SDag-Erling Smørgrav 		}
1348bc421551SDag-Erling Smørgrav 	} else {
1349bc421551SDag-Erling Smørgrav 		dstlen = 0;
1350bc421551SDag-Erling Smørgrav 		sp->typecnt = 1;		/* only standard time */
1351bc421551SDag-Erling Smørgrav 		sp->timecnt = 0;
1352bc421551SDag-Erling Smørgrav 		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1353bc421551SDag-Erling Smørgrav 	}
1354bc421551SDag-Erling Smørgrav 	sp->charcnt = charcnt;
1355bc421551SDag-Erling Smørgrav 	cp = sp->chars;
1356bc421551SDag-Erling Smørgrav 	memcpy(cp, stdname, stdlen);
1357bc421551SDag-Erling Smørgrav 	cp += stdlen;
1358bc421551SDag-Erling Smørgrav 	*cp++ = '\0';
1359bc421551SDag-Erling Smørgrav 	if (dstlen != 0) {
1360bc421551SDag-Erling Smørgrav 		memcpy(cp, dstname, dstlen);
1361bc421551SDag-Erling Smørgrav 		*(cp + dstlen) = '\0';
1362bc421551SDag-Erling Smørgrav 	}
1363bc421551SDag-Erling Smørgrav 	return true;
1364bc421551SDag-Erling Smørgrav }
1365bc421551SDag-Erling Smørgrav 
1366bc421551SDag-Erling Smørgrav static void
1367bc421551SDag-Erling Smørgrav gmtload(struct state *const sp)
1368bc421551SDag-Erling Smørgrav {
1369bc421551SDag-Erling Smørgrav 	if (tzload(etc_utc, sp, true) != 0)
1370bc421551SDag-Erling Smørgrav 	  tzparse("UTC0", sp, NULL);
1371bc421551SDag-Erling Smørgrav }
1372bc421551SDag-Erling Smørgrav 
1373bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES
1374bc421551SDag-Erling Smørgrav static int
1375bc421551SDag-Erling Smørgrav recheck_tzdata()
1376bc421551SDag-Erling Smørgrav {
1377bc421551SDag-Erling Smørgrav 	static time_t last_checked;
1378bc421551SDag-Erling Smørgrav 	struct timespec now;
1379bc421551SDag-Erling Smørgrav 	time_t current_time;
1380bc421551SDag-Erling Smørgrav 	int error;
1381bc421551SDag-Erling Smørgrav 
1382bc421551SDag-Erling Smørgrav 	/*
1383bc421551SDag-Erling Smørgrav 	 * We want to recheck the timezone file every 61 sec.
1384bc421551SDag-Erling Smørgrav 	 */
1385bc421551SDag-Erling Smørgrav 	error = clock_gettime(CLOCK_MONOTONIC, &now);
1386bc421551SDag-Erling Smørgrav 	if (error < 0) {
1387bc421551SDag-Erling Smørgrav 		/* XXX: Can we somehow report this? */
1388bc421551SDag-Erling Smørgrav 		return 0;
1389bc421551SDag-Erling Smørgrav 	}
1390bc421551SDag-Erling Smørgrav 
1391bc421551SDag-Erling Smørgrav 	current_time = now.tv_sec;
1392bc421551SDag-Erling Smørgrav 	if ((current_time - last_checked > DETECT_TZ_CHANGES_INTERVAL) ||
1393bc421551SDag-Erling Smørgrav 	    (last_checked > current_time)) {
1394bc421551SDag-Erling Smørgrav 		last_checked = current_time;
1395bc421551SDag-Erling Smørgrav 		return 1;
1396bc421551SDag-Erling Smørgrav 	}
1397bc421551SDag-Erling Smørgrav 
1398bc421551SDag-Erling Smørgrav 	return 0;
1399bc421551SDag-Erling Smørgrav }
1400bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */
1401bc421551SDag-Erling Smørgrav #define	recheck_tzdata()	0
1402bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */
1403bc421551SDag-Erling Smørgrav 
1404bc421551SDag-Erling Smørgrav /* Initialize *SP to a value appropriate for the TZ setting NAME.
1405bc421551SDag-Erling Smørgrav    Return 0 on success, an errno value on failure.  */
1406bc421551SDag-Erling Smørgrav static int
1407bc421551SDag-Erling Smørgrav zoneinit(struct state *sp, char const *name)
1408bc421551SDag-Erling Smørgrav {
1409bc421551SDag-Erling Smørgrav   if (name && ! name[0]) {
1410bc421551SDag-Erling Smørgrav     /*
1411bc421551SDag-Erling Smørgrav     ** User wants it fast rather than right.
1412bc421551SDag-Erling Smørgrav     */
1413bc421551SDag-Erling Smørgrav     sp->leapcnt = 0;		/* so, we're off a little */
1414bc421551SDag-Erling Smørgrav     sp->timecnt = 0;
1415bc421551SDag-Erling Smørgrav     sp->typecnt = 0;
1416bc421551SDag-Erling Smørgrav     sp->charcnt = 0;
1417bc421551SDag-Erling Smørgrav     sp->goback = sp->goahead = false;
1418bc421551SDag-Erling Smørgrav     init_ttinfo(&sp->ttis[0], 0, false, 0);
1419bc421551SDag-Erling Smørgrav     strcpy(sp->chars, utc);
1420bc421551SDag-Erling Smørgrav     return 0;
1421bc421551SDag-Erling Smørgrav   } else {
1422bc421551SDag-Erling Smørgrav     int err = tzload(name, sp, true);
1423bc421551SDag-Erling Smørgrav     if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
1424bc421551SDag-Erling Smørgrav       err = 0;
1425bc421551SDag-Erling Smørgrav     if (err == 0)
142675411d15SDag-Erling Smørgrav       err = scrub_abbrs(sp);
1427bc421551SDag-Erling Smørgrav     return err;
1428bc421551SDag-Erling Smørgrav   }
1429bc421551SDag-Erling Smørgrav }
1430bc421551SDag-Erling Smørgrav 
1431bc421551SDag-Erling Smørgrav static void
143271e0c890SDag-Erling Smørgrav tzset_unlocked_name(char const *name)
1433bc421551SDag-Erling Smørgrav {
1434bc421551SDag-Erling Smørgrav   struct state *sp = lclptr;
1435bc421551SDag-Erling Smørgrav   int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1436bc421551SDag-Erling Smørgrav   if (lcl < 0
1437bc421551SDag-Erling Smørgrav       ? lcl_is_set < 0
1438bc421551SDag-Erling Smørgrav       : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1439bc421551SDag-Erling Smørgrav     if (recheck_tzdata() == 0)
1440bc421551SDag-Erling Smørgrav       return;
1441bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
1442bc421551SDag-Erling Smørgrav   if (! sp)
1443bc421551SDag-Erling Smørgrav     lclptr = sp = malloc(sizeof *lclptr);
1444bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */
1445bc421551SDag-Erling Smørgrav   if (sp) {
1446bc421551SDag-Erling Smørgrav     if (zoneinit(sp, name) != 0)
1447bc421551SDag-Erling Smørgrav       zoneinit(sp, "");
1448bc421551SDag-Erling Smørgrav     if (0 < lcl)
1449bc421551SDag-Erling Smørgrav       strcpy(lcl_TZname, name);
1450bc421551SDag-Erling Smørgrav   }
1451bc421551SDag-Erling Smørgrav   settzname();
1452bc421551SDag-Erling Smørgrav   lcl_is_set = lcl;
1453bc421551SDag-Erling Smørgrav }
1454bc421551SDag-Erling Smørgrav 
145571e0c890SDag-Erling Smørgrav static void
145671e0c890SDag-Erling Smørgrav tzset_unlocked(void)
145771e0c890SDag-Erling Smørgrav {
145871e0c890SDag-Erling Smørgrav   tzset_unlocked_name(getenv("TZ"));
145971e0c890SDag-Erling Smørgrav }
146071e0c890SDag-Erling Smørgrav 
1461bc421551SDag-Erling Smørgrav void
1462bc421551SDag-Erling Smørgrav tzset(void)
1463bc421551SDag-Erling Smørgrav {
1464bc421551SDag-Erling Smørgrav   if (lock() != 0)
1465bc421551SDag-Erling Smørgrav     return;
1466bc421551SDag-Erling Smørgrav   tzset_unlocked();
1467bc421551SDag-Erling Smørgrav   unlock();
1468bc421551SDag-Erling Smørgrav }
1469bc421551SDag-Erling Smørgrav 
147071e0c890SDag-Erling Smørgrav void
147171e0c890SDag-Erling Smørgrav freebsd13_tzsetwall(void)
147271e0c890SDag-Erling Smørgrav {
147371e0c890SDag-Erling Smørgrav   if (lock() != 0)
147471e0c890SDag-Erling Smørgrav     return;
147571e0c890SDag-Erling Smørgrav   tzset_unlocked_name(NULL);
147671e0c890SDag-Erling Smørgrav   unlock();
147771e0c890SDag-Erling Smørgrav }
147871e0c890SDag-Erling Smørgrav __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
147971e0c890SDag-Erling Smørgrav __warn_references(tzsetwall,
148071e0c890SDag-Erling Smørgrav     "warning: tzsetwall() is deprecated, use tzset() instead.");
148171e0c890SDag-Erling Smørgrav 
1482bc421551SDag-Erling Smørgrav static void
1483bc421551SDag-Erling Smørgrav gmtcheck(void)
1484bc421551SDag-Erling Smørgrav {
1485bc421551SDag-Erling Smørgrav   static bool gmt_is_set;
1486bc421551SDag-Erling Smørgrav   if (lock() != 0)
1487bc421551SDag-Erling Smørgrav     return;
1488bc421551SDag-Erling Smørgrav   if (! gmt_is_set) {
1489bc421551SDag-Erling Smørgrav #ifdef ALL_STATE
1490bc421551SDag-Erling Smørgrav     gmtptr = malloc(sizeof *gmtptr);
1491bc421551SDag-Erling Smørgrav #endif
1492bc421551SDag-Erling Smørgrav     if (gmtptr)
1493bc421551SDag-Erling Smørgrav       gmtload(gmtptr);
1494bc421551SDag-Erling Smørgrav     gmt_is_set = true;
1495bc421551SDag-Erling Smørgrav   }
1496bc421551SDag-Erling Smørgrav   unlock();
1497bc421551SDag-Erling Smørgrav }
1498bc421551SDag-Erling Smørgrav 
1499bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
1500bc421551SDag-Erling Smørgrav 
1501bc421551SDag-Erling Smørgrav timezone_t
1502bc421551SDag-Erling Smørgrav tzalloc(char const *name)
1503bc421551SDag-Erling Smørgrav {
1504bc421551SDag-Erling Smørgrav   timezone_t sp = malloc(sizeof *sp);
1505bc421551SDag-Erling Smørgrav   if (sp) {
1506bc421551SDag-Erling Smørgrav     int err = zoneinit(sp, name);
1507bc421551SDag-Erling Smørgrav     if (err != 0) {
1508bc421551SDag-Erling Smørgrav       free(sp);
1509bc421551SDag-Erling Smørgrav       errno = err;
1510bc421551SDag-Erling Smørgrav       return NULL;
1511bc421551SDag-Erling Smørgrav     }
1512bc421551SDag-Erling Smørgrav   } else if (!HAVE_MALLOC_ERRNO)
1513bc421551SDag-Erling Smørgrav     errno = ENOMEM;
1514bc421551SDag-Erling Smørgrav   return sp;
1515bc421551SDag-Erling Smørgrav }
1516bc421551SDag-Erling Smørgrav 
1517bc421551SDag-Erling Smørgrav void
1518bc421551SDag-Erling Smørgrav tzfree(timezone_t sp)
1519bc421551SDag-Erling Smørgrav {
1520bc421551SDag-Erling Smørgrav   free(sp);
1521bc421551SDag-Erling Smørgrav }
1522bc421551SDag-Erling Smørgrav 
1523bc421551SDag-Erling Smørgrav /*
1524*a979394aSDag-Erling Smørgrav ** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and
1525*a979394aSDag-Erling Smørgrav ** POSIX.1-2024 removes ctime_r.  Both have potential security problems that
1526bc421551SDag-Erling Smørgrav ** ctime_rz would share.  Callers can instead use localtime_rz + strftime.
1527bc421551SDag-Erling Smørgrav **
1528bc421551SDag-Erling Smørgrav ** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1529bc421551SDag-Erling Smørgrav ** in zones with three or more time zone abbreviations.
1530bc421551SDag-Erling Smørgrav ** Callers can instead use localtime_rz + strftime.
1531bc421551SDag-Erling Smørgrav */
1532bc421551SDag-Erling Smørgrav 
1533bc421551SDag-Erling Smørgrav #endif
1534bc421551SDag-Erling Smørgrav 
1535bc421551SDag-Erling Smørgrav /*
1536bc421551SDag-Erling Smørgrav ** The easy way to behave "as if no library function calls" localtime
1537bc421551SDag-Erling Smørgrav ** is to not call it, so we drop its guts into "localsub", which can be
1538bc421551SDag-Erling Smørgrav ** freely called. (And no, the PANS doesn't require the above behavior,
1539bc421551SDag-Erling Smørgrav ** but it *is* desirable.)
1540bc421551SDag-Erling Smørgrav **
1541bc421551SDag-Erling Smørgrav ** If successful and SETNAME is nonzero,
1542bc421551SDag-Erling Smørgrav ** set the applicable parts of tzname, timezone and altzone;
1543*a979394aSDag-Erling Smørgrav ** however, it's OK to omit this step for proleptic TZ strings
1544bc421551SDag-Erling Smørgrav ** since in that case tzset should have already done this step correctly.
1545bc421551SDag-Erling Smørgrav ** SETNAME's type is int_fast32_t for compatibility with gmtsub,
1546bc421551SDag-Erling Smørgrav ** but it is actually a boolean and its value should be 0 or 1.
1547bc421551SDag-Erling Smørgrav */
1548bc421551SDag-Erling Smørgrav 
1549bc421551SDag-Erling Smørgrav /*ARGSUSED*/
1550bc421551SDag-Erling Smørgrav static struct tm *
1551bc421551SDag-Erling Smørgrav localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1552bc421551SDag-Erling Smørgrav 	 struct tm *const tmp)
1553bc421551SDag-Erling Smørgrav {
1554bc421551SDag-Erling Smørgrav 	register const struct ttinfo *	ttisp;
1555bc421551SDag-Erling Smørgrav 	register int			i;
1556bc421551SDag-Erling Smørgrav 	register struct tm *		result;
1557bc421551SDag-Erling Smørgrav 	const time_t			t = *timep;
1558bc421551SDag-Erling Smørgrav 
1559bc421551SDag-Erling Smørgrav 	if (sp == NULL) {
1560bc421551SDag-Erling Smørgrav 	  /* Don't bother to set tzname etc.; tzset has already done it.  */
1561bc421551SDag-Erling Smørgrav 	  return gmtsub(gmtptr, timep, 0, tmp);
1562bc421551SDag-Erling Smørgrav 	}
1563bc421551SDag-Erling Smørgrav 	if ((sp->goback && t < sp->ats[0]) ||
1564bc421551SDag-Erling Smørgrav 		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1565bc421551SDag-Erling Smørgrav 			time_t newt;
1566bc421551SDag-Erling Smørgrav 			register time_t		seconds;
1567bc421551SDag-Erling Smørgrav 			register time_t		years;
1568bc421551SDag-Erling Smørgrav 
1569bc421551SDag-Erling Smørgrav 			if (t < sp->ats[0])
1570bc421551SDag-Erling Smørgrav 				seconds = sp->ats[0] - t;
1571bc421551SDag-Erling Smørgrav 			else	seconds = t - sp->ats[sp->timecnt - 1];
1572bc421551SDag-Erling Smørgrav 			--seconds;
1573bc421551SDag-Erling Smørgrav 
1574bc421551SDag-Erling Smørgrav 			/* Beware integer overflow, as SECONDS might
1575bc421551SDag-Erling Smørgrav 			   be close to the maximum time_t.  */
1576bc421551SDag-Erling Smørgrav 			years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
1577bc421551SDag-Erling Smørgrav 			seconds = years * AVGSECSPERYEAR;
1578bc421551SDag-Erling Smørgrav 			years += YEARSPERREPEAT;
1579bc421551SDag-Erling Smørgrav 			if (t < sp->ats[0])
1580bc421551SDag-Erling Smørgrav 			  newt = t + seconds + SECSPERREPEAT;
1581bc421551SDag-Erling Smørgrav 			else
1582bc421551SDag-Erling Smørgrav 			  newt = t - seconds - SECSPERREPEAT;
1583bc421551SDag-Erling Smørgrav 
1584bc421551SDag-Erling Smørgrav 			if (newt < sp->ats[0] ||
1585bc421551SDag-Erling Smørgrav 				newt > sp->ats[sp->timecnt - 1])
1586bc421551SDag-Erling Smørgrav 					return NULL;	/* "cannot happen" */
1587bc421551SDag-Erling Smørgrav 			result = localsub(sp, &newt, setname, tmp);
1588bc421551SDag-Erling Smørgrav 			if (result) {
1589bc421551SDag-Erling Smørgrav #if defined ckd_add && defined ckd_sub
1590bc421551SDag-Erling Smørgrav 				if (t < sp->ats[0]
1591bc421551SDag-Erling Smørgrav 				    ? ckd_sub(&result->tm_year,
1592bc421551SDag-Erling Smørgrav 					      result->tm_year, years)
1593bc421551SDag-Erling Smørgrav 				    : ckd_add(&result->tm_year,
1594bc421551SDag-Erling Smørgrav 					      result->tm_year, years))
1595bc421551SDag-Erling Smørgrav 				  return NULL;
1596bc421551SDag-Erling Smørgrav #else
1597bc421551SDag-Erling Smørgrav 				register int_fast64_t newy;
1598bc421551SDag-Erling Smørgrav 
1599bc421551SDag-Erling Smørgrav 				newy = result->tm_year;
1600bc421551SDag-Erling Smørgrav 				if (t < sp->ats[0])
1601bc421551SDag-Erling Smørgrav 					newy -= years;
1602bc421551SDag-Erling Smørgrav 				else	newy += years;
1603bc421551SDag-Erling Smørgrav 				if (! (INT_MIN <= newy && newy <= INT_MAX))
1604bc421551SDag-Erling Smørgrav 					return NULL;
1605bc421551SDag-Erling Smørgrav 				result->tm_year = newy;
1606bc421551SDag-Erling Smørgrav #endif
1607bc421551SDag-Erling Smørgrav 			}
1608bc421551SDag-Erling Smørgrav 			return result;
1609bc421551SDag-Erling Smørgrav 	}
1610bc421551SDag-Erling Smørgrav 	if (sp->timecnt == 0 || t < sp->ats[0]) {
1611*a979394aSDag-Erling Smørgrav 		i = 0;
1612bc421551SDag-Erling Smørgrav 	} else {
1613bc421551SDag-Erling Smørgrav 		register int	lo = 1;
1614bc421551SDag-Erling Smørgrav 		register int	hi = sp->timecnt;
1615bc421551SDag-Erling Smørgrav 
1616bc421551SDag-Erling Smørgrav 		while (lo < hi) {
1617bc421551SDag-Erling Smørgrav 			register int	mid = (lo + hi) >> 1;
1618bc421551SDag-Erling Smørgrav 
1619bc421551SDag-Erling Smørgrav 			if (t < sp->ats[mid])
1620bc421551SDag-Erling Smørgrav 				hi = mid;
1621bc421551SDag-Erling Smørgrav 			else	lo = mid + 1;
1622bc421551SDag-Erling Smørgrav 		}
1623bc421551SDag-Erling Smørgrav 		i = sp->types[lo - 1];
1624bc421551SDag-Erling Smørgrav 	}
1625bc421551SDag-Erling Smørgrav 	ttisp = &sp->ttis[i];
1626bc421551SDag-Erling Smørgrav 	/*
1627bc421551SDag-Erling Smørgrav 	** To get (wrong) behavior that's compatible with System V Release 2.0
1628bc421551SDag-Erling Smørgrav 	** you'd replace the statement below with
1629bc421551SDag-Erling Smørgrav 	**	t += ttisp->tt_utoff;
1630bc421551SDag-Erling Smørgrav 	**	timesub(&t, 0L, sp, tmp);
1631bc421551SDag-Erling Smørgrav 	*/
1632bc421551SDag-Erling Smørgrav 	result = timesub(&t, ttisp->tt_utoff, sp, tmp);
1633bc421551SDag-Erling Smørgrav 	if (result) {
1634bc421551SDag-Erling Smørgrav 	  result->tm_isdst = ttisp->tt_isdst;
1635bc421551SDag-Erling Smørgrav #ifdef TM_ZONE
1636bc421551SDag-Erling Smørgrav 	  result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
1637bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */
1638bc421551SDag-Erling Smørgrav 	  if (setname)
1639bc421551SDag-Erling Smørgrav 	    update_tzname_etc(sp, ttisp);
1640bc421551SDag-Erling Smørgrav 	}
1641bc421551SDag-Erling Smørgrav 	return result;
1642bc421551SDag-Erling Smørgrav }
1643bc421551SDag-Erling Smørgrav 
1644bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
1645bc421551SDag-Erling Smørgrav 
1646bc421551SDag-Erling Smørgrav struct tm *
164775411d15SDag-Erling Smørgrav localtime_rz(struct state *restrict sp, time_t const *restrict timep,
164875411d15SDag-Erling Smørgrav 	     struct tm *restrict tmp)
1649bc421551SDag-Erling Smørgrav {
1650bc421551SDag-Erling Smørgrav   return localsub(sp, timep, 0, tmp);
1651bc421551SDag-Erling Smørgrav }
1652bc421551SDag-Erling Smørgrav 
1653bc421551SDag-Erling Smørgrav #endif
1654bc421551SDag-Erling Smørgrav 
1655bc421551SDag-Erling Smørgrav static struct tm *
1656bc421551SDag-Erling Smørgrav localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
1657bc421551SDag-Erling Smørgrav {
1658bc421551SDag-Erling Smørgrav   int err = lock();
1659bc421551SDag-Erling Smørgrav   if (err) {
1660bc421551SDag-Erling Smørgrav     errno = err;
1661bc421551SDag-Erling Smørgrav     return NULL;
1662bc421551SDag-Erling Smørgrav   }
1663bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
1664bc421551SDag-Erling Smørgrav   if (setname || !lcl_is_set)
1665bc421551SDag-Erling Smørgrav #endif
1666bc421551SDag-Erling Smørgrav     tzset_unlocked();
1667bc421551SDag-Erling Smørgrav   tmp = localsub(lclptr, timep, setname, tmp);
1668bc421551SDag-Erling Smørgrav   unlock();
1669bc421551SDag-Erling Smørgrav   return tmp;
1670bc421551SDag-Erling Smørgrav }
1671bc421551SDag-Erling Smørgrav 
1672bc421551SDag-Erling Smørgrav static void
1673bc421551SDag-Erling Smørgrav localtime_key_init(void)
1674bc421551SDag-Erling Smørgrav {
1675bc421551SDag-Erling Smørgrav 
1676bc421551SDag-Erling Smørgrav 	localtime_key_error = _pthread_key_create(&localtime_key, free);
1677bc421551SDag-Erling Smørgrav }
1678bc421551SDag-Erling Smørgrav 
1679bc421551SDag-Erling Smørgrav struct tm *
1680bc421551SDag-Erling Smørgrav localtime(const time_t *timep)
1681bc421551SDag-Erling Smørgrav {
168275411d15SDag-Erling Smørgrav #if !SUPPORT_C89
168375411d15SDag-Erling Smørgrav 	static struct tm tm;
168475411d15SDag-Erling Smørgrav #endif
1685bc421551SDag-Erling Smørgrav 	struct tm *p_tm = &tm;
1686bc421551SDag-Erling Smørgrav 
1687bc421551SDag-Erling Smørgrav 	if (__isthreaded != 0) {
1688bc421551SDag-Erling Smørgrav 		_pthread_once(&localtime_once, localtime_key_init);
1689bc421551SDag-Erling Smørgrav 		if (localtime_key_error != 0) {
1690bc421551SDag-Erling Smørgrav 			errno = localtime_key_error;
1691bc421551SDag-Erling Smørgrav 			return (NULL);
1692bc421551SDag-Erling Smørgrav 		}
1693bc421551SDag-Erling Smørgrav 		if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
1694bc421551SDag-Erling Smørgrav 			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
1695bc421551SDag-Erling Smørgrav 				return (NULL);
1696bc421551SDag-Erling Smørgrav 			}
169796e68c39SDag-Erling Smørgrav 			if (_pthread_setspecific(localtime_key, p_tm) != 0) {
169896e68c39SDag-Erling Smørgrav 				free(p_tm);
169996e68c39SDag-Erling Smørgrav 				return (NULL);
170096e68c39SDag-Erling Smørgrav 			}
1701bc421551SDag-Erling Smørgrav 		}
1702bc421551SDag-Erling Smørgrav 	}
1703bc421551SDag-Erling Smørgrav 	return localtime_tzset(timep, p_tm, true);
1704bc421551SDag-Erling Smørgrav }
1705bc421551SDag-Erling Smørgrav 
1706bc421551SDag-Erling Smørgrav struct tm *
170775411d15SDag-Erling Smørgrav localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
1708bc421551SDag-Erling Smørgrav {
1709bc421551SDag-Erling Smørgrav   return localtime_tzset(timep, tmp, false);
1710bc421551SDag-Erling Smørgrav }
1711bc421551SDag-Erling Smørgrav 
1712bc421551SDag-Erling Smørgrav /*
1713bc421551SDag-Erling Smørgrav ** gmtsub is to gmtime as localsub is to localtime.
1714bc421551SDag-Erling Smørgrav */
1715bc421551SDag-Erling Smørgrav 
1716bc421551SDag-Erling Smørgrav static struct tm *
1717bc421551SDag-Erling Smørgrav gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
1718bc421551SDag-Erling Smørgrav        int_fast32_t offset, struct tm *tmp)
1719bc421551SDag-Erling Smørgrav {
1720bc421551SDag-Erling Smørgrav 	register struct tm *	result;
1721bc421551SDag-Erling Smørgrav 
1722bc421551SDag-Erling Smørgrav 	result = timesub(timep, offset, gmtptr, tmp);
1723bc421551SDag-Erling Smørgrav #ifdef TM_ZONE
1724bc421551SDag-Erling Smørgrav 	/*
1725bc421551SDag-Erling Smørgrav 	** Could get fancy here and deliver something such as
1726bc421551SDag-Erling Smørgrav 	** "+xx" or "-xx" if offset is non-zero,
1727bc421551SDag-Erling Smørgrav 	** but this is no time for a treasure hunt.
1728bc421551SDag-Erling Smørgrav 	*/
1729bc421551SDag-Erling Smørgrav 	tmp->TM_ZONE = ((char *)
1730bc421551SDag-Erling Smørgrav 			(offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
1731bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */
1732bc421551SDag-Erling Smørgrav 	return result;
1733bc421551SDag-Erling Smørgrav }
1734bc421551SDag-Erling Smørgrav 
1735bc421551SDag-Erling Smørgrav /*
1736bc421551SDag-Erling Smørgrav * Re-entrant version of gmtime.
1737bc421551SDag-Erling Smørgrav */
1738bc421551SDag-Erling Smørgrav 
1739bc421551SDag-Erling Smørgrav struct tm *
174075411d15SDag-Erling Smørgrav gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
1741bc421551SDag-Erling Smørgrav {
1742bc421551SDag-Erling Smørgrav 	_once(&gmt_once, gmtcheck);
1743bc421551SDag-Erling Smørgrav 	return gmtsub(gmtptr, timep, 0, tmp);
1744bc421551SDag-Erling Smørgrav }
1745bc421551SDag-Erling Smørgrav 
1746bc421551SDag-Erling Smørgrav static void
1747bc421551SDag-Erling Smørgrav gmtime_key_init(void)
1748bc421551SDag-Erling Smørgrav {
1749bc421551SDag-Erling Smørgrav 
1750bc421551SDag-Erling Smørgrav 	gmtime_key_error = _pthread_key_create(&gmtime_key, free);
1751bc421551SDag-Erling Smørgrav }
1752bc421551SDag-Erling Smørgrav 
1753bc421551SDag-Erling Smørgrav struct tm *
1754bc421551SDag-Erling Smørgrav gmtime(const time_t *timep)
1755bc421551SDag-Erling Smørgrav {
175675411d15SDag-Erling Smørgrav #if !SUPPORT_C89
175775411d15SDag-Erling Smørgrav 	static struct tm tm;
175875411d15SDag-Erling Smørgrav #endif
1759bc421551SDag-Erling Smørgrav 	struct tm *p_tm = &tm;
1760bc421551SDag-Erling Smørgrav 
1761bc421551SDag-Erling Smørgrav 	if (__isthreaded != 0) {
1762bc421551SDag-Erling Smørgrav 		_pthread_once(&gmtime_once, gmtime_key_init);
1763bc421551SDag-Erling Smørgrav 		if (gmtime_key_error != 0) {
1764bc421551SDag-Erling Smørgrav 			errno = gmtime_key_error;
1765bc421551SDag-Erling Smørgrav 			return (NULL);
1766bc421551SDag-Erling Smørgrav 		}
1767bc421551SDag-Erling Smørgrav 		if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
1768bc421551SDag-Erling Smørgrav 			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
1769bc421551SDag-Erling Smørgrav 				return (NULL);
1770bc421551SDag-Erling Smørgrav 			}
177196e68c39SDag-Erling Smørgrav 			if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
177296e68c39SDag-Erling Smørgrav 				free(p_tm);
177396e68c39SDag-Erling Smørgrav 				return (NULL);
177496e68c39SDag-Erling Smørgrav 			}
1775bc421551SDag-Erling Smørgrav 		}
1776bc421551SDag-Erling Smørgrav 	}
1777bc421551SDag-Erling Smørgrav 	return gmtime_r(timep, p_tm);
1778bc421551SDag-Erling Smørgrav }
1779bc421551SDag-Erling Smørgrav 
178075411d15SDag-Erling Smørgrav #if STD_INSPIRED
178175411d15SDag-Erling Smørgrav 
178246c59934SDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases.
178346c59934SDag-Erling Smørgrav    Callers can instead use localtime_rz with a fixed-offset zone.  */
178446c59934SDag-Erling Smørgrav 
178575411d15SDag-Erling Smørgrav struct tm *
178675411d15SDag-Erling Smørgrav offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
178775411d15SDag-Erling Smørgrav {
178875411d15SDag-Erling Smørgrav 	_once(&gmt_once, gmtcheck);
178975411d15SDag-Erling Smørgrav 	return gmtsub(gmtptr, timep, offset, tmp);
179075411d15SDag-Erling Smørgrav }
179175411d15SDag-Erling Smørgrav 
179275411d15SDag-Erling Smørgrav static void
179375411d15SDag-Erling Smørgrav offtime_key_init(void)
179475411d15SDag-Erling Smørgrav {
179575411d15SDag-Erling Smørgrav 
179675411d15SDag-Erling Smørgrav 	offtime_key_error = _pthread_key_create(&offtime_key, free);
179775411d15SDag-Erling Smørgrav }
1798bc421551SDag-Erling Smørgrav 
1799bc421551SDag-Erling Smørgrav struct tm *
1800bc421551SDag-Erling Smørgrav offtime(const time_t *timep, long offset)
1801bc421551SDag-Erling Smørgrav {
180275411d15SDag-Erling Smørgrav #if !SUPPORT_C89
180375411d15SDag-Erling Smørgrav 	static struct tm tm;
180475411d15SDag-Erling Smørgrav #endif
180575411d15SDag-Erling Smørgrav 	struct tm *p_tm = &tm;
180675411d15SDag-Erling Smørgrav 
180775411d15SDag-Erling Smørgrav 	if (__isthreaded != 0) {
180875411d15SDag-Erling Smørgrav 		_pthread_once(&offtime_once, offtime_key_init);
180975411d15SDag-Erling Smørgrav 		if (offtime_key_error != 0) {
181075411d15SDag-Erling Smørgrav 			errno = offtime_key_error;
181175411d15SDag-Erling Smørgrav 			return (NULL);
181275411d15SDag-Erling Smørgrav 		}
181375411d15SDag-Erling Smørgrav 		if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
181475411d15SDag-Erling Smørgrav 			if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
181575411d15SDag-Erling Smørgrav 				return (NULL);
181675411d15SDag-Erling Smørgrav 			}
181775411d15SDag-Erling Smørgrav 			if (_pthread_setspecific(offtime_key, p_tm) != 0) {
181875411d15SDag-Erling Smørgrav 				free(p_tm);
181975411d15SDag-Erling Smørgrav 				return (NULL);
182075411d15SDag-Erling Smørgrav 			}
182175411d15SDag-Erling Smørgrav 		}
182275411d15SDag-Erling Smørgrav 	}
182375411d15SDag-Erling Smørgrav 	return offtime_r(timep, offset, p_tm);
1824bc421551SDag-Erling Smørgrav }
1825bc421551SDag-Erling Smørgrav 
182675411d15SDag-Erling Smørgrav #endif
1827bc421551SDag-Erling Smørgrav 
1828bc421551SDag-Erling Smørgrav /*
1829bc421551SDag-Erling Smørgrav ** Return the number of leap years through the end of the given year
1830bc421551SDag-Erling Smørgrav ** where, to make the math easy, the answer for year zero is defined as zero.
1831bc421551SDag-Erling Smørgrav */
1832bc421551SDag-Erling Smørgrav 
1833bc421551SDag-Erling Smørgrav static time_t
1834bc421551SDag-Erling Smørgrav leaps_thru_end_of_nonneg(time_t y)
1835bc421551SDag-Erling Smørgrav {
1836bc421551SDag-Erling Smørgrav   return y / 4 - y / 100 + y / 400;
1837bc421551SDag-Erling Smørgrav }
1838bc421551SDag-Erling Smørgrav 
1839bc421551SDag-Erling Smørgrav static time_t
1840bc421551SDag-Erling Smørgrav leaps_thru_end_of(time_t y)
1841bc421551SDag-Erling Smørgrav {
1842bc421551SDag-Erling Smørgrav   return (y < 0
1843bc421551SDag-Erling Smørgrav 	  ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1844bc421551SDag-Erling Smørgrav 	  : leaps_thru_end_of_nonneg(y));
1845bc421551SDag-Erling Smørgrav }
1846bc421551SDag-Erling Smørgrav 
1847bc421551SDag-Erling Smørgrav static struct tm *
1848bc421551SDag-Erling Smørgrav timesub(const time_t *timep, int_fast32_t offset,
1849bc421551SDag-Erling Smørgrav 	const struct state *sp, struct tm *tmp)
1850bc421551SDag-Erling Smørgrav {
1851bc421551SDag-Erling Smørgrav 	register const struct lsinfo *	lp;
1852bc421551SDag-Erling Smørgrav 	register time_t			tdays;
1853bc421551SDag-Erling Smørgrav 	register const int *		ip;
1854bc421551SDag-Erling Smørgrav 	register int_fast32_t		corr;
1855bc421551SDag-Erling Smørgrav 	register int			i;
1856bc421551SDag-Erling Smørgrav 	int_fast32_t idays, rem, dayoff, dayrem;
1857bc421551SDag-Erling Smørgrav 	time_t y;
1858bc421551SDag-Erling Smørgrav 
1859bc421551SDag-Erling Smørgrav 	/* If less than SECSPERMIN, the number of seconds since the
1860bc421551SDag-Erling Smørgrav 	   most recent positive leap second; otherwise, do not add 1
1861bc421551SDag-Erling Smørgrav 	   to localtime tm_sec because of leap seconds.  */
1862bc421551SDag-Erling Smørgrav 	time_t secs_since_posleap = SECSPERMIN;
1863bc421551SDag-Erling Smørgrav 
1864bc421551SDag-Erling Smørgrav 	corr = 0;
1865bc421551SDag-Erling Smørgrav 	i = (sp == NULL) ? 0 : sp->leapcnt;
1866bc421551SDag-Erling Smørgrav 	while (--i >= 0) {
1867bc421551SDag-Erling Smørgrav 		lp = &sp->lsis[i];
1868bc421551SDag-Erling Smørgrav 		if (*timep >= lp->ls_trans) {
1869bc421551SDag-Erling Smørgrav 			corr = lp->ls_corr;
1870bc421551SDag-Erling Smørgrav 			if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
1871bc421551SDag-Erling Smørgrav 			  secs_since_posleap = *timep - lp->ls_trans;
1872bc421551SDag-Erling Smørgrav 			break;
1873bc421551SDag-Erling Smørgrav 		}
1874bc421551SDag-Erling Smørgrav 	}
1875bc421551SDag-Erling Smørgrav 
1876bc421551SDag-Erling Smørgrav 	/* Calculate the year, avoiding integer overflow even if
1877bc421551SDag-Erling Smørgrav 	   time_t is unsigned.  */
1878bc421551SDag-Erling Smørgrav 	tdays = *timep / SECSPERDAY;
1879bc421551SDag-Erling Smørgrav 	rem = *timep % SECSPERDAY;
1880bc421551SDag-Erling Smørgrav 	rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
1881bc421551SDag-Erling Smørgrav 	dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
1882bc421551SDag-Erling Smørgrav 	rem %= SECSPERDAY;
1883bc421551SDag-Erling Smørgrav 	/* y = (EPOCH_YEAR
1884bc421551SDag-Erling Smørgrav 	        + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
1885bc421551SDag-Erling Smørgrav 	   sans overflow.  But calculate against 1570 (EPOCH_YEAR -
1886bc421551SDag-Erling Smørgrav 	   YEARSPERREPEAT) instead of against 1970 so that things work
1887bc421551SDag-Erling Smørgrav 	   for localtime values before 1970 when time_t is unsigned.  */
1888bc421551SDag-Erling Smørgrav 	dayrem = tdays % DAYSPERREPEAT;
1889bc421551SDag-Erling Smørgrav 	dayrem += dayoff % DAYSPERREPEAT;
1890bc421551SDag-Erling Smørgrav 	y = (EPOCH_YEAR - YEARSPERREPEAT
1891bc421551SDag-Erling Smørgrav 	     + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
1892bc421551SDag-Erling Smørgrav 		 - ((dayrem % DAYSPERREPEAT) < 0)
1893bc421551SDag-Erling Smørgrav 		 + tdays / DAYSPERREPEAT)
1894bc421551SDag-Erling Smørgrav 		* YEARSPERREPEAT));
1895bc421551SDag-Erling Smørgrav 	/* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow.  */
1896bc421551SDag-Erling Smørgrav 	idays = tdays % DAYSPERREPEAT;
1897bc421551SDag-Erling Smørgrav 	idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
1898bc421551SDag-Erling Smørgrav 	idays %= DAYSPERREPEAT;
1899bc421551SDag-Erling Smørgrav 	/* Increase Y and decrease IDAYS until IDAYS is in range for Y.  */
1900bc421551SDag-Erling Smørgrav 	while (year_lengths[isleap(y)] <= idays) {
1901bc421551SDag-Erling Smørgrav 		int tdelta = idays / DAYSPERLYEAR;
1902bc421551SDag-Erling Smørgrav 		int_fast32_t ydelta = tdelta + !tdelta;
1903bc421551SDag-Erling Smørgrav 		time_t newy = y + ydelta;
1904bc421551SDag-Erling Smørgrav 		register int	leapdays;
1905bc421551SDag-Erling Smørgrav 		leapdays = leaps_thru_end_of(newy - 1) -
1906bc421551SDag-Erling Smørgrav 			leaps_thru_end_of(y - 1);
1907bc421551SDag-Erling Smørgrav 		idays -= ydelta * DAYSPERNYEAR;
1908bc421551SDag-Erling Smørgrav 		idays -= leapdays;
1909bc421551SDag-Erling Smørgrav 		y = newy;
1910bc421551SDag-Erling Smørgrav 	}
1911bc421551SDag-Erling Smørgrav 
1912bc421551SDag-Erling Smørgrav #ifdef ckd_add
1913bc421551SDag-Erling Smørgrav 	if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
1914bc421551SDag-Erling Smørgrav 	  errno = EOVERFLOW;
1915bc421551SDag-Erling Smørgrav 	  return NULL;
1916bc421551SDag-Erling Smørgrav 	}
1917bc421551SDag-Erling Smørgrav #else
1918bc421551SDag-Erling Smørgrav 	if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
1919bc421551SDag-Erling Smørgrav 	  int signed_y = y;
1920bc421551SDag-Erling Smørgrav 	  tmp->tm_year = signed_y - TM_YEAR_BASE;
1921bc421551SDag-Erling Smørgrav 	} else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
1922bc421551SDag-Erling Smørgrav 		   && y - TM_YEAR_BASE <= INT_MAX)
1923bc421551SDag-Erling Smørgrav 	  tmp->tm_year = y - TM_YEAR_BASE;
1924bc421551SDag-Erling Smørgrav 	else {
1925bc421551SDag-Erling Smørgrav 	  errno = EOVERFLOW;
1926bc421551SDag-Erling Smørgrav 	  return NULL;
1927bc421551SDag-Erling Smørgrav 	}
1928bc421551SDag-Erling Smørgrav #endif
1929bc421551SDag-Erling Smørgrav 	tmp->tm_yday = idays;
1930bc421551SDag-Erling Smørgrav 	/*
1931bc421551SDag-Erling Smørgrav 	** The "extra" mods below avoid overflow problems.
1932bc421551SDag-Erling Smørgrav 	*/
1933bc421551SDag-Erling Smørgrav 	tmp->tm_wday = (TM_WDAY_BASE
1934bc421551SDag-Erling Smørgrav 			+ ((tmp->tm_year % DAYSPERWEEK)
1935bc421551SDag-Erling Smørgrav 			   * (DAYSPERNYEAR % DAYSPERWEEK))
1936bc421551SDag-Erling Smørgrav 			+ leaps_thru_end_of(y - 1)
1937bc421551SDag-Erling Smørgrav 			- leaps_thru_end_of(TM_YEAR_BASE - 1)
1938bc421551SDag-Erling Smørgrav 			+ idays);
1939bc421551SDag-Erling Smørgrav 	tmp->tm_wday %= DAYSPERWEEK;
1940bc421551SDag-Erling Smørgrav 	if (tmp->tm_wday < 0)
1941bc421551SDag-Erling Smørgrav 		tmp->tm_wday += DAYSPERWEEK;
1942bc421551SDag-Erling Smørgrav 	tmp->tm_hour = rem / SECSPERHOUR;
1943bc421551SDag-Erling Smørgrav 	rem %= SECSPERHOUR;
1944bc421551SDag-Erling Smørgrav 	tmp->tm_min = rem / SECSPERMIN;
1945bc421551SDag-Erling Smørgrav 	tmp->tm_sec = rem % SECSPERMIN;
1946bc421551SDag-Erling Smørgrav 
1947bc421551SDag-Erling Smørgrav 	/* Use "... ??:??:60" at the end of the localtime minute containing
1948bc421551SDag-Erling Smørgrav 	   the second just before the positive leap second.  */
1949bc421551SDag-Erling Smørgrav 	tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
1950bc421551SDag-Erling Smørgrav 
1951bc421551SDag-Erling Smørgrav 	ip = mon_lengths[isleap(y)];
1952bc421551SDag-Erling Smørgrav 	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1953bc421551SDag-Erling Smørgrav 		idays -= ip[tmp->tm_mon];
1954bc421551SDag-Erling Smørgrav 	tmp->tm_mday = idays + 1;
1955bc421551SDag-Erling Smørgrav 	tmp->tm_isdst = 0;
1956bc421551SDag-Erling Smørgrav #ifdef TM_GMTOFF
1957bc421551SDag-Erling Smørgrav 	tmp->TM_GMTOFF = offset;
1958bc421551SDag-Erling Smørgrav #endif /* defined TM_GMTOFF */
1959bc421551SDag-Erling Smørgrav 	return tmp;
1960bc421551SDag-Erling Smørgrav }
1961bc421551SDag-Erling Smørgrav 
1962bc421551SDag-Erling Smørgrav /*
1963bc421551SDag-Erling Smørgrav ** Adapted from code provided by Robert Elz, who writes:
1964bc421551SDag-Erling Smørgrav **	The "best" way to do mktime I think is based on an idea of Bob
1965bc421551SDag-Erling Smørgrav **	Kridle's (so its said...) from a long time ago.
1966bc421551SDag-Erling Smørgrav **	It does a binary search of the time_t space. Since time_t's are
1967bc421551SDag-Erling Smørgrav **	just 32 bits, its a max of 32 iterations (even at 64 bits it
1968bc421551SDag-Erling Smørgrav **	would still be very reasonable).
1969bc421551SDag-Erling Smørgrav */
1970bc421551SDag-Erling Smørgrav 
1971bc421551SDag-Erling Smørgrav #ifndef WRONG
1972bc421551SDag-Erling Smørgrav # define WRONG (-1)
1973bc421551SDag-Erling Smørgrav #endif /* !defined WRONG */
1974bc421551SDag-Erling Smørgrav 
1975bc421551SDag-Erling Smørgrav /*
1976bc421551SDag-Erling Smørgrav ** Normalize logic courtesy Paul Eggert.
1977bc421551SDag-Erling Smørgrav */
1978bc421551SDag-Erling Smørgrav 
1979bc421551SDag-Erling Smørgrav static bool
1980bc421551SDag-Erling Smørgrav increment_overflow(int *ip, int j)
1981bc421551SDag-Erling Smørgrav {
1982bc421551SDag-Erling Smørgrav #ifdef ckd_add
1983bc421551SDag-Erling Smørgrav 	return ckd_add(ip, *ip, j);
1984bc421551SDag-Erling Smørgrav #else
1985bc421551SDag-Erling Smørgrav 	register int const	i = *ip;
1986bc421551SDag-Erling Smørgrav 
1987bc421551SDag-Erling Smørgrav 	/*
1988bc421551SDag-Erling Smørgrav 	** If i >= 0 there can only be overflow if i + j > INT_MAX
1989bc421551SDag-Erling Smørgrav 	** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1990bc421551SDag-Erling Smørgrav 	** If i < 0 there can only be overflow if i + j < INT_MIN
1991bc421551SDag-Erling Smørgrav 	** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1992bc421551SDag-Erling Smørgrav 	*/
1993bc421551SDag-Erling Smørgrav 	if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1994bc421551SDag-Erling Smørgrav 		return true;
1995bc421551SDag-Erling Smørgrav 	*ip += j;
1996bc421551SDag-Erling Smørgrav 	return false;
1997bc421551SDag-Erling Smørgrav #endif
1998bc421551SDag-Erling Smørgrav }
1999bc421551SDag-Erling Smørgrav 
2000bc421551SDag-Erling Smørgrav static bool
2001bc421551SDag-Erling Smørgrav increment_overflow32(int_fast32_t *const lp, int const m)
2002bc421551SDag-Erling Smørgrav {
2003bc421551SDag-Erling Smørgrav #ifdef ckd_add
2004bc421551SDag-Erling Smørgrav 	return ckd_add(lp, *lp, m);
2005bc421551SDag-Erling Smørgrav #else
2006bc421551SDag-Erling Smørgrav 	register int_fast32_t const	l = *lp;
2007bc421551SDag-Erling Smørgrav 
2008bc421551SDag-Erling Smørgrav 	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
2009bc421551SDag-Erling Smørgrav 		return true;
2010bc421551SDag-Erling Smørgrav 	*lp += m;
2011bc421551SDag-Erling Smørgrav 	return false;
2012bc421551SDag-Erling Smørgrav #endif
2013bc421551SDag-Erling Smørgrav }
2014bc421551SDag-Erling Smørgrav 
2015bc421551SDag-Erling Smørgrav static bool
2016bc421551SDag-Erling Smørgrav increment_overflow_time(time_t *tp, int_fast32_t j)
2017bc421551SDag-Erling Smørgrav {
2018bc421551SDag-Erling Smørgrav #ifdef ckd_add
2019bc421551SDag-Erling Smørgrav 	return ckd_add(tp, *tp, j);
2020bc421551SDag-Erling Smørgrav #else
2021bc421551SDag-Erling Smørgrav 	/*
2022bc421551SDag-Erling Smørgrav 	** This is like
2023bc421551SDag-Erling Smørgrav 	** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
2024bc421551SDag-Erling Smørgrav 	** except that it does the right thing even if *tp + j would overflow.
2025bc421551SDag-Erling Smørgrav 	*/
2026bc421551SDag-Erling Smørgrav 	if (! (j < 0
2027bc421551SDag-Erling Smørgrav 	       ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
2028bc421551SDag-Erling Smørgrav 	       : *tp <= TIME_T_MAX - j))
2029bc421551SDag-Erling Smørgrav 		return true;
2030bc421551SDag-Erling Smørgrav 	*tp += j;
2031bc421551SDag-Erling Smørgrav 	return false;
2032bc421551SDag-Erling Smørgrav #endif
2033bc421551SDag-Erling Smørgrav }
2034bc421551SDag-Erling Smørgrav 
2035bc421551SDag-Erling Smørgrav static bool
2036bc421551SDag-Erling Smørgrav normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
2037bc421551SDag-Erling Smørgrav {
2038bc421551SDag-Erling Smørgrav 	register int	tensdelta;
2039bc421551SDag-Erling Smørgrav 
2040bc421551SDag-Erling Smørgrav 	tensdelta = (*unitsptr >= 0) ?
2041bc421551SDag-Erling Smørgrav 		(*unitsptr / base) :
2042bc421551SDag-Erling Smørgrav 		(-1 - (-1 - *unitsptr) / base);
2043bc421551SDag-Erling Smørgrav 	*unitsptr -= tensdelta * base;
2044bc421551SDag-Erling Smørgrav 	return increment_overflow(tensptr, tensdelta);
2045bc421551SDag-Erling Smørgrav }
2046bc421551SDag-Erling Smørgrav 
2047bc421551SDag-Erling Smørgrav static bool
2048bc421551SDag-Erling Smørgrav normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
2049bc421551SDag-Erling Smørgrav {
2050bc421551SDag-Erling Smørgrav 	register int	tensdelta;
2051bc421551SDag-Erling Smørgrav 
2052bc421551SDag-Erling Smørgrav 	tensdelta = (*unitsptr >= 0) ?
2053bc421551SDag-Erling Smørgrav 		(*unitsptr / base) :
2054bc421551SDag-Erling Smørgrav 		(-1 - (-1 - *unitsptr) / base);
2055bc421551SDag-Erling Smørgrav 	*unitsptr -= tensdelta * base;
2056bc421551SDag-Erling Smørgrav 	return increment_overflow32(tensptr, tensdelta);
2057bc421551SDag-Erling Smørgrav }
2058bc421551SDag-Erling Smørgrav 
2059bc421551SDag-Erling Smørgrav static int
2060bc421551SDag-Erling Smørgrav tmcomp(register const struct tm *const atmp,
2061bc421551SDag-Erling Smørgrav        register const struct tm *const btmp)
2062bc421551SDag-Erling Smørgrav {
2063bc421551SDag-Erling Smørgrav 	register int	result;
2064bc421551SDag-Erling Smørgrav 
2065bc421551SDag-Erling Smørgrav 	if (atmp->tm_year != btmp->tm_year)
2066bc421551SDag-Erling Smørgrav 		return atmp->tm_year < btmp->tm_year ? -1 : 1;
2067bc421551SDag-Erling Smørgrav 	if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
2068bc421551SDag-Erling Smørgrav 		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
2069bc421551SDag-Erling Smørgrav 		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
2070bc421551SDag-Erling Smørgrav 		(result = (atmp->tm_min - btmp->tm_min)) == 0)
2071bc421551SDag-Erling Smørgrav 			result = atmp->tm_sec - btmp->tm_sec;
2072bc421551SDag-Erling Smørgrav 	return result;
2073bc421551SDag-Erling Smørgrav }
2074bc421551SDag-Erling Smørgrav 
2075bc421551SDag-Erling Smørgrav /* Copy to *DEST from *SRC.  Copy only the members needed for mktime,
2076bc421551SDag-Erling Smørgrav    as other members might not be initialized.  */
2077bc421551SDag-Erling Smørgrav static void
2078bc421551SDag-Erling Smørgrav mktmcpy(struct tm *dest, struct tm const *src)
2079bc421551SDag-Erling Smørgrav {
2080bc421551SDag-Erling Smørgrav   dest->tm_sec = src->tm_sec;
2081bc421551SDag-Erling Smørgrav   dest->tm_min = src->tm_min;
2082bc421551SDag-Erling Smørgrav   dest->tm_hour = src->tm_hour;
2083bc421551SDag-Erling Smørgrav   dest->tm_mday = src->tm_mday;
2084bc421551SDag-Erling Smørgrav   dest->tm_mon = src->tm_mon;
2085bc421551SDag-Erling Smørgrav   dest->tm_year = src->tm_year;
2086bc421551SDag-Erling Smørgrav   dest->tm_isdst = src->tm_isdst;
2087bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP
2088bc421551SDag-Erling Smørgrav   dest->TM_GMTOFF = src->TM_GMTOFF;
2089bc421551SDag-Erling Smørgrav #endif
2090bc421551SDag-Erling Smørgrav }
2091bc421551SDag-Erling Smørgrav 
2092bc421551SDag-Erling Smørgrav static time_t
2093bc421551SDag-Erling Smørgrav time2sub(struct tm *const tmp,
2094bc421551SDag-Erling Smørgrav 	 struct tm *(*funcp)(struct state const *, time_t const *,
2095bc421551SDag-Erling Smørgrav 			     int_fast32_t, struct tm *),
2096bc421551SDag-Erling Smørgrav 	 struct state const *sp,
2097bc421551SDag-Erling Smørgrav 	 const int_fast32_t offset,
2098bc421551SDag-Erling Smørgrav 	 bool *okayp,
2099bc421551SDag-Erling Smørgrav 	 bool do_norm_secs)
2100bc421551SDag-Erling Smørgrav {
2101bc421551SDag-Erling Smørgrav 	register int			dir;
2102bc421551SDag-Erling Smørgrav 	register int			i, j;
2103bc421551SDag-Erling Smørgrav 	register int			saved_seconds;
2104bc421551SDag-Erling Smørgrav 	register int_fast32_t		li;
2105bc421551SDag-Erling Smørgrav 	register time_t			lo;
2106bc421551SDag-Erling Smørgrav 	register time_t			hi;
2107bc421551SDag-Erling Smørgrav 	int_fast32_t			y;
2108bc421551SDag-Erling Smørgrav 	time_t				newt;
2109bc421551SDag-Erling Smørgrav 	time_t				t;
2110bc421551SDag-Erling Smørgrav 	struct tm			yourtm, mytm;
2111bc421551SDag-Erling Smørgrav 
2112bc421551SDag-Erling Smørgrav 	*okayp = false;
2113bc421551SDag-Erling Smørgrav 	mktmcpy(&yourtm, tmp);
2114bc421551SDag-Erling Smørgrav 
2115bc421551SDag-Erling Smørgrav 	if (do_norm_secs) {
2116bc421551SDag-Erling Smørgrav 		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2117bc421551SDag-Erling Smørgrav 			SECSPERMIN))
2118bc421551SDag-Erling Smørgrav 				return WRONG;
2119bc421551SDag-Erling Smørgrav 	}
2120bc421551SDag-Erling Smørgrav 	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2121bc421551SDag-Erling Smørgrav 		return WRONG;
2122bc421551SDag-Erling Smørgrav 	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2123bc421551SDag-Erling Smørgrav 		return WRONG;
2124bc421551SDag-Erling Smørgrav 	y = yourtm.tm_year;
2125bc421551SDag-Erling Smørgrav 	if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
2126bc421551SDag-Erling Smørgrav 		return WRONG;
2127bc421551SDag-Erling Smørgrav 	/*
2128bc421551SDag-Erling Smørgrav 	** Turn y into an actual year number for now.
2129bc421551SDag-Erling Smørgrav 	** It is converted back to an offset from TM_YEAR_BASE later.
2130bc421551SDag-Erling Smørgrav 	*/
2131bc421551SDag-Erling Smørgrav 	if (increment_overflow32(&y, TM_YEAR_BASE))
2132bc421551SDag-Erling Smørgrav 		return WRONG;
2133bc421551SDag-Erling Smørgrav 	while (yourtm.tm_mday <= 0) {
2134bc421551SDag-Erling Smørgrav 		if (increment_overflow32(&y, -1))
2135bc421551SDag-Erling Smørgrav 			return WRONG;
2136bc421551SDag-Erling Smørgrav 		li = y + (1 < yourtm.tm_mon);
2137bc421551SDag-Erling Smørgrav 		yourtm.tm_mday += year_lengths[isleap(li)];
2138bc421551SDag-Erling Smørgrav 	}
2139bc421551SDag-Erling Smørgrav 	while (yourtm.tm_mday > DAYSPERLYEAR) {
2140bc421551SDag-Erling Smørgrav 		li = y + (1 < yourtm.tm_mon);
2141bc421551SDag-Erling Smørgrav 		yourtm.tm_mday -= year_lengths[isleap(li)];
2142bc421551SDag-Erling Smørgrav 		if (increment_overflow32(&y, 1))
2143bc421551SDag-Erling Smørgrav 			return WRONG;
2144bc421551SDag-Erling Smørgrav 	}
2145bc421551SDag-Erling Smørgrav 	for ( ; ; ) {
2146bc421551SDag-Erling Smørgrav 		i = mon_lengths[isleap(y)][yourtm.tm_mon];
2147bc421551SDag-Erling Smørgrav 		if (yourtm.tm_mday <= i)
2148bc421551SDag-Erling Smørgrav 			break;
2149bc421551SDag-Erling Smørgrav 		yourtm.tm_mday -= i;
2150bc421551SDag-Erling Smørgrav 		if (++yourtm.tm_mon >= MONSPERYEAR) {
2151bc421551SDag-Erling Smørgrav 			yourtm.tm_mon = 0;
2152bc421551SDag-Erling Smørgrav 			if (increment_overflow32(&y, 1))
2153bc421551SDag-Erling Smørgrav 				return WRONG;
2154bc421551SDag-Erling Smørgrav 		}
2155bc421551SDag-Erling Smørgrav 	}
2156bc421551SDag-Erling Smørgrav #ifdef ckd_add
2157bc421551SDag-Erling Smørgrav 	if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
2158bc421551SDag-Erling Smørgrav 	  return WRONG;
2159bc421551SDag-Erling Smørgrav #else
2160bc421551SDag-Erling Smørgrav 	if (increment_overflow32(&y, -TM_YEAR_BASE))
2161bc421551SDag-Erling Smørgrav 		return WRONG;
2162bc421551SDag-Erling Smørgrav 	if (! (INT_MIN <= y && y <= INT_MAX))
2163bc421551SDag-Erling Smørgrav 		return WRONG;
2164bc421551SDag-Erling Smørgrav 	yourtm.tm_year = y;
2165bc421551SDag-Erling Smørgrav #endif
2166bc421551SDag-Erling Smørgrav 	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2167bc421551SDag-Erling Smørgrav 		saved_seconds = 0;
2168bc421551SDag-Erling Smørgrav 	else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
2169bc421551SDag-Erling Smørgrav 		/*
2170bc421551SDag-Erling Smørgrav 		** We can't set tm_sec to 0, because that might push the
2171bc421551SDag-Erling Smørgrav 		** time below the minimum representable time.
2172bc421551SDag-Erling Smørgrav 		** Set tm_sec to 59 instead.
2173bc421551SDag-Erling Smørgrav 		** This assumes that the minimum representable time is
2174bc421551SDag-Erling Smørgrav 		** not in the same minute that a leap second was deleted from,
2175bc421551SDag-Erling Smørgrav 		** which is a safer assumption than using 58 would be.
2176bc421551SDag-Erling Smørgrav 		*/
2177bc421551SDag-Erling Smørgrav 		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2178bc421551SDag-Erling Smørgrav 			return WRONG;
2179bc421551SDag-Erling Smørgrav 		saved_seconds = yourtm.tm_sec;
2180bc421551SDag-Erling Smørgrav 		yourtm.tm_sec = SECSPERMIN - 1;
2181bc421551SDag-Erling Smørgrav 	} else {
2182bc421551SDag-Erling Smørgrav 		saved_seconds = yourtm.tm_sec;
2183bc421551SDag-Erling Smørgrav 		yourtm.tm_sec = 0;
2184bc421551SDag-Erling Smørgrav 	}
2185bc421551SDag-Erling Smørgrav 	/*
2186bc421551SDag-Erling Smørgrav 	** Do a binary search (this works whatever time_t's type is).
2187bc421551SDag-Erling Smørgrav 	*/
2188bc421551SDag-Erling Smørgrav 	lo = TIME_T_MIN;
2189bc421551SDag-Erling Smørgrav 	hi = TIME_T_MAX;
2190bc421551SDag-Erling Smørgrav 	for ( ; ; ) {
2191bc421551SDag-Erling Smørgrav 		t = lo / 2 + hi / 2;
2192bc421551SDag-Erling Smørgrav 		if (t < lo)
2193bc421551SDag-Erling Smørgrav 			t = lo;
2194bc421551SDag-Erling Smørgrav 		else if (t > hi)
2195bc421551SDag-Erling Smørgrav 			t = hi;
2196bc421551SDag-Erling Smørgrav 		if (! funcp(sp, &t, offset, &mytm)) {
2197bc421551SDag-Erling Smørgrav 			/*
2198bc421551SDag-Erling Smørgrav 			** Assume that t is too extreme to be represented in
2199bc421551SDag-Erling Smørgrav 			** a struct tm; arrange things so that it is less
2200bc421551SDag-Erling Smørgrav 			** extreme on the next pass.
2201bc421551SDag-Erling Smørgrav 			*/
2202bc421551SDag-Erling Smørgrav 			dir = (t > 0) ? 1 : -1;
2203bc421551SDag-Erling Smørgrav 		} else	dir = tmcomp(&mytm, &yourtm);
2204bc421551SDag-Erling Smørgrav 		if (dir != 0) {
2205bc421551SDag-Erling Smørgrav 			if (t == lo) {
2206bc421551SDag-Erling Smørgrav 				if (t == TIME_T_MAX)
2207bc421551SDag-Erling Smørgrav 					return WRONG;
2208bc421551SDag-Erling Smørgrav 				++t;
2209bc421551SDag-Erling Smørgrav 				++lo;
2210bc421551SDag-Erling Smørgrav 			} else if (t == hi) {
2211bc421551SDag-Erling Smørgrav 				if (t == TIME_T_MIN)
2212bc421551SDag-Erling Smørgrav 					return WRONG;
2213bc421551SDag-Erling Smørgrav 				--t;
2214bc421551SDag-Erling Smørgrav 				--hi;
2215bc421551SDag-Erling Smørgrav 			}
2216bc421551SDag-Erling Smørgrav 			if (lo > hi)
2217bc421551SDag-Erling Smørgrav 				return WRONG;
2218bc421551SDag-Erling Smørgrav 			if (dir > 0)
2219bc421551SDag-Erling Smørgrav 				hi = t;
2220bc421551SDag-Erling Smørgrav 			else	lo = t;
2221bc421551SDag-Erling Smørgrav 			continue;
2222bc421551SDag-Erling Smørgrav 		}
2223bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP
2224bc421551SDag-Erling Smørgrav 		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
2225bc421551SDag-Erling Smørgrav 		    && (yourtm.TM_GMTOFF < 0
2226bc421551SDag-Erling Smørgrav 			? (-SECSPERDAY <= yourtm.TM_GMTOFF
2227bc421551SDag-Erling Smørgrav 			   && (mytm.TM_GMTOFF <=
2228bc421551SDag-Erling Smørgrav 			       (min(INT_FAST32_MAX, LONG_MAX)
2229bc421551SDag-Erling Smørgrav 				+ yourtm.TM_GMTOFF)))
2230bc421551SDag-Erling Smørgrav 			: (yourtm.TM_GMTOFF <= SECSPERDAY
2231bc421551SDag-Erling Smørgrav 			   && ((max(INT_FAST32_MIN, LONG_MIN)
2232bc421551SDag-Erling Smørgrav 				+ yourtm.TM_GMTOFF)
2233bc421551SDag-Erling Smørgrav 			       <= mytm.TM_GMTOFF)))) {
2234bc421551SDag-Erling Smørgrav 		  /* MYTM matches YOURTM except with the wrong UT offset.
2235bc421551SDag-Erling Smørgrav 		     YOURTM.TM_GMTOFF is plausible, so try it instead.
2236bc421551SDag-Erling Smørgrav 		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2237bc421551SDag-Erling Smørgrav 		     since the guess gets checked.  */
2238bc421551SDag-Erling Smørgrav 		  time_t altt = t;
2239bc421551SDag-Erling Smørgrav 		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2240bc421551SDag-Erling Smørgrav 		  if (!increment_overflow_time(&altt, diff)) {
2241bc421551SDag-Erling Smørgrav 		    struct tm alttm;
2242bc421551SDag-Erling Smørgrav 		    if (funcp(sp, &altt, offset, &alttm)
2243bc421551SDag-Erling Smørgrav 			&& alttm.tm_isdst == mytm.tm_isdst
2244bc421551SDag-Erling Smørgrav 			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2245bc421551SDag-Erling Smørgrav 			&& tmcomp(&alttm, &yourtm) == 0) {
2246bc421551SDag-Erling Smørgrav 		      t = altt;
2247bc421551SDag-Erling Smørgrav 		      mytm = alttm;
2248bc421551SDag-Erling Smørgrav 		    }
2249bc421551SDag-Erling Smørgrav 		  }
2250bc421551SDag-Erling Smørgrav 		}
2251bc421551SDag-Erling Smørgrav #endif
2252bc421551SDag-Erling Smørgrav 		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2253bc421551SDag-Erling Smørgrav 			break;
2254bc421551SDag-Erling Smørgrav 		/*
2255bc421551SDag-Erling Smørgrav 		** Right time, wrong type.
2256bc421551SDag-Erling Smørgrav 		** Hunt for right time, right type.
2257bc421551SDag-Erling Smørgrav 		** It's okay to guess wrong since the guess
2258bc421551SDag-Erling Smørgrav 		** gets checked.
2259bc421551SDag-Erling Smørgrav 		*/
2260bc421551SDag-Erling Smørgrav 		if (sp == NULL)
2261bc421551SDag-Erling Smørgrav 			return WRONG;
2262bc421551SDag-Erling Smørgrav 		for (i = sp->typecnt - 1; i >= 0; --i) {
2263bc421551SDag-Erling Smørgrav 			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2264bc421551SDag-Erling Smørgrav 				continue;
2265bc421551SDag-Erling Smørgrav 			for (j = sp->typecnt - 1; j >= 0; --j) {
2266bc421551SDag-Erling Smørgrav 				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2267bc421551SDag-Erling Smørgrav 					continue;
2268bc421551SDag-Erling Smørgrav 				if (ttunspecified(sp, j))
2269bc421551SDag-Erling Smørgrav 				  continue;
2270bc421551SDag-Erling Smørgrav 				newt = (t + sp->ttis[j].tt_utoff
2271bc421551SDag-Erling Smørgrav 					- sp->ttis[i].tt_utoff);
2272bc421551SDag-Erling Smørgrav 				if (! funcp(sp, &newt, offset, &mytm))
2273bc421551SDag-Erling Smørgrav 					continue;
2274bc421551SDag-Erling Smørgrav 				if (tmcomp(&mytm, &yourtm) != 0)
2275bc421551SDag-Erling Smørgrav 					continue;
2276bc421551SDag-Erling Smørgrav 				if (mytm.tm_isdst != yourtm.tm_isdst)
2277bc421551SDag-Erling Smørgrav 					continue;
2278bc421551SDag-Erling Smørgrav 				/*
2279bc421551SDag-Erling Smørgrav 				** We have a match.
2280bc421551SDag-Erling Smørgrav 				*/
2281bc421551SDag-Erling Smørgrav 				t = newt;
2282bc421551SDag-Erling Smørgrav 				goto label;
2283bc421551SDag-Erling Smørgrav 			}
2284bc421551SDag-Erling Smørgrav 		}
2285bc421551SDag-Erling Smørgrav 		return WRONG;
2286bc421551SDag-Erling Smørgrav 	}
2287bc421551SDag-Erling Smørgrav label:
2288bc421551SDag-Erling Smørgrav 	newt = t + saved_seconds;
2289bc421551SDag-Erling Smørgrav 	if ((newt < t) != (saved_seconds < 0))
2290bc421551SDag-Erling Smørgrav 		return WRONG;
2291bc421551SDag-Erling Smørgrav 	t = newt;
2292bc421551SDag-Erling Smørgrav 	if (funcp(sp, &t, offset, tmp))
2293bc421551SDag-Erling Smørgrav 		*okayp = true;
2294bc421551SDag-Erling Smørgrav 	return t;
2295bc421551SDag-Erling Smørgrav }
2296bc421551SDag-Erling Smørgrav 
2297bc421551SDag-Erling Smørgrav static time_t
2298bc421551SDag-Erling Smørgrav time2(struct tm * const	tmp,
2299bc421551SDag-Erling Smørgrav       struct tm *(*funcp)(struct state const *, time_t const *,
2300bc421551SDag-Erling Smørgrav 			  int_fast32_t, struct tm *),
2301bc421551SDag-Erling Smørgrav       struct state const *sp,
2302bc421551SDag-Erling Smørgrav       const int_fast32_t offset,
2303bc421551SDag-Erling Smørgrav       bool *okayp)
2304bc421551SDag-Erling Smørgrav {
2305bc421551SDag-Erling Smørgrav 	time_t	t;
2306bc421551SDag-Erling Smørgrav 
2307bc421551SDag-Erling Smørgrav 	/*
2308bc421551SDag-Erling Smørgrav 	** First try without normalization of seconds
2309bc421551SDag-Erling Smørgrav 	** (in case tm_sec contains a value associated with a leap second).
2310bc421551SDag-Erling Smørgrav 	** If that fails, try with normalization of seconds.
2311bc421551SDag-Erling Smørgrav 	*/
2312bc421551SDag-Erling Smørgrav 	t = time2sub(tmp, funcp, sp, offset, okayp, false);
2313bc421551SDag-Erling Smørgrav 	return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
2314bc421551SDag-Erling Smørgrav }
2315bc421551SDag-Erling Smørgrav 
2316bc421551SDag-Erling Smørgrav static time_t
2317bc421551SDag-Erling Smørgrav time1(struct tm *const tmp,
2318bc421551SDag-Erling Smørgrav       struct tm *(*funcp)(struct state const *, time_t const *,
2319bc421551SDag-Erling Smørgrav 			  int_fast32_t, struct tm *),
2320bc421551SDag-Erling Smørgrav       struct state const *sp,
2321bc421551SDag-Erling Smørgrav       const int_fast32_t offset)
2322bc421551SDag-Erling Smørgrav {
2323bc421551SDag-Erling Smørgrav 	register time_t			t;
2324bc421551SDag-Erling Smørgrav 	register int			samei, otheri;
2325bc421551SDag-Erling Smørgrav 	register int			sameind, otherind;
2326bc421551SDag-Erling Smørgrav 	register int			i;
2327bc421551SDag-Erling Smørgrav 	register int			nseen;
2328bc421551SDag-Erling Smørgrav 	char				seen[TZ_MAX_TYPES];
2329bc421551SDag-Erling Smørgrav 	unsigned char			types[TZ_MAX_TYPES];
2330bc421551SDag-Erling Smørgrav 	bool				okay;
2331bc421551SDag-Erling Smørgrav 
2332bc421551SDag-Erling Smørgrav 	if (tmp == NULL) {
2333bc421551SDag-Erling Smørgrav 		errno = EINVAL;
2334bc421551SDag-Erling Smørgrav 		return WRONG;
2335bc421551SDag-Erling Smørgrav 	}
2336bc421551SDag-Erling Smørgrav 
2337bc421551SDag-Erling Smørgrav 	if (tmp->tm_isdst > 1)
2338bc421551SDag-Erling Smørgrav 		tmp->tm_isdst = 1;
2339bc421551SDag-Erling Smørgrav 	t = time2(tmp, funcp, sp, offset, &okay);
2340bc421551SDag-Erling Smørgrav 	if (okay)
2341bc421551SDag-Erling Smørgrav 		return t;
2342bc421551SDag-Erling Smørgrav 	if (tmp->tm_isdst < 0)
2343bc421551SDag-Erling Smørgrav #ifdef PCTS
2344bc421551SDag-Erling Smørgrav 		/*
2345bc421551SDag-Erling Smørgrav 		** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2346bc421551SDag-Erling Smørgrav 		*/
2347bc421551SDag-Erling Smørgrav 		tmp->tm_isdst = 0;	/* reset to std and try again */
2348bc421551SDag-Erling Smørgrav #else
2349bc421551SDag-Erling Smørgrav 		return t;
2350bc421551SDag-Erling Smørgrav #endif /* !defined PCTS */
2351bc421551SDag-Erling Smørgrav 	/*
2352bc421551SDag-Erling Smørgrav 	** We're supposed to assume that somebody took a time of one type
2353bc421551SDag-Erling Smørgrav 	** and did some math on it that yielded a "struct tm" that's bad.
2354bc421551SDag-Erling Smørgrav 	** We try to divine the type they started from and adjust to the
2355bc421551SDag-Erling Smørgrav 	** type they need.
2356bc421551SDag-Erling Smørgrav 	*/
2357bc421551SDag-Erling Smørgrav 	if (sp == NULL)
2358bc421551SDag-Erling Smørgrav 		return WRONG;
2359bc421551SDag-Erling Smørgrav 	for (i = 0; i < sp->typecnt; ++i)
2360bc421551SDag-Erling Smørgrav 		seen[i] = false;
2361bc421551SDag-Erling Smørgrav 	nseen = 0;
2362bc421551SDag-Erling Smørgrav 	for (i = sp->timecnt - 1; i >= 0; --i)
2363bc421551SDag-Erling Smørgrav 		if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
2364bc421551SDag-Erling Smørgrav 			seen[sp->types[i]] = true;
2365bc421551SDag-Erling Smørgrav 			types[nseen++] = sp->types[i];
2366bc421551SDag-Erling Smørgrav 		}
2367bc421551SDag-Erling Smørgrav 	for (sameind = 0; sameind < nseen; ++sameind) {
2368bc421551SDag-Erling Smørgrav 		samei = types[sameind];
2369bc421551SDag-Erling Smørgrav 		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2370bc421551SDag-Erling Smørgrav 			continue;
2371bc421551SDag-Erling Smørgrav 		for (otherind = 0; otherind < nseen; ++otherind) {
2372bc421551SDag-Erling Smørgrav 			otheri = types[otherind];
2373bc421551SDag-Erling Smørgrav 			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2374bc421551SDag-Erling Smørgrav 				continue;
2375bc421551SDag-Erling Smørgrav 			tmp->tm_sec += (sp->ttis[otheri].tt_utoff
2376bc421551SDag-Erling Smørgrav 					- sp->ttis[samei].tt_utoff);
2377bc421551SDag-Erling Smørgrav 			tmp->tm_isdst = !tmp->tm_isdst;
2378bc421551SDag-Erling Smørgrav 			t = time2(tmp, funcp, sp, offset, &okay);
2379bc421551SDag-Erling Smørgrav 			if (okay)
2380bc421551SDag-Erling Smørgrav 				return t;
2381bc421551SDag-Erling Smørgrav 			tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
2382bc421551SDag-Erling Smørgrav 					- sp->ttis[samei].tt_utoff);
2383bc421551SDag-Erling Smørgrav 			tmp->tm_isdst = !tmp->tm_isdst;
2384bc421551SDag-Erling Smørgrav 		}
2385bc421551SDag-Erling Smørgrav 	}
2386bc421551SDag-Erling Smørgrav 	return WRONG;
2387bc421551SDag-Erling Smørgrav }
2388bc421551SDag-Erling Smørgrav 
2389bc421551SDag-Erling Smørgrav static time_t
2390bc421551SDag-Erling Smørgrav mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2391bc421551SDag-Erling Smørgrav {
2392bc421551SDag-Erling Smørgrav   if (sp)
2393bc421551SDag-Erling Smørgrav     return time1(tmp, localsub, sp, setname);
2394bc421551SDag-Erling Smørgrav   else {
2395bc421551SDag-Erling Smørgrav     _once(&gmt_once, gmtcheck);
2396bc421551SDag-Erling Smørgrav     return time1(tmp, gmtsub, gmtptr, 0);
2397bc421551SDag-Erling Smørgrav   }
2398bc421551SDag-Erling Smørgrav }
2399bc421551SDag-Erling Smørgrav 
2400bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED
2401bc421551SDag-Erling Smørgrav 
2402bc421551SDag-Erling Smørgrav time_t
240375411d15SDag-Erling Smørgrav mktime_z(struct state *restrict sp, struct tm *restrict tmp)
2404bc421551SDag-Erling Smørgrav {
2405bc421551SDag-Erling Smørgrav   return mktime_tzname(sp, tmp, false);
2406bc421551SDag-Erling Smørgrav }
2407bc421551SDag-Erling Smørgrav 
2408bc421551SDag-Erling Smørgrav #endif
2409bc421551SDag-Erling Smørgrav 
2410bc421551SDag-Erling Smørgrav time_t
2411bc421551SDag-Erling Smørgrav mktime(struct tm *tmp)
2412bc421551SDag-Erling Smørgrav {
2413bc421551SDag-Erling Smørgrav   time_t t;
2414bc421551SDag-Erling Smørgrav   int err = lock();
2415bc421551SDag-Erling Smørgrav   if (err) {
2416bc421551SDag-Erling Smørgrav     errno = err;
2417bc421551SDag-Erling Smørgrav     return -1;
2418bc421551SDag-Erling Smørgrav   }
2419bc421551SDag-Erling Smørgrav   tzset_unlocked();
2420bc421551SDag-Erling Smørgrav   t = mktime_tzname(lclptr, tmp, true);
2421bc421551SDag-Erling Smørgrav   unlock();
2422bc421551SDag-Erling Smørgrav   return t;
2423bc421551SDag-Erling Smørgrav }
2424bc421551SDag-Erling Smørgrav 
242575411d15SDag-Erling Smørgrav #if STD_INSPIRED
2426*a979394aSDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases.
242746c59934SDag-Erling Smørgrav    Callers can instead use mktime.  */
2428bc421551SDag-Erling Smørgrav time_t
2429bc421551SDag-Erling Smørgrav timelocal(struct tm *tmp)
2430bc421551SDag-Erling Smørgrav {
2431bc421551SDag-Erling Smørgrav 	if (tmp != NULL)
2432bc421551SDag-Erling Smørgrav 		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
2433bc421551SDag-Erling Smørgrav 	return mktime(tmp);
2434bc421551SDag-Erling Smørgrav }
2435bc421551SDag-Erling Smørgrav #endif
243646c59934SDag-Erling Smørgrav 
243746c59934SDag-Erling Smørgrav #ifndef EXTERN_TIMEOFF
243846c59934SDag-Erling Smørgrav # ifndef timeoff
243946c59934SDag-Erling Smørgrav #  define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>.  */
244046c59934SDag-Erling Smørgrav # endif
244146c59934SDag-Erling Smørgrav # define EXTERN_TIMEOFF static
244246c59934SDag-Erling Smørgrav #endif
244346c59934SDag-Erling Smørgrav 
2444*a979394aSDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases.
244546c59934SDag-Erling Smørgrav    Callers can instead use mktime_z with a fixed-offset zone.  */
244646c59934SDag-Erling Smørgrav EXTERN_TIMEOFF time_t
2447bc421551SDag-Erling Smørgrav timeoff(struct tm *tmp, long offset)
2448bc421551SDag-Erling Smørgrav {
2449bc421551SDag-Erling Smørgrav   if (tmp)
2450bc421551SDag-Erling Smørgrav     tmp->tm_isdst = 0;
2451bc421551SDag-Erling Smørgrav   _once(&gmt_once, gmtcheck);
2452bc421551SDag-Erling Smørgrav   return time1(tmp, gmtsub, gmtptr, offset);
2453bc421551SDag-Erling Smørgrav }
2454bc421551SDag-Erling Smørgrav 
2455bc421551SDag-Erling Smørgrav time_t
2456bc421551SDag-Erling Smørgrav timegm(struct tm *tmp)
2457bc421551SDag-Erling Smørgrav {
2458bc421551SDag-Erling Smørgrav   time_t t;
2459bc421551SDag-Erling Smørgrav   struct tm tmcpy;
2460bc421551SDag-Erling Smørgrav   mktmcpy(&tmcpy, tmp);
2461bc421551SDag-Erling Smørgrav   tmcpy.tm_wday = -1;
2462bc421551SDag-Erling Smørgrav   t = timeoff(&tmcpy, 0);
2463bc421551SDag-Erling Smørgrav   if (0 <= tmcpy.tm_wday)
2464bc421551SDag-Erling Smørgrav     *tmp = tmcpy;
2465bc421551SDag-Erling Smørgrav   return t;
2466bc421551SDag-Erling Smørgrav }
2467bc421551SDag-Erling Smørgrav 
2468bc421551SDag-Erling Smørgrav static int_fast32_t
2469bc421551SDag-Erling Smørgrav leapcorr(struct state const *sp, time_t t)
2470bc421551SDag-Erling Smørgrav {
2471bc421551SDag-Erling Smørgrav 	register struct lsinfo const *	lp;
2472bc421551SDag-Erling Smørgrav 	register int			i;
2473bc421551SDag-Erling Smørgrav 
2474bc421551SDag-Erling Smørgrav 	i = sp->leapcnt;
2475bc421551SDag-Erling Smørgrav 	while (--i >= 0) {
2476bc421551SDag-Erling Smørgrav 		lp = &sp->lsis[i];
2477bc421551SDag-Erling Smørgrav 		if (t >= lp->ls_trans)
2478bc421551SDag-Erling Smørgrav 			return lp->ls_corr;
2479bc421551SDag-Erling Smørgrav 	}
2480bc421551SDag-Erling Smørgrav 	return 0;
2481bc421551SDag-Erling Smørgrav }
2482bc421551SDag-Erling Smørgrav 
2483bc421551SDag-Erling Smørgrav /*
2484bc421551SDag-Erling Smørgrav ** XXX--is the below the right way to conditionalize??
2485bc421551SDag-Erling Smørgrav */
2486bc421551SDag-Erling Smørgrav 
248775411d15SDag-Erling Smørgrav #if STD_INSPIRED
2488bc421551SDag-Erling Smørgrav 
2489bc421551SDag-Erling Smørgrav /* NETBSD_INSPIRED_EXTERN functions are exported to callers if
2490bc421551SDag-Erling Smørgrav    NETBSD_INSPIRED is defined, and are private otherwise.  */
2491bc421551SDag-Erling Smørgrav # if NETBSD_INSPIRED
2492bc421551SDag-Erling Smørgrav #  define NETBSD_INSPIRED_EXTERN
2493bc421551SDag-Erling Smørgrav # else
2494bc421551SDag-Erling Smørgrav #  define NETBSD_INSPIRED_EXTERN static
2495bc421551SDag-Erling Smørgrav # endif
2496bc421551SDag-Erling Smørgrav 
2497bc421551SDag-Erling Smørgrav /*
2498bc421551SDag-Erling Smørgrav ** IEEE Std 1003.1 (POSIX) says that 536457599
2499bc421551SDag-Erling Smørgrav ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2500bc421551SDag-Erling Smørgrav ** is not the case if we are accounting for leap seconds.
2501bc421551SDag-Erling Smørgrav ** So, we provide the following conversion routines for use
2502bc421551SDag-Erling Smørgrav ** when exchanging timestamps with POSIX conforming systems.
2503bc421551SDag-Erling Smørgrav */
2504bc421551SDag-Erling Smørgrav 
2505bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t
2506bc421551SDag-Erling Smørgrav time2posix_z(struct state *sp, time_t t)
2507bc421551SDag-Erling Smørgrav {
2508bc421551SDag-Erling Smørgrav   return t - leapcorr(sp, t);
2509bc421551SDag-Erling Smørgrav }
2510bc421551SDag-Erling Smørgrav 
2511bc421551SDag-Erling Smørgrav time_t
2512bc421551SDag-Erling Smørgrav time2posix(time_t t)
2513bc421551SDag-Erling Smørgrav {
2514bc421551SDag-Erling Smørgrav   int err = lock();
2515bc421551SDag-Erling Smørgrav   if (err) {
2516bc421551SDag-Erling Smørgrav     errno = err;
2517bc421551SDag-Erling Smørgrav     return -1;
2518bc421551SDag-Erling Smørgrav   }
2519bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
2520bc421551SDag-Erling Smørgrav   if (!lcl_is_set)
2521bc421551SDag-Erling Smørgrav #endif
2522bc421551SDag-Erling Smørgrav     tzset_unlocked();
2523bc421551SDag-Erling Smørgrav   if (lclptr)
2524bc421551SDag-Erling Smørgrav     t = time2posix_z(lclptr, t);
2525bc421551SDag-Erling Smørgrav   unlock();
2526bc421551SDag-Erling Smørgrav   return t;
2527bc421551SDag-Erling Smørgrav }
2528bc421551SDag-Erling Smørgrav 
2529bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t
2530bc421551SDag-Erling Smørgrav posix2time_z(struct state *sp, time_t t)
2531bc421551SDag-Erling Smørgrav {
2532bc421551SDag-Erling Smørgrav 	time_t	x;
2533bc421551SDag-Erling Smørgrav 	time_t	y;
2534bc421551SDag-Erling Smørgrav 	/*
2535bc421551SDag-Erling Smørgrav 	** For a positive leap second hit, the result
2536bc421551SDag-Erling Smørgrav 	** is not unique. For a negative leap second
2537bc421551SDag-Erling Smørgrav 	** hit, the corresponding time doesn't exist,
2538bc421551SDag-Erling Smørgrav 	** so we return an adjacent second.
2539bc421551SDag-Erling Smørgrav 	*/
2540bc421551SDag-Erling Smørgrav 	x = t + leapcorr(sp, t);
2541bc421551SDag-Erling Smørgrav 	y = x - leapcorr(sp, x);
2542bc421551SDag-Erling Smørgrav 	if (y < t) {
2543bc421551SDag-Erling Smørgrav 		do {
2544bc421551SDag-Erling Smørgrav 			x++;
2545bc421551SDag-Erling Smørgrav 			y = x - leapcorr(sp, x);
2546bc421551SDag-Erling Smørgrav 		} while (y < t);
2547bc421551SDag-Erling Smørgrav 		x -= y != t;
2548bc421551SDag-Erling Smørgrav 	} else if (y > t) {
2549bc421551SDag-Erling Smørgrav 		do {
2550bc421551SDag-Erling Smørgrav 			--x;
2551bc421551SDag-Erling Smørgrav 			y = x - leapcorr(sp, x);
2552bc421551SDag-Erling Smørgrav 		} while (y > t);
2553bc421551SDag-Erling Smørgrav 		x += y != t;
2554bc421551SDag-Erling Smørgrav 	}
2555bc421551SDag-Erling Smørgrav 	return x;
2556bc421551SDag-Erling Smørgrav }
2557bc421551SDag-Erling Smørgrav 
2558bc421551SDag-Erling Smørgrav time_t
2559bc421551SDag-Erling Smørgrav posix2time(time_t t)
2560bc421551SDag-Erling Smørgrav {
2561bc421551SDag-Erling Smørgrav   int err = lock();
2562bc421551SDag-Erling Smørgrav   if (err) {
2563bc421551SDag-Erling Smørgrav     errno = err;
2564bc421551SDag-Erling Smørgrav     return -1;
2565bc421551SDag-Erling Smørgrav   }
2566bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES
2567bc421551SDag-Erling Smørgrav   if (!lcl_is_set)
2568bc421551SDag-Erling Smørgrav #endif
2569bc421551SDag-Erling Smørgrav     tzset_unlocked();
2570bc421551SDag-Erling Smørgrav   if (lclptr)
2571bc421551SDag-Erling Smørgrav     t = posix2time_z(lclptr, t);
2572bc421551SDag-Erling Smørgrav   unlock();
2573bc421551SDag-Erling Smørgrav   return t;
2574bc421551SDag-Erling Smørgrav }
2575bc421551SDag-Erling Smørgrav 
257675411d15SDag-Erling Smørgrav #endif /* STD_INSPIRED */
2577bc421551SDag-Erling Smørgrav 
2578bc421551SDag-Erling Smørgrav #if TZ_TIME_T
2579bc421551SDag-Erling Smørgrav 
2580bc421551SDag-Erling Smørgrav # if !USG_COMPAT
2581bc421551SDag-Erling Smørgrav #  define daylight 0
2582bc421551SDag-Erling Smørgrav #  define timezone 0
2583bc421551SDag-Erling Smørgrav # endif
2584bc421551SDag-Erling Smørgrav # if !ALTZONE
2585bc421551SDag-Erling Smørgrav #  define altzone 0
2586bc421551SDag-Erling Smørgrav # endif
2587bc421551SDag-Erling Smørgrav 
2588bc421551SDag-Erling Smørgrav /* Convert from the underlying system's time_t to the ersatz time_tz,
2589bc421551SDag-Erling Smørgrav    which is called 'time_t' in this file.  Typically, this merely
2590bc421551SDag-Erling Smørgrav    converts the time's integer width.  On some platforms, the system
2591bc421551SDag-Erling Smørgrav    time is local time not UT, or uses some epoch other than the POSIX
2592bc421551SDag-Erling Smørgrav    epoch.
2593bc421551SDag-Erling Smørgrav 
2594bc421551SDag-Erling Smørgrav    Although this code appears to define a function named 'time' that
2595bc421551SDag-Erling Smørgrav    returns time_t, the macros in private.h cause this code to actually
2596bc421551SDag-Erling Smørgrav    define a function named 'tz_time' that returns tz_time_t.  The call
2597bc421551SDag-Erling Smørgrav    to sys_time invokes the underlying system's 'time' function.  */
2598bc421551SDag-Erling Smørgrav 
2599bc421551SDag-Erling Smørgrav time_t
2600bc421551SDag-Erling Smørgrav time(time_t *p)
2601bc421551SDag-Erling Smørgrav {
2602bc421551SDag-Erling Smørgrav   time_t r = sys_time(0);
2603bc421551SDag-Erling Smørgrav   if (r != (time_t) -1) {
2604bc421551SDag-Erling Smørgrav     int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
2605bc421551SDag-Erling Smørgrav     if (increment_overflow32(&offset, -EPOCH_OFFSET)
2606bc421551SDag-Erling Smørgrav 	|| increment_overflow_time(&r, offset)) {
2607bc421551SDag-Erling Smørgrav       errno = EOVERFLOW;
2608bc421551SDag-Erling Smørgrav       r = -1;
2609bc421551SDag-Erling Smørgrav     }
2610bc421551SDag-Erling Smørgrav   }
2611bc421551SDag-Erling Smørgrav   if (p)
2612bc421551SDag-Erling Smørgrav     *p = r;
2613bc421551SDag-Erling Smørgrav   return r;
2614bc421551SDag-Erling Smørgrav }
2615bc421551SDag-Erling Smørgrav 
2616bc421551SDag-Erling Smørgrav #endif
2617