aboutsummaryrefslogtreecommitdiff
path: root/contrib/tzcode/localtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tzcode/localtime.c')
-rw-r--r--contrib/tzcode/localtime.c854
1 files changed, 541 insertions, 313 deletions
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index a6ec3d8e4e21..a80d422f2955 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -13,42 +13,116 @@
/*LINTLIBRARY*/
#define LOCALTIME_IMPLEMENTATION
+#ifdef __FreeBSD__
#include "namespace.h"
+#include <pthread.h>
+#endif /* __FreeBSD__ */
#ifdef DETECT_TZ_CHANGES
-#ifndef DETECT_TZ_CHANGES_INTERVAL
-#define DETECT_TZ_CHANGES_INTERVAL 61
-#endif
+# ifndef DETECT_TZ_CHANGES_INTERVAL
+# define DETECT_TZ_CHANGES_INTERVAL 61
+# endif
int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
-#include <sys/stat.h>
-#endif
-#include <fcntl.h>
-#if THREAD_SAFE
-#include <pthread.h>
-#endif
+# include <sys/stat.h>
+#endif /* DETECT_TZ_CHANGES */
#include "private.h"
-#include "un-namespace.h"
#include "tzdir.h"
#include "tzfile.h"
-
+#include <fcntl.h>
+#ifdef __FreeBSD__
#include "libc_private.h"
+#include "un-namespace.h"
+#endif /* __FreeBSD__ */
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if !defined S_ISREG && defined S_IFREG
+/* Ancient UNIX or recent MS-Windows. */
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
#if defined THREAD_SAFE && THREAD_SAFE
+# include <pthread.h>
+#ifdef __FreeBSD__
+# define pthread_mutex_lock(l) (__isthreaded ? _pthread_mutex_lock(l) : 0)
+# define pthread_mutex_unlock(l) (__isthreaded ? _pthread_mutex_unlock(l) : 0)
+#endif /* __FreeBSD__ */
static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
-static int lock(void) {
- if (__isthreaded)
- return _pthread_mutex_lock(&locallock);
- return 0;
-}
-static void unlock(void) {
- if (__isthreaded)
- _pthread_mutex_unlock(&locallock);
-}
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
#else
static int lock(void) { return 0; }
static void unlock(void) { }
#endif
+/* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs.
+ Use this carefully, as the casts disable type checking.
+ This is a macro so that it can be used in static initializers. */
+#ifdef INTPTR_MAX
+# define UNCONST(a) ((char *) (intptr_t) (a))
+#else
+# define UNCONST(a) ((char *) (a))
+#endif
+
+/* A signed type wider than int, so that we can add 1900 + tm_mon/12 to tm_year
+ without overflow. The static_assert checks that it is indeed wider
+ than int; if this fails on your platform please let us know. */
+#if INT_MAX < LONG_MAX
+typedef long iinntt;
+# define IINNTT_MIN LONG_MIN
+# define IINNTT_MAX LONG_MAX
+#elif INT_MAX < LLONG_MAX
+typedef long long iinntt;
+# define IINNTT_MIN LLONG_MIN
+# define IINNTT_MAX LLONG_MAX
+#else
+typedef intmax_t iinntt;
+# define IINNTT_MIN INTMAX_MIN
+# define IINNTT_MAX INTMAX_MAX
+#endif
+static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX);
+
+/* On platforms where offtime or mktime might overflow,
+ strftime.c defines USE_TIMEX_T to be true and includes us.
+ This tells us to #define time_t to an internal type timex_t that is
+ wide enough so that strftime %s never suffers from integer overflow,
+ and to #define offtime (if TM_GMTOFF is defined) or mktime (otherwise)
+ to a static function that returns the redefined time_t.
+ It also tells us to define only data and code needed
+ to support the offtime or mktime variant. */
+#ifndef USE_TIMEX_T
+# define USE_TIMEX_T false
+#endif
+#if USE_TIMEX_T
+# undef TIME_T_MIN
+# undef TIME_T_MAX
+# undef time_t
+# define time_t timex_t
+# if MKTIME_FITS_IN(LONG_MIN, LONG_MAX)
+typedef long timex_t;
+# define TIME_T_MIN LONG_MIN
+# define TIME_T_MAX LONG_MAX
+# elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX)
+typedef long long timex_t;
+# define TIME_T_MIN LLONG_MIN
+# define TIME_T_MAX LLONG_MAX
+# else
+typedef intmax_t timex_t;
+# define TIME_T_MIN INTMAX_MIN
+# define TIME_T_MAX INTMAX_MAX
+# endif
+
+# ifdef TM_GMTOFF
+# undef timeoff
+# define timeoff timex_timeoff
+# undef EXTERN_TIMEOFF
+# else
+# undef mktime
+# define mktime timex_mktime
+# endif
+#endif
+
#ifndef TZ_ABBR_CHAR_SET
# define TZ_ABBR_CHAR_SET \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
@@ -58,12 +132,23 @@ static void unlock(void) { }
# define TZ_ABBR_ERR_CHAR '_'
#endif /* !defined TZ_ABBR_ERR_CHAR */
-/*
-** Support non-POSIX platforms that distinguish between text and binary files.
-*/
+/* Port to platforms that lack some O_* flags. Unless otherwise
+ specified, the flags are standardized by POSIX. */
#ifndef O_BINARY
-# define O_BINARY 0
+# define O_BINARY 0 /* MS-Windows */
+#endif
+#ifndef O_CLOEXEC
+# define O_CLOEXEC 0
+#endif
+#ifndef O_CLOFORK
+# define O_CLOFORK 0
+#endif
+#ifndef O_IGNORE_CTTY
+# define O_IGNORE_CTTY 0 /* GNU/Hurd */
+#endif
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
#endif
#ifndef WILDABBR
@@ -92,7 +177,10 @@ static void unlock(void) { }
static const char wildabbr[] = WILDABBR;
static char const etc_utc[] = "Etc/UTC";
+
+#if !USE_TIMEX_T || defined TM_ZONE || !defined TM_GMTOFF
static char const *utc = etc_utc + sizeof "Etc/" - 1;
+#endif
/*
** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
@@ -104,10 +192,31 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1;
# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
#endif
+/* Limit to time zone abbreviation length in proleptic TZ strings.
+ This is distinct from TZ_MAX_CHARS, which limits TZif file contents.
+ It defaults to 254, not 255, so that desigidx_type can be an unsigned char.
+ unsigned char suffices for TZif files, so the only reason to increase
+ TZNAME_MAXIMUM is to support TZ strings specifying abbreviations
+ longer than 254 bytes. There is little reason to do that, though,
+ as strings that long are hardly "abbreviations". */
+#ifndef TZNAME_MAXIMUM
+# define TZNAME_MAXIMUM 254
+#endif
+
+#if TZNAME_MAXIMUM < UCHAR_MAX
+typedef unsigned char desigidx_type;
+#elif TZNAME_MAXIMUM < INT_MAX
+typedef int desigidx_type;
+#elif TZNAME_MAXIMUM < PTRDIFF_MAX
+typedef ptrdiff_t desigidx_type;
+#else
+# error "TZNAME_MAXIMUM too large"
+#endif
+
struct ttinfo { /* time type information */
- int_fast32_t tt_utoff; /* UT offset in seconds */
+ int_least32_t tt_utoff; /* UT offset in seconds */
+ desigidx_type tt_desigidx; /* abbreviation list index */
bool tt_isdst; /* used to set tm_isdst */
- int tt_desigidx; /* abbreviation list index */
bool tt_ttisstd; /* transition is std time */
bool tt_ttisut; /* transition is UT */
};
@@ -126,12 +235,6 @@ static char const UNSPEC[] = "-00";
for ttunspecified to work without crashing. */
enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
-/* Limit to time zone abbreviation length in proleptic TZ strings.
- This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
-#ifndef TZNAME_MAXIMUM
-# define TZNAME_MAXIMUM 255
-#endif
-
/* A representation of the contents of a TZif file. Ideally this
would have no size limits; the following sizes should suffice for
practical use. This struct should not be too large, as instances
@@ -166,12 +269,14 @@ struct rule {
int_fast32_t r_time; /* transition time of rule */
};
+#ifdef __FreeBSD__
+static void tzset_unlocked_name(char const *);
+#endif /* __FreeBSD__ */
static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
struct tm *);
static bool increment_overflow(int *, int);
static bool increment_overflow_time(time_t *, int_fast32_t);
static int_fast32_t leapcorr(struct state const *, time_t);
-static bool normalize_overflow32(int_fast32_t *, int *, int);
static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
struct tm *);
static bool tzparse(char const *, struct state *, struct state const *);
@@ -192,9 +297,11 @@ static struct state *const gmtptr = &gmtmem;
# define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */
+#if !USE_TIMEX_T || !defined TM_GMTOFF
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
-
+#endif
+#ifdef __FreeBSD__
static pthread_once_t gmt_once = PTHREAD_ONCE_INIT;
static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT;
static pthread_key_t gmtime_key;
@@ -205,6 +312,7 @@ static int offtime_key_error;
static pthread_once_t localtime_once = PTHREAD_ONCE_INIT;
static pthread_key_t localtime_key;
static int localtime_key_error;
+#endif /* __FreeBSD__ */
/*
** Section 4.12.3 of X3.159-1989 requires that
@@ -218,27 +326,29 @@ static int localtime_key_error;
** trigger latent bugs in programs.
*/
-#if SUPPORT_C89
+#if !USE_TIMEX_T
+
+# if SUPPORT_C89
static struct tm tm;
#endif
-#if 2 <= HAVE_TZNAME + TZ_TIME_T
-char * tzname[2] = {
- (char *) wildabbr,
- (char *) wildabbr
-};
-#endif
-#if 2 <= USG_COMPAT + TZ_TIME_T
+# if 2 <= HAVE_TZNAME + TZ_TIME_T
+char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) };
+# endif
+# if 2 <= USG_COMPAT + TZ_TIME_T
long timezone;
int daylight;
-#endif
-#if 2 <= ALTZONE + TZ_TIME_T
+# endif
+# if 2 <= ALTZONE + TZ_TIME_T
long altzone;
+# endif
+
#endif
/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
static void
-init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
+init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst,
+ desigidx_type desigidx)
{
s->tt_utoff = utoff;
s->tt_isdst = isdst;
@@ -302,20 +412,22 @@ detzcode64(const char *const codep)
return result;
}
+#if !USE_TIMEX_T || !defined TM_GMTOFF
+
static void
update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
{
-#if HAVE_TZNAME
- tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
-#endif
-#if USG_COMPAT
+# if HAVE_TZNAME
+ tzname[ttisp->tt_isdst] = UNCONST(&sp->chars[ttisp->tt_desigidx]);
+# endif
+# if USG_COMPAT
if (!ttisp->tt_isdst)
timezone = - ttisp->tt_utoff;
-#endif
-#if ALTZONE
+# endif
+# if ALTZONE
if (ttisp->tt_isdst)
altzone = - ttisp->tt_utoff;
-#endif
+# endif
}
/* If STDDST_MASK indicates that SP's TYPE provides useful info,
@@ -346,18 +458,18 @@ settzname(void)
When STDDST_MASK becomes zero we can stop looking. */
int stddst_mask = 0;
-#if HAVE_TZNAME
- tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
+# if HAVE_TZNAME
+ tzname[0] = tzname[1] = UNCONST(sp ? wildabbr : utc);
stddst_mask = 3;
-#endif
-#if USG_COMPAT
+# endif
+# if USG_COMPAT
timezone = 0;
stddst_mask = 3;
-#endif
-#if ALTZONE
+# endif
+# if ALTZONE
altzone = 0;
stddst_mask |= 2;
-#endif
+# endif
/*
** And to get the latest time zone abbreviations into tzname. . .
*/
@@ -367,9 +479,9 @@ settzname(void)
for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
}
-#if USG_COMPAT
+# if USG_COMPAT
daylight = stddst_mask >> 1 ^ 1;
-#endif
+# endif
}
/* Replace bogus characters in time zone abbreviations.
@@ -396,21 +508,24 @@ scrub_abbrs(struct state *sp)
return 0;
}
+#endif
+
#ifdef DETECT_TZ_CHANGES
/*
- * Determine if there's a change in the timezone since the last time we checked.
+ * Check whether either the time zone name or the file it refers to has
+ * changed since the last time we checked.
* Returns: -1 on error
- * 0 if the timezone has not changed
- * 1 if the timezone has changed
+ * 0 if the time zone has not changed
+ * 1 if the time zone has changed
*/
static int
-change_in_tz(const char *name)
+tzfile_changed(const char *name, int fd)
{
static char old_name[PATH_MAX];
static struct stat old_sb;
struct stat sb;
- if (stat(name, &sb) != 0)
+ if (_fstat(fd, &sb) != 0)
return -1;
if (strcmp(name, old_name) != 0) {
@@ -429,9 +544,7 @@ change_in_tz(const char *name)
return 0;
}
-#else /* !DETECT_TZ_CHANGES */
-#define change_in_tz(X) 1
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
/* Input buffer for data read from a compiled tz file. */
union input_buffer {
@@ -444,8 +557,10 @@ union input_buffer {
+ 4 * TZ_MAX_TIMES];
};
+#ifndef __FreeBSD__
/* TZDIR with a trailing '/' rather than a trailing '\0'. */
static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
+#endif /* !__FreeBSD__ */
/* Local storage needed for 'tzloadbody'. */
union local_storage {
@@ -458,6 +573,7 @@ union local_storage {
struct state st;
} u;
+#ifndef __FreeBSD__
/* The name of the file to be opened. Ideally this would have no
size limits, to support arbitrarily long Zone names.
Limiting Zone names to 1024 bytes should suffice for practical use.
@@ -465,19 +581,31 @@ union local_storage {
file_analysis as that struct is allocated anyway, as the other
union member. */
char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
+#endif /* !__FreeBSD__ */
};
-/* Load tz data from the file named NAME into *SP. Read extended
- format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
+/* These tzload flags can be ORed together, and fit into 'char'. */
+enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */
+enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */
+
+/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
+ Use *LSP for temporary storage. Return 0 on
success, an errno value on failure. */
static int
-tzloadbody(char const *name, struct state *sp, bool doextend,
+tzloadbody(char const *name, struct state *sp, char tzloadflags,
union local_storage *lsp)
{
register int i;
register int fid;
register int stored;
register ssize_t nread;
+#ifdef __FreeBSD__
+ struct stat sb;
+ const char *relname;
+ int dd, serrno;
+#else /* !__FreeBSD__ */
+ register bool doaccess;
+#endif /* !__FreeBSD__ */
register union input_buffer *up = &lsp->u.u;
register int tzheadsize = sizeof(struct tzhead);
@@ -491,7 +619,16 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (name[0] == ':')
++name;
- if (name[0] != '/') {
+#ifndef __FreeBSD__
+#ifdef SUPPRESS_TZDIR
+ /* Do not prepend TZDIR. This is intended for specialized
+ applications only, due to its security implications. */
+ doaccess = true;
+#else
+ doaccess = name[0] == '/';
+#endif
+ if (!doaccess) {
+ char const *dot;
if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
return ENAMETOOLONG;
@@ -501,27 +638,89 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
strcpy(lsp->fullname + sizeof tzdirslash, name);
+ /* Set doaccess if NAME contains a ".." file name
+ component, as such a name could read a file outside
+ the TZDIR virtual subtree. */
+ for (dot = name; (dot = strchr(dot, '.')); dot++)
+ if ((dot == name || dot[-1] == '/') && dot[1] == '.'
+ && (dot[2] == '/' || !dot[2])) {
+ doaccess = true;
+ break;
+ }
+
name = lsp->fullname;
}
- if (doextend) {
- /*
- * Detect if the timezone file has changed. Check
- * 'doextend' to ignore TZDEFRULES; the change_in_tz()
- * function can only keep state for a single file.
- */
- switch (change_in_tz(name)) {
- case -1:
- return errno;
- case 0:
- return 0;
- case 1:
- break;
- }
+ if (doaccess && (tzloadflags & TZLOAD_FROMENV)) {
+ /* Check for security violations and for devices whose mere
+ opening could have unwanted side effects. Although these
+ checks are racy, they're better than nothing and there is
+ no portable way to fix the races. */
+ if (access(name, R_OK) < 0)
+ return errno;
+#ifdef S_ISREG
+ {
+ struct stat st;
+ if (stat(name, &st) < 0)
+ return errno;
+ if (!S_ISREG(st.st_mode))
+ return EINVAL;
+ }
+#endif
+ }
+ fid = _open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
+ | O_IGNORE_CTTY | O_NOCTTY));
+#else /* __FreeBSD__ */
+ relname = name;
+ if (strncmp(relname, TZDIR "/", strlen(TZDIR) + 1) == 0)
+ relname += strlen(TZDIR) + 1;
+ dd = _open(TZDIR, O_DIRECTORY | O_RDONLY);
+ if (issetugid() && (tzloadflags & TZLOAD_FROMENV)) {
+ if (dd < 0)
+ return errno;
+ if (fstatat(dd, name, &sb, AT_RESOLVE_BENEATH) < 0) {
+ fid = -1;
+ } else if (!S_ISREG(sb.st_mode)) {
+ fid = -1;
+ errno = EINVAL;
+ } else {
+ fid = _openat(dd, relname, O_RDONLY | O_BINARY, AT_RESOLVE_BENEATH);
+ }
+ } else {
+ if (dd < 0) {
+ relname = name;
+ dd = AT_FDCWD;
+ }
+ fid = _openat(dd, relname, O_RDONLY | O_BINARY, 0);
}
- fid = _open(name, O_RDONLY | O_BINARY);
+ if (dd != AT_FDCWD && dd >= 0) {
+ serrno = errno;
+ _close(dd);
+ errno = serrno;
+ }
+#endif /* __FreeBSD__ */
if (fid < 0)
return errno;
+#ifdef DETECT_TZ_CHANGES
+ if (tzloadflags) {
+ /*
+ * Detect if the timezone file has changed. Check tzloadflags
+ * to ignore TZDEFRULES; the tzfile_changed() function can only
+ * keep state for a single file.
+ */
+ switch (tzfile_changed(name, fid)) {
+ case -1:
+ serrno = errno;
+ _close(fid);
+ return serrno;
+ case 0:
+ _close(fid);
+ return 0;
+ case 1:
+ break;
+ }
+ }
+#endif /* DETECT_TZ_CHANGES */
nread = _read(fid, up->buf, sizeof up->buf);
if (nread < tzheadsize) {
int err = nread < 0 ? errno : EINVAL;
@@ -645,7 +844,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
correction must differ from the previous one's by 1
second or less, except that the first correction can be
any value; these requirements are more generous than
- RFC 8536, to allow future RFC extensions. */
+ RFC 9636, to allow future RFC extensions. */
if (! (i == 0
|| (prevcorr < corr
? corr == prevcorr + 1
@@ -696,7 +895,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
if (!version)
break;
}
- if (doextend && nread > 2 &&
+ if ((tzloadflags & TZLOAD_TZSTRING) && nread > 2 &&
up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
sp->typecnt + 2 <= TZ_MAX_TYPES) {
struct state *ts = &lsp->u.st;
@@ -771,23 +970,23 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
return 0;
}
-/* Load tz data from the file named NAME into *SP. Read extended
- format if DOEXTEND. Return 0 on success, an errno value on failure. */
+/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS.
+ Return 0 on success, an errno value on failure. */
static int
-tzload(char const *name, struct state *sp, bool doextend)
+tzload(char const *name, struct state *sp, char tzloadflags)
{
#ifdef ALL_STATE
union local_storage *lsp = malloc(sizeof *lsp);
if (!lsp) {
return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
} else {
- int err = tzloadbody(name, sp, doextend, lsp);
+ int err = tzloadbody(name, sp, tzloadflags, lsp);
free(lsp);
return err;
}
#else
union local_storage ls;
- return tzloadbody(name, sp, doextend, &ls);
+ return tzloadbody(name, sp, tzloadflags, &ls);
#endif
}
@@ -1128,7 +1327,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
sp->leapcnt = basep->leapcnt;
memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
} else {
- load_ok = tzload(TZDEFRULES, sp, false) == 0;
+ load_ok = tzload(TZDEFRULES, sp, 0) == 0;
if (!load_ok)
sp->leapcnt = 0; /* So, we're off a little. */
}
@@ -1365,13 +1564,16 @@ tzparse(const char *name, struct state *sp, struct state const *basep)
static void
gmtload(struct state *const sp)
{
- if (tzload(etc_utc, sp, true) != 0)
+ if (tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0)
tzparse("UTC0", sp, NULL);
}
#ifdef DETECT_TZ_CHANGES
+/*
+ * Check if the time zone data we have is still fresh.
+ */
static int
-recheck_tzdata()
+tzdata_is_fresh(void)
{
static time_t last_checked;
struct timespec now;
@@ -1387,14 +1589,15 @@ recheck_tzdata()
return 0;
}
-#else /* !DETECT_TZ_CHANGES */
-#define recheck_tzdata() 0
-#endif /* !DETECT_TZ_CHANGES */
+#endif /* DETECT_TZ_CHANGES */
+
+#if !USE_TIMEX_T || !defined TM_GMTOFF
/* Initialize *SP to a value appropriate for the TZ setting NAME.
+ Respect TZLOADFLAGS.
Return 0 on success, an errno value on failure. */
static int
-zoneinit(struct state *sp, char const *name)
+zoneinit(struct state *sp, char const *name, char tzloadflags)
{
if (name && ! name[0]) {
/*
@@ -1409,7 +1612,7 @@ zoneinit(struct state *sp, char const *name)
strcpy(sp->chars, utc);
return 0;
} else {
- int err = tzload(name, sp, true);
+ int err = tzload(name, sp, tzloadflags);
if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
err = 0;
if (err == 0)
@@ -1419,22 +1622,35 @@ zoneinit(struct state *sp, char const *name)
}
static void
+tzset_unlocked(void)
+{
+#ifdef __FreeBSD__
+ tzset_unlocked_name(getenv("TZ"));
+}
+static void
tzset_unlocked_name(char const *name)
{
+#else
+ char const *name = getenv("TZ");
+#endif
struct state *sp = lclptr;
int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
if (lcl < 0
? lcl_is_set < 0
: 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
- if (recheck_tzdata() == 0)
- return;
-#ifdef ALL_STATE
+#ifdef DETECT_TZ_CHANGES
+ if (tzdata_is_fresh() == 0)
+#endif /* DETECT_TZ_CHANGES */
+ return;
+# ifdef ALL_STATE
if (! sp)
lclptr = sp = malloc(sizeof *lclptr);
-#endif /* defined ALL_STATE */
+# endif
if (sp) {
- if (zoneinit(sp, name) != 0)
- zoneinit(sp, "");
+ if (zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING) != 0) {
+ zoneinit(sp, "", 0);
+ strcpy(sp->chars, UNSPEC);
+ }
if (0 < lcl)
strcpy(lcl_TZname, name);
}
@@ -1442,12 +1658,9 @@ tzset_unlocked_name(char const *name)
lcl_is_set = lcl;
}
-static void
-tzset_unlocked(void)
-{
- tzset_unlocked_name(getenv("TZ"));
-}
+#endif
+#if !USE_TIMEX_T
void
tzset(void)
{
@@ -1456,7 +1669,9 @@ tzset(void)
tzset_unlocked();
unlock();
}
+#endif
+#ifdef __FreeBSD__
void
freebsd13_tzsetwall(void)
{
@@ -1468,7 +1683,7 @@ freebsd13_tzsetwall(void)
__sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0);
__warn_references(tzsetwall,
"warning: tzsetwall() is deprecated, use tzset() instead.");
-
+#endif /* __FreeBSD__ */
static void
gmtcheck(void)
{
@@ -1485,15 +1700,18 @@ gmtcheck(void)
}
unlock();
}
+#ifdef __FreeBSD__
+#define gmtcheck() _once(&gmt_once, gmtcheck)
+#endif
-#if NETBSD_INSPIRED
+#if NETBSD_INSPIRED && !USE_TIMEX_T
timezone_t
tzalloc(char const *name)
{
timezone_t sp = malloc(sizeof *sp);
if (sp) {
- int err = zoneinit(sp, name);
+ int err = zoneinit(sp, name, TZLOAD_TZSTRING);
if (err != 0) {
free(sp);
errno = err;
@@ -1522,6 +1740,8 @@ tzfree(timezone_t sp)
#endif
+#if !USE_TIMEX_T || !defined TM_GMTOFF
+
/*
** The easy way to behave "as if no library function calls" localtime
** is to not call it, so we drop its guts into "localsub", which can be
@@ -1576,14 +1796,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
return NULL; /* "cannot happen" */
result = localsub(sp, &newt, setname, tmp);
if (result) {
-#if defined ckd_add && defined ckd_sub
+# if defined ckd_add && defined ckd_sub
if (t < sp->ats[0]
? ckd_sub(&result->tm_year,
result->tm_year, years)
: ckd_add(&result->tm_year,
result->tm_year, years))
return NULL;
-#else
+# else
register int_fast64_t newy;
newy = result->tm_year;
@@ -1593,7 +1813,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
if (! (INT_MIN <= newy && newy <= INT_MAX))
return NULL;
result->tm_year = newy;
-#endif
+# endif
}
return result;
}
@@ -1622,25 +1842,26 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
result = timesub(&t, ttisp->tt_utoff, sp, tmp);
if (result) {
result->tm_isdst = ttisp->tt_isdst;
-#ifdef TM_ZONE
- result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
-#endif /* defined TM_ZONE */
+# ifdef TM_ZONE
+ result->TM_ZONE = UNCONST(&sp->chars[ttisp->tt_desigidx]);
+# endif
if (setname)
update_tzname_etc(sp, ttisp);
}
return result;
}
+#endif
-#if NETBSD_INSPIRED
+#if !USE_TIMEX_T
+# if NETBSD_INSPIRED
struct tm *
localtime_rz(struct state *restrict sp, time_t const *restrict timep,
struct tm *restrict tmp)
{
return localsub(sp, timep, 0, tmp);
}
-
-#endif
+# endif
static struct tm *
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
@@ -1652,45 +1873,47 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
}
#ifndef DETECT_TZ_CHANGES
if (setname || !lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
tmp = localsub(lclptr, timep, setname, tmp);
unlock();
return tmp;
}
+#ifdef __FreeBSD__
static void
localtime_key_init(void)
{
-
- localtime_key_error = _pthread_key_create(&localtime_key, free);
+ localtime_key_error = _pthread_key_create(&localtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
localtime(const time_t *timep)
{
-#if !SUPPORT_C89
- static struct tm tm;
-#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&localtime_once, localtime_key_init);
- if (localtime_key_error != 0) {
- errno = localtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(localtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return localtime_tzset(timep, p_tm, true);
+# if !SUPPORT_C89
+ static struct tm tm;
+# endif
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&localtime_once, localtime_key_init);
+ if (localtime_key_error != 0) {
+ errno = localtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(localtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
+#endif /* __FreeBSD__ */
+ return localtime_tzset(timep, p_tm, true);
}
struct tm *
@@ -1698,6 +1921,7 @@ localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
{
return localtime_tzset(timep, tmp, false);
}
+#endif
/*
** gmtsub is to gmtime as localsub is to localtime.
@@ -1716,12 +1940,14 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
** "+xx" or "-xx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
- tmp->TM_ZONE = ((char *)
- (offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
+ tmp->TM_ZONE = UNCONST(offset ? wildabbr
+ : gmtptr ? gmtptr->chars : utc);
#endif /* defined TM_ZONE */
return result;
}
+#if !USE_TIMEX_T
+
/*
* Re-entrant version of gmtime.
*/
@@ -1729,45 +1955,47 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
struct tm *
gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
{
- _once(&gmt_once, gmtcheck);
- return gmtsub(gmtptr, timep, 0, tmp);
+ gmtcheck();
+ return gmtsub(gmtptr, timep, 0, tmp);
}
+#ifdef __FreeBSD__
static void
gmtime_key_init(void)
{
-
- gmtime_key_error = _pthread_key_create(&gmtime_key, free);
+ gmtime_key_error = _pthread_key_create(&gmtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
gmtime(const time_t *timep)
{
-#if !SUPPORT_C89
- static struct tm tm;
-#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&gmtime_once, gmtime_key_init);
- if (gmtime_key_error != 0) {
- errno = gmtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return gmtime_r(timep, p_tm);
+# if !SUPPORT_C89
+ static struct tm tm;
+# endif
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&gmtime_once, gmtime_key_init);
+ if (gmtime_key_error != 0) {
+ errno = gmtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(gmtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
+#endif /* __FreeBSD__ */
+ return gmtime_r(timep, p_tm);
}
-#if STD_INSPIRED
+# if STD_INSPIRED
/* This function is obsolescent and may disappear in future releases.
Callers can instead use localtime_rz with a fixed-offset zone. */
@@ -1775,44 +2003,47 @@ gmtime(const time_t *timep)
struct tm *
offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp)
{
- _once(&gmt_once, gmtcheck);
- return gmtsub(gmtptr, timep, offset, tmp);
+ gmtcheck();
+ return gmtsub(gmtptr, timep, offset, tmp);
}
+#ifdef __FreeBSD__
static void
offtime_key_init(void)
{
-
- offtime_key_error = _pthread_key_create(&offtime_key, free);
+ offtime_key_error = _pthread_key_create(&offtime_key, free);
}
-
+#endif /* __FreeBSD__ */
struct tm *
offtime(const time_t *timep, long offset)
{
-#if !SUPPORT_C89
- static struct tm tm;
+# if !SUPPORT_C89
+ static struct tm tm;
+# endif
+#ifdef __FreeBSD__
+ struct tm *p_tm = &tm;
+
+ if (__isthreaded != 0) {
+ _pthread_once(&offtime_once, offtime_key_init);
+ if (offtime_key_error != 0) {
+ errno = offtime_key_error;
+ return (NULL);
+ }
+ if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
+ if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
+ return (NULL);
+ }
+ if (_pthread_setspecific(offtime_key, p_tm) != 0) {
+ free(p_tm);
+ return (NULL);
+ }
+ }
+ }
#endif
- struct tm *p_tm = &tm;
-
- if (__isthreaded != 0) {
- _pthread_once(&offtime_once, offtime_key_init);
- if (offtime_key_error != 0) {
- errno = offtime_key_error;
- return (NULL);
- }
- if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) {
- if ((p_tm = malloc(sizeof(*p_tm))) == NULL) {
- return (NULL);
- }
- if (_pthread_setspecific(offtime_key, p_tm) != 0) {
- free(p_tm);
- return (NULL);
- }
- }
- }
- return offtime_r(timep, offset, p_tm);
+ return offtime_r(timep, offset, p_tm);
}
+# endif
#endif
/*
@@ -1871,7 +2102,7 @@ timesub(const time_t *timep, int_fast32_t offset,
dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
rem %= SECSPERDAY;
/* y = (EPOCH_YEAR
- + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
+ + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
sans overflow. But calculate against 1570 (EPOCH_YEAR -
YEARSPERREPEAT) instead of against 1970 so that things work
for localtime values before 1970 when time_t is unsigned. */
@@ -1988,17 +2219,17 @@ increment_overflow(int *ip, int j)
}
static bool
-increment_overflow32(int_fast32_t *const lp, int const m)
+increment_overflow_time_iinntt(time_t *tp, iinntt j)
{
#ifdef ckd_add
- return ckd_add(lp, *lp, m);
+ return ckd_add(tp, *tp, j);
#else
- register int_fast32_t const l = *lp;
-
- if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
- return true;
- *lp += m;
- return false;
+ if (j < 0
+ ? (TYPE_SIGNED(time_t) ? *tp < TIME_T_MIN - j : *tp <= -1 - j)
+ : TIME_T_MAX - j < *tp)
+ return true;
+ *tp += j;
+ return false;
#endif
}
@@ -2022,30 +2253,6 @@ increment_overflow_time(time_t *tp, int_fast32_t j)
#endif
}
-static bool
-normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
-{
- register int tensdelta;
-
- tensdelta = (*unitsptr >= 0) ?
- (*unitsptr / base) :
- (-1 - (-1 - *unitsptr) / base);
- *unitsptr -= tensdelta * base;
- return increment_overflow(tensptr, tensdelta);
-}
-
-static bool
-normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
-{
- register int tensdelta;
-
- tensdelta = (*unitsptr >= 0) ?
- (*unitsptr / base) :
- (-1 - (-1 - *unitsptr) / base);
- *unitsptr -= tensdelta * base;
- return increment_overflow32(tensptr, tensdelta);
-}
-
static int
tmcomp(register const struct tm *const atmp,
register const struct tm *const btmp)
@@ -2090,11 +2297,9 @@ time2sub(struct tm *const tmp,
{
register int dir;
register int i, j;
- register int saved_seconds;
- register int_fast32_t li;
register time_t lo;
register time_t hi;
- int_fast32_t y;
+ iinntt y, mday, hour, min, saved_seconds;
time_t newt;
time_t t;
struct tm yourtm, mytm;
@@ -2102,36 +2307,57 @@ time2sub(struct tm *const tmp,
*okayp = false;
mktmcpy(&yourtm, tmp);
+ min = yourtm.tm_min;
if (do_norm_secs) {
- if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
- SECSPERMIN))
- return WRONG;
+ min += yourtm.tm_sec / SECSPERMIN;
+ yourtm.tm_sec %= SECSPERMIN;
+ if (yourtm.tm_sec < 0) {
+ yourtm.tm_sec += SECSPERMIN;
+ min--;
+ }
}
- if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
- return WRONG;
- if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
- return WRONG;
+
+ hour = yourtm.tm_hour;
+ hour += min / MINSPERHOUR;
+ yourtm.tm_min = min % MINSPERHOUR;
+ if (yourtm.tm_min < 0) {
+ yourtm.tm_min += MINSPERHOUR;
+ hour--;
+ }
+
+ mday = yourtm.tm_mday;
+ mday += hour / HOURSPERDAY;
+ yourtm.tm_hour = hour % HOURSPERDAY;
+ if (yourtm.tm_hour < 0) {
+ yourtm.tm_hour += HOURSPERDAY;
+ mday--;
+ }
+
y = yourtm.tm_year;
- if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
- return WRONG;
+ y += yourtm.tm_mon / MONSPERYEAR;
+ yourtm.tm_mon %= MONSPERYEAR;
+ if (yourtm.tm_mon < 0) {
+ yourtm.tm_mon += MONSPERYEAR;
+ y--;
+ }
+
/*
** Turn y into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
- if (increment_overflow32(&y, TM_YEAR_BASE))
- return WRONG;
- while (yourtm.tm_mday <= 0) {
- if (increment_overflow32(&y, -1))
- return WRONG;
- li = y + (1 < yourtm.tm_mon);
- yourtm.tm_mday += year_lengths[isleap(li)];
+ y += TM_YEAR_BASE;
+
+ while (mday <= 0) {
+ iinntt li = y - (yourtm.tm_mon <= 1);
+ mday += year_lengths[isleap(li)];
+ y--;
}
- while (yourtm.tm_mday > DAYSPERLYEAR) {
- li = y + (1 < yourtm.tm_mon);
- yourtm.tm_mday -= year_lengths[isleap(li)];
- if (increment_overflow32(&y, 1))
- return WRONG;
+ while (DAYSPERLYEAR < mday) {
+ iinntt li = y + (1 < yourtm.tm_mon);
+ mday -= year_lengths[isleap(li)];
+ y++;
}
+ yourtm.tm_mday = mday;
for ( ; ; ) {
i = mon_lengths[isleap(y)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
@@ -2139,16 +2365,14 @@ time2sub(struct tm *const tmp,
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
- if (increment_overflow32(&y, 1))
- return WRONG;
+ y++;
}
}
#ifdef ckd_add
if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
return WRONG;
#else
- if (increment_overflow32(&y, -TM_YEAR_BASE))
- return WRONG;
+ y -= TM_YEAR_BASE;
if (! (INT_MIN <= y && y <= INT_MAX))
return WRONG;
yourtm.tm_year = y;
@@ -2164,9 +2388,8 @@ time2sub(struct tm *const tmp,
** not in the same minute that a leap second was deleted from,
** which is a safer assumption than using 58 would be.
*/
- if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
- return WRONG;
saved_seconds = yourtm.tm_sec;
+ saved_seconds -= SECSPERMIN - 1;
yourtm.tm_sec = SECSPERMIN - 1;
} else {
saved_seconds = yourtm.tm_sec;
@@ -2275,10 +2498,8 @@ time2sub(struct tm *const tmp,
return WRONG;
}
label:
- newt = t + saved_seconds;
- if ((newt < t) != (saved_seconds < 0))
+ if (increment_overflow_time_iinntt(&t, saved_seconds))
return WRONG;
- t = newt;
if (funcp(sp, &t, offset, tmp))
*okayp = true;
return t;
@@ -2323,7 +2544,6 @@ time1(struct tm *const tmp,
errno = EINVAL;
return WRONG;
}
-
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, funcp, sp, offset, &okay);
@@ -2376,27 +2596,22 @@ time1(struct tm *const tmp,
return WRONG;
}
+#if !defined TM_GMTOFF || !USE_TIMEX_T
+
static time_t
mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
{
if (sp)
return time1(tmp, localsub, sp, setname);
else {
- _once(&gmt_once, gmtcheck);
+ gmtcheck();
return time1(tmp, gmtsub, gmtptr, 0);
}
}
-#if NETBSD_INSPIRED
-
-time_t
-mktime_z(struct state *restrict sp, struct tm *restrict tmp)
-{
- return mktime_tzname(sp, tmp, false);
-}
-
-#endif
-
+# if USE_TIMEX_T
+static
+# endif
time_t
mktime(struct tm *tmp)
{
@@ -2412,7 +2627,17 @@ mktime(struct tm *tmp)
return t;
}
-#if STD_INSPIRED
+#endif
+
+#if NETBSD_INSPIRED && !USE_TIMEX_T
+time_t
+mktime_z(struct state *restrict sp, struct tm *restrict tmp)
+{
+ return mktime_tzname(sp, tmp, false);
+}
+#endif
+
+#if STD_INSPIRED && !USE_TIMEX_T
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime. */
time_t
@@ -2424,12 +2649,14 @@ timelocal(struct tm *tmp)
}
#endif
-#ifndef EXTERN_TIMEOFF
-# ifndef timeoff
-# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */
+#if defined TM_GMTOFF || !USE_TIMEX_T
+
+# ifndef EXTERN_TIMEOFF
+# ifndef timeoff
+# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */
+# endif
+# define EXTERN_TIMEOFF static
# endif
-# define EXTERN_TIMEOFF static
-#endif
/* This function is obsolescent and may disappear in future releases.
Callers can instead use mktime_z with a fixed-offset zone. */
@@ -2438,10 +2665,12 @@ timeoff(struct tm *tmp, long offset)
{
if (tmp)
tmp->tm_isdst = 0;
- _once(&gmt_once, gmtcheck);
+ gmtcheck();
return time1(tmp, gmtsub, gmtptr, offset);
}
+#endif
+#if !USE_TIMEX_T
time_t
timegm(struct tm *tmp)
{
@@ -2454,6 +2683,7 @@ timegm(struct tm *tmp)
*tmp = tmcpy;
return t;
}
+#endif
static int_fast32_t
leapcorr(struct state const *sp, time_t t)
@@ -2474,15 +2704,16 @@ leapcorr(struct state const *sp, time_t t)
** XXX--is the below the right way to conditionalize??
*/
-#if STD_INSPIRED
+#if !USE_TIMEX_T
+# if STD_INSPIRED
/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
NETBSD_INSPIRED is defined, and are private otherwise. */
-# if NETBSD_INSPIRED
-# define NETBSD_INSPIRED_EXTERN
-# else
-# define NETBSD_INSPIRED_EXTERN static
-# endif
+# if NETBSD_INSPIRED
+# define NETBSD_INSPIRED_EXTERN
+# else
+# define NETBSD_INSPIRED_EXTERN static
+# endif
/*
** IEEE Std 1003.1 (POSIX) says that 536457599
@@ -2508,7 +2739,7 @@ time2posix(time_t t)
}
#ifndef DETECT_TZ_CHANGES
if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
if (lclptr)
t = time2posix_z(lclptr, t);
@@ -2555,7 +2786,7 @@ posix2time(time_t t)
}
#ifndef DETECT_TZ_CHANGES
if (!lcl_is_set)
-#endif
+#endif /* DETECT_TZ_CHANGES */
tzset_unlocked();
if (lclptr)
t = posix2time_z(lclptr, t);
@@ -2563,17 +2794,13 @@ posix2time(time_t t)
return t;
}
-#endif /* STD_INSPIRED */
+# endif /* STD_INSPIRED */
-#if TZ_TIME_T
+# if TZ_TIME_T
-# if !USG_COMPAT
-# define daylight 0
-# define timezone 0
-# endif
-# if !ALTZONE
-# define altzone 0
-# endif
+# if !USG_COMPAT
+# define timezone 0
+# endif
/* Convert from the underlying system's time_t to the ersatz time_tz,
which is called 'time_t' in this file. Typically, this merely
@@ -2591,9 +2818,9 @@ time(time_t *p)
{
time_t r = sys_time(0);
if (r != (time_t) -1) {
- int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
- if (increment_overflow32(&offset, -EPOCH_OFFSET)
- || increment_overflow_time(&r, offset)) {
+ iinntt offset = EPOCH_LOCAL ? timezone : 0;
+ if (offset < IINNTT_MIN + EPOCH_OFFSET
+ || increment_overflow_time_iinntt(&r, offset - EPOCH_OFFSET)) {
errno = EOVERFLOW;
r = -1;
}
@@ -2603,4 +2830,5 @@ time(time_t *p)
return r;
}
+# endif
#endif