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