14616d0f9Sopenharmony_ci/* Convert timestamp from time_t to struct tm.  */
24616d0f9Sopenharmony_ci
34616d0f9Sopenharmony_ci/*
44616d0f9Sopenharmony_ci** This file is in the public domain, so clarified as of
54616d0f9Sopenharmony_ci** 1996-06-05 by Arthur David Olson.
64616d0f9Sopenharmony_ci*/
74616d0f9Sopenharmony_ci
84616d0f9Sopenharmony_ci/*
94616d0f9Sopenharmony_ci** Leap second handling from Bradley White.
104616d0f9Sopenharmony_ci** POSIX.1-1988 style TZ environment variable handling from Guy Harris.
114616d0f9Sopenharmony_ci*/
124616d0f9Sopenharmony_ci
134616d0f9Sopenharmony_ci/*LINTLIBRARY*/
144616d0f9Sopenharmony_ci
154616d0f9Sopenharmony_ci#define LOCALTIME_IMPLEMENTATION
164616d0f9Sopenharmony_ci#include "private.h"
174616d0f9Sopenharmony_ci
184616d0f9Sopenharmony_ci#include "tzdir.h"
194616d0f9Sopenharmony_ci#include "tzfile.h"
204616d0f9Sopenharmony_ci#include <fcntl.h>
214616d0f9Sopenharmony_ci
224616d0f9Sopenharmony_ci#if defined THREAD_SAFE && THREAD_SAFE
234616d0f9Sopenharmony_ci# include <pthread.h>
244616d0f9Sopenharmony_cistatic pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
254616d0f9Sopenharmony_cistatic int lock(void) { return pthread_mutex_lock(&locallock); }
264616d0f9Sopenharmony_cistatic void unlock(void) { pthread_mutex_unlock(&locallock); }
274616d0f9Sopenharmony_ci#else
284616d0f9Sopenharmony_cistatic int lock(void) { return 0; }
294616d0f9Sopenharmony_cistatic void unlock(void) { }
304616d0f9Sopenharmony_ci#endif
314616d0f9Sopenharmony_ci
324616d0f9Sopenharmony_ci#ifndef TZ_ABBR_CHAR_SET
334616d0f9Sopenharmony_ci# define TZ_ABBR_CHAR_SET \
344616d0f9Sopenharmony_ci	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
354616d0f9Sopenharmony_ci#endif /* !defined TZ_ABBR_CHAR_SET */
364616d0f9Sopenharmony_ci
374616d0f9Sopenharmony_ci#ifndef TZ_ABBR_ERR_CHAR
384616d0f9Sopenharmony_ci# define TZ_ABBR_ERR_CHAR '_'
394616d0f9Sopenharmony_ci#endif /* !defined TZ_ABBR_ERR_CHAR */
404616d0f9Sopenharmony_ci
414616d0f9Sopenharmony_ci/*
424616d0f9Sopenharmony_ci** Support non-POSIX platforms that distinguish between text and binary files.
434616d0f9Sopenharmony_ci*/
444616d0f9Sopenharmony_ci
454616d0f9Sopenharmony_ci#ifndef O_BINARY
464616d0f9Sopenharmony_ci# define O_BINARY 0
474616d0f9Sopenharmony_ci#endif
484616d0f9Sopenharmony_ci
494616d0f9Sopenharmony_ci#ifndef WILDABBR
504616d0f9Sopenharmony_ci/*
514616d0f9Sopenharmony_ci** Someone might make incorrect use of a time zone abbreviation:
524616d0f9Sopenharmony_ci**	1.	They might reference tzname[0] before calling tzset (explicitly
534616d0f9Sopenharmony_ci**		or implicitly).
544616d0f9Sopenharmony_ci**	2.	They might reference tzname[1] before calling tzset (explicitly
554616d0f9Sopenharmony_ci**		or implicitly).
564616d0f9Sopenharmony_ci**	3.	They might reference tzname[1] after setting to a time zone
574616d0f9Sopenharmony_ci**		in which Daylight Saving Time is never observed.
584616d0f9Sopenharmony_ci**	4.	They might reference tzname[0] after setting to a time zone
594616d0f9Sopenharmony_ci**		in which Standard Time is never observed.
604616d0f9Sopenharmony_ci**	5.	They might reference tm.TM_ZONE after calling offtime.
614616d0f9Sopenharmony_ci** What's best to do in the above cases is open to debate;
624616d0f9Sopenharmony_ci** for now, we just set things up so that in any of the five cases
634616d0f9Sopenharmony_ci** WILDABBR is used. Another possibility: initialize tzname[0] to the
644616d0f9Sopenharmony_ci** string "tzname[0] used before set", and similarly for the other cases.
654616d0f9Sopenharmony_ci** And another: initialize tzname[0] to "ERA", with an explanation in the
664616d0f9Sopenharmony_ci** manual page of what this "time zone abbreviation" means (doing this so
674616d0f9Sopenharmony_ci** that tzname[0] has the "normal" length of three characters).
684616d0f9Sopenharmony_ci*/
694616d0f9Sopenharmony_ci# define WILDABBR "   "
704616d0f9Sopenharmony_ci#endif /* !defined WILDABBR */
714616d0f9Sopenharmony_ci
724616d0f9Sopenharmony_cistatic const char	wildabbr[] = WILDABBR;
734616d0f9Sopenharmony_ci
744616d0f9Sopenharmony_cistatic char const etc_utc[] = "Etc/UTC";
754616d0f9Sopenharmony_cistatic char const *utc = etc_utc + sizeof "Etc/" - 1;
764616d0f9Sopenharmony_ci
774616d0f9Sopenharmony_ci/*
784616d0f9Sopenharmony_ci** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
794616d0f9Sopenharmony_ci** Default to US rules as of 2017-05-07.
804616d0f9Sopenharmony_ci** POSIX does not specify the default DST rules;
814616d0f9Sopenharmony_ci** for historical reasons, US rules are a common default.
824616d0f9Sopenharmony_ci*/
834616d0f9Sopenharmony_ci#ifndef TZDEFRULESTRING
844616d0f9Sopenharmony_ci# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
854616d0f9Sopenharmony_ci#endif
864616d0f9Sopenharmony_ci
874616d0f9Sopenharmony_cistruct ttinfo {				/* time type information */
884616d0f9Sopenharmony_ci	int_fast32_t	tt_utoff;	/* UT offset in seconds */
894616d0f9Sopenharmony_ci	bool		tt_isdst;	/* used to set tm_isdst */
904616d0f9Sopenharmony_ci	int		tt_desigidx;	/* abbreviation list index */
914616d0f9Sopenharmony_ci	bool		tt_ttisstd;	/* transition is std time */
924616d0f9Sopenharmony_ci	bool		tt_ttisut;	/* transition is UT */
934616d0f9Sopenharmony_ci};
944616d0f9Sopenharmony_ci
954616d0f9Sopenharmony_cistruct lsinfo {				/* leap second information */
964616d0f9Sopenharmony_ci	time_t		ls_trans;	/* transition time */
974616d0f9Sopenharmony_ci	int_fast32_t	ls_corr;	/* correction to apply */
984616d0f9Sopenharmony_ci};
994616d0f9Sopenharmony_ci
1004616d0f9Sopenharmony_ci/* This abbreviation means local time is unspecified.  */
1014616d0f9Sopenharmony_cistatic char const UNSPEC[] = "-00";
1024616d0f9Sopenharmony_ci
1034616d0f9Sopenharmony_ci/* How many extra bytes are needed at the end of struct state's chars array.
1044616d0f9Sopenharmony_ci   This needs to be at least 1 for null termination in case the input
1054616d0f9Sopenharmony_ci   data isn't properly terminated, and it also needs to be big enough
1064616d0f9Sopenharmony_ci   for ttunspecified to work without crashing.  */
1074616d0f9Sopenharmony_cienum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
1084616d0f9Sopenharmony_ci
1094616d0f9Sopenharmony_ci/* Limit to time zone abbreviation length in POSIX.1-2017-style TZ strings.
1104616d0f9Sopenharmony_ci   This is distinct from TZ_MAX_CHARS, which limits TZif file contents.  */
1114616d0f9Sopenharmony_ci#ifndef TZNAME_MAXIMUM
1124616d0f9Sopenharmony_ci# define TZNAME_MAXIMUM 255
1134616d0f9Sopenharmony_ci#endif
1144616d0f9Sopenharmony_ci
1154616d0f9Sopenharmony_ci/* A representation of the contents of a TZif file.  Ideally this
1164616d0f9Sopenharmony_ci   would have no size limits; the following sizes should suffice for
1174616d0f9Sopenharmony_ci   practical use.  This struct should not be too large, as instances
1184616d0f9Sopenharmony_ci   are put on the stack and stacks are relatively small on some platforms.
1194616d0f9Sopenharmony_ci   See tzfile.h for more about the sizes.  */
1204616d0f9Sopenharmony_cistruct state {
1214616d0f9Sopenharmony_ci	int		leapcnt;
1224616d0f9Sopenharmony_ci	int		timecnt;
1234616d0f9Sopenharmony_ci	int		typecnt;
1244616d0f9Sopenharmony_ci	int		charcnt;
1254616d0f9Sopenharmony_ci	bool		goback;
1264616d0f9Sopenharmony_ci	bool		goahead;
1274616d0f9Sopenharmony_ci	time_t		ats[TZ_MAX_TIMES];
1284616d0f9Sopenharmony_ci	unsigned char	types[TZ_MAX_TIMES];
1294616d0f9Sopenharmony_ci	struct ttinfo	ttis[TZ_MAX_TYPES];
1304616d0f9Sopenharmony_ci	char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
1314616d0f9Sopenharmony_ci		       2 * (TZNAME_MAXIMUM + 1))];
1324616d0f9Sopenharmony_ci	struct lsinfo	lsis[TZ_MAX_LEAPS];
1334616d0f9Sopenharmony_ci
1344616d0f9Sopenharmony_ci	/* The time type to use for early times or if no transitions.
1354616d0f9Sopenharmony_ci	   It is always zero for recent tzdb releases.
1364616d0f9Sopenharmony_ci	   It might be nonzero for data from tzdb 2018e or earlier.  */
1374616d0f9Sopenharmony_ci	int defaulttype;
1384616d0f9Sopenharmony_ci};
1394616d0f9Sopenharmony_ci
1404616d0f9Sopenharmony_cienum r_type {
1414616d0f9Sopenharmony_ci  JULIAN_DAY,		/* Jn = Julian day */
1424616d0f9Sopenharmony_ci  DAY_OF_YEAR,		/* n = day of year */
1434616d0f9Sopenharmony_ci  MONTH_NTH_DAY_OF_WEEK	/* Mm.n.d = month, week, day of week */
1444616d0f9Sopenharmony_ci};
1454616d0f9Sopenharmony_ci
1464616d0f9Sopenharmony_cistruct rule {
1474616d0f9Sopenharmony_ci	enum r_type	r_type;		/* type of rule */
1484616d0f9Sopenharmony_ci	int		r_day;		/* day number of rule */
1494616d0f9Sopenharmony_ci	int		r_week;		/* week number of rule */
1504616d0f9Sopenharmony_ci	int		r_mon;		/* month number of rule */
1514616d0f9Sopenharmony_ci	int_fast32_t	r_time;		/* transition time of rule */
1524616d0f9Sopenharmony_ci};
1534616d0f9Sopenharmony_ci
1544616d0f9Sopenharmony_cistatic struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
1554616d0f9Sopenharmony_ci			 struct tm *);
1564616d0f9Sopenharmony_cistatic bool increment_overflow(int *, int);
1574616d0f9Sopenharmony_cistatic bool increment_overflow_time(time_t *, int_fast32_t);
1584616d0f9Sopenharmony_cistatic int_fast32_t leapcorr(struct state const *, time_t);
1594616d0f9Sopenharmony_cistatic bool normalize_overflow32(int_fast32_t *, int *, int);
1604616d0f9Sopenharmony_cistatic struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
1614616d0f9Sopenharmony_ci			  struct tm *);
1624616d0f9Sopenharmony_cistatic bool tzparse(char const *, struct state *, struct state const *);
1634616d0f9Sopenharmony_ci
1644616d0f9Sopenharmony_ci#ifdef ALL_STATE
1654616d0f9Sopenharmony_cistatic struct state *	lclptr;
1664616d0f9Sopenharmony_cistatic struct state *	gmtptr;
1674616d0f9Sopenharmony_ci#endif /* defined ALL_STATE */
1684616d0f9Sopenharmony_ci
1694616d0f9Sopenharmony_ci#ifndef ALL_STATE
1704616d0f9Sopenharmony_cistatic struct state	lclmem;
1714616d0f9Sopenharmony_cistatic struct state	gmtmem;
1724616d0f9Sopenharmony_cistatic struct state *const lclptr = &lclmem;
1734616d0f9Sopenharmony_cistatic struct state *const gmtptr = &gmtmem;
1744616d0f9Sopenharmony_ci#endif /* State Farm */
1754616d0f9Sopenharmony_ci
1764616d0f9Sopenharmony_ci#ifndef TZ_STRLEN_MAX
1774616d0f9Sopenharmony_ci# define TZ_STRLEN_MAX 255
1784616d0f9Sopenharmony_ci#endif /* !defined TZ_STRLEN_MAX */
1794616d0f9Sopenharmony_ci
1804616d0f9Sopenharmony_cistatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
1814616d0f9Sopenharmony_cistatic int		lcl_is_set;
1824616d0f9Sopenharmony_ci
1834616d0f9Sopenharmony_ci/*
1844616d0f9Sopenharmony_ci** Section 4.12.3 of X3.159-1989 requires that
1854616d0f9Sopenharmony_ci**	Except for the strftime function, these functions [asctime,
1864616d0f9Sopenharmony_ci**	ctime, gmtime, localtime] return values in one of two static
1874616d0f9Sopenharmony_ci**	objects: a broken-down time structure and an array of char.
1884616d0f9Sopenharmony_ci** Thanks to Paul Eggert for noting this.
1894616d0f9Sopenharmony_ci**
1904616d0f9Sopenharmony_ci** This requirement was removed in C99, so support it only if requested,
1914616d0f9Sopenharmony_ci** as support is more likely to lead to bugs in badly written programs.
1924616d0f9Sopenharmony_ci*/
1934616d0f9Sopenharmony_ci
1944616d0f9Sopenharmony_ci#if SUPPORT_C89
1954616d0f9Sopenharmony_cistatic struct tm	tm;
1964616d0f9Sopenharmony_ci#endif
1974616d0f9Sopenharmony_ci
1984616d0f9Sopenharmony_ci#if 2 <= HAVE_TZNAME + TZ_TIME_T
1994616d0f9Sopenharmony_cichar *			tzname[2] = {
2004616d0f9Sopenharmony_ci	(char *) wildabbr,
2014616d0f9Sopenharmony_ci	(char *) wildabbr
2024616d0f9Sopenharmony_ci};
2034616d0f9Sopenharmony_ci#endif
2044616d0f9Sopenharmony_ci#if 2 <= USG_COMPAT + TZ_TIME_T
2054616d0f9Sopenharmony_cilong			timezone;
2064616d0f9Sopenharmony_ciint			daylight;
2074616d0f9Sopenharmony_ci#endif
2084616d0f9Sopenharmony_ci#if 2 <= ALTZONE + TZ_TIME_T
2094616d0f9Sopenharmony_cilong			altzone;
2104616d0f9Sopenharmony_ci#endif
2114616d0f9Sopenharmony_ci
2124616d0f9Sopenharmony_ci/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX.  */
2134616d0f9Sopenharmony_cistatic void
2144616d0f9Sopenharmony_ciinit_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
2154616d0f9Sopenharmony_ci{
2164616d0f9Sopenharmony_ci  s->tt_utoff = utoff;
2174616d0f9Sopenharmony_ci  s->tt_isdst = isdst;
2184616d0f9Sopenharmony_ci  s->tt_desigidx = desigidx;
2194616d0f9Sopenharmony_ci  s->tt_ttisstd = false;
2204616d0f9Sopenharmony_ci  s->tt_ttisut = false;
2214616d0f9Sopenharmony_ci}
2224616d0f9Sopenharmony_ci
2234616d0f9Sopenharmony_ci/* Return true if SP's time type I does not specify local time.  */
2244616d0f9Sopenharmony_cistatic bool
2254616d0f9Sopenharmony_cittunspecified(struct state const *sp, int i)
2264616d0f9Sopenharmony_ci{
2274616d0f9Sopenharmony_ci  char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
2284616d0f9Sopenharmony_ci  /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA.  */
2294616d0f9Sopenharmony_ci  return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
2304616d0f9Sopenharmony_ci}
2314616d0f9Sopenharmony_ci
2324616d0f9Sopenharmony_cistatic int_fast32_t
2334616d0f9Sopenharmony_cidetzcode(const char *const codep)
2344616d0f9Sopenharmony_ci{
2354616d0f9Sopenharmony_ci	register int_fast32_t	result;
2364616d0f9Sopenharmony_ci	register int		i;
2374616d0f9Sopenharmony_ci	int_fast32_t one = 1;
2384616d0f9Sopenharmony_ci	int_fast32_t halfmaxval = one << (32 - 2);
2394616d0f9Sopenharmony_ci	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
2404616d0f9Sopenharmony_ci	int_fast32_t minval = -1 - maxval;
2414616d0f9Sopenharmony_ci
2424616d0f9Sopenharmony_ci	result = codep[0] & 0x7f;
2434616d0f9Sopenharmony_ci	for (i = 1; i < 4; ++i)
2444616d0f9Sopenharmony_ci		result = (result << 8) | (codep[i] & 0xff);
2454616d0f9Sopenharmony_ci
2464616d0f9Sopenharmony_ci	if (codep[0] & 0x80) {
2474616d0f9Sopenharmony_ci	  /* Do two's-complement negation even on non-two's-complement machines.
2484616d0f9Sopenharmony_ci	     If the result would be minval - 1, return minval.  */
2494616d0f9Sopenharmony_ci	  result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
2504616d0f9Sopenharmony_ci	  result += minval;
2514616d0f9Sopenharmony_ci	}
2524616d0f9Sopenharmony_ci	return result;
2534616d0f9Sopenharmony_ci}
2544616d0f9Sopenharmony_ci
2554616d0f9Sopenharmony_cistatic int_fast64_t
2564616d0f9Sopenharmony_cidetzcode64(const char *const codep)
2574616d0f9Sopenharmony_ci{
2584616d0f9Sopenharmony_ci	register int_fast64_t result;
2594616d0f9Sopenharmony_ci	register int	i;
2604616d0f9Sopenharmony_ci	int_fast64_t one = 1;
2614616d0f9Sopenharmony_ci	int_fast64_t halfmaxval = one << (64 - 2);
2624616d0f9Sopenharmony_ci	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
2634616d0f9Sopenharmony_ci	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
2644616d0f9Sopenharmony_ci
2654616d0f9Sopenharmony_ci	result = codep[0] & 0x7f;
2664616d0f9Sopenharmony_ci	for (i = 1; i < 8; ++i)
2674616d0f9Sopenharmony_ci		result = (result << 8) | (codep[i] & 0xff);
2684616d0f9Sopenharmony_ci
2694616d0f9Sopenharmony_ci	if (codep[0] & 0x80) {
2704616d0f9Sopenharmony_ci	  /* Do two's-complement negation even on non-two's-complement machines.
2714616d0f9Sopenharmony_ci	     If the result would be minval - 1, return minval.  */
2724616d0f9Sopenharmony_ci	  result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
2734616d0f9Sopenharmony_ci	  result += minval;
2744616d0f9Sopenharmony_ci	}
2754616d0f9Sopenharmony_ci	return result;
2764616d0f9Sopenharmony_ci}
2774616d0f9Sopenharmony_ci
2784616d0f9Sopenharmony_cistatic void
2794616d0f9Sopenharmony_ciupdate_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
2804616d0f9Sopenharmony_ci{
2814616d0f9Sopenharmony_ci#if HAVE_TZNAME
2824616d0f9Sopenharmony_ci  tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
2834616d0f9Sopenharmony_ci#endif
2844616d0f9Sopenharmony_ci#if USG_COMPAT
2854616d0f9Sopenharmony_ci  if (!ttisp->tt_isdst)
2864616d0f9Sopenharmony_ci    timezone = - ttisp->tt_utoff;
2874616d0f9Sopenharmony_ci#endif
2884616d0f9Sopenharmony_ci#if ALTZONE
2894616d0f9Sopenharmony_ci  if (ttisp->tt_isdst)
2904616d0f9Sopenharmony_ci    altzone = - ttisp->tt_utoff;
2914616d0f9Sopenharmony_ci#endif
2924616d0f9Sopenharmony_ci}
2934616d0f9Sopenharmony_ci
2944616d0f9Sopenharmony_ci/* If STDDST_MASK indicates that SP's TYPE provides useful info,
2954616d0f9Sopenharmony_ci   update tzname, timezone, and/or altzone and return STDDST_MASK,
2964616d0f9Sopenharmony_ci   diminished by the provided info if it is a specified local time.
2974616d0f9Sopenharmony_ci   Otherwise, return STDDST_MASK.  See settzname for STDDST_MASK.  */
2984616d0f9Sopenharmony_cistatic int
2994616d0f9Sopenharmony_cimay_update_tzname_etc(int stddst_mask, struct state *sp, int type)
3004616d0f9Sopenharmony_ci{
3014616d0f9Sopenharmony_ci  struct ttinfo *ttisp = &sp->ttis[type];
3024616d0f9Sopenharmony_ci  int this_bit = 1 << ttisp->tt_isdst;
3034616d0f9Sopenharmony_ci  if (stddst_mask & this_bit) {
3044616d0f9Sopenharmony_ci    update_tzname_etc(sp, ttisp);
3054616d0f9Sopenharmony_ci    if (!ttunspecified(sp, type))
3064616d0f9Sopenharmony_ci      return stddst_mask & ~this_bit;
3074616d0f9Sopenharmony_ci  }
3084616d0f9Sopenharmony_ci  return stddst_mask;
3094616d0f9Sopenharmony_ci}
3104616d0f9Sopenharmony_ci
3114616d0f9Sopenharmony_cistatic void
3124616d0f9Sopenharmony_cisettzname(void)
3134616d0f9Sopenharmony_ci{
3144616d0f9Sopenharmony_ci	register struct state * const	sp = lclptr;
3154616d0f9Sopenharmony_ci	register int			i;
3164616d0f9Sopenharmony_ci
3174616d0f9Sopenharmony_ci	/* If STDDST_MASK & 1 we need info about a standard time.
3184616d0f9Sopenharmony_ci	   If STDDST_MASK & 2 we need info about a daylight saving time.
3194616d0f9Sopenharmony_ci	   When STDDST_MASK becomes zero we can stop looking.  */
3204616d0f9Sopenharmony_ci	int stddst_mask = 0;
3214616d0f9Sopenharmony_ci
3224616d0f9Sopenharmony_ci#if HAVE_TZNAME
3234616d0f9Sopenharmony_ci	tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
3244616d0f9Sopenharmony_ci	stddst_mask = 3;
3254616d0f9Sopenharmony_ci#endif
3264616d0f9Sopenharmony_ci#if USG_COMPAT
3274616d0f9Sopenharmony_ci	timezone = 0;
3284616d0f9Sopenharmony_ci	stddst_mask = 3;
3294616d0f9Sopenharmony_ci#endif
3304616d0f9Sopenharmony_ci#if ALTZONE
3314616d0f9Sopenharmony_ci	altzone = 0;
3324616d0f9Sopenharmony_ci	stddst_mask |= 2;
3334616d0f9Sopenharmony_ci#endif
3344616d0f9Sopenharmony_ci	/*
3354616d0f9Sopenharmony_ci	** And to get the latest time zone abbreviations into tzname. . .
3364616d0f9Sopenharmony_ci	*/
3374616d0f9Sopenharmony_ci	if (sp) {
3384616d0f9Sopenharmony_ci	  for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
3394616d0f9Sopenharmony_ci	    stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
3404616d0f9Sopenharmony_ci	  for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
3414616d0f9Sopenharmony_ci	    stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
3424616d0f9Sopenharmony_ci	}
3434616d0f9Sopenharmony_ci#if USG_COMPAT
3444616d0f9Sopenharmony_ci	daylight = stddst_mask >> 1 ^ 1;
3454616d0f9Sopenharmony_ci#endif
3464616d0f9Sopenharmony_ci}
3474616d0f9Sopenharmony_ci
3484616d0f9Sopenharmony_ci/* Replace bogus characters in time zone abbreviations.
3494616d0f9Sopenharmony_ci   Return 0 on success, an errno value if a time zone abbreviation is
3504616d0f9Sopenharmony_ci   too long.  */
3514616d0f9Sopenharmony_cistatic int
3524616d0f9Sopenharmony_ciscrub_abbrs(struct state *sp)
3534616d0f9Sopenharmony_ci{
3544616d0f9Sopenharmony_ci	int i;
3554616d0f9Sopenharmony_ci
3564616d0f9Sopenharmony_ci	/* Reject overlong abbreviations.  */
3574616d0f9Sopenharmony_ci	for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
3584616d0f9Sopenharmony_ci	  int len = strlen(&sp->chars[i]);
3594616d0f9Sopenharmony_ci	  if (TZNAME_MAXIMUM < len)
3604616d0f9Sopenharmony_ci	    return EOVERFLOW;
3614616d0f9Sopenharmony_ci	  i += len + 1;
3624616d0f9Sopenharmony_ci	}
3634616d0f9Sopenharmony_ci
3644616d0f9Sopenharmony_ci	/* Replace bogus characters.  */
3654616d0f9Sopenharmony_ci	for (i = 0; i < sp->charcnt; ++i)
3664616d0f9Sopenharmony_ci		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
3674616d0f9Sopenharmony_ci			sp->chars[i] = TZ_ABBR_ERR_CHAR;
3684616d0f9Sopenharmony_ci
3694616d0f9Sopenharmony_ci	return 0;
3704616d0f9Sopenharmony_ci}
3714616d0f9Sopenharmony_ci
3724616d0f9Sopenharmony_ci/* Input buffer for data read from a compiled tz file.  */
3734616d0f9Sopenharmony_ciunion input_buffer {
3744616d0f9Sopenharmony_ci  /* The first part of the buffer, interpreted as a header.  */
3754616d0f9Sopenharmony_ci  struct tzhead tzhead;
3764616d0f9Sopenharmony_ci
3774616d0f9Sopenharmony_ci  /* The entire buffer.  Ideally this would have no size limits;
3784616d0f9Sopenharmony_ci     the following should suffice for practical use.  */
3794616d0f9Sopenharmony_ci  char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
3804616d0f9Sopenharmony_ci	   + 4 * TZ_MAX_TIMES];
3814616d0f9Sopenharmony_ci};
3824616d0f9Sopenharmony_ci
3834616d0f9Sopenharmony_ci/* TZDIR with a trailing '/' rather than a trailing '\0'.  */
3844616d0f9Sopenharmony_cistatic char const tzdirslash[sizeof TZDIR] = TZDIR "/";
3854616d0f9Sopenharmony_ci
3864616d0f9Sopenharmony_ci/* Local storage needed for 'tzloadbody'.  */
3874616d0f9Sopenharmony_ciunion local_storage {
3884616d0f9Sopenharmony_ci  /* The results of analyzing the file's contents after it is opened.  */
3894616d0f9Sopenharmony_ci  struct file_analysis {
3904616d0f9Sopenharmony_ci    /* The input buffer.  */
3914616d0f9Sopenharmony_ci    union input_buffer u;
3924616d0f9Sopenharmony_ci
3934616d0f9Sopenharmony_ci    /* A temporary state used for parsing a TZ string in the file.  */
3944616d0f9Sopenharmony_ci    struct state st;
3954616d0f9Sopenharmony_ci  } u;
3964616d0f9Sopenharmony_ci
3974616d0f9Sopenharmony_ci  /* The name of the file to be opened.  Ideally this would have no
3984616d0f9Sopenharmony_ci     size limits, to support arbitrarily long Zone names.
3994616d0f9Sopenharmony_ci     Limiting Zone names to 1024 bytes should suffice for practical use.
4004616d0f9Sopenharmony_ci     However, there is no need for this to be smaller than struct
4014616d0f9Sopenharmony_ci     file_analysis as that struct is allocated anyway, as the other
4024616d0f9Sopenharmony_ci     union member.  */
4034616d0f9Sopenharmony_ci  char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
4044616d0f9Sopenharmony_ci};
4054616d0f9Sopenharmony_ci
4064616d0f9Sopenharmony_ci/* Load tz data from the file named NAME into *SP.  Read extended
4074616d0f9Sopenharmony_ci   format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
4084616d0f9Sopenharmony_ci   success, an errno value on failure.  */
4094616d0f9Sopenharmony_cistatic int
4104616d0f9Sopenharmony_citzloadbody(char const *name, struct state *sp, bool doextend,
4114616d0f9Sopenharmony_ci	   union local_storage *lsp)
4124616d0f9Sopenharmony_ci{
4134616d0f9Sopenharmony_ci	register int			i;
4144616d0f9Sopenharmony_ci	register int			fid;
4154616d0f9Sopenharmony_ci	register int			stored;
4164616d0f9Sopenharmony_ci	register ssize_t		nread;
4174616d0f9Sopenharmony_ci	register bool doaccess;
4184616d0f9Sopenharmony_ci	register union input_buffer *up = &lsp->u.u;
4194616d0f9Sopenharmony_ci	register int tzheadsize = sizeof(struct tzhead);
4204616d0f9Sopenharmony_ci
4214616d0f9Sopenharmony_ci	sp->goback = sp->goahead = false;
4224616d0f9Sopenharmony_ci
4234616d0f9Sopenharmony_ci	if (! name) {
4244616d0f9Sopenharmony_ci		name = TZDEFAULT;
4254616d0f9Sopenharmony_ci		if (! name)
4264616d0f9Sopenharmony_ci		  return EINVAL;
4274616d0f9Sopenharmony_ci	}
4284616d0f9Sopenharmony_ci
4294616d0f9Sopenharmony_ci	if (name[0] == ':')
4304616d0f9Sopenharmony_ci		++name;
4314616d0f9Sopenharmony_ci#ifdef SUPPRESS_TZDIR
4324616d0f9Sopenharmony_ci	/* Do not prepend TZDIR.  This is intended for specialized
4334616d0f9Sopenharmony_ci	   applications only, due to its security implications.  */
4344616d0f9Sopenharmony_ci	doaccess = true;
4354616d0f9Sopenharmony_ci#else
4364616d0f9Sopenharmony_ci	doaccess = name[0] == '/';
4374616d0f9Sopenharmony_ci#endif
4384616d0f9Sopenharmony_ci	if (!doaccess) {
4394616d0f9Sopenharmony_ci		char const *dot;
4404616d0f9Sopenharmony_ci		if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
4414616d0f9Sopenharmony_ci		  return ENAMETOOLONG;
4424616d0f9Sopenharmony_ci
4434616d0f9Sopenharmony_ci		/* Create a string "TZDIR/NAME".  Using sprintf here
4444616d0f9Sopenharmony_ci		   would pull in stdio (and would fail if the
4454616d0f9Sopenharmony_ci		   resulting string length exceeded INT_MAX!).  */
4464616d0f9Sopenharmony_ci		memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
4474616d0f9Sopenharmony_ci		strcpy(lsp->fullname + sizeof tzdirslash, name);
4484616d0f9Sopenharmony_ci
4494616d0f9Sopenharmony_ci		/* Set doaccess if NAME contains a ".." file name
4504616d0f9Sopenharmony_ci		   component, as such a name could read a file outside
4514616d0f9Sopenharmony_ci		   the TZDIR virtual subtree.  */
4524616d0f9Sopenharmony_ci		for (dot = name; (dot = strchr(dot, '.')); dot++)
4534616d0f9Sopenharmony_ci		  if ((dot == name || dot[-1] == '/') && dot[1] == '.'
4544616d0f9Sopenharmony_ci		      && (dot[2] == '/' || !dot[2])) {
4554616d0f9Sopenharmony_ci		    doaccess = true;
4564616d0f9Sopenharmony_ci		    break;
4574616d0f9Sopenharmony_ci		  }
4584616d0f9Sopenharmony_ci
4594616d0f9Sopenharmony_ci		name = lsp->fullname;
4604616d0f9Sopenharmony_ci	}
4614616d0f9Sopenharmony_ci	if (doaccess && access(name, R_OK) != 0)
4624616d0f9Sopenharmony_ci	  return errno;
4634616d0f9Sopenharmony_ci	fid = open(name, O_RDONLY | O_BINARY);
4644616d0f9Sopenharmony_ci	if (fid < 0)
4654616d0f9Sopenharmony_ci	  return errno;
4664616d0f9Sopenharmony_ci
4674616d0f9Sopenharmony_ci	nread = read(fid, up->buf, sizeof up->buf);
4684616d0f9Sopenharmony_ci	if (nread < tzheadsize) {
4694616d0f9Sopenharmony_ci	  int err = nread < 0 ? errno : EINVAL;
4704616d0f9Sopenharmony_ci	  close(fid);
4714616d0f9Sopenharmony_ci	  return err;
4724616d0f9Sopenharmony_ci	}
4734616d0f9Sopenharmony_ci	if (close(fid) < 0)
4744616d0f9Sopenharmony_ci	  return errno;
4754616d0f9Sopenharmony_ci	for (stored = 4; stored <= 8; stored *= 2) {
4764616d0f9Sopenharmony_ci	    char version = up->tzhead.tzh_version[0];
4774616d0f9Sopenharmony_ci	    bool skip_datablock = stored == 4 && version;
4784616d0f9Sopenharmony_ci	    int_fast32_t datablock_size;
4794616d0f9Sopenharmony_ci	    int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
4804616d0f9Sopenharmony_ci	    int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
4814616d0f9Sopenharmony_ci	    int_fast64_t prevtr = -1;
4824616d0f9Sopenharmony_ci	    int_fast32_t prevcorr;
4834616d0f9Sopenharmony_ci	    int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
4844616d0f9Sopenharmony_ci	    int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
4854616d0f9Sopenharmony_ci	    int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
4864616d0f9Sopenharmony_ci	    int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
4874616d0f9Sopenharmony_ci	    char const *p = up->buf + tzheadsize;
4884616d0f9Sopenharmony_ci	    /* Although tzfile(5) currently requires typecnt to be nonzero,
4894616d0f9Sopenharmony_ci	       support future formats that may allow zero typecnt
4904616d0f9Sopenharmony_ci	       in files that have a TZ string and no transitions.  */
4914616d0f9Sopenharmony_ci	    if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
4924616d0f9Sopenharmony_ci		   && 0 <= typecnt && typecnt < TZ_MAX_TYPES
4934616d0f9Sopenharmony_ci		   && 0 <= timecnt && timecnt < TZ_MAX_TIMES
4944616d0f9Sopenharmony_ci		   && 0 <= charcnt && charcnt < TZ_MAX_CHARS
4954616d0f9Sopenharmony_ci		   && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
4964616d0f9Sopenharmony_ci		   && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
4974616d0f9Sopenharmony_ci	      return EINVAL;
4984616d0f9Sopenharmony_ci	    datablock_size
4994616d0f9Sopenharmony_ci		    = (timecnt * stored		/* ats */
5004616d0f9Sopenharmony_ci		       + timecnt		/* types */
5014616d0f9Sopenharmony_ci		       + typecnt * 6		/* ttinfos */
5024616d0f9Sopenharmony_ci		       + charcnt		/* chars */
5034616d0f9Sopenharmony_ci		       + leapcnt * (stored + 4)	/* lsinfos */
5044616d0f9Sopenharmony_ci		       + ttisstdcnt		/* ttisstds */
5054616d0f9Sopenharmony_ci		       + ttisutcnt);		/* ttisuts */
5064616d0f9Sopenharmony_ci	    if (nread < tzheadsize + datablock_size)
5074616d0f9Sopenharmony_ci	      return EINVAL;
5084616d0f9Sopenharmony_ci	    if (skip_datablock)
5094616d0f9Sopenharmony_ci		p += datablock_size;
5104616d0f9Sopenharmony_ci	    else {
5114616d0f9Sopenharmony_ci		if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
5124616d0f9Sopenharmony_ci		       && (ttisutcnt == typecnt || ttisutcnt == 0)))
5134616d0f9Sopenharmony_ci		  return EINVAL;
5144616d0f9Sopenharmony_ci
5154616d0f9Sopenharmony_ci		sp->leapcnt = leapcnt;
5164616d0f9Sopenharmony_ci		sp->timecnt = timecnt;
5174616d0f9Sopenharmony_ci		sp->typecnt = typecnt;
5184616d0f9Sopenharmony_ci		sp->charcnt = charcnt;
5194616d0f9Sopenharmony_ci
5204616d0f9Sopenharmony_ci		/* Read transitions, discarding those out of time_t range.
5214616d0f9Sopenharmony_ci		   But pretend the last transition before TIME_T_MIN
5224616d0f9Sopenharmony_ci		   occurred at TIME_T_MIN.  */
5234616d0f9Sopenharmony_ci		timecnt = 0;
5244616d0f9Sopenharmony_ci		for (i = 0; i < sp->timecnt; ++i) {
5254616d0f9Sopenharmony_ci			int_fast64_t at
5264616d0f9Sopenharmony_ci			  = stored == 4 ? detzcode(p) : detzcode64(p);
5274616d0f9Sopenharmony_ci			sp->types[i] = at <= TIME_T_MAX;
5284616d0f9Sopenharmony_ci			if (sp->types[i]) {
5294616d0f9Sopenharmony_ci			  time_t attime
5304616d0f9Sopenharmony_ci			    = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
5314616d0f9Sopenharmony_ci			       ? TIME_T_MIN : at);
5324616d0f9Sopenharmony_ci			  if (timecnt && attime <= sp->ats[timecnt - 1]) {
5334616d0f9Sopenharmony_ci			    if (attime < sp->ats[timecnt - 1])
5344616d0f9Sopenharmony_ci			      return EINVAL;
5354616d0f9Sopenharmony_ci			    sp->types[i - 1] = 0;
5364616d0f9Sopenharmony_ci			    timecnt--;
5374616d0f9Sopenharmony_ci			  }
5384616d0f9Sopenharmony_ci			  sp->ats[timecnt++] = attime;
5394616d0f9Sopenharmony_ci			}
5404616d0f9Sopenharmony_ci			p += stored;
5414616d0f9Sopenharmony_ci		}
5424616d0f9Sopenharmony_ci
5434616d0f9Sopenharmony_ci		timecnt = 0;
5444616d0f9Sopenharmony_ci		for (i = 0; i < sp->timecnt; ++i) {
5454616d0f9Sopenharmony_ci			unsigned char typ = *p++;
5464616d0f9Sopenharmony_ci			if (sp->typecnt <= typ)
5474616d0f9Sopenharmony_ci			  return EINVAL;
5484616d0f9Sopenharmony_ci			if (sp->types[i])
5494616d0f9Sopenharmony_ci				sp->types[timecnt++] = typ;
5504616d0f9Sopenharmony_ci		}
5514616d0f9Sopenharmony_ci		sp->timecnt = timecnt;
5524616d0f9Sopenharmony_ci		for (i = 0; i < sp->typecnt; ++i) {
5534616d0f9Sopenharmony_ci			register struct ttinfo *	ttisp;
5544616d0f9Sopenharmony_ci			unsigned char isdst, desigidx;
5554616d0f9Sopenharmony_ci
5564616d0f9Sopenharmony_ci			ttisp = &sp->ttis[i];
5574616d0f9Sopenharmony_ci			ttisp->tt_utoff = detzcode(p);
5584616d0f9Sopenharmony_ci			p += 4;
5594616d0f9Sopenharmony_ci			isdst = *p++;
5604616d0f9Sopenharmony_ci			if (! (isdst < 2))
5614616d0f9Sopenharmony_ci			  return EINVAL;
5624616d0f9Sopenharmony_ci			ttisp->tt_isdst = isdst;
5634616d0f9Sopenharmony_ci			desigidx = *p++;
5644616d0f9Sopenharmony_ci			if (! (desigidx < sp->charcnt))
5654616d0f9Sopenharmony_ci			  return EINVAL;
5664616d0f9Sopenharmony_ci			ttisp->tt_desigidx = desigidx;
5674616d0f9Sopenharmony_ci		}
5684616d0f9Sopenharmony_ci		for (i = 0; i < sp->charcnt; ++i)
5694616d0f9Sopenharmony_ci			sp->chars[i] = *p++;
5704616d0f9Sopenharmony_ci		/* Ensure '\0'-terminated, and make it safe to call
5714616d0f9Sopenharmony_ci		   ttunspecified later.  */
5724616d0f9Sopenharmony_ci		memset(&sp->chars[i], 0, CHARS_EXTRA);
5734616d0f9Sopenharmony_ci
5744616d0f9Sopenharmony_ci		/* Read leap seconds, discarding those out of time_t range.  */
5754616d0f9Sopenharmony_ci		leapcnt = 0;
5764616d0f9Sopenharmony_ci		for (i = 0; i < sp->leapcnt; ++i) {
5774616d0f9Sopenharmony_ci		  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
5784616d0f9Sopenharmony_ci		  int_fast32_t corr = detzcode(p + stored);
5794616d0f9Sopenharmony_ci		  p += stored + 4;
5804616d0f9Sopenharmony_ci
5814616d0f9Sopenharmony_ci		  /* Leap seconds cannot occur before the Epoch,
5824616d0f9Sopenharmony_ci		     or out of order.  */
5834616d0f9Sopenharmony_ci		  if (tr <= prevtr)
5844616d0f9Sopenharmony_ci		    return EINVAL;
5854616d0f9Sopenharmony_ci
5864616d0f9Sopenharmony_ci		  /* To avoid other botches in this code, each leap second's
5874616d0f9Sopenharmony_ci		     correction must differ from the previous one's by 1
5884616d0f9Sopenharmony_ci		     second or less, except that the first correction can be
5894616d0f9Sopenharmony_ci		     any value; these requirements are more generous than
5904616d0f9Sopenharmony_ci		     RFC 8536, to allow future RFC extensions.  */
5914616d0f9Sopenharmony_ci		  if (! (i == 0
5924616d0f9Sopenharmony_ci			 || (prevcorr < corr
5934616d0f9Sopenharmony_ci			     ? corr == prevcorr + 1
5944616d0f9Sopenharmony_ci			     : (corr == prevcorr
5954616d0f9Sopenharmony_ci				|| corr == prevcorr - 1))))
5964616d0f9Sopenharmony_ci		    return EINVAL;
5974616d0f9Sopenharmony_ci		  prevtr = tr;
5984616d0f9Sopenharmony_ci		  prevcorr = corr;
5994616d0f9Sopenharmony_ci
6004616d0f9Sopenharmony_ci		  if (tr <= TIME_T_MAX) {
6014616d0f9Sopenharmony_ci		    sp->lsis[leapcnt].ls_trans = tr;
6024616d0f9Sopenharmony_ci		    sp->lsis[leapcnt].ls_corr = corr;
6034616d0f9Sopenharmony_ci		    leapcnt++;
6044616d0f9Sopenharmony_ci		  }
6054616d0f9Sopenharmony_ci		}
6064616d0f9Sopenharmony_ci		sp->leapcnt = leapcnt;
6074616d0f9Sopenharmony_ci
6084616d0f9Sopenharmony_ci		for (i = 0; i < sp->typecnt; ++i) {
6094616d0f9Sopenharmony_ci			register struct ttinfo *	ttisp;
6104616d0f9Sopenharmony_ci
6114616d0f9Sopenharmony_ci			ttisp = &sp->ttis[i];
6124616d0f9Sopenharmony_ci			if (ttisstdcnt == 0)
6134616d0f9Sopenharmony_ci				ttisp->tt_ttisstd = false;
6144616d0f9Sopenharmony_ci			else {
6154616d0f9Sopenharmony_ci				if (*p != true && *p != false)
6164616d0f9Sopenharmony_ci				  return EINVAL;
6174616d0f9Sopenharmony_ci				ttisp->tt_ttisstd = *p++;
6184616d0f9Sopenharmony_ci			}
6194616d0f9Sopenharmony_ci		}
6204616d0f9Sopenharmony_ci		for (i = 0; i < sp->typecnt; ++i) {
6214616d0f9Sopenharmony_ci			register struct ttinfo *	ttisp;
6224616d0f9Sopenharmony_ci
6234616d0f9Sopenharmony_ci			ttisp = &sp->ttis[i];
6244616d0f9Sopenharmony_ci			if (ttisutcnt == 0)
6254616d0f9Sopenharmony_ci				ttisp->tt_ttisut = false;
6264616d0f9Sopenharmony_ci			else {
6274616d0f9Sopenharmony_ci				if (*p != true && *p != false)
6284616d0f9Sopenharmony_ci						return EINVAL;
6294616d0f9Sopenharmony_ci				ttisp->tt_ttisut = *p++;
6304616d0f9Sopenharmony_ci			}
6314616d0f9Sopenharmony_ci		}
6324616d0f9Sopenharmony_ci	    }
6334616d0f9Sopenharmony_ci
6344616d0f9Sopenharmony_ci	    nread -= p - up->buf;
6354616d0f9Sopenharmony_ci	    memmove(up->buf, p, nread);
6364616d0f9Sopenharmony_ci
6374616d0f9Sopenharmony_ci	    /* If this is an old file, we're done.  */
6384616d0f9Sopenharmony_ci	    if (!version)
6394616d0f9Sopenharmony_ci	      break;
6404616d0f9Sopenharmony_ci	}
6414616d0f9Sopenharmony_ci	if (doextend && nread > 2 &&
6424616d0f9Sopenharmony_ci		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
6434616d0f9Sopenharmony_ci		sp->typecnt + 2 <= TZ_MAX_TYPES) {
6444616d0f9Sopenharmony_ci			struct state	*ts = &lsp->u.st;
6454616d0f9Sopenharmony_ci
6464616d0f9Sopenharmony_ci			up->buf[nread - 1] = '\0';
6474616d0f9Sopenharmony_ci			if (tzparse(&up->buf[1], ts, sp)) {
6484616d0f9Sopenharmony_ci
6494616d0f9Sopenharmony_ci			  /* Attempt to reuse existing abbreviations.
6504616d0f9Sopenharmony_ci			     Without this, America/Anchorage would be right on
6514616d0f9Sopenharmony_ci			     the edge after 2037 when TZ_MAX_CHARS is 50, as
6524616d0f9Sopenharmony_ci			     sp->charcnt equals 40 (for LMT AST AWT APT AHST
6534616d0f9Sopenharmony_ci			     AHDT YST AKDT AKST) and ts->charcnt equals 10
6544616d0f9Sopenharmony_ci			     (for AKST AKDT).  Reusing means sp->charcnt can
6554616d0f9Sopenharmony_ci			     stay 40 in this example.  */
6564616d0f9Sopenharmony_ci			  int gotabbr = 0;
6574616d0f9Sopenharmony_ci			  int charcnt = sp->charcnt;
6584616d0f9Sopenharmony_ci			  for (i = 0; i < ts->typecnt; i++) {
6594616d0f9Sopenharmony_ci			    char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
6604616d0f9Sopenharmony_ci			    int j;
6614616d0f9Sopenharmony_ci			    for (j = 0; j < charcnt; j++)
6624616d0f9Sopenharmony_ci			      if (strcmp(sp->chars + j, tsabbr) == 0) {
6634616d0f9Sopenharmony_ci				ts->ttis[i].tt_desigidx = j;
6644616d0f9Sopenharmony_ci				gotabbr++;
6654616d0f9Sopenharmony_ci				break;
6664616d0f9Sopenharmony_ci			      }
6674616d0f9Sopenharmony_ci			    if (! (j < charcnt)) {
6684616d0f9Sopenharmony_ci			      int tsabbrlen = strlen(tsabbr);
6694616d0f9Sopenharmony_ci			      if (j + tsabbrlen < TZ_MAX_CHARS) {
6704616d0f9Sopenharmony_ci				strcpy(sp->chars + j, tsabbr);
6714616d0f9Sopenharmony_ci				charcnt = j + tsabbrlen + 1;
6724616d0f9Sopenharmony_ci				ts->ttis[i].tt_desigidx = j;
6734616d0f9Sopenharmony_ci				gotabbr++;
6744616d0f9Sopenharmony_ci			      }
6754616d0f9Sopenharmony_ci			    }
6764616d0f9Sopenharmony_ci			  }
6774616d0f9Sopenharmony_ci			  if (gotabbr == ts->typecnt) {
6784616d0f9Sopenharmony_ci			    sp->charcnt = charcnt;
6794616d0f9Sopenharmony_ci
6804616d0f9Sopenharmony_ci			    /* Ignore any trailing, no-op transitions generated
6814616d0f9Sopenharmony_ci			       by zic as they don't help here and can run afoul
6824616d0f9Sopenharmony_ci			       of bugs in zic 2016j or earlier.  */
6834616d0f9Sopenharmony_ci			    while (1 < sp->timecnt
6844616d0f9Sopenharmony_ci				   && (sp->types[sp->timecnt - 1]
6854616d0f9Sopenharmony_ci				       == sp->types[sp->timecnt - 2]))
6864616d0f9Sopenharmony_ci			      sp->timecnt--;
6874616d0f9Sopenharmony_ci
6884616d0f9Sopenharmony_ci			    sp->goahead = ts->goahead;
6894616d0f9Sopenharmony_ci
6904616d0f9Sopenharmony_ci			    for (i = 0; i < ts->timecnt; i++) {
6914616d0f9Sopenharmony_ci			      time_t t = ts->ats[i];
6924616d0f9Sopenharmony_ci			      if (increment_overflow_time(&t, leapcorr(sp, t))
6934616d0f9Sopenharmony_ci				  || (0 < sp->timecnt
6944616d0f9Sopenharmony_ci				      && t <= sp->ats[sp->timecnt - 1]))
6954616d0f9Sopenharmony_ci				continue;
6964616d0f9Sopenharmony_ci			      if (TZ_MAX_TIMES <= sp->timecnt) {
6974616d0f9Sopenharmony_ci				sp->goahead = false;
6984616d0f9Sopenharmony_ci				break;
6994616d0f9Sopenharmony_ci			      }
7004616d0f9Sopenharmony_ci			      sp->ats[sp->timecnt] = t;
7014616d0f9Sopenharmony_ci			      sp->types[sp->timecnt] = (sp->typecnt
7024616d0f9Sopenharmony_ci							+ ts->types[i]);
7034616d0f9Sopenharmony_ci			      sp->timecnt++;
7044616d0f9Sopenharmony_ci			    }
7054616d0f9Sopenharmony_ci			    for (i = 0; i < ts->typecnt; i++)
7064616d0f9Sopenharmony_ci			      sp->ttis[sp->typecnt++] = ts->ttis[i];
7074616d0f9Sopenharmony_ci			  }
7084616d0f9Sopenharmony_ci			}
7094616d0f9Sopenharmony_ci	}
7104616d0f9Sopenharmony_ci	if (sp->typecnt == 0)
7114616d0f9Sopenharmony_ci	  return EINVAL;
7124616d0f9Sopenharmony_ci
7134616d0f9Sopenharmony_ci	/* Infer sp->defaulttype from the data.  Although this default
7144616d0f9Sopenharmony_ci	   type is always zero for data from recent tzdb releases,
7154616d0f9Sopenharmony_ci	   things are trickier for data from tzdb 2018e or earlier.
7164616d0f9Sopenharmony_ci
7174616d0f9Sopenharmony_ci	   The first set of heuristics work around bugs in 32-bit data
7184616d0f9Sopenharmony_ci	   generated by tzdb 2013c or earlier.  The workaround is for
7194616d0f9Sopenharmony_ci	   zones like Australia/Macquarie where timestamps before the
7204616d0f9Sopenharmony_ci	   first transition have a time type that is not the earliest
7214616d0f9Sopenharmony_ci	   standard-time type.  See:
7224616d0f9Sopenharmony_ci	   https://mm.icann.org/pipermail/tz/2013-May/019368.html */
7234616d0f9Sopenharmony_ci	/*
7244616d0f9Sopenharmony_ci	** If type 0 does not specify local time, or is unused in transitions,
7254616d0f9Sopenharmony_ci	** it's the type to use for early times.
7264616d0f9Sopenharmony_ci	*/
7274616d0f9Sopenharmony_ci	for (i = 0; i < sp->timecnt; ++i)
7284616d0f9Sopenharmony_ci		if (sp->types[i] == 0)
7294616d0f9Sopenharmony_ci			break;
7304616d0f9Sopenharmony_ci	i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
7314616d0f9Sopenharmony_ci	/*
7324616d0f9Sopenharmony_ci	** Absent the above,
7334616d0f9Sopenharmony_ci	** if there are transition times
7344616d0f9Sopenharmony_ci	** and the first transition is to a daylight time
7354616d0f9Sopenharmony_ci	** find the standard type less than and closest to
7364616d0f9Sopenharmony_ci	** the type of the first transition.
7374616d0f9Sopenharmony_ci	*/
7384616d0f9Sopenharmony_ci	if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
7394616d0f9Sopenharmony_ci		i = sp->types[0];
7404616d0f9Sopenharmony_ci		while (--i >= 0)
7414616d0f9Sopenharmony_ci			if (!sp->ttis[i].tt_isdst)
7424616d0f9Sopenharmony_ci				break;
7434616d0f9Sopenharmony_ci	}
7444616d0f9Sopenharmony_ci	/* The next heuristics are for data generated by tzdb 2018e or
7454616d0f9Sopenharmony_ci	   earlier, for zones like EST5EDT where the first transition
7464616d0f9Sopenharmony_ci	   is to DST.  */
7474616d0f9Sopenharmony_ci	/*
7484616d0f9Sopenharmony_ci	** If no result yet, find the first standard type.
7494616d0f9Sopenharmony_ci	** If there is none, punt to type zero.
7504616d0f9Sopenharmony_ci	*/
7514616d0f9Sopenharmony_ci	if (i < 0) {
7524616d0f9Sopenharmony_ci		i = 0;
7534616d0f9Sopenharmony_ci		while (sp->ttis[i].tt_isdst)
7544616d0f9Sopenharmony_ci			if (++i >= sp->typecnt) {
7554616d0f9Sopenharmony_ci				i = 0;
7564616d0f9Sopenharmony_ci				break;
7574616d0f9Sopenharmony_ci			}
7584616d0f9Sopenharmony_ci	}
7594616d0f9Sopenharmony_ci	/* A simple 'sp->defaulttype = 0;' would suffice here if we
7604616d0f9Sopenharmony_ci	   didn't have to worry about 2018e-or-earlier data.  Even
7614616d0f9Sopenharmony_ci	   simpler would be to remove the defaulttype member and just
7624616d0f9Sopenharmony_ci	   use 0 in its place.  */
7634616d0f9Sopenharmony_ci	sp->defaulttype = i;
7644616d0f9Sopenharmony_ci
7654616d0f9Sopenharmony_ci	return 0;
7664616d0f9Sopenharmony_ci}
7674616d0f9Sopenharmony_ci
7684616d0f9Sopenharmony_ci/* Load tz data from the file named NAME into *SP.  Read extended
7694616d0f9Sopenharmony_ci   format if DOEXTEND.  Return 0 on success, an errno value on failure.  */
7704616d0f9Sopenharmony_cistatic int
7714616d0f9Sopenharmony_citzload(char const *name, struct state *sp, bool doextend)
7724616d0f9Sopenharmony_ci{
7734616d0f9Sopenharmony_ci#ifdef ALL_STATE
7744616d0f9Sopenharmony_ci  union local_storage *lsp = malloc(sizeof *lsp);
7754616d0f9Sopenharmony_ci  if (!lsp) {
7764616d0f9Sopenharmony_ci    return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
7774616d0f9Sopenharmony_ci  } else {
7784616d0f9Sopenharmony_ci    int err = tzloadbody(name, sp, doextend, lsp);
7794616d0f9Sopenharmony_ci    free(lsp);
7804616d0f9Sopenharmony_ci    return err;
7814616d0f9Sopenharmony_ci  }
7824616d0f9Sopenharmony_ci#else
7834616d0f9Sopenharmony_ci  union local_storage ls;
7844616d0f9Sopenharmony_ci  return tzloadbody(name, sp, doextend, &ls);
7854616d0f9Sopenharmony_ci#endif
7864616d0f9Sopenharmony_ci}
7874616d0f9Sopenharmony_ci
7884616d0f9Sopenharmony_cistatic const int	mon_lengths[2][MONSPERYEAR] = {
7894616d0f9Sopenharmony_ci	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
7904616d0f9Sopenharmony_ci	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
7914616d0f9Sopenharmony_ci};
7924616d0f9Sopenharmony_ci
7934616d0f9Sopenharmony_cistatic const int	year_lengths[2] = {
7944616d0f9Sopenharmony_ci	DAYSPERNYEAR, DAYSPERLYEAR
7954616d0f9Sopenharmony_ci};
7964616d0f9Sopenharmony_ci
7974616d0f9Sopenharmony_ci/* Is C an ASCII digit?  */
7984616d0f9Sopenharmony_cistatic bool
7994616d0f9Sopenharmony_ciis_digit(char c)
8004616d0f9Sopenharmony_ci{
8014616d0f9Sopenharmony_ci  return '0' <= c && c <= '9';
8024616d0f9Sopenharmony_ci}
8034616d0f9Sopenharmony_ci
8044616d0f9Sopenharmony_ci/*
8054616d0f9Sopenharmony_ci** Given a pointer into a timezone string, scan until a character that is not
8064616d0f9Sopenharmony_ci** a valid character in a time zone abbreviation is found.
8074616d0f9Sopenharmony_ci** Return a pointer to that character.
8084616d0f9Sopenharmony_ci*/
8094616d0f9Sopenharmony_ci
8104616d0f9Sopenharmony_ciATTRIBUTE_REPRODUCIBLE static const char *
8114616d0f9Sopenharmony_cigetzname(register const char *strp)
8124616d0f9Sopenharmony_ci{
8134616d0f9Sopenharmony_ci	register char	c;
8144616d0f9Sopenharmony_ci
8154616d0f9Sopenharmony_ci	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
8164616d0f9Sopenharmony_ci		c != '+')
8174616d0f9Sopenharmony_ci			++strp;
8184616d0f9Sopenharmony_ci	return strp;
8194616d0f9Sopenharmony_ci}
8204616d0f9Sopenharmony_ci
8214616d0f9Sopenharmony_ci/*
8224616d0f9Sopenharmony_ci** Given a pointer into an extended timezone string, scan until the ending
8234616d0f9Sopenharmony_ci** delimiter of the time zone abbreviation is located.
8244616d0f9Sopenharmony_ci** Return a pointer to the delimiter.
8254616d0f9Sopenharmony_ci**
8264616d0f9Sopenharmony_ci** As with getzname above, the legal character set is actually quite
8274616d0f9Sopenharmony_ci** restricted, with other characters producing undefined results.
8284616d0f9Sopenharmony_ci** We don't do any checking here; checking is done later in common-case code.
8294616d0f9Sopenharmony_ci*/
8304616d0f9Sopenharmony_ci
8314616d0f9Sopenharmony_ciATTRIBUTE_REPRODUCIBLE static const char *
8324616d0f9Sopenharmony_cigetqzname(register const char *strp, const int delim)
8334616d0f9Sopenharmony_ci{
8344616d0f9Sopenharmony_ci	register int	c;
8354616d0f9Sopenharmony_ci
8364616d0f9Sopenharmony_ci	while ((c = *strp) != '\0' && c != delim)
8374616d0f9Sopenharmony_ci		++strp;
8384616d0f9Sopenharmony_ci	return strp;
8394616d0f9Sopenharmony_ci}
8404616d0f9Sopenharmony_ci
8414616d0f9Sopenharmony_ci/*
8424616d0f9Sopenharmony_ci** Given a pointer into a timezone string, extract a number from that string.
8434616d0f9Sopenharmony_ci** Check that the number is within a specified range; if it is not, return
8444616d0f9Sopenharmony_ci** NULL.
8454616d0f9Sopenharmony_ci** Otherwise, return a pointer to the first character not part of the number.
8464616d0f9Sopenharmony_ci*/
8474616d0f9Sopenharmony_ci
8484616d0f9Sopenharmony_cistatic const char *
8494616d0f9Sopenharmony_cigetnum(register const char *strp, int *const nump, const int min, const int max)
8504616d0f9Sopenharmony_ci{
8514616d0f9Sopenharmony_ci	register char	c;
8524616d0f9Sopenharmony_ci	register int	num;
8534616d0f9Sopenharmony_ci
8544616d0f9Sopenharmony_ci	if (strp == NULL || !is_digit(c = *strp))
8554616d0f9Sopenharmony_ci		return NULL;
8564616d0f9Sopenharmony_ci	num = 0;
8574616d0f9Sopenharmony_ci	do {
8584616d0f9Sopenharmony_ci		num = num * 10 + (c - '0');
8594616d0f9Sopenharmony_ci		if (num > max)
8604616d0f9Sopenharmony_ci			return NULL;	/* illegal value */
8614616d0f9Sopenharmony_ci		c = *++strp;
8624616d0f9Sopenharmony_ci	} while (is_digit(c));
8634616d0f9Sopenharmony_ci	if (num < min)
8644616d0f9Sopenharmony_ci		return NULL;		/* illegal value */
8654616d0f9Sopenharmony_ci	*nump = num;
8664616d0f9Sopenharmony_ci	return strp;
8674616d0f9Sopenharmony_ci}
8684616d0f9Sopenharmony_ci
8694616d0f9Sopenharmony_ci/*
8704616d0f9Sopenharmony_ci** Given a pointer into a timezone string, extract a number of seconds,
8714616d0f9Sopenharmony_ci** in hh[:mm[:ss]] form, from the string.
8724616d0f9Sopenharmony_ci** If any error occurs, return NULL.
8734616d0f9Sopenharmony_ci** Otherwise, return a pointer to the first character not part of the number
8744616d0f9Sopenharmony_ci** of seconds.
8754616d0f9Sopenharmony_ci*/
8764616d0f9Sopenharmony_ci
8774616d0f9Sopenharmony_cistatic const char *
8784616d0f9Sopenharmony_cigetsecs(register const char *strp, int_fast32_t *const secsp)
8794616d0f9Sopenharmony_ci{
8804616d0f9Sopenharmony_ci	int	num;
8814616d0f9Sopenharmony_ci	int_fast32_t secsperhour = SECSPERHOUR;
8824616d0f9Sopenharmony_ci
8834616d0f9Sopenharmony_ci	/*
8844616d0f9Sopenharmony_ci	** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like
8854616d0f9Sopenharmony_ci	** "M10.4.6/26", which does not conform to POSIX,
8864616d0f9Sopenharmony_ci	** but which specifies the equivalent of
8874616d0f9Sopenharmony_ci	** "02:00 on the first Sunday on or after 23 Oct".
8884616d0f9Sopenharmony_ci	*/
8894616d0f9Sopenharmony_ci	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
8904616d0f9Sopenharmony_ci	if (strp == NULL)
8914616d0f9Sopenharmony_ci		return NULL;
8924616d0f9Sopenharmony_ci	*secsp = num * secsperhour;
8934616d0f9Sopenharmony_ci	if (*strp == ':') {
8944616d0f9Sopenharmony_ci		++strp;
8954616d0f9Sopenharmony_ci		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
8964616d0f9Sopenharmony_ci		if (strp == NULL)
8974616d0f9Sopenharmony_ci			return NULL;
8984616d0f9Sopenharmony_ci		*secsp += num * SECSPERMIN;
8994616d0f9Sopenharmony_ci		if (*strp == ':') {
9004616d0f9Sopenharmony_ci			++strp;
9014616d0f9Sopenharmony_ci			/* 'SECSPERMIN' allows for leap seconds.  */
9024616d0f9Sopenharmony_ci			strp = getnum(strp, &num, 0, SECSPERMIN);
9034616d0f9Sopenharmony_ci			if (strp == NULL)
9044616d0f9Sopenharmony_ci				return NULL;
9054616d0f9Sopenharmony_ci			*secsp += num;
9064616d0f9Sopenharmony_ci		}
9074616d0f9Sopenharmony_ci	}
9084616d0f9Sopenharmony_ci	return strp;
9094616d0f9Sopenharmony_ci}
9104616d0f9Sopenharmony_ci
9114616d0f9Sopenharmony_ci/*
9124616d0f9Sopenharmony_ci** Given a pointer into a timezone string, extract an offset, in
9134616d0f9Sopenharmony_ci** [+-]hh[:mm[:ss]] form, from the string.
9144616d0f9Sopenharmony_ci** If any error occurs, return NULL.
9154616d0f9Sopenharmony_ci** Otherwise, return a pointer to the first character not part of the time.
9164616d0f9Sopenharmony_ci*/
9174616d0f9Sopenharmony_ci
9184616d0f9Sopenharmony_cistatic const char *
9194616d0f9Sopenharmony_cigetoffset(register const char *strp, int_fast32_t *const offsetp)
9204616d0f9Sopenharmony_ci{
9214616d0f9Sopenharmony_ci	register bool neg = false;
9224616d0f9Sopenharmony_ci
9234616d0f9Sopenharmony_ci	if (*strp == '-') {
9244616d0f9Sopenharmony_ci		neg = true;
9254616d0f9Sopenharmony_ci		++strp;
9264616d0f9Sopenharmony_ci	} else if (*strp == '+')
9274616d0f9Sopenharmony_ci		++strp;
9284616d0f9Sopenharmony_ci	strp = getsecs(strp, offsetp);
9294616d0f9Sopenharmony_ci	if (strp == NULL)
9304616d0f9Sopenharmony_ci		return NULL;		/* illegal time */
9314616d0f9Sopenharmony_ci	if (neg)
9324616d0f9Sopenharmony_ci		*offsetp = -*offsetp;
9334616d0f9Sopenharmony_ci	return strp;
9344616d0f9Sopenharmony_ci}
9354616d0f9Sopenharmony_ci
9364616d0f9Sopenharmony_ci/*
9374616d0f9Sopenharmony_ci** Given a pointer into a timezone string, extract a rule in the form
9384616d0f9Sopenharmony_ci** date[/time]. See POSIX Base Definitions section 8.3 variable TZ
9394616d0f9Sopenharmony_ci** for the format of "date" and "time".
9404616d0f9Sopenharmony_ci** If a valid rule is not found, return NULL.
9414616d0f9Sopenharmony_ci** Otherwise, return a pointer to the first character not part of the rule.
9424616d0f9Sopenharmony_ci*/
9434616d0f9Sopenharmony_ci
9444616d0f9Sopenharmony_cistatic const char *
9454616d0f9Sopenharmony_cigetrule(const char *strp, register struct rule *const rulep)
9464616d0f9Sopenharmony_ci{
9474616d0f9Sopenharmony_ci	if (*strp == 'J') {
9484616d0f9Sopenharmony_ci		/*
9494616d0f9Sopenharmony_ci		** Julian day.
9504616d0f9Sopenharmony_ci		*/
9514616d0f9Sopenharmony_ci		rulep->r_type = JULIAN_DAY;
9524616d0f9Sopenharmony_ci		++strp;
9534616d0f9Sopenharmony_ci		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
9544616d0f9Sopenharmony_ci	} else if (*strp == 'M') {
9554616d0f9Sopenharmony_ci		/*
9564616d0f9Sopenharmony_ci		** Month, week, day.
9574616d0f9Sopenharmony_ci		*/
9584616d0f9Sopenharmony_ci		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
9594616d0f9Sopenharmony_ci		++strp;
9604616d0f9Sopenharmony_ci		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
9614616d0f9Sopenharmony_ci		if (strp == NULL)
9624616d0f9Sopenharmony_ci			return NULL;
9634616d0f9Sopenharmony_ci		if (*strp++ != '.')
9644616d0f9Sopenharmony_ci			return NULL;
9654616d0f9Sopenharmony_ci		strp = getnum(strp, &rulep->r_week, 1, 5);
9664616d0f9Sopenharmony_ci		if (strp == NULL)
9674616d0f9Sopenharmony_ci			return NULL;
9684616d0f9Sopenharmony_ci		if (*strp++ != '.')
9694616d0f9Sopenharmony_ci			return NULL;
9704616d0f9Sopenharmony_ci		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
9714616d0f9Sopenharmony_ci	} else if (is_digit(*strp)) {
9724616d0f9Sopenharmony_ci		/*
9734616d0f9Sopenharmony_ci		** Day of year.
9744616d0f9Sopenharmony_ci		*/
9754616d0f9Sopenharmony_ci		rulep->r_type = DAY_OF_YEAR;
9764616d0f9Sopenharmony_ci		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
9774616d0f9Sopenharmony_ci	} else	return NULL;		/* invalid format */
9784616d0f9Sopenharmony_ci	if (strp == NULL)
9794616d0f9Sopenharmony_ci		return NULL;
9804616d0f9Sopenharmony_ci	if (*strp == '/') {
9814616d0f9Sopenharmony_ci		/*
9824616d0f9Sopenharmony_ci		** Time specified.
9834616d0f9Sopenharmony_ci		*/
9844616d0f9Sopenharmony_ci		++strp;
9854616d0f9Sopenharmony_ci		strp = getoffset(strp, &rulep->r_time);
9864616d0f9Sopenharmony_ci	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
9874616d0f9Sopenharmony_ci	return strp;
9884616d0f9Sopenharmony_ci}
9894616d0f9Sopenharmony_ci
9904616d0f9Sopenharmony_ci/*
9914616d0f9Sopenharmony_ci** Given a year, a rule, and the offset from UT at the time that rule takes
9924616d0f9Sopenharmony_ci** effect, calculate the year-relative time that rule takes effect.
9934616d0f9Sopenharmony_ci*/
9944616d0f9Sopenharmony_ci
9954616d0f9Sopenharmony_cistatic int_fast32_t
9964616d0f9Sopenharmony_citranstime(const int year, register const struct rule *const rulep,
9974616d0f9Sopenharmony_ci	  const int_fast32_t offset)
9984616d0f9Sopenharmony_ci{
9994616d0f9Sopenharmony_ci	register bool	leapyear;
10004616d0f9Sopenharmony_ci	register int_fast32_t value;
10014616d0f9Sopenharmony_ci	register int	i;
10024616d0f9Sopenharmony_ci	int		d, m1, yy0, yy1, yy2, dow;
10034616d0f9Sopenharmony_ci
10044616d0f9Sopenharmony_ci	leapyear = isleap(year);
10054616d0f9Sopenharmony_ci	switch (rulep->r_type) {
10064616d0f9Sopenharmony_ci
10074616d0f9Sopenharmony_ci	case JULIAN_DAY:
10084616d0f9Sopenharmony_ci		/*
10094616d0f9Sopenharmony_ci		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
10104616d0f9Sopenharmony_ci		** years.
10114616d0f9Sopenharmony_ci		** In non-leap years, or if the day number is 59 or less, just
10124616d0f9Sopenharmony_ci		** add SECSPERDAY times the day number-1 to the time of
10134616d0f9Sopenharmony_ci		** January 1, midnight, to get the day.
10144616d0f9Sopenharmony_ci		*/
10154616d0f9Sopenharmony_ci		value = (rulep->r_day - 1) * SECSPERDAY;
10164616d0f9Sopenharmony_ci		if (leapyear && rulep->r_day >= 60)
10174616d0f9Sopenharmony_ci			value += SECSPERDAY;
10184616d0f9Sopenharmony_ci		break;
10194616d0f9Sopenharmony_ci
10204616d0f9Sopenharmony_ci	case DAY_OF_YEAR:
10214616d0f9Sopenharmony_ci		/*
10224616d0f9Sopenharmony_ci		** n - day of year.
10234616d0f9Sopenharmony_ci		** Just add SECSPERDAY times the day number to the time of
10244616d0f9Sopenharmony_ci		** January 1, midnight, to get the day.
10254616d0f9Sopenharmony_ci		*/
10264616d0f9Sopenharmony_ci		value = rulep->r_day * SECSPERDAY;
10274616d0f9Sopenharmony_ci		break;
10284616d0f9Sopenharmony_ci
10294616d0f9Sopenharmony_ci	case MONTH_NTH_DAY_OF_WEEK:
10304616d0f9Sopenharmony_ci		/*
10314616d0f9Sopenharmony_ci		** Mm.n.d - nth "dth day" of month m.
10324616d0f9Sopenharmony_ci		*/
10334616d0f9Sopenharmony_ci
10344616d0f9Sopenharmony_ci		/*
10354616d0f9Sopenharmony_ci		** Use Zeller's Congruence to get day-of-week of first day of
10364616d0f9Sopenharmony_ci		** month.
10374616d0f9Sopenharmony_ci		*/
10384616d0f9Sopenharmony_ci		m1 = (rulep->r_mon + 9) % 12 + 1;
10394616d0f9Sopenharmony_ci		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
10404616d0f9Sopenharmony_ci		yy1 = yy0 / 100;
10414616d0f9Sopenharmony_ci		yy2 = yy0 % 100;
10424616d0f9Sopenharmony_ci		dow = ((26 * m1 - 2) / 10 +
10434616d0f9Sopenharmony_ci			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
10444616d0f9Sopenharmony_ci		if (dow < 0)
10454616d0f9Sopenharmony_ci			dow += DAYSPERWEEK;
10464616d0f9Sopenharmony_ci
10474616d0f9Sopenharmony_ci		/*
10484616d0f9Sopenharmony_ci		** "dow" is the day-of-week of the first day of the month. Get
10494616d0f9Sopenharmony_ci		** the day-of-month (zero-origin) of the first "dow" day of the
10504616d0f9Sopenharmony_ci		** month.
10514616d0f9Sopenharmony_ci		*/
10524616d0f9Sopenharmony_ci		d = rulep->r_day - dow;
10534616d0f9Sopenharmony_ci		if (d < 0)
10544616d0f9Sopenharmony_ci			d += DAYSPERWEEK;
10554616d0f9Sopenharmony_ci		for (i = 1; i < rulep->r_week; ++i) {
10564616d0f9Sopenharmony_ci			if (d + DAYSPERWEEK >=
10574616d0f9Sopenharmony_ci				mon_lengths[leapyear][rulep->r_mon - 1])
10584616d0f9Sopenharmony_ci					break;
10594616d0f9Sopenharmony_ci			d += DAYSPERWEEK;
10604616d0f9Sopenharmony_ci		}
10614616d0f9Sopenharmony_ci
10624616d0f9Sopenharmony_ci		/*
10634616d0f9Sopenharmony_ci		** "d" is the day-of-month (zero-origin) of the day we want.
10644616d0f9Sopenharmony_ci		*/
10654616d0f9Sopenharmony_ci		value = d * SECSPERDAY;
10664616d0f9Sopenharmony_ci		for (i = 0; i < rulep->r_mon - 1; ++i)
10674616d0f9Sopenharmony_ci			value += mon_lengths[leapyear][i] * SECSPERDAY;
10684616d0f9Sopenharmony_ci		break;
10694616d0f9Sopenharmony_ci
10704616d0f9Sopenharmony_ci	default: unreachable();
10714616d0f9Sopenharmony_ci	}
10724616d0f9Sopenharmony_ci
10734616d0f9Sopenharmony_ci	/*
10744616d0f9Sopenharmony_ci	** "value" is the year-relative time of 00:00:00 UT on the day in
10754616d0f9Sopenharmony_ci	** question. To get the year-relative time of the specified local
10764616d0f9Sopenharmony_ci	** time on that day, add the transition time and the current offset
10774616d0f9Sopenharmony_ci	** from UT.
10784616d0f9Sopenharmony_ci	*/
10794616d0f9Sopenharmony_ci	return value + rulep->r_time + offset;
10804616d0f9Sopenharmony_ci}
10814616d0f9Sopenharmony_ci
10824616d0f9Sopenharmony_ci/*
10834616d0f9Sopenharmony_ci** Given a POSIX.1-2017-style TZ string, fill in the rule tables as
10844616d0f9Sopenharmony_ci** appropriate.
10854616d0f9Sopenharmony_ci*/
10864616d0f9Sopenharmony_ci
10874616d0f9Sopenharmony_cistatic bool
10884616d0f9Sopenharmony_citzparse(const char *name, struct state *sp, struct state const *basep)
10894616d0f9Sopenharmony_ci{
10904616d0f9Sopenharmony_ci	const char *			stdname;
10914616d0f9Sopenharmony_ci	const char *			dstname;
10924616d0f9Sopenharmony_ci	int_fast32_t			stdoffset;
10934616d0f9Sopenharmony_ci	int_fast32_t			dstoffset;
10944616d0f9Sopenharmony_ci	register char *			cp;
10954616d0f9Sopenharmony_ci	register bool			load_ok;
10964616d0f9Sopenharmony_ci	ptrdiff_t stdlen, dstlen, charcnt;
10974616d0f9Sopenharmony_ci	time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
10984616d0f9Sopenharmony_ci
10994616d0f9Sopenharmony_ci	stdname = name;
11004616d0f9Sopenharmony_ci	if (*name == '<') {
11014616d0f9Sopenharmony_ci	  name++;
11024616d0f9Sopenharmony_ci	  stdname = name;
11034616d0f9Sopenharmony_ci	  name = getqzname(name, '>');
11044616d0f9Sopenharmony_ci	  if (*name != '>')
11054616d0f9Sopenharmony_ci	    return false;
11064616d0f9Sopenharmony_ci	  stdlen = name - stdname;
11074616d0f9Sopenharmony_ci	  name++;
11084616d0f9Sopenharmony_ci	} else {
11094616d0f9Sopenharmony_ci	  name = getzname(name);
11104616d0f9Sopenharmony_ci	  stdlen = name - stdname;
11114616d0f9Sopenharmony_ci	}
11124616d0f9Sopenharmony_ci	if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
11134616d0f9Sopenharmony_ci	  return false;
11144616d0f9Sopenharmony_ci	name = getoffset(name, &stdoffset);
11154616d0f9Sopenharmony_ci	if (name == NULL)
11164616d0f9Sopenharmony_ci	  return false;
11174616d0f9Sopenharmony_ci	charcnt = stdlen + 1;
11184616d0f9Sopenharmony_ci	if (basep) {
11194616d0f9Sopenharmony_ci	  if (0 < basep->timecnt)
11204616d0f9Sopenharmony_ci	    atlo = basep->ats[basep->timecnt - 1];
11214616d0f9Sopenharmony_ci	  load_ok = false;
11224616d0f9Sopenharmony_ci	  sp->leapcnt = basep->leapcnt;
11234616d0f9Sopenharmony_ci	  memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
11244616d0f9Sopenharmony_ci	} else {
11254616d0f9Sopenharmony_ci	  load_ok = tzload(TZDEFRULES, sp, false) == 0;
11264616d0f9Sopenharmony_ci	  if (!load_ok)
11274616d0f9Sopenharmony_ci	    sp->leapcnt = 0;	/* So, we're off a little.  */
11284616d0f9Sopenharmony_ci	}
11294616d0f9Sopenharmony_ci	if (0 < sp->leapcnt)
11304616d0f9Sopenharmony_ci	  leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
11314616d0f9Sopenharmony_ci	sp->goback = sp->goahead = false;
11324616d0f9Sopenharmony_ci	if (*name != '\0') {
11334616d0f9Sopenharmony_ci		if (*name == '<') {
11344616d0f9Sopenharmony_ci			dstname = ++name;
11354616d0f9Sopenharmony_ci			name = getqzname(name, '>');
11364616d0f9Sopenharmony_ci			if (*name != '>')
11374616d0f9Sopenharmony_ci			  return false;
11384616d0f9Sopenharmony_ci			dstlen = name - dstname;
11394616d0f9Sopenharmony_ci			name++;
11404616d0f9Sopenharmony_ci		} else {
11414616d0f9Sopenharmony_ci			dstname = name;
11424616d0f9Sopenharmony_ci			name = getzname(name);
11434616d0f9Sopenharmony_ci			dstlen = name - dstname; /* length of DST abbr. */
11444616d0f9Sopenharmony_ci		}
11454616d0f9Sopenharmony_ci		if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
11464616d0f9Sopenharmony_ci		  return false;
11474616d0f9Sopenharmony_ci		charcnt += dstlen + 1;
11484616d0f9Sopenharmony_ci		if (*name != '\0' && *name != ',' && *name != ';') {
11494616d0f9Sopenharmony_ci			name = getoffset(name, &dstoffset);
11504616d0f9Sopenharmony_ci			if (name == NULL)
11514616d0f9Sopenharmony_ci			  return false;
11524616d0f9Sopenharmony_ci		} else	dstoffset = stdoffset - SECSPERHOUR;
11534616d0f9Sopenharmony_ci		if (*name == '\0' && !load_ok)
11544616d0f9Sopenharmony_ci			name = TZDEFRULESTRING;
11554616d0f9Sopenharmony_ci		if (*name == ',' || *name == ';') {
11564616d0f9Sopenharmony_ci			struct rule	start;
11574616d0f9Sopenharmony_ci			struct rule	end;
11584616d0f9Sopenharmony_ci			register int	year;
11594616d0f9Sopenharmony_ci			register int	timecnt;
11604616d0f9Sopenharmony_ci			time_t		janfirst;
11614616d0f9Sopenharmony_ci			int_fast32_t janoffset = 0;
11624616d0f9Sopenharmony_ci			int yearbeg, yearlim;
11634616d0f9Sopenharmony_ci
11644616d0f9Sopenharmony_ci			++name;
11654616d0f9Sopenharmony_ci			if ((name = getrule(name, &start)) == NULL)
11664616d0f9Sopenharmony_ci			  return false;
11674616d0f9Sopenharmony_ci			if (*name++ != ',')
11684616d0f9Sopenharmony_ci			  return false;
11694616d0f9Sopenharmony_ci			if ((name = getrule(name, &end)) == NULL)
11704616d0f9Sopenharmony_ci			  return false;
11714616d0f9Sopenharmony_ci			if (*name != '\0')
11724616d0f9Sopenharmony_ci			  return false;
11734616d0f9Sopenharmony_ci			sp->typecnt = 2;	/* standard time and DST */
11744616d0f9Sopenharmony_ci			/*
11754616d0f9Sopenharmony_ci			** Two transitions per year, from EPOCH_YEAR forward.
11764616d0f9Sopenharmony_ci			*/
11774616d0f9Sopenharmony_ci			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
11784616d0f9Sopenharmony_ci			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
11794616d0f9Sopenharmony_ci			timecnt = 0;
11804616d0f9Sopenharmony_ci			janfirst = 0;
11814616d0f9Sopenharmony_ci			yearbeg = EPOCH_YEAR;
11824616d0f9Sopenharmony_ci
11834616d0f9Sopenharmony_ci			do {
11844616d0f9Sopenharmony_ci			  int_fast32_t yearsecs
11854616d0f9Sopenharmony_ci			    = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
11864616d0f9Sopenharmony_ci			  yearbeg--;
11874616d0f9Sopenharmony_ci			  if (increment_overflow_time(&janfirst, -yearsecs)) {
11884616d0f9Sopenharmony_ci			    janoffset = -yearsecs;
11894616d0f9Sopenharmony_ci			    break;
11904616d0f9Sopenharmony_ci			  }
11914616d0f9Sopenharmony_ci			} while (atlo < janfirst
11924616d0f9Sopenharmony_ci				 && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
11934616d0f9Sopenharmony_ci
11944616d0f9Sopenharmony_ci			while (true) {
11954616d0f9Sopenharmony_ci			  int_fast32_t yearsecs
11964616d0f9Sopenharmony_ci			    = year_lengths[isleap(yearbeg)] * SECSPERDAY;
11974616d0f9Sopenharmony_ci			  int yearbeg1 = yearbeg;
11984616d0f9Sopenharmony_ci			  time_t janfirst1 = janfirst;
11994616d0f9Sopenharmony_ci			  if (increment_overflow_time(&janfirst1, yearsecs)
12004616d0f9Sopenharmony_ci			      || increment_overflow(&yearbeg1, 1)
12014616d0f9Sopenharmony_ci			      || atlo <= janfirst1)
12024616d0f9Sopenharmony_ci			    break;
12034616d0f9Sopenharmony_ci			  yearbeg = yearbeg1;
12044616d0f9Sopenharmony_ci			  janfirst = janfirst1;
12054616d0f9Sopenharmony_ci			}
12064616d0f9Sopenharmony_ci
12074616d0f9Sopenharmony_ci			yearlim = yearbeg;
12084616d0f9Sopenharmony_ci			if (increment_overflow(&yearlim, years_of_observations))
12094616d0f9Sopenharmony_ci			  yearlim = INT_MAX;
12104616d0f9Sopenharmony_ci			for (year = yearbeg; year < yearlim; year++) {
12114616d0f9Sopenharmony_ci				int_fast32_t
12124616d0f9Sopenharmony_ci				  starttime = transtime(year, &start, stdoffset),
12134616d0f9Sopenharmony_ci				  endtime = transtime(year, &end, dstoffset);
12144616d0f9Sopenharmony_ci				int_fast32_t
12154616d0f9Sopenharmony_ci				  yearsecs = (year_lengths[isleap(year)]
12164616d0f9Sopenharmony_ci					      * SECSPERDAY);
12174616d0f9Sopenharmony_ci				bool reversed = endtime < starttime;
12184616d0f9Sopenharmony_ci				if (reversed) {
12194616d0f9Sopenharmony_ci					int_fast32_t swap = starttime;
12204616d0f9Sopenharmony_ci					starttime = endtime;
12214616d0f9Sopenharmony_ci					endtime = swap;
12224616d0f9Sopenharmony_ci				}
12234616d0f9Sopenharmony_ci				if (reversed
12244616d0f9Sopenharmony_ci				    || (starttime < endtime
12254616d0f9Sopenharmony_ci					&& endtime - starttime < yearsecs)) {
12264616d0f9Sopenharmony_ci					if (TZ_MAX_TIMES - 2 < timecnt)
12274616d0f9Sopenharmony_ci						break;
12284616d0f9Sopenharmony_ci					sp->ats[timecnt] = janfirst;
12294616d0f9Sopenharmony_ci					if (! increment_overflow_time
12304616d0f9Sopenharmony_ci					    (&sp->ats[timecnt],
12314616d0f9Sopenharmony_ci					     janoffset + starttime)
12324616d0f9Sopenharmony_ci					    && atlo <= sp->ats[timecnt])
12334616d0f9Sopenharmony_ci					  sp->types[timecnt++] = !reversed;
12344616d0f9Sopenharmony_ci					sp->ats[timecnt] = janfirst;
12354616d0f9Sopenharmony_ci					if (! increment_overflow_time
12364616d0f9Sopenharmony_ci					    (&sp->ats[timecnt],
12374616d0f9Sopenharmony_ci					     janoffset + endtime)
12384616d0f9Sopenharmony_ci					    && atlo <= sp->ats[timecnt]) {
12394616d0f9Sopenharmony_ci					  sp->types[timecnt++] = reversed;
12404616d0f9Sopenharmony_ci					}
12414616d0f9Sopenharmony_ci				}
12424616d0f9Sopenharmony_ci				if (endtime < leaplo) {
12434616d0f9Sopenharmony_ci				  yearlim = year;
12444616d0f9Sopenharmony_ci				  if (increment_overflow(&yearlim,
12454616d0f9Sopenharmony_ci							 years_of_observations))
12464616d0f9Sopenharmony_ci				    yearlim = INT_MAX;
12474616d0f9Sopenharmony_ci				}
12484616d0f9Sopenharmony_ci				if (increment_overflow_time
12494616d0f9Sopenharmony_ci				    (&janfirst, janoffset + yearsecs))
12504616d0f9Sopenharmony_ci					break;
12514616d0f9Sopenharmony_ci				janoffset = 0;
12524616d0f9Sopenharmony_ci			}
12534616d0f9Sopenharmony_ci			sp->timecnt = timecnt;
12544616d0f9Sopenharmony_ci			if (! timecnt) {
12554616d0f9Sopenharmony_ci				sp->ttis[0] = sp->ttis[1];
12564616d0f9Sopenharmony_ci				sp->typecnt = 1;	/* Perpetual DST.  */
12574616d0f9Sopenharmony_ci			} else if (years_of_observations <= year - yearbeg)
12584616d0f9Sopenharmony_ci				sp->goback = sp->goahead = true;
12594616d0f9Sopenharmony_ci		} else {
12604616d0f9Sopenharmony_ci			register int_fast32_t	theirstdoffset;
12614616d0f9Sopenharmony_ci			register int_fast32_t	theirdstoffset;
12624616d0f9Sopenharmony_ci			register int_fast32_t	theiroffset;
12634616d0f9Sopenharmony_ci			register bool		isdst;
12644616d0f9Sopenharmony_ci			register int		i;
12654616d0f9Sopenharmony_ci			register int		j;
12664616d0f9Sopenharmony_ci
12674616d0f9Sopenharmony_ci			if (*name != '\0')
12684616d0f9Sopenharmony_ci			  return false;
12694616d0f9Sopenharmony_ci			/*
12704616d0f9Sopenharmony_ci			** Initial values of theirstdoffset and theirdstoffset.
12714616d0f9Sopenharmony_ci			*/
12724616d0f9Sopenharmony_ci			theirstdoffset = 0;
12734616d0f9Sopenharmony_ci			for (i = 0; i < sp->timecnt; ++i) {
12744616d0f9Sopenharmony_ci				j = sp->types[i];
12754616d0f9Sopenharmony_ci				if (!sp->ttis[j].tt_isdst) {
12764616d0f9Sopenharmony_ci					theirstdoffset =
12774616d0f9Sopenharmony_ci						- sp->ttis[j].tt_utoff;
12784616d0f9Sopenharmony_ci					break;
12794616d0f9Sopenharmony_ci				}
12804616d0f9Sopenharmony_ci			}
12814616d0f9Sopenharmony_ci			theirdstoffset = 0;
12824616d0f9Sopenharmony_ci			for (i = 0; i < sp->timecnt; ++i) {
12834616d0f9Sopenharmony_ci				j = sp->types[i];
12844616d0f9Sopenharmony_ci				if (sp->ttis[j].tt_isdst) {
12854616d0f9Sopenharmony_ci					theirdstoffset =
12864616d0f9Sopenharmony_ci						- sp->ttis[j].tt_utoff;
12874616d0f9Sopenharmony_ci					break;
12884616d0f9Sopenharmony_ci				}
12894616d0f9Sopenharmony_ci			}
12904616d0f9Sopenharmony_ci			/*
12914616d0f9Sopenharmony_ci			** Initially we're assumed to be in standard time.
12924616d0f9Sopenharmony_ci			*/
12934616d0f9Sopenharmony_ci			isdst = false;
12944616d0f9Sopenharmony_ci			/*
12954616d0f9Sopenharmony_ci			** Now juggle transition times and types
12964616d0f9Sopenharmony_ci			** tracking offsets as you do.
12974616d0f9Sopenharmony_ci			*/
12984616d0f9Sopenharmony_ci			for (i = 0; i < sp->timecnt; ++i) {
12994616d0f9Sopenharmony_ci				j = sp->types[i];
13004616d0f9Sopenharmony_ci				sp->types[i] = sp->ttis[j].tt_isdst;
13014616d0f9Sopenharmony_ci				if (sp->ttis[j].tt_ttisut) {
13024616d0f9Sopenharmony_ci					/* No adjustment to transition time */
13034616d0f9Sopenharmony_ci				} else {
13044616d0f9Sopenharmony_ci					/*
13054616d0f9Sopenharmony_ci					** If daylight saving time is in
13064616d0f9Sopenharmony_ci					** effect, and the transition time was
13074616d0f9Sopenharmony_ci					** not specified as standard time, add
13084616d0f9Sopenharmony_ci					** the daylight saving time offset to
13094616d0f9Sopenharmony_ci					** the transition time; otherwise, add
13104616d0f9Sopenharmony_ci					** the standard time offset to the
13114616d0f9Sopenharmony_ci					** transition time.
13124616d0f9Sopenharmony_ci					*/
13134616d0f9Sopenharmony_ci					/*
13144616d0f9Sopenharmony_ci					** Transitions from DST to DDST
13154616d0f9Sopenharmony_ci					** will effectively disappear since
13164616d0f9Sopenharmony_ci					** POSIX.1-2017 provides for only one
13174616d0f9Sopenharmony_ci					** DST offset.
13184616d0f9Sopenharmony_ci					*/
13194616d0f9Sopenharmony_ci					if (isdst && !sp->ttis[j].tt_ttisstd) {
13204616d0f9Sopenharmony_ci						sp->ats[i] += dstoffset -
13214616d0f9Sopenharmony_ci							theirdstoffset;
13224616d0f9Sopenharmony_ci					} else {
13234616d0f9Sopenharmony_ci						sp->ats[i] += stdoffset -
13244616d0f9Sopenharmony_ci							theirstdoffset;
13254616d0f9Sopenharmony_ci					}
13264616d0f9Sopenharmony_ci				}
13274616d0f9Sopenharmony_ci				theiroffset = -sp->ttis[j].tt_utoff;
13284616d0f9Sopenharmony_ci				if (sp->ttis[j].tt_isdst)
13294616d0f9Sopenharmony_ci					theirdstoffset = theiroffset;
13304616d0f9Sopenharmony_ci				else	theirstdoffset = theiroffset;
13314616d0f9Sopenharmony_ci			}
13324616d0f9Sopenharmony_ci			/*
13334616d0f9Sopenharmony_ci			** Finally, fill in ttis.
13344616d0f9Sopenharmony_ci			*/
13354616d0f9Sopenharmony_ci			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
13364616d0f9Sopenharmony_ci			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
13374616d0f9Sopenharmony_ci			sp->typecnt = 2;
13384616d0f9Sopenharmony_ci		}
13394616d0f9Sopenharmony_ci	} else {
13404616d0f9Sopenharmony_ci		dstlen = 0;
13414616d0f9Sopenharmony_ci		sp->typecnt = 1;		/* only standard time */
13424616d0f9Sopenharmony_ci		sp->timecnt = 0;
13434616d0f9Sopenharmony_ci		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
13444616d0f9Sopenharmony_ci	}
13454616d0f9Sopenharmony_ci	sp->defaulttype = 0;
13464616d0f9Sopenharmony_ci	sp->charcnt = charcnt;
13474616d0f9Sopenharmony_ci	cp = sp->chars;
13484616d0f9Sopenharmony_ci	memcpy(cp, stdname, stdlen);
13494616d0f9Sopenharmony_ci	cp += stdlen;
13504616d0f9Sopenharmony_ci	*cp++ = '\0';
13514616d0f9Sopenharmony_ci	if (dstlen != 0) {
13524616d0f9Sopenharmony_ci		memcpy(cp, dstname, dstlen);
13534616d0f9Sopenharmony_ci		*(cp + dstlen) = '\0';
13544616d0f9Sopenharmony_ci	}
13554616d0f9Sopenharmony_ci	return true;
13564616d0f9Sopenharmony_ci}
13574616d0f9Sopenharmony_ci
13584616d0f9Sopenharmony_cistatic void
13594616d0f9Sopenharmony_cigmtload(struct state *const sp)
13604616d0f9Sopenharmony_ci{
13614616d0f9Sopenharmony_ci	if (tzload(etc_utc, sp, true) != 0)
13624616d0f9Sopenharmony_ci	  tzparse("UTC0", sp, NULL);
13634616d0f9Sopenharmony_ci}
13644616d0f9Sopenharmony_ci
13654616d0f9Sopenharmony_ci/* Initialize *SP to a value appropriate for the TZ setting NAME.
13664616d0f9Sopenharmony_ci   Return 0 on success, an errno value on failure.  */
13674616d0f9Sopenharmony_cistatic int
13684616d0f9Sopenharmony_cizoneinit(struct state *sp, char const *name)
13694616d0f9Sopenharmony_ci{
13704616d0f9Sopenharmony_ci  if (name && ! name[0]) {
13714616d0f9Sopenharmony_ci    /*
13724616d0f9Sopenharmony_ci    ** User wants it fast rather than right.
13734616d0f9Sopenharmony_ci    */
13744616d0f9Sopenharmony_ci    sp->leapcnt = 0;		/* so, we're off a little */
13754616d0f9Sopenharmony_ci    sp->timecnt = 0;
13764616d0f9Sopenharmony_ci    sp->typecnt = 0;
13774616d0f9Sopenharmony_ci    sp->charcnt = 0;
13784616d0f9Sopenharmony_ci    sp->goback = sp->goahead = false;
13794616d0f9Sopenharmony_ci    init_ttinfo(&sp->ttis[0], 0, false, 0);
13804616d0f9Sopenharmony_ci    strcpy(sp->chars, utc);
13814616d0f9Sopenharmony_ci    sp->defaulttype = 0;
13824616d0f9Sopenharmony_ci    return 0;
13834616d0f9Sopenharmony_ci  } else {
13844616d0f9Sopenharmony_ci    int err = tzload(name, sp, true);
13854616d0f9Sopenharmony_ci    if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
13864616d0f9Sopenharmony_ci      err = 0;
13874616d0f9Sopenharmony_ci    if (err == 0)
13884616d0f9Sopenharmony_ci      err = scrub_abbrs(sp);
13894616d0f9Sopenharmony_ci    return err;
13904616d0f9Sopenharmony_ci  }
13914616d0f9Sopenharmony_ci}
13924616d0f9Sopenharmony_ci
13934616d0f9Sopenharmony_cistatic void
13944616d0f9Sopenharmony_citzset_unlocked(void)
13954616d0f9Sopenharmony_ci{
13964616d0f9Sopenharmony_ci  char const *name = getenv("TZ");
13974616d0f9Sopenharmony_ci  struct state *sp = lclptr;
13984616d0f9Sopenharmony_ci  int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
13994616d0f9Sopenharmony_ci  if (lcl < 0
14004616d0f9Sopenharmony_ci      ? lcl_is_set < 0
14014616d0f9Sopenharmony_ci      : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
14024616d0f9Sopenharmony_ci    return;
14034616d0f9Sopenharmony_ci#ifdef ALL_STATE
14044616d0f9Sopenharmony_ci  if (! sp)
14054616d0f9Sopenharmony_ci    lclptr = sp = malloc(sizeof *lclptr);
14064616d0f9Sopenharmony_ci#endif /* defined ALL_STATE */
14074616d0f9Sopenharmony_ci  if (sp) {
14084616d0f9Sopenharmony_ci    if (zoneinit(sp, name) != 0)
14094616d0f9Sopenharmony_ci      zoneinit(sp, "");
14104616d0f9Sopenharmony_ci    if (0 < lcl)
14114616d0f9Sopenharmony_ci      strcpy(lcl_TZname, name);
14124616d0f9Sopenharmony_ci  }
14134616d0f9Sopenharmony_ci  settzname();
14144616d0f9Sopenharmony_ci  lcl_is_set = lcl;
14154616d0f9Sopenharmony_ci}
14164616d0f9Sopenharmony_ci
14174616d0f9Sopenharmony_civoid
14184616d0f9Sopenharmony_citzset(void)
14194616d0f9Sopenharmony_ci{
14204616d0f9Sopenharmony_ci  if (lock() != 0)
14214616d0f9Sopenharmony_ci    return;
14224616d0f9Sopenharmony_ci  tzset_unlocked();
14234616d0f9Sopenharmony_ci  unlock();
14244616d0f9Sopenharmony_ci}
14254616d0f9Sopenharmony_ci
14264616d0f9Sopenharmony_cistatic void
14274616d0f9Sopenharmony_cigmtcheck(void)
14284616d0f9Sopenharmony_ci{
14294616d0f9Sopenharmony_ci  static bool gmt_is_set;
14304616d0f9Sopenharmony_ci  if (lock() != 0)
14314616d0f9Sopenharmony_ci    return;
14324616d0f9Sopenharmony_ci  if (! gmt_is_set) {
14334616d0f9Sopenharmony_ci#ifdef ALL_STATE
14344616d0f9Sopenharmony_ci    gmtptr = malloc(sizeof *gmtptr);
14354616d0f9Sopenharmony_ci#endif
14364616d0f9Sopenharmony_ci    if (gmtptr)
14374616d0f9Sopenharmony_ci      gmtload(gmtptr);
14384616d0f9Sopenharmony_ci    gmt_is_set = true;
14394616d0f9Sopenharmony_ci  }
14404616d0f9Sopenharmony_ci  unlock();
14414616d0f9Sopenharmony_ci}
14424616d0f9Sopenharmony_ci
14434616d0f9Sopenharmony_ci#if NETBSD_INSPIRED
14444616d0f9Sopenharmony_ci
14454616d0f9Sopenharmony_citimezone_t
14464616d0f9Sopenharmony_citzalloc(char const *name)
14474616d0f9Sopenharmony_ci{
14484616d0f9Sopenharmony_ci  timezone_t sp = malloc(sizeof *sp);
14494616d0f9Sopenharmony_ci  if (sp) {
14504616d0f9Sopenharmony_ci    int err = zoneinit(sp, name);
14514616d0f9Sopenharmony_ci    if (err != 0) {
14524616d0f9Sopenharmony_ci      free(sp);
14534616d0f9Sopenharmony_ci      errno = err;
14544616d0f9Sopenharmony_ci      return NULL;
14554616d0f9Sopenharmony_ci    }
14564616d0f9Sopenharmony_ci  } else if (!HAVE_MALLOC_ERRNO)
14574616d0f9Sopenharmony_ci    errno = ENOMEM;
14584616d0f9Sopenharmony_ci  return sp;
14594616d0f9Sopenharmony_ci}
14604616d0f9Sopenharmony_ci
14614616d0f9Sopenharmony_civoid
14624616d0f9Sopenharmony_citzfree(timezone_t sp)
14634616d0f9Sopenharmony_ci{
14644616d0f9Sopenharmony_ci  free(sp);
14654616d0f9Sopenharmony_ci}
14664616d0f9Sopenharmony_ci
14674616d0f9Sopenharmony_ci/*
14684616d0f9Sopenharmony_ci** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
14694616d0f9Sopenharmony_ci** ctime_r are obsolescent and have potential security problems that
14704616d0f9Sopenharmony_ci** ctime_rz would share.  Callers can instead use localtime_rz + strftime.
14714616d0f9Sopenharmony_ci**
14724616d0f9Sopenharmony_ci** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
14734616d0f9Sopenharmony_ci** in zones with three or more time zone abbreviations.
14744616d0f9Sopenharmony_ci** Callers can instead use localtime_rz + strftime.
14754616d0f9Sopenharmony_ci*/
14764616d0f9Sopenharmony_ci
14774616d0f9Sopenharmony_ci#endif
14784616d0f9Sopenharmony_ci
14794616d0f9Sopenharmony_ci/*
14804616d0f9Sopenharmony_ci** The easy way to behave "as if no library function calls" localtime
14814616d0f9Sopenharmony_ci** is to not call it, so we drop its guts into "localsub", which can be
14824616d0f9Sopenharmony_ci** freely called. (And no, the PANS doesn't require the above behavior,
14834616d0f9Sopenharmony_ci** but it *is* desirable.)
14844616d0f9Sopenharmony_ci**
14854616d0f9Sopenharmony_ci** If successful and SETNAME is nonzero,
14864616d0f9Sopenharmony_ci** set the applicable parts of tzname, timezone and altzone;
14874616d0f9Sopenharmony_ci** however, it's OK to omit this step
14884616d0f9Sopenharmony_ci** if the timezone is compatible with POSIX.1-2017
14894616d0f9Sopenharmony_ci** since in that case tzset should have already done this step correctly.
14904616d0f9Sopenharmony_ci** SETNAME's type is int_fast32_t for compatibility with gmtsub,
14914616d0f9Sopenharmony_ci** but it is actually a boolean and its value should be 0 or 1.
14924616d0f9Sopenharmony_ci*/
14934616d0f9Sopenharmony_ci
14944616d0f9Sopenharmony_ci/*ARGSUSED*/
14954616d0f9Sopenharmony_cistatic struct tm *
14964616d0f9Sopenharmony_cilocalsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
14974616d0f9Sopenharmony_ci	 struct tm *const tmp)
14984616d0f9Sopenharmony_ci{
14994616d0f9Sopenharmony_ci	register const struct ttinfo *	ttisp;
15004616d0f9Sopenharmony_ci	register int			i;
15014616d0f9Sopenharmony_ci	register struct tm *		result;
15024616d0f9Sopenharmony_ci	const time_t			t = *timep;
15034616d0f9Sopenharmony_ci
15044616d0f9Sopenharmony_ci	if (sp == NULL) {
15054616d0f9Sopenharmony_ci	  /* Don't bother to set tzname etc.; tzset has already done it.  */
15064616d0f9Sopenharmony_ci	  return gmtsub(gmtptr, timep, 0, tmp);
15074616d0f9Sopenharmony_ci	}
15084616d0f9Sopenharmony_ci	if ((sp->goback && t < sp->ats[0]) ||
15094616d0f9Sopenharmony_ci		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
15104616d0f9Sopenharmony_ci			time_t newt;
15114616d0f9Sopenharmony_ci			register time_t		seconds;
15124616d0f9Sopenharmony_ci			register time_t		years;
15134616d0f9Sopenharmony_ci
15144616d0f9Sopenharmony_ci			if (t < sp->ats[0])
15154616d0f9Sopenharmony_ci				seconds = sp->ats[0] - t;
15164616d0f9Sopenharmony_ci			else	seconds = t - sp->ats[sp->timecnt - 1];
15174616d0f9Sopenharmony_ci			--seconds;
15184616d0f9Sopenharmony_ci
15194616d0f9Sopenharmony_ci			/* Beware integer overflow, as SECONDS might
15204616d0f9Sopenharmony_ci			   be close to the maximum time_t.  */
15214616d0f9Sopenharmony_ci			years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
15224616d0f9Sopenharmony_ci			seconds = years * AVGSECSPERYEAR;
15234616d0f9Sopenharmony_ci			years += YEARSPERREPEAT;
15244616d0f9Sopenharmony_ci			if (t < sp->ats[0])
15254616d0f9Sopenharmony_ci			  newt = t + seconds + SECSPERREPEAT;
15264616d0f9Sopenharmony_ci			else
15274616d0f9Sopenharmony_ci			  newt = t - seconds - SECSPERREPEAT;
15284616d0f9Sopenharmony_ci
15294616d0f9Sopenharmony_ci			if (newt < sp->ats[0] ||
15304616d0f9Sopenharmony_ci				newt > sp->ats[sp->timecnt - 1])
15314616d0f9Sopenharmony_ci					return NULL;	/* "cannot happen" */
15324616d0f9Sopenharmony_ci			result = localsub(sp, &newt, setname, tmp);
15334616d0f9Sopenharmony_ci			if (result) {
15344616d0f9Sopenharmony_ci#if defined ckd_add && defined ckd_sub
15354616d0f9Sopenharmony_ci				if (t < sp->ats[0]
15364616d0f9Sopenharmony_ci				    ? ckd_sub(&result->tm_year,
15374616d0f9Sopenharmony_ci					      result->tm_year, years)
15384616d0f9Sopenharmony_ci				    : ckd_add(&result->tm_year,
15394616d0f9Sopenharmony_ci					      result->tm_year, years))
15404616d0f9Sopenharmony_ci				  return NULL;
15414616d0f9Sopenharmony_ci#else
15424616d0f9Sopenharmony_ci				register int_fast64_t newy;
15434616d0f9Sopenharmony_ci
15444616d0f9Sopenharmony_ci				newy = result->tm_year;
15454616d0f9Sopenharmony_ci				if (t < sp->ats[0])
15464616d0f9Sopenharmony_ci					newy -= years;
15474616d0f9Sopenharmony_ci				else	newy += years;
15484616d0f9Sopenharmony_ci				if (! (INT_MIN <= newy && newy <= INT_MAX))
15494616d0f9Sopenharmony_ci					return NULL;
15504616d0f9Sopenharmony_ci				result->tm_year = newy;
15514616d0f9Sopenharmony_ci#endif
15524616d0f9Sopenharmony_ci			}
15534616d0f9Sopenharmony_ci			return result;
15544616d0f9Sopenharmony_ci	}
15554616d0f9Sopenharmony_ci	if (sp->timecnt == 0 || t < sp->ats[0]) {
15564616d0f9Sopenharmony_ci		i = sp->defaulttype;
15574616d0f9Sopenharmony_ci	} else {
15584616d0f9Sopenharmony_ci		register int	lo = 1;
15594616d0f9Sopenharmony_ci		register int	hi = sp->timecnt;
15604616d0f9Sopenharmony_ci
15614616d0f9Sopenharmony_ci		while (lo < hi) {
15624616d0f9Sopenharmony_ci			register int	mid = (lo + hi) >> 1;
15634616d0f9Sopenharmony_ci
15644616d0f9Sopenharmony_ci			if (t < sp->ats[mid])
15654616d0f9Sopenharmony_ci				hi = mid;
15664616d0f9Sopenharmony_ci			else	lo = mid + 1;
15674616d0f9Sopenharmony_ci		}
15684616d0f9Sopenharmony_ci		i = sp->types[lo - 1];
15694616d0f9Sopenharmony_ci	}
15704616d0f9Sopenharmony_ci	ttisp = &sp->ttis[i];
15714616d0f9Sopenharmony_ci	/*
15724616d0f9Sopenharmony_ci	** To get (wrong) behavior that's compatible with System V Release 2.0
15734616d0f9Sopenharmony_ci	** you'd replace the statement below with
15744616d0f9Sopenharmony_ci	**	t += ttisp->tt_utoff;
15754616d0f9Sopenharmony_ci	**	timesub(&t, 0L, sp, tmp);
15764616d0f9Sopenharmony_ci	*/
15774616d0f9Sopenharmony_ci	result = timesub(&t, ttisp->tt_utoff, sp, tmp);
15784616d0f9Sopenharmony_ci	if (result) {
15794616d0f9Sopenharmony_ci	  result->tm_isdst = ttisp->tt_isdst;
15804616d0f9Sopenharmony_ci#ifdef TM_ZONE
15814616d0f9Sopenharmony_ci	  result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
15824616d0f9Sopenharmony_ci#endif /* defined TM_ZONE */
15834616d0f9Sopenharmony_ci	  if (setname)
15844616d0f9Sopenharmony_ci	    update_tzname_etc(sp, ttisp);
15854616d0f9Sopenharmony_ci	}
15864616d0f9Sopenharmony_ci	return result;
15874616d0f9Sopenharmony_ci}
15884616d0f9Sopenharmony_ci
15894616d0f9Sopenharmony_ci#if NETBSD_INSPIRED
15904616d0f9Sopenharmony_ci
15914616d0f9Sopenharmony_cistruct tm *
15924616d0f9Sopenharmony_cilocaltime_rz(struct state *restrict sp, time_t const *restrict timep,
15934616d0f9Sopenharmony_ci	     struct tm *restrict tmp)
15944616d0f9Sopenharmony_ci{
15954616d0f9Sopenharmony_ci  return localsub(sp, timep, 0, tmp);
15964616d0f9Sopenharmony_ci}
15974616d0f9Sopenharmony_ci
15984616d0f9Sopenharmony_ci#endif
15994616d0f9Sopenharmony_ci
16004616d0f9Sopenharmony_cistatic struct tm *
16014616d0f9Sopenharmony_cilocaltime_tzset(time_t const *timep, struct tm *tmp, bool setname)
16024616d0f9Sopenharmony_ci{
16034616d0f9Sopenharmony_ci  int err = lock();
16044616d0f9Sopenharmony_ci  if (err) {
16054616d0f9Sopenharmony_ci    errno = err;
16064616d0f9Sopenharmony_ci    return NULL;
16074616d0f9Sopenharmony_ci  }
16084616d0f9Sopenharmony_ci  if (setname || !lcl_is_set)
16094616d0f9Sopenharmony_ci    tzset_unlocked();
16104616d0f9Sopenharmony_ci  tmp = localsub(lclptr, timep, setname, tmp);
16114616d0f9Sopenharmony_ci  unlock();
16124616d0f9Sopenharmony_ci  return tmp;
16134616d0f9Sopenharmony_ci}
16144616d0f9Sopenharmony_ci
16154616d0f9Sopenharmony_cistruct tm *
16164616d0f9Sopenharmony_cilocaltime(const time_t *timep)
16174616d0f9Sopenharmony_ci{
16184616d0f9Sopenharmony_ci#if !SUPPORT_C89
16194616d0f9Sopenharmony_ci  static struct tm tm;
16204616d0f9Sopenharmony_ci#endif
16214616d0f9Sopenharmony_ci  return localtime_tzset(timep, &tm, true);
16224616d0f9Sopenharmony_ci}
16234616d0f9Sopenharmony_ci
16244616d0f9Sopenharmony_cistruct tm *
16254616d0f9Sopenharmony_cilocaltime_r(const time_t *restrict timep, struct tm *restrict tmp)
16264616d0f9Sopenharmony_ci{
16274616d0f9Sopenharmony_ci  return localtime_tzset(timep, tmp, false);
16284616d0f9Sopenharmony_ci}
16294616d0f9Sopenharmony_ci
16304616d0f9Sopenharmony_ci/*
16314616d0f9Sopenharmony_ci** gmtsub is to gmtime as localsub is to localtime.
16324616d0f9Sopenharmony_ci*/
16334616d0f9Sopenharmony_ci
16344616d0f9Sopenharmony_cistatic struct tm *
16354616d0f9Sopenharmony_cigmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
16364616d0f9Sopenharmony_ci       int_fast32_t offset, struct tm *tmp)
16374616d0f9Sopenharmony_ci{
16384616d0f9Sopenharmony_ci	register struct tm *	result;
16394616d0f9Sopenharmony_ci
16404616d0f9Sopenharmony_ci	result = timesub(timep, offset, gmtptr, tmp);
16414616d0f9Sopenharmony_ci#ifdef TM_ZONE
16424616d0f9Sopenharmony_ci	/*
16434616d0f9Sopenharmony_ci	** Could get fancy here and deliver something such as
16444616d0f9Sopenharmony_ci	** "+xx" or "-xx" if offset is non-zero,
16454616d0f9Sopenharmony_ci	** but this is no time for a treasure hunt.
16464616d0f9Sopenharmony_ci	*/
16474616d0f9Sopenharmony_ci	tmp->TM_ZONE = ((char *)
16484616d0f9Sopenharmony_ci			(offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
16494616d0f9Sopenharmony_ci#endif /* defined TM_ZONE */
16504616d0f9Sopenharmony_ci	return result;
16514616d0f9Sopenharmony_ci}
16524616d0f9Sopenharmony_ci
16534616d0f9Sopenharmony_ci/*
16544616d0f9Sopenharmony_ci* Re-entrant version of gmtime.
16554616d0f9Sopenharmony_ci*/
16564616d0f9Sopenharmony_ci
16574616d0f9Sopenharmony_cistruct tm *
16584616d0f9Sopenharmony_cigmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
16594616d0f9Sopenharmony_ci{
16604616d0f9Sopenharmony_ci  gmtcheck();
16614616d0f9Sopenharmony_ci  return gmtsub(gmtptr, timep, 0, tmp);
16624616d0f9Sopenharmony_ci}
16634616d0f9Sopenharmony_ci
16644616d0f9Sopenharmony_cistruct tm *
16654616d0f9Sopenharmony_cigmtime(const time_t *timep)
16664616d0f9Sopenharmony_ci{
16674616d0f9Sopenharmony_ci#if !SUPPORT_C89
16684616d0f9Sopenharmony_ci  static struct tm tm;
16694616d0f9Sopenharmony_ci#endif
16704616d0f9Sopenharmony_ci  return gmtime_r(timep, &tm);
16714616d0f9Sopenharmony_ci}
16724616d0f9Sopenharmony_ci
16734616d0f9Sopenharmony_ci#if STD_INSPIRED
16744616d0f9Sopenharmony_ci
16754616d0f9Sopenharmony_ci/* This function is obsolescent and may disappear in future releases.
16764616d0f9Sopenharmony_ci   Callers can instead use localtime_rz with a fixed-offset zone.  */
16774616d0f9Sopenharmony_ci
16784616d0f9Sopenharmony_cistruct tm *
16794616d0f9Sopenharmony_ciofftime(const time_t *timep, long offset)
16804616d0f9Sopenharmony_ci{
16814616d0f9Sopenharmony_ci  gmtcheck();
16824616d0f9Sopenharmony_ci
16834616d0f9Sopenharmony_ci#if !SUPPORT_C89
16844616d0f9Sopenharmony_ci  static struct tm tm;
16854616d0f9Sopenharmony_ci#endif
16864616d0f9Sopenharmony_ci  return gmtsub(gmtptr, timep, offset, &tm);
16874616d0f9Sopenharmony_ci}
16884616d0f9Sopenharmony_ci
16894616d0f9Sopenharmony_ci#endif
16904616d0f9Sopenharmony_ci
16914616d0f9Sopenharmony_ci/*
16924616d0f9Sopenharmony_ci** Return the number of leap years through the end of the given year
16934616d0f9Sopenharmony_ci** where, to make the math easy, the answer for year zero is defined as zero.
16944616d0f9Sopenharmony_ci*/
16954616d0f9Sopenharmony_ci
16964616d0f9Sopenharmony_cistatic time_t
16974616d0f9Sopenharmony_cileaps_thru_end_of_nonneg(time_t y)
16984616d0f9Sopenharmony_ci{
16994616d0f9Sopenharmony_ci  return y / 4 - y / 100 + y / 400;
17004616d0f9Sopenharmony_ci}
17014616d0f9Sopenharmony_ci
17024616d0f9Sopenharmony_cistatic time_t
17034616d0f9Sopenharmony_cileaps_thru_end_of(time_t y)
17044616d0f9Sopenharmony_ci{
17054616d0f9Sopenharmony_ci  return (y < 0
17064616d0f9Sopenharmony_ci	  ? -1 - leaps_thru_end_of_nonneg(-1 - y)
17074616d0f9Sopenharmony_ci	  : leaps_thru_end_of_nonneg(y));
17084616d0f9Sopenharmony_ci}
17094616d0f9Sopenharmony_ci
17104616d0f9Sopenharmony_cistatic struct tm *
17114616d0f9Sopenharmony_citimesub(const time_t *timep, int_fast32_t offset,
17124616d0f9Sopenharmony_ci	const struct state *sp, struct tm *tmp)
17134616d0f9Sopenharmony_ci{
17144616d0f9Sopenharmony_ci	register const struct lsinfo *	lp;
17154616d0f9Sopenharmony_ci	register time_t			tdays;
17164616d0f9Sopenharmony_ci	register const int *		ip;
17174616d0f9Sopenharmony_ci	register int_fast32_t		corr;
17184616d0f9Sopenharmony_ci	register int			i;
17194616d0f9Sopenharmony_ci	int_fast32_t idays, rem, dayoff, dayrem;
17204616d0f9Sopenharmony_ci	time_t y;
17214616d0f9Sopenharmony_ci
17224616d0f9Sopenharmony_ci	/* If less than SECSPERMIN, the number of seconds since the
17234616d0f9Sopenharmony_ci	   most recent positive leap second; otherwise, do not add 1
17244616d0f9Sopenharmony_ci	   to localtime tm_sec because of leap seconds.  */
17254616d0f9Sopenharmony_ci	time_t secs_since_posleap = SECSPERMIN;
17264616d0f9Sopenharmony_ci
17274616d0f9Sopenharmony_ci	corr = 0;
17284616d0f9Sopenharmony_ci	i = (sp == NULL) ? 0 : sp->leapcnt;
17294616d0f9Sopenharmony_ci	while (--i >= 0) {
17304616d0f9Sopenharmony_ci		lp = &sp->lsis[i];
17314616d0f9Sopenharmony_ci		if (*timep >= lp->ls_trans) {
17324616d0f9Sopenharmony_ci			corr = lp->ls_corr;
17334616d0f9Sopenharmony_ci			if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
17344616d0f9Sopenharmony_ci			  secs_since_posleap = *timep - lp->ls_trans;
17354616d0f9Sopenharmony_ci			break;
17364616d0f9Sopenharmony_ci		}
17374616d0f9Sopenharmony_ci	}
17384616d0f9Sopenharmony_ci
17394616d0f9Sopenharmony_ci	/* Calculate the year, avoiding integer overflow even if
17404616d0f9Sopenharmony_ci	   time_t is unsigned.  */
17414616d0f9Sopenharmony_ci	tdays = *timep / SECSPERDAY;
17424616d0f9Sopenharmony_ci	rem = *timep % SECSPERDAY;
17434616d0f9Sopenharmony_ci	rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
17444616d0f9Sopenharmony_ci	dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
17454616d0f9Sopenharmony_ci	rem %= SECSPERDAY;
17464616d0f9Sopenharmony_ci	/* y = (EPOCH_YEAR
17474616d0f9Sopenharmony_ci	        + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
17484616d0f9Sopenharmony_ci	   sans overflow.  But calculate against 1570 (EPOCH_YEAR -
17494616d0f9Sopenharmony_ci	   YEARSPERREPEAT) instead of against 1970 so that things work
17504616d0f9Sopenharmony_ci	   for localtime values before 1970 when time_t is unsigned.  */
17514616d0f9Sopenharmony_ci	dayrem = tdays % DAYSPERREPEAT;
17524616d0f9Sopenharmony_ci	dayrem += dayoff % DAYSPERREPEAT;
17534616d0f9Sopenharmony_ci	y = (EPOCH_YEAR - YEARSPERREPEAT
17544616d0f9Sopenharmony_ci	     + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
17554616d0f9Sopenharmony_ci		 - ((dayrem % DAYSPERREPEAT) < 0)
17564616d0f9Sopenharmony_ci		 + tdays / DAYSPERREPEAT)
17574616d0f9Sopenharmony_ci		* YEARSPERREPEAT));
17584616d0f9Sopenharmony_ci	/* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow.  */
17594616d0f9Sopenharmony_ci	idays = tdays % DAYSPERREPEAT;
17604616d0f9Sopenharmony_ci	idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
17614616d0f9Sopenharmony_ci	idays %= DAYSPERREPEAT;
17624616d0f9Sopenharmony_ci	/* Increase Y and decrease IDAYS until IDAYS is in range for Y.  */
17634616d0f9Sopenharmony_ci	while (year_lengths[isleap(y)] <= idays) {
17644616d0f9Sopenharmony_ci		int tdelta = idays / DAYSPERLYEAR;
17654616d0f9Sopenharmony_ci		int_fast32_t ydelta = tdelta + !tdelta;
17664616d0f9Sopenharmony_ci		time_t newy = y + ydelta;
17674616d0f9Sopenharmony_ci		register int	leapdays;
17684616d0f9Sopenharmony_ci		leapdays = leaps_thru_end_of(newy - 1) -
17694616d0f9Sopenharmony_ci			leaps_thru_end_of(y - 1);
17704616d0f9Sopenharmony_ci		idays -= ydelta * DAYSPERNYEAR;
17714616d0f9Sopenharmony_ci		idays -= leapdays;
17724616d0f9Sopenharmony_ci		y = newy;
17734616d0f9Sopenharmony_ci	}
17744616d0f9Sopenharmony_ci
17754616d0f9Sopenharmony_ci#ifdef ckd_add
17764616d0f9Sopenharmony_ci	if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
17774616d0f9Sopenharmony_ci	  errno = EOVERFLOW;
17784616d0f9Sopenharmony_ci	  return NULL;
17794616d0f9Sopenharmony_ci	}
17804616d0f9Sopenharmony_ci#else
17814616d0f9Sopenharmony_ci	if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
17824616d0f9Sopenharmony_ci	  int signed_y = y;
17834616d0f9Sopenharmony_ci	  tmp->tm_year = signed_y - TM_YEAR_BASE;
17844616d0f9Sopenharmony_ci	} else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
17854616d0f9Sopenharmony_ci		   && y - TM_YEAR_BASE <= INT_MAX)
17864616d0f9Sopenharmony_ci	  tmp->tm_year = y - TM_YEAR_BASE;
17874616d0f9Sopenharmony_ci	else {
17884616d0f9Sopenharmony_ci	  errno = EOVERFLOW;
17894616d0f9Sopenharmony_ci	  return NULL;
17904616d0f9Sopenharmony_ci	}
17914616d0f9Sopenharmony_ci#endif
17924616d0f9Sopenharmony_ci	tmp->tm_yday = idays;
17934616d0f9Sopenharmony_ci	/*
17944616d0f9Sopenharmony_ci	** The "extra" mods below avoid overflow problems.
17954616d0f9Sopenharmony_ci	*/
17964616d0f9Sopenharmony_ci	tmp->tm_wday = (TM_WDAY_BASE
17974616d0f9Sopenharmony_ci			+ ((tmp->tm_year % DAYSPERWEEK)
17984616d0f9Sopenharmony_ci			   * (DAYSPERNYEAR % DAYSPERWEEK))
17994616d0f9Sopenharmony_ci			+ leaps_thru_end_of(y - 1)
18004616d0f9Sopenharmony_ci			- leaps_thru_end_of(TM_YEAR_BASE - 1)
18014616d0f9Sopenharmony_ci			+ idays);
18024616d0f9Sopenharmony_ci	tmp->tm_wday %= DAYSPERWEEK;
18034616d0f9Sopenharmony_ci	if (tmp->tm_wday < 0)
18044616d0f9Sopenharmony_ci		tmp->tm_wday += DAYSPERWEEK;
18054616d0f9Sopenharmony_ci	tmp->tm_hour = rem / SECSPERHOUR;
18064616d0f9Sopenharmony_ci	rem %= SECSPERHOUR;
18074616d0f9Sopenharmony_ci	tmp->tm_min = rem / SECSPERMIN;
18084616d0f9Sopenharmony_ci	tmp->tm_sec = rem % SECSPERMIN;
18094616d0f9Sopenharmony_ci
18104616d0f9Sopenharmony_ci	/* Use "... ??:??:60" at the end of the localtime minute containing
18114616d0f9Sopenharmony_ci	   the second just before the positive leap second.  */
18124616d0f9Sopenharmony_ci	tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
18134616d0f9Sopenharmony_ci
18144616d0f9Sopenharmony_ci	ip = mon_lengths[isleap(y)];
18154616d0f9Sopenharmony_ci	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
18164616d0f9Sopenharmony_ci		idays -= ip[tmp->tm_mon];
18174616d0f9Sopenharmony_ci	tmp->tm_mday = idays + 1;
18184616d0f9Sopenharmony_ci	tmp->tm_isdst = 0;
18194616d0f9Sopenharmony_ci#ifdef TM_GMTOFF
18204616d0f9Sopenharmony_ci	tmp->TM_GMTOFF = offset;
18214616d0f9Sopenharmony_ci#endif /* defined TM_GMTOFF */
18224616d0f9Sopenharmony_ci	return tmp;
18234616d0f9Sopenharmony_ci}
18244616d0f9Sopenharmony_ci
18254616d0f9Sopenharmony_ci/*
18264616d0f9Sopenharmony_ci** Adapted from code provided by Robert Elz, who writes:
18274616d0f9Sopenharmony_ci**	The "best" way to do mktime I think is based on an idea of Bob
18284616d0f9Sopenharmony_ci**	Kridle's (so its said...) from a long time ago.
18294616d0f9Sopenharmony_ci**	It does a binary search of the time_t space. Since time_t's are
18304616d0f9Sopenharmony_ci**	just 32 bits, its a max of 32 iterations (even at 64 bits it
18314616d0f9Sopenharmony_ci**	would still be very reasonable).
18324616d0f9Sopenharmony_ci*/
18334616d0f9Sopenharmony_ci
18344616d0f9Sopenharmony_ci#ifndef WRONG
18354616d0f9Sopenharmony_ci# define WRONG (-1)
18364616d0f9Sopenharmony_ci#endif /* !defined WRONG */
18374616d0f9Sopenharmony_ci
18384616d0f9Sopenharmony_ci/*
18394616d0f9Sopenharmony_ci** Normalize logic courtesy Paul Eggert.
18404616d0f9Sopenharmony_ci*/
18414616d0f9Sopenharmony_ci
18424616d0f9Sopenharmony_cistatic bool
18434616d0f9Sopenharmony_ciincrement_overflow(int *ip, int j)
18444616d0f9Sopenharmony_ci{
18454616d0f9Sopenharmony_ci#ifdef ckd_add
18464616d0f9Sopenharmony_ci	return ckd_add(ip, *ip, j);
18474616d0f9Sopenharmony_ci#else
18484616d0f9Sopenharmony_ci	register int const	i = *ip;
18494616d0f9Sopenharmony_ci
18504616d0f9Sopenharmony_ci	/*
18514616d0f9Sopenharmony_ci	** If i >= 0 there can only be overflow if i + j > INT_MAX
18524616d0f9Sopenharmony_ci	** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
18534616d0f9Sopenharmony_ci	** If i < 0 there can only be overflow if i + j < INT_MIN
18544616d0f9Sopenharmony_ci	** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
18554616d0f9Sopenharmony_ci	*/
18564616d0f9Sopenharmony_ci	if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
18574616d0f9Sopenharmony_ci		return true;
18584616d0f9Sopenharmony_ci	*ip += j;
18594616d0f9Sopenharmony_ci	return false;
18604616d0f9Sopenharmony_ci#endif
18614616d0f9Sopenharmony_ci}
18624616d0f9Sopenharmony_ci
18634616d0f9Sopenharmony_cistatic bool
18644616d0f9Sopenharmony_ciincrement_overflow32(int_fast32_t *const lp, int const m)
18654616d0f9Sopenharmony_ci{
18664616d0f9Sopenharmony_ci#ifdef ckd_add
18674616d0f9Sopenharmony_ci	return ckd_add(lp, *lp, m);
18684616d0f9Sopenharmony_ci#else
18694616d0f9Sopenharmony_ci	register int_fast32_t const	l = *lp;
18704616d0f9Sopenharmony_ci
18714616d0f9Sopenharmony_ci	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
18724616d0f9Sopenharmony_ci		return true;
18734616d0f9Sopenharmony_ci	*lp += m;
18744616d0f9Sopenharmony_ci	return false;
18754616d0f9Sopenharmony_ci#endif
18764616d0f9Sopenharmony_ci}
18774616d0f9Sopenharmony_ci
18784616d0f9Sopenharmony_cistatic bool
18794616d0f9Sopenharmony_ciincrement_overflow_time(time_t *tp, int_fast32_t j)
18804616d0f9Sopenharmony_ci{
18814616d0f9Sopenharmony_ci#ifdef ckd_add
18824616d0f9Sopenharmony_ci	return ckd_add(tp, *tp, j);
18834616d0f9Sopenharmony_ci#else
18844616d0f9Sopenharmony_ci	/*
18854616d0f9Sopenharmony_ci	** This is like
18864616d0f9Sopenharmony_ci	** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
18874616d0f9Sopenharmony_ci	** except that it does the right thing even if *tp + j would overflow.
18884616d0f9Sopenharmony_ci	*/
18894616d0f9Sopenharmony_ci	if (! (j < 0
18904616d0f9Sopenharmony_ci	       ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
18914616d0f9Sopenharmony_ci	       : *tp <= TIME_T_MAX - j))
18924616d0f9Sopenharmony_ci		return true;
18934616d0f9Sopenharmony_ci	*tp += j;
18944616d0f9Sopenharmony_ci	return false;
18954616d0f9Sopenharmony_ci#endif
18964616d0f9Sopenharmony_ci}
18974616d0f9Sopenharmony_ci
18984616d0f9Sopenharmony_cistatic bool
18994616d0f9Sopenharmony_cinormalize_overflow(int *const tensptr, int *const unitsptr, const int base)
19004616d0f9Sopenharmony_ci{
19014616d0f9Sopenharmony_ci	register int	tensdelta;
19024616d0f9Sopenharmony_ci
19034616d0f9Sopenharmony_ci	tensdelta = (*unitsptr >= 0) ?
19044616d0f9Sopenharmony_ci		(*unitsptr / base) :
19054616d0f9Sopenharmony_ci		(-1 - (-1 - *unitsptr) / base);
19064616d0f9Sopenharmony_ci	*unitsptr -= tensdelta * base;
19074616d0f9Sopenharmony_ci	return increment_overflow(tensptr, tensdelta);
19084616d0f9Sopenharmony_ci}
19094616d0f9Sopenharmony_ci
19104616d0f9Sopenharmony_cistatic bool
19114616d0f9Sopenharmony_cinormalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
19124616d0f9Sopenharmony_ci{
19134616d0f9Sopenharmony_ci	register int	tensdelta;
19144616d0f9Sopenharmony_ci
19154616d0f9Sopenharmony_ci	tensdelta = (*unitsptr >= 0) ?
19164616d0f9Sopenharmony_ci		(*unitsptr / base) :
19174616d0f9Sopenharmony_ci		(-1 - (-1 - *unitsptr) / base);
19184616d0f9Sopenharmony_ci	*unitsptr -= tensdelta * base;
19194616d0f9Sopenharmony_ci	return increment_overflow32(tensptr, tensdelta);
19204616d0f9Sopenharmony_ci}
19214616d0f9Sopenharmony_ci
19224616d0f9Sopenharmony_cistatic int
19234616d0f9Sopenharmony_citmcomp(register const struct tm *const atmp,
19244616d0f9Sopenharmony_ci       register const struct tm *const btmp)
19254616d0f9Sopenharmony_ci{
19264616d0f9Sopenharmony_ci	register int	result;
19274616d0f9Sopenharmony_ci
19284616d0f9Sopenharmony_ci	if (atmp->tm_year != btmp->tm_year)
19294616d0f9Sopenharmony_ci		return atmp->tm_year < btmp->tm_year ? -1 : 1;
19304616d0f9Sopenharmony_ci	if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
19314616d0f9Sopenharmony_ci		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
19324616d0f9Sopenharmony_ci		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
19334616d0f9Sopenharmony_ci		(result = (atmp->tm_min - btmp->tm_min)) == 0)
19344616d0f9Sopenharmony_ci			result = atmp->tm_sec - btmp->tm_sec;
19354616d0f9Sopenharmony_ci	return result;
19364616d0f9Sopenharmony_ci}
19374616d0f9Sopenharmony_ci
19384616d0f9Sopenharmony_ci/* Copy to *DEST from *SRC.  Copy only the members needed for mktime,
19394616d0f9Sopenharmony_ci   as other members might not be initialized.  */
19404616d0f9Sopenharmony_cistatic void
19414616d0f9Sopenharmony_cimktmcpy(struct tm *dest, struct tm const *src)
19424616d0f9Sopenharmony_ci{
19434616d0f9Sopenharmony_ci  dest->tm_sec = src->tm_sec;
19444616d0f9Sopenharmony_ci  dest->tm_min = src->tm_min;
19454616d0f9Sopenharmony_ci  dest->tm_hour = src->tm_hour;
19464616d0f9Sopenharmony_ci  dest->tm_mday = src->tm_mday;
19474616d0f9Sopenharmony_ci  dest->tm_mon = src->tm_mon;
19484616d0f9Sopenharmony_ci  dest->tm_year = src->tm_year;
19494616d0f9Sopenharmony_ci  dest->tm_isdst = src->tm_isdst;
19504616d0f9Sopenharmony_ci#if defined TM_GMTOFF && ! UNINIT_TRAP
19514616d0f9Sopenharmony_ci  dest->TM_GMTOFF = src->TM_GMTOFF;
19524616d0f9Sopenharmony_ci#endif
19534616d0f9Sopenharmony_ci}
19544616d0f9Sopenharmony_ci
19554616d0f9Sopenharmony_cistatic time_t
19564616d0f9Sopenharmony_citime2sub(struct tm *const tmp,
19574616d0f9Sopenharmony_ci	 struct tm *(*funcp)(struct state const *, time_t const *,
19584616d0f9Sopenharmony_ci			     int_fast32_t, struct tm *),
19594616d0f9Sopenharmony_ci	 struct state const *sp,
19604616d0f9Sopenharmony_ci	 const int_fast32_t offset,
19614616d0f9Sopenharmony_ci	 bool *okayp,
19624616d0f9Sopenharmony_ci	 bool do_norm_secs)
19634616d0f9Sopenharmony_ci{
19644616d0f9Sopenharmony_ci	register int			dir;
19654616d0f9Sopenharmony_ci	register int			i, j;
19664616d0f9Sopenharmony_ci	register int			saved_seconds;
19674616d0f9Sopenharmony_ci	register int_fast32_t		li;
19684616d0f9Sopenharmony_ci	register time_t			lo;
19694616d0f9Sopenharmony_ci	register time_t			hi;
19704616d0f9Sopenharmony_ci	int_fast32_t			y;
19714616d0f9Sopenharmony_ci	time_t				newt;
19724616d0f9Sopenharmony_ci	time_t				t;
19734616d0f9Sopenharmony_ci	struct tm			yourtm, mytm;
19744616d0f9Sopenharmony_ci
19754616d0f9Sopenharmony_ci	*okayp = false;
19764616d0f9Sopenharmony_ci	mktmcpy(&yourtm, tmp);
19774616d0f9Sopenharmony_ci
19784616d0f9Sopenharmony_ci	if (do_norm_secs) {
19794616d0f9Sopenharmony_ci		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
19804616d0f9Sopenharmony_ci			SECSPERMIN))
19814616d0f9Sopenharmony_ci				return WRONG;
19824616d0f9Sopenharmony_ci	}
19834616d0f9Sopenharmony_ci	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
19844616d0f9Sopenharmony_ci		return WRONG;
19854616d0f9Sopenharmony_ci	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
19864616d0f9Sopenharmony_ci		return WRONG;
19874616d0f9Sopenharmony_ci	y = yourtm.tm_year;
19884616d0f9Sopenharmony_ci	if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
19894616d0f9Sopenharmony_ci		return WRONG;
19904616d0f9Sopenharmony_ci	/*
19914616d0f9Sopenharmony_ci	** Turn y into an actual year number for now.
19924616d0f9Sopenharmony_ci	** It is converted back to an offset from TM_YEAR_BASE later.
19934616d0f9Sopenharmony_ci	*/
19944616d0f9Sopenharmony_ci	if (increment_overflow32(&y, TM_YEAR_BASE))
19954616d0f9Sopenharmony_ci		return WRONG;
19964616d0f9Sopenharmony_ci	while (yourtm.tm_mday <= 0) {
19974616d0f9Sopenharmony_ci		if (increment_overflow32(&y, -1))
19984616d0f9Sopenharmony_ci			return WRONG;
19994616d0f9Sopenharmony_ci		li = y + (1 < yourtm.tm_mon);
20004616d0f9Sopenharmony_ci		yourtm.tm_mday += year_lengths[isleap(li)];
20014616d0f9Sopenharmony_ci	}
20024616d0f9Sopenharmony_ci	while (yourtm.tm_mday > DAYSPERLYEAR) {
20034616d0f9Sopenharmony_ci		li = y + (1 < yourtm.tm_mon);
20044616d0f9Sopenharmony_ci		yourtm.tm_mday -= year_lengths[isleap(li)];
20054616d0f9Sopenharmony_ci		if (increment_overflow32(&y, 1))
20064616d0f9Sopenharmony_ci			return WRONG;
20074616d0f9Sopenharmony_ci	}
20084616d0f9Sopenharmony_ci	for ( ; ; ) {
20094616d0f9Sopenharmony_ci		i = mon_lengths[isleap(y)][yourtm.tm_mon];
20104616d0f9Sopenharmony_ci		if (yourtm.tm_mday <= i)
20114616d0f9Sopenharmony_ci			break;
20124616d0f9Sopenharmony_ci		yourtm.tm_mday -= i;
20134616d0f9Sopenharmony_ci		if (++yourtm.tm_mon >= MONSPERYEAR) {
20144616d0f9Sopenharmony_ci			yourtm.tm_mon = 0;
20154616d0f9Sopenharmony_ci			if (increment_overflow32(&y, 1))
20164616d0f9Sopenharmony_ci				return WRONG;
20174616d0f9Sopenharmony_ci		}
20184616d0f9Sopenharmony_ci	}
20194616d0f9Sopenharmony_ci#ifdef ckd_add
20204616d0f9Sopenharmony_ci	if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
20214616d0f9Sopenharmony_ci	  return WRONG;
20224616d0f9Sopenharmony_ci#else
20234616d0f9Sopenharmony_ci	if (increment_overflow32(&y, -TM_YEAR_BASE))
20244616d0f9Sopenharmony_ci		return WRONG;
20254616d0f9Sopenharmony_ci	if (! (INT_MIN <= y && y <= INT_MAX))
20264616d0f9Sopenharmony_ci		return WRONG;
20274616d0f9Sopenharmony_ci	yourtm.tm_year = y;
20284616d0f9Sopenharmony_ci#endif
20294616d0f9Sopenharmony_ci	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
20304616d0f9Sopenharmony_ci		saved_seconds = 0;
20314616d0f9Sopenharmony_ci	else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
20324616d0f9Sopenharmony_ci		/*
20334616d0f9Sopenharmony_ci		** We can't set tm_sec to 0, because that might push the
20344616d0f9Sopenharmony_ci		** time below the minimum representable time.
20354616d0f9Sopenharmony_ci		** Set tm_sec to 59 instead.
20364616d0f9Sopenharmony_ci		** This assumes that the minimum representable time is
20374616d0f9Sopenharmony_ci		** not in the same minute that a leap second was deleted from,
20384616d0f9Sopenharmony_ci		** which is a safer assumption than using 58 would be.
20394616d0f9Sopenharmony_ci		*/
20404616d0f9Sopenharmony_ci		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
20414616d0f9Sopenharmony_ci			return WRONG;
20424616d0f9Sopenharmony_ci		saved_seconds = yourtm.tm_sec;
20434616d0f9Sopenharmony_ci		yourtm.tm_sec = SECSPERMIN - 1;
20444616d0f9Sopenharmony_ci	} else {
20454616d0f9Sopenharmony_ci		saved_seconds = yourtm.tm_sec;
20464616d0f9Sopenharmony_ci		yourtm.tm_sec = 0;
20474616d0f9Sopenharmony_ci	}
20484616d0f9Sopenharmony_ci	/*
20494616d0f9Sopenharmony_ci	** Do a binary search (this works whatever time_t's type is).
20504616d0f9Sopenharmony_ci	*/
20514616d0f9Sopenharmony_ci	lo = TIME_T_MIN;
20524616d0f9Sopenharmony_ci	hi = TIME_T_MAX;
20534616d0f9Sopenharmony_ci	for ( ; ; ) {
20544616d0f9Sopenharmony_ci		t = lo / 2 + hi / 2;
20554616d0f9Sopenharmony_ci		if (t < lo)
20564616d0f9Sopenharmony_ci			t = lo;
20574616d0f9Sopenharmony_ci		else if (t > hi)
20584616d0f9Sopenharmony_ci			t = hi;
20594616d0f9Sopenharmony_ci		if (! funcp(sp, &t, offset, &mytm)) {
20604616d0f9Sopenharmony_ci			/*
20614616d0f9Sopenharmony_ci			** Assume that t is too extreme to be represented in
20624616d0f9Sopenharmony_ci			** a struct tm; arrange things so that it is less
20634616d0f9Sopenharmony_ci			** extreme on the next pass.
20644616d0f9Sopenharmony_ci			*/
20654616d0f9Sopenharmony_ci			dir = (t > 0) ? 1 : -1;
20664616d0f9Sopenharmony_ci		} else	dir = tmcomp(&mytm, &yourtm);
20674616d0f9Sopenharmony_ci		if (dir != 0) {
20684616d0f9Sopenharmony_ci			if (t == lo) {
20694616d0f9Sopenharmony_ci				if (t == TIME_T_MAX)
20704616d0f9Sopenharmony_ci					return WRONG;
20714616d0f9Sopenharmony_ci				++t;
20724616d0f9Sopenharmony_ci				++lo;
20734616d0f9Sopenharmony_ci			} else if (t == hi) {
20744616d0f9Sopenharmony_ci				if (t == TIME_T_MIN)
20754616d0f9Sopenharmony_ci					return WRONG;
20764616d0f9Sopenharmony_ci				--t;
20774616d0f9Sopenharmony_ci				--hi;
20784616d0f9Sopenharmony_ci			}
20794616d0f9Sopenharmony_ci			if (lo > hi)
20804616d0f9Sopenharmony_ci				return WRONG;
20814616d0f9Sopenharmony_ci			if (dir > 0)
20824616d0f9Sopenharmony_ci				hi = t;
20834616d0f9Sopenharmony_ci			else	lo = t;
20844616d0f9Sopenharmony_ci			continue;
20854616d0f9Sopenharmony_ci		}
20864616d0f9Sopenharmony_ci#if defined TM_GMTOFF && ! UNINIT_TRAP
20874616d0f9Sopenharmony_ci		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
20884616d0f9Sopenharmony_ci		    && (yourtm.TM_GMTOFF < 0
20894616d0f9Sopenharmony_ci			? (-SECSPERDAY <= yourtm.TM_GMTOFF
20904616d0f9Sopenharmony_ci			   && (mytm.TM_GMTOFF <=
20914616d0f9Sopenharmony_ci			       (min(INT_FAST32_MAX, LONG_MAX)
20924616d0f9Sopenharmony_ci				+ yourtm.TM_GMTOFF)))
20934616d0f9Sopenharmony_ci			: (yourtm.TM_GMTOFF <= SECSPERDAY
20944616d0f9Sopenharmony_ci			   && ((max(INT_FAST32_MIN, LONG_MIN)
20954616d0f9Sopenharmony_ci				+ yourtm.TM_GMTOFF)
20964616d0f9Sopenharmony_ci			       <= mytm.TM_GMTOFF)))) {
20974616d0f9Sopenharmony_ci		  /* MYTM matches YOURTM except with the wrong UT offset.
20984616d0f9Sopenharmony_ci		     YOURTM.TM_GMTOFF is plausible, so try it instead.
20994616d0f9Sopenharmony_ci		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
21004616d0f9Sopenharmony_ci		     since the guess gets checked.  */
21014616d0f9Sopenharmony_ci		  time_t altt = t;
21024616d0f9Sopenharmony_ci		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
21034616d0f9Sopenharmony_ci		  if (!increment_overflow_time(&altt, diff)) {
21044616d0f9Sopenharmony_ci		    struct tm alttm;
21054616d0f9Sopenharmony_ci		    if (funcp(sp, &altt, offset, &alttm)
21064616d0f9Sopenharmony_ci			&& alttm.tm_isdst == mytm.tm_isdst
21074616d0f9Sopenharmony_ci			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
21084616d0f9Sopenharmony_ci			&& tmcomp(&alttm, &yourtm) == 0) {
21094616d0f9Sopenharmony_ci		      t = altt;
21104616d0f9Sopenharmony_ci		      mytm = alttm;
21114616d0f9Sopenharmony_ci		    }
21124616d0f9Sopenharmony_ci		  }
21134616d0f9Sopenharmony_ci		}
21144616d0f9Sopenharmony_ci#endif
21154616d0f9Sopenharmony_ci		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
21164616d0f9Sopenharmony_ci			break;
21174616d0f9Sopenharmony_ci		/*
21184616d0f9Sopenharmony_ci		** Right time, wrong type.
21194616d0f9Sopenharmony_ci		** Hunt for right time, right type.
21204616d0f9Sopenharmony_ci		** It's okay to guess wrong since the guess
21214616d0f9Sopenharmony_ci		** gets checked.
21224616d0f9Sopenharmony_ci		*/
21234616d0f9Sopenharmony_ci		if (sp == NULL)
21244616d0f9Sopenharmony_ci			return WRONG;
21254616d0f9Sopenharmony_ci		for (i = sp->typecnt - 1; i >= 0; --i) {
21264616d0f9Sopenharmony_ci			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
21274616d0f9Sopenharmony_ci				continue;
21284616d0f9Sopenharmony_ci			for (j = sp->typecnt - 1; j >= 0; --j) {
21294616d0f9Sopenharmony_ci				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
21304616d0f9Sopenharmony_ci					continue;
21314616d0f9Sopenharmony_ci				if (ttunspecified(sp, j))
21324616d0f9Sopenharmony_ci				  continue;
21334616d0f9Sopenharmony_ci				newt = (t + sp->ttis[j].tt_utoff
21344616d0f9Sopenharmony_ci					- sp->ttis[i].tt_utoff);
21354616d0f9Sopenharmony_ci				if (! funcp(sp, &newt, offset, &mytm))
21364616d0f9Sopenharmony_ci					continue;
21374616d0f9Sopenharmony_ci				if (tmcomp(&mytm, &yourtm) != 0)
21384616d0f9Sopenharmony_ci					continue;
21394616d0f9Sopenharmony_ci				if (mytm.tm_isdst != yourtm.tm_isdst)
21404616d0f9Sopenharmony_ci					continue;
21414616d0f9Sopenharmony_ci				/*
21424616d0f9Sopenharmony_ci				** We have a match.
21434616d0f9Sopenharmony_ci				*/
21444616d0f9Sopenharmony_ci				t = newt;
21454616d0f9Sopenharmony_ci				goto label;
21464616d0f9Sopenharmony_ci			}
21474616d0f9Sopenharmony_ci		}
21484616d0f9Sopenharmony_ci		return WRONG;
21494616d0f9Sopenharmony_ci	}
21504616d0f9Sopenharmony_cilabel:
21514616d0f9Sopenharmony_ci	newt = t + saved_seconds;
21524616d0f9Sopenharmony_ci	if ((newt < t) != (saved_seconds < 0))
21534616d0f9Sopenharmony_ci		return WRONG;
21544616d0f9Sopenharmony_ci	t = newt;
21554616d0f9Sopenharmony_ci	if (funcp(sp, &t, offset, tmp))
21564616d0f9Sopenharmony_ci		*okayp = true;
21574616d0f9Sopenharmony_ci	return t;
21584616d0f9Sopenharmony_ci}
21594616d0f9Sopenharmony_ci
21604616d0f9Sopenharmony_cistatic time_t
21614616d0f9Sopenharmony_citime2(struct tm * const	tmp,
21624616d0f9Sopenharmony_ci      struct tm *(*funcp)(struct state const *, time_t const *,
21634616d0f9Sopenharmony_ci			  int_fast32_t, struct tm *),
21644616d0f9Sopenharmony_ci      struct state const *sp,
21654616d0f9Sopenharmony_ci      const int_fast32_t offset,
21664616d0f9Sopenharmony_ci      bool *okayp)
21674616d0f9Sopenharmony_ci{
21684616d0f9Sopenharmony_ci	time_t	t;
21694616d0f9Sopenharmony_ci
21704616d0f9Sopenharmony_ci	/*
21714616d0f9Sopenharmony_ci	** First try without normalization of seconds
21724616d0f9Sopenharmony_ci	** (in case tm_sec contains a value associated with a leap second).
21734616d0f9Sopenharmony_ci	** If that fails, try with normalization of seconds.
21744616d0f9Sopenharmony_ci	*/
21754616d0f9Sopenharmony_ci	t = time2sub(tmp, funcp, sp, offset, okayp, false);
21764616d0f9Sopenharmony_ci	return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
21774616d0f9Sopenharmony_ci}
21784616d0f9Sopenharmony_ci
21794616d0f9Sopenharmony_cistatic time_t
21804616d0f9Sopenharmony_citime1(struct tm *const tmp,
21814616d0f9Sopenharmony_ci      struct tm *(*funcp)(struct state const *, time_t const *,
21824616d0f9Sopenharmony_ci			  int_fast32_t, struct tm *),
21834616d0f9Sopenharmony_ci      struct state const *sp,
21844616d0f9Sopenharmony_ci      const int_fast32_t offset)
21854616d0f9Sopenharmony_ci{
21864616d0f9Sopenharmony_ci	register time_t			t;
21874616d0f9Sopenharmony_ci	register int			samei, otheri;
21884616d0f9Sopenharmony_ci	register int			sameind, otherind;
21894616d0f9Sopenharmony_ci	register int			i;
21904616d0f9Sopenharmony_ci	register int			nseen;
21914616d0f9Sopenharmony_ci	char				seen[TZ_MAX_TYPES];
21924616d0f9Sopenharmony_ci	unsigned char			types[TZ_MAX_TYPES];
21934616d0f9Sopenharmony_ci	bool				okay;
21944616d0f9Sopenharmony_ci
21954616d0f9Sopenharmony_ci	if (tmp == NULL) {
21964616d0f9Sopenharmony_ci		errno = EINVAL;
21974616d0f9Sopenharmony_ci		return WRONG;
21984616d0f9Sopenharmony_ci	}
21994616d0f9Sopenharmony_ci	if (tmp->tm_isdst > 1)
22004616d0f9Sopenharmony_ci		tmp->tm_isdst = 1;
22014616d0f9Sopenharmony_ci	t = time2(tmp, funcp, sp, offset, &okay);
22024616d0f9Sopenharmony_ci	if (okay)
22034616d0f9Sopenharmony_ci		return t;
22044616d0f9Sopenharmony_ci	if (tmp->tm_isdst < 0)
22054616d0f9Sopenharmony_ci#ifdef PCTS
22064616d0f9Sopenharmony_ci		/*
22074616d0f9Sopenharmony_ci		** POSIX Conformance Test Suite code courtesy Grant Sullivan.
22084616d0f9Sopenharmony_ci		*/
22094616d0f9Sopenharmony_ci		tmp->tm_isdst = 0;	/* reset to std and try again */
22104616d0f9Sopenharmony_ci#else
22114616d0f9Sopenharmony_ci		return t;
22124616d0f9Sopenharmony_ci#endif /* !defined PCTS */
22134616d0f9Sopenharmony_ci	/*
22144616d0f9Sopenharmony_ci	** We're supposed to assume that somebody took a time of one type
22154616d0f9Sopenharmony_ci	** and did some math on it that yielded a "struct tm" that's bad.
22164616d0f9Sopenharmony_ci	** We try to divine the type they started from and adjust to the
22174616d0f9Sopenharmony_ci	** type they need.
22184616d0f9Sopenharmony_ci	*/
22194616d0f9Sopenharmony_ci	if (sp == NULL)
22204616d0f9Sopenharmony_ci		return WRONG;
22214616d0f9Sopenharmony_ci	for (i = 0; i < sp->typecnt; ++i)
22224616d0f9Sopenharmony_ci		seen[i] = false;
22234616d0f9Sopenharmony_ci	nseen = 0;
22244616d0f9Sopenharmony_ci	for (i = sp->timecnt - 1; i >= 0; --i)
22254616d0f9Sopenharmony_ci		if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
22264616d0f9Sopenharmony_ci			seen[sp->types[i]] = true;
22274616d0f9Sopenharmony_ci			types[nseen++] = sp->types[i];
22284616d0f9Sopenharmony_ci		}
22294616d0f9Sopenharmony_ci	for (sameind = 0; sameind < nseen; ++sameind) {
22304616d0f9Sopenharmony_ci		samei = types[sameind];
22314616d0f9Sopenharmony_ci		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
22324616d0f9Sopenharmony_ci			continue;
22334616d0f9Sopenharmony_ci		for (otherind = 0; otherind < nseen; ++otherind) {
22344616d0f9Sopenharmony_ci			otheri = types[otherind];
22354616d0f9Sopenharmony_ci			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
22364616d0f9Sopenharmony_ci				continue;
22374616d0f9Sopenharmony_ci			tmp->tm_sec += (sp->ttis[otheri].tt_utoff
22384616d0f9Sopenharmony_ci					- sp->ttis[samei].tt_utoff);
22394616d0f9Sopenharmony_ci			tmp->tm_isdst = !tmp->tm_isdst;
22404616d0f9Sopenharmony_ci			t = time2(tmp, funcp, sp, offset, &okay);
22414616d0f9Sopenharmony_ci			if (okay)
22424616d0f9Sopenharmony_ci				return t;
22434616d0f9Sopenharmony_ci			tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
22444616d0f9Sopenharmony_ci					- sp->ttis[samei].tt_utoff);
22454616d0f9Sopenharmony_ci			tmp->tm_isdst = !tmp->tm_isdst;
22464616d0f9Sopenharmony_ci		}
22474616d0f9Sopenharmony_ci	}
22484616d0f9Sopenharmony_ci	return WRONG;
22494616d0f9Sopenharmony_ci}
22504616d0f9Sopenharmony_ci
22514616d0f9Sopenharmony_cistatic time_t
22524616d0f9Sopenharmony_cimktime_tzname(struct state *sp, struct tm *tmp, bool setname)
22534616d0f9Sopenharmony_ci{
22544616d0f9Sopenharmony_ci  if (sp)
22554616d0f9Sopenharmony_ci    return time1(tmp, localsub, sp, setname);
22564616d0f9Sopenharmony_ci  else {
22574616d0f9Sopenharmony_ci    gmtcheck();
22584616d0f9Sopenharmony_ci    return time1(tmp, gmtsub, gmtptr, 0);
22594616d0f9Sopenharmony_ci  }
22604616d0f9Sopenharmony_ci}
22614616d0f9Sopenharmony_ci
22624616d0f9Sopenharmony_ci#if NETBSD_INSPIRED
22634616d0f9Sopenharmony_ci
22644616d0f9Sopenharmony_citime_t
22654616d0f9Sopenharmony_cimktime_z(struct state *restrict sp, struct tm *restrict tmp)
22664616d0f9Sopenharmony_ci{
22674616d0f9Sopenharmony_ci  return mktime_tzname(sp, tmp, false);
22684616d0f9Sopenharmony_ci}
22694616d0f9Sopenharmony_ci
22704616d0f9Sopenharmony_ci#endif
22714616d0f9Sopenharmony_ci
22724616d0f9Sopenharmony_citime_t
22734616d0f9Sopenharmony_cimktime(struct tm *tmp)
22744616d0f9Sopenharmony_ci{
22754616d0f9Sopenharmony_ci  time_t t;
22764616d0f9Sopenharmony_ci  int err = lock();
22774616d0f9Sopenharmony_ci  if (err) {
22784616d0f9Sopenharmony_ci    errno = err;
22794616d0f9Sopenharmony_ci    return -1;
22804616d0f9Sopenharmony_ci  }
22814616d0f9Sopenharmony_ci  tzset_unlocked();
22824616d0f9Sopenharmony_ci  t = mktime_tzname(lclptr, tmp, true);
22834616d0f9Sopenharmony_ci  unlock();
22844616d0f9Sopenharmony_ci  return t;
22854616d0f9Sopenharmony_ci}
22864616d0f9Sopenharmony_ci
22874616d0f9Sopenharmony_ci#if STD_INSPIRED
22884616d0f9Sopenharmony_ci/* This function is obsolescent and may disapper in future releases.
22894616d0f9Sopenharmony_ci   Callers can instead use mktime.  */
22904616d0f9Sopenharmony_citime_t
22914616d0f9Sopenharmony_citimelocal(struct tm *tmp)
22924616d0f9Sopenharmony_ci{
22934616d0f9Sopenharmony_ci	if (tmp != NULL)
22944616d0f9Sopenharmony_ci		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
22954616d0f9Sopenharmony_ci	return mktime(tmp);
22964616d0f9Sopenharmony_ci}
22974616d0f9Sopenharmony_ci#endif
22984616d0f9Sopenharmony_ci
22994616d0f9Sopenharmony_ci#ifndef EXTERN_TIMEOFF
23004616d0f9Sopenharmony_ci# ifndef timeoff
23014616d0f9Sopenharmony_ci#  define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>.  */
23024616d0f9Sopenharmony_ci# endif
23034616d0f9Sopenharmony_ci# define EXTERN_TIMEOFF static
23044616d0f9Sopenharmony_ci#endif
23054616d0f9Sopenharmony_ci
23064616d0f9Sopenharmony_ci/* This function is obsolescent and may disapper in future releases.
23074616d0f9Sopenharmony_ci   Callers can instead use mktime_z with a fixed-offset zone.  */
23084616d0f9Sopenharmony_ciEXTERN_TIMEOFF time_t
23094616d0f9Sopenharmony_citimeoff(struct tm *tmp, long offset)
23104616d0f9Sopenharmony_ci{
23114616d0f9Sopenharmony_ci  if (tmp)
23124616d0f9Sopenharmony_ci    tmp->tm_isdst = 0;
23134616d0f9Sopenharmony_ci  gmtcheck();
23144616d0f9Sopenharmony_ci  return time1(tmp, gmtsub, gmtptr, offset);
23154616d0f9Sopenharmony_ci}
23164616d0f9Sopenharmony_ci
23174616d0f9Sopenharmony_citime_t
23184616d0f9Sopenharmony_citimegm(struct tm *tmp)
23194616d0f9Sopenharmony_ci{
23204616d0f9Sopenharmony_ci  time_t t;
23214616d0f9Sopenharmony_ci  struct tm tmcpy;
23224616d0f9Sopenharmony_ci  mktmcpy(&tmcpy, tmp);
23234616d0f9Sopenharmony_ci  tmcpy.tm_wday = -1;
23244616d0f9Sopenharmony_ci  t = timeoff(&tmcpy, 0);
23254616d0f9Sopenharmony_ci  if (0 <= tmcpy.tm_wday)
23264616d0f9Sopenharmony_ci    *tmp = tmcpy;
23274616d0f9Sopenharmony_ci  return t;
23284616d0f9Sopenharmony_ci}
23294616d0f9Sopenharmony_ci
23304616d0f9Sopenharmony_cistatic int_fast32_t
23314616d0f9Sopenharmony_cileapcorr(struct state const *sp, time_t t)
23324616d0f9Sopenharmony_ci{
23334616d0f9Sopenharmony_ci	register struct lsinfo const *	lp;
23344616d0f9Sopenharmony_ci	register int			i;
23354616d0f9Sopenharmony_ci
23364616d0f9Sopenharmony_ci	i = sp->leapcnt;
23374616d0f9Sopenharmony_ci	while (--i >= 0) {
23384616d0f9Sopenharmony_ci		lp = &sp->lsis[i];
23394616d0f9Sopenharmony_ci		if (t >= lp->ls_trans)
23404616d0f9Sopenharmony_ci			return lp->ls_corr;
23414616d0f9Sopenharmony_ci	}
23424616d0f9Sopenharmony_ci	return 0;
23434616d0f9Sopenharmony_ci}
23444616d0f9Sopenharmony_ci
23454616d0f9Sopenharmony_ci/*
23464616d0f9Sopenharmony_ci** XXX--is the below the right way to conditionalize??
23474616d0f9Sopenharmony_ci*/
23484616d0f9Sopenharmony_ci
23494616d0f9Sopenharmony_ci#if STD_INSPIRED
23504616d0f9Sopenharmony_ci
23514616d0f9Sopenharmony_ci/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
23524616d0f9Sopenharmony_ci   NETBSD_INSPIRED is defined, and are private otherwise.  */
23534616d0f9Sopenharmony_ci# if NETBSD_INSPIRED
23544616d0f9Sopenharmony_ci#  define NETBSD_INSPIRED_EXTERN
23554616d0f9Sopenharmony_ci# else
23564616d0f9Sopenharmony_ci#  define NETBSD_INSPIRED_EXTERN static
23574616d0f9Sopenharmony_ci# endif
23584616d0f9Sopenharmony_ci
23594616d0f9Sopenharmony_ci/*
23604616d0f9Sopenharmony_ci** IEEE Std 1003.1 (POSIX) says that 536457599
23614616d0f9Sopenharmony_ci** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
23624616d0f9Sopenharmony_ci** is not the case if we are accounting for leap seconds.
23634616d0f9Sopenharmony_ci** So, we provide the following conversion routines for use
23644616d0f9Sopenharmony_ci** when exchanging timestamps with POSIX conforming systems.
23654616d0f9Sopenharmony_ci*/
23664616d0f9Sopenharmony_ci
23674616d0f9Sopenharmony_ciNETBSD_INSPIRED_EXTERN time_t
23684616d0f9Sopenharmony_citime2posix_z(struct state *sp, time_t t)
23694616d0f9Sopenharmony_ci{
23704616d0f9Sopenharmony_ci  return t - leapcorr(sp, t);
23714616d0f9Sopenharmony_ci}
23724616d0f9Sopenharmony_ci
23734616d0f9Sopenharmony_citime_t
23744616d0f9Sopenharmony_citime2posix(time_t t)
23754616d0f9Sopenharmony_ci{
23764616d0f9Sopenharmony_ci  int err = lock();
23774616d0f9Sopenharmony_ci  if (err) {
23784616d0f9Sopenharmony_ci    errno = err;
23794616d0f9Sopenharmony_ci    return -1;
23804616d0f9Sopenharmony_ci  }
23814616d0f9Sopenharmony_ci  if (!lcl_is_set)
23824616d0f9Sopenharmony_ci    tzset_unlocked();
23834616d0f9Sopenharmony_ci  if (lclptr)
23844616d0f9Sopenharmony_ci    t = time2posix_z(lclptr, t);
23854616d0f9Sopenharmony_ci  unlock();
23864616d0f9Sopenharmony_ci  return t;
23874616d0f9Sopenharmony_ci}
23884616d0f9Sopenharmony_ci
23894616d0f9Sopenharmony_ciNETBSD_INSPIRED_EXTERN time_t
23904616d0f9Sopenharmony_ciposix2time_z(struct state *sp, time_t t)
23914616d0f9Sopenharmony_ci{
23924616d0f9Sopenharmony_ci	time_t	x;
23934616d0f9Sopenharmony_ci	time_t	y;
23944616d0f9Sopenharmony_ci	/*
23954616d0f9Sopenharmony_ci	** For a positive leap second hit, the result
23964616d0f9Sopenharmony_ci	** is not unique. For a negative leap second
23974616d0f9Sopenharmony_ci	** hit, the corresponding time doesn't exist,
23984616d0f9Sopenharmony_ci	** so we return an adjacent second.
23994616d0f9Sopenharmony_ci	*/
24004616d0f9Sopenharmony_ci	x = t + leapcorr(sp, t);
24014616d0f9Sopenharmony_ci	y = x - leapcorr(sp, x);
24024616d0f9Sopenharmony_ci	if (y < t) {
24034616d0f9Sopenharmony_ci		do {
24044616d0f9Sopenharmony_ci			x++;
24054616d0f9Sopenharmony_ci			y = x - leapcorr(sp, x);
24064616d0f9Sopenharmony_ci		} while (y < t);
24074616d0f9Sopenharmony_ci		x -= y != t;
24084616d0f9Sopenharmony_ci	} else if (y > t) {
24094616d0f9Sopenharmony_ci		do {
24104616d0f9Sopenharmony_ci			--x;
24114616d0f9Sopenharmony_ci			y = x - leapcorr(sp, x);
24124616d0f9Sopenharmony_ci		} while (y > t);
24134616d0f9Sopenharmony_ci		x += y != t;
24144616d0f9Sopenharmony_ci	}
24154616d0f9Sopenharmony_ci	return x;
24164616d0f9Sopenharmony_ci}
24174616d0f9Sopenharmony_ci
24184616d0f9Sopenharmony_citime_t
24194616d0f9Sopenharmony_ciposix2time(time_t t)
24204616d0f9Sopenharmony_ci{
24214616d0f9Sopenharmony_ci  int err = lock();
24224616d0f9Sopenharmony_ci  if (err) {
24234616d0f9Sopenharmony_ci    errno = err;
24244616d0f9Sopenharmony_ci    return -1;
24254616d0f9Sopenharmony_ci  }
24264616d0f9Sopenharmony_ci  if (!lcl_is_set)
24274616d0f9Sopenharmony_ci    tzset_unlocked();
24284616d0f9Sopenharmony_ci  if (lclptr)
24294616d0f9Sopenharmony_ci    t = posix2time_z(lclptr, t);
24304616d0f9Sopenharmony_ci  unlock();
24314616d0f9Sopenharmony_ci  return t;
24324616d0f9Sopenharmony_ci}
24334616d0f9Sopenharmony_ci
24344616d0f9Sopenharmony_ci#endif /* STD_INSPIRED */
24354616d0f9Sopenharmony_ci
24364616d0f9Sopenharmony_ci#if TZ_TIME_T
24374616d0f9Sopenharmony_ci
24384616d0f9Sopenharmony_ci# if !USG_COMPAT
24394616d0f9Sopenharmony_ci#  define daylight 0
24404616d0f9Sopenharmony_ci#  define timezone 0
24414616d0f9Sopenharmony_ci# endif
24424616d0f9Sopenharmony_ci# if !ALTZONE
24434616d0f9Sopenharmony_ci#  define altzone 0
24444616d0f9Sopenharmony_ci# endif
24454616d0f9Sopenharmony_ci
24464616d0f9Sopenharmony_ci/* Convert from the underlying system's time_t to the ersatz time_tz,
24474616d0f9Sopenharmony_ci   which is called 'time_t' in this file.  Typically, this merely
24484616d0f9Sopenharmony_ci   converts the time's integer width.  On some platforms, the system
24494616d0f9Sopenharmony_ci   time is local time not UT, or uses some epoch other than the POSIX
24504616d0f9Sopenharmony_ci   epoch.
24514616d0f9Sopenharmony_ci
24524616d0f9Sopenharmony_ci   Although this code appears to define a function named 'time' that
24534616d0f9Sopenharmony_ci   returns time_t, the macros in private.h cause this code to actually
24544616d0f9Sopenharmony_ci   define a function named 'tz_time' that returns tz_time_t.  The call
24554616d0f9Sopenharmony_ci   to sys_time invokes the underlying system's 'time' function.  */
24564616d0f9Sopenharmony_ci
24574616d0f9Sopenharmony_citime_t
24584616d0f9Sopenharmony_citime(time_t *p)
24594616d0f9Sopenharmony_ci{
24604616d0f9Sopenharmony_ci  time_t r = sys_time(0);
24614616d0f9Sopenharmony_ci  if (r != (time_t) -1) {
24624616d0f9Sopenharmony_ci    int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
24634616d0f9Sopenharmony_ci    if (increment_overflow32(&offset, -EPOCH_OFFSET)
24644616d0f9Sopenharmony_ci	|| increment_overflow_time(&r, offset)) {
24654616d0f9Sopenharmony_ci      errno = EOVERFLOW;
24664616d0f9Sopenharmony_ci      r = -1;
24674616d0f9Sopenharmony_ci    }
24684616d0f9Sopenharmony_ci  }
24694616d0f9Sopenharmony_ci  if (p)
24704616d0f9Sopenharmony_ci    *p = r;
24714616d0f9Sopenharmony_ci  return r;
24724616d0f9Sopenharmony_ci}
24734616d0f9Sopenharmony_ci
24744616d0f9Sopenharmony_ci#endif
2475