summaryrefslogtreecommitdiff
path: root/elsie.nci.nih.gov/src/localtime.c
diff options
context:
space:
mode:
authorStuart Bishop <stuart@stuartbishop.net>2014-09-01 10:11:26 +0000
committerStuart Bishop <stuart@stuartbishop.net>2014-09-01 10:11:26 +0000
commitc985dd429ec25d4233f1b26c0dc0517a66253b0c (patch)
treecce3e1ef8bd8d0c4e440f72a3d40e101b3b22e12 /elsie.nci.nih.gov/src/localtime.c
parent056207cdda4a8f01f7f0bd924e89d0df434c7547 (diff)
downloadpytz-c985dd429ec25d4233f1b26c0dc0517a66253b0c.tar.gz
Import 2014g
Diffstat (limited to 'elsie.nci.nih.gov/src/localtime.c')
-rw-r--r--elsie.nci.nih.gov/src/localtime.c934
1 files changed, 532 insertions, 402 deletions
diff --git a/elsie.nci.nih.gov/src/localtime.c b/elsie.nci.nih.gov/src/localtime.c
index ff07c70..622f7d4 100644
--- a/elsie.nci.nih.gov/src/localtime.c
+++ b/elsie.nci.nih.gov/src/localtime.c
@@ -10,10 +10,32 @@
/*LINTLIBRARY*/
+#define LOCALTIME_IMPLEMENTATION
#include "private.h"
+
#include "tzfile.h"
#include "fcntl.h"
+#if THREAD_SAFE
+# include <pthread.h>
+# define VOLATILE volatile
+static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
+static int lock(void) { return pthread_mutex_lock(&locallock); }
+static void unlock(void) { pthread_mutex_unlock(&locallock); }
+#else
+# define VOLATILE
+static int lock(void) { return 0; }
+static void unlock(void) { }
+#endif
+
+/* 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
+
#ifndef TZ_ABBR_MAX_LEN
#define TZ_ABBR_MAX_LEN 16
#endif /* !defined TZ_ABBR_MAX_LEN */
@@ -78,10 +100,10 @@ static const char gmt[] = "GMT";
struct ttinfo { /* time type information */
int_fast32_t tt_gmtoff; /* UT offset in seconds */
- int tt_isdst; /* used to set tm_isdst */
+ bool tt_isdst; /* used to set tm_isdst */
int tt_abbrind; /* abbreviation list index */
- int tt_ttisstd; /* TRUE if transition is std time */
- int tt_ttisgmt; /* TRUE if transition is UT */
+ bool tt_ttisstd; /* transition is std time */
+ bool tt_ttisgmt; /* transition is UT */
};
struct lsinfo { /* leap second information */
@@ -89,6 +111,7 @@ struct lsinfo { /* leap second information */
int_fast64_t ls_corr; /* correction to apply */
};
+#define SMALLEST(a, b) (((a) < (b)) ? (a) : (b))
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
#ifdef TZNAME_MAX
@@ -103,8 +126,8 @@ struct state {
int timecnt;
int typecnt;
int charcnt;
- int goback;
- int goahead;
+ bool goback;
+ bool goahead;
time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
@@ -115,70 +138,26 @@ struct state {
};
struct rule {
- int r_type; /* type of rule--see below */
+ int r_type; /* type of rule; see below */
int r_day; /* day number of rule */
int r_week; /* week number of rule */
int r_mon; /* month number of rule */
int_fast32_t r_time; /* transition time of rule */
};
-#define JULIAN_DAY 0 /* Jn - Julian day */
-#define DAY_OF_YEAR 1 /* n - day of year */
-#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
-
-/*
-** Prototypes for static functions.
-*/
+#define JULIAN_DAY 0 /* Jn = Julian day */
+#define DAY_OF_YEAR 1 /* n = day of year */
+#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d = month, week, day of week */
-static int_fast32_t detzcode(const char * codep);
-static int_fast64_t detzcode64(const char * codep);
-static int differ_by_repeat(time_t t1, time_t t0);
-static const char * getzname(const char * strp) ATTRIBUTE_PURE;
-static const char * getqzname(const char * strp, const int delim)
- ATTRIBUTE_PURE;
-static const char * getnum(const char * strp, int * nump, int min,
- int max);
-static const char * getsecs(const char * strp, int_fast32_t * secsp);
-static const char * getoffset(const char * strp, int_fast32_t * offsetp);
-static const char * getrule(const char * strp, struct rule * rulep);
-static void gmtload(struct state * sp);
-static struct tm * gmtsub(const time_t * timep, int_fast32_t offset,
- struct tm * tmp);
-static struct tm * localsub(const time_t * timep, int_fast32_t offset,
- struct tm * tmp);
-static int increment_overflow(int * number, int delta);
-static int leaps_thru_end_of(int y) ATTRIBUTE_PURE;
-static int increment_overflow32(int_fast32_t * number, int delta);
-static int increment_overflow_time(time_t *t, int_fast32_t delta);
-static int normalize_overflow32(int_fast32_t * tensptr,
- int * unitsptr, int base);
-static int normalize_overflow(int * tensptr, int * unitsptr,
- int base);
-static void settzname(void);
-static time_t time1(struct tm * tmp,
- struct tm * (*funcp)(const time_t *,
- int_fast32_t, struct tm *),
- int_fast32_t offset);
-static time_t time2(struct tm *tmp,
- struct tm * (*funcp)(const time_t *,
- int_fast32_t, struct tm*),
- int_fast32_t offset, int * okayp);
-static time_t time2sub(struct tm *tmp,
- struct tm * (*funcp)(const time_t *,
- int_fast32_t, struct tm*),
- int_fast32_t offset, int * okayp, int do_norm_secs);
-static struct tm * timesub(const time_t * timep, int_fast32_t offset,
- const struct state * sp, struct tm * tmp);
-static int tmcomp(const struct tm * atmp,
- const struct tm * btmp);
-static int_fast32_t transtime(int year, const struct rule * rulep,
- int_fast32_t offset)
- ATTRIBUTE_PURE;
-static int typesequiv(const struct state * sp, int a, int b);
-static int tzload(const char * name, struct state * sp,
- int doextend);
-static int tzparse(const char * name, struct state * sp,
- int lastditch);
+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 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 typesequiv(struct state const *, int, int);
+static bool tzparse(char const *, struct state *, bool);
#ifdef ALL_STATE
static struct state * lclptr;
@@ -197,8 +176,7 @@ static struct state gmtmem;
#endif /* !defined TZ_STRLEN_MAX */
static char lcl_TZname[TZ_STRLEN_MAX + 1];
-static int lcl_is_set;
-static int gmt_is_set;
+static int VOLATILE lcl_is_set;
char * tzname[2] = {
(char *) wildabbr,
@@ -312,7 +290,7 @@ settzname(void)
}
}
-static int
+static bool
differ_by_repeat(const time_t t1, const time_t t0)
{
if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
@@ -320,9 +298,9 @@ differ_by_repeat(const time_t t1, const time_t t0)
return t1 - t0 == SECSPERREPEAT;
}
-static int
+static bool
tzload(register const char *name, register struct state *const sp,
- register const int doextend)
+ bool doextend)
{
register const char * p;
register int i;
@@ -335,22 +313,7 @@ tzload(register const char *name, register struct state *const sp,
2 * sizeof *sp +
4 * TZ_MAX_TIMES];
} u_t;
-#ifdef ALL_STATE
- register u_t * const up = malloc(sizeof *up);
-#else /* !defined ALL_STATE */
- u_t u;
- register u_t * const up = &u;
-#endif /* !defined ALL_STATE */
-
- sp->goback = sp->goahead = FALSE;
-
- if (up == NULL)
- return -1;
-
- if (name == NULL && (name = TZDEFAULT) == NULL)
- goto oops;
- {
- register int doaccess;
+ union local_storage {
/*
** Section 4.9.1 of the C standard says that
** "FILENAME_MAX expands to an integral constant expression
@@ -360,82 +323,111 @@ tzload(register const char *name, register struct state *const sp,
*/
char fullname[FILENAME_MAX + 1];
- if (name[0] == ':')
- ++name;
- doaccess = name[0] == '/';
- if (!doaccess) {
- if ((p = TZDIR) == NULL)
- goto oops;
- if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
- goto oops;
- (void) strcpy(fullname, p);
- (void) strcat(fullname, "/");
- (void) strcat(fullname, name);
- /*
- ** Set doaccess if '.' (as in "../") shows up in name.
- */
- if (strchr(name, '.') != NULL)
- doaccess = TRUE;
- name = fullname;
- }
- if (doaccess && access(name, R_OK) != 0)
+ /* The main part of the storage for this function. */
+ struct {
+ u_t u;
+ struct state st;
+ } u;
+ };
+ register char *fullname;
+ register u_t *up;
+ register bool doaccess;
+ register union local_storage *lsp;
+#ifdef ALL_STATE
+ lsp = malloc(sizeof *lsp);
+ if (!lsp)
+ return false;
+#else /* !defined ALL_STATE */
+ union local_storage ls;
+ lsp = &ls;
+#endif /* !defined ALL_STATE */
+ fullname = lsp->fullname;
+ up = &lsp->u.u;
+
+ sp->goback = sp->goahead = false;
+
+ if (! name) {
+ name = TZDEFAULT;
+ if (! name)
goto oops;
- if ((fid = open(name, OPEN_MODE)) == -1)
+ }
+
+ if (name[0] == ':')
+ ++name;
+ doaccess = name[0] == '/';
+ if (!doaccess) {
+ p = TZDIR;
+ if (! p || sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
goto oops;
+ strcpy(fullname, p);
+ strcat(fullname, "/");
+ strcat(fullname, name);
+ /* Set doaccess if '.' (as in "../") shows up in name. */
+ if (strchr(name, '.'))
+ doaccess = true;
+ name = fullname;
}
+ if (doaccess && access(name, R_OK) != 0)
+ goto oops;
+ fid = open(name, OPEN_MODE);
+ if (fid < 0)
+ goto oops;
+
nread = read(fid, up->buf, sizeof up->buf);
if (close(fid) < 0 || nread <= 0)
goto oops;
for (stored = 4; stored <= 8; stored *= 2) {
- int ttisstdcnt;
- int ttisgmtcnt;
- int timecnt;
-
- ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
- ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
- sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
- sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
- sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
- sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
+ int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
+ int_fast32_t ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt);
+ int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
+ int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
+ int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
+ int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
- if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
- sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
- sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
- sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
- (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
- (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
+ if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
+ && 0 < typecnt && typecnt < TZ_MAX_TYPES
+ && 0 <= timecnt && timecnt < TZ_MAX_TIMES
+ && 0 <= charcnt && charcnt < TZ_MAX_CHARS
+ && (ttisstdcnt == typecnt || ttisstdcnt == 0)
+ && (ttisgmtcnt == typecnt || ttisgmtcnt == 0)))
goto oops;
- if (nread - (p - up->buf) <
- sp->timecnt * stored + /* ats */
- sp->timecnt + /* types */
- sp->typecnt * 6 + /* ttinfos */
- sp->charcnt + /* chars */
- sp->leapcnt * (stored + 4) + /* lsinfos */
- ttisstdcnt + /* ttisstds */
- ttisgmtcnt) /* ttisgmts */
+ if (nread - (p - up->buf)
+ < (timecnt * stored /* ats */
+ + timecnt /* types */
+ + typecnt * 6 /* ttinfos */
+ + charcnt /* chars */
+ + leapcnt * (stored + 4) /* lsinfos */
+ + ttisstdcnt /* ttisstds */
+ + ttisgmtcnt)) /* ttisgmts */
goto oops;
+ sp->leapcnt = leapcnt;
+ sp->timecnt = timecnt;
+ sp->typecnt = typecnt;
+ sp->charcnt = charcnt;
+
+ /* Read transitions, discarding those out of time_t range.
+ But pretend the last transition before time_t_min
+ occurred at time_t_min. */
timecnt = 0;
for (i = 0; i < sp->timecnt; ++i) {
int_fast64_t at
= stored == 4 ? detzcode(p) : detzcode64(p);
- sp->types[i] = ((TYPE_SIGNED(time_t)
- ? time_t_min <= at
- : 0 <= at)
- && at <= time_t_max);
+ sp->types[i] = at <= time_t_max;
if (sp->types[i]) {
- if (i && !timecnt && at != time_t_min) {
- /*
- ** Keep the earlier record, but tweak
- ** it so that it starts with the
- ** minimum time_t value.
- */
- sp->types[i - 1] = 1;
- sp->ats[timecnt++] = time_t_min;
- }
- sp->ats[timecnt++] = at;
+ time_t attime
+ = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
+ ? time_t_min : at);
+ if (timecnt && attime <= sp->ats[timecnt - 1]) {
+ if (attime < sp->ats[timecnt - 1])
+ goto oops;
+ sp->types[i - 1] = 0;
+ timecnt--;
+ }
+ sp->ats[timecnt++] = attime;
}
p += stored;
}
+
timecnt = 0;
for (i = 0; i < sp->timecnt; ++i) {
unsigned char typ = *p++;
@@ -447,42 +439,56 @@ tzload(register const char *name, register struct state *const sp,
sp->timecnt = timecnt;
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
+ unsigned char isdst, abbrind;
ttisp = &sp->ttis[i];
ttisp->tt_gmtoff = detzcode(p);
p += 4;
- ttisp->tt_isdst = (unsigned char) *p++;
- if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
- goto oops;
- ttisp->tt_abbrind = (unsigned char) *p++;
- if (ttisp->tt_abbrind < 0 ||
- ttisp->tt_abbrind > sp->charcnt)
- goto oops;
+ isdst = *p++;
+ if (! (isdst < 2))
+ goto oops;
+ ttisp->tt_isdst = isdst;
+ abbrind = *p++;
+ if (! (abbrind < sp->charcnt))
+ goto oops;
+ ttisp->tt_abbrind = abbrind;
}
for (i = 0; i < sp->charcnt; ++i)
sp->chars[i] = *p++;
sp->chars[i] = '\0'; /* ensure '\0' at end */
- for (i = 0; i < sp->leapcnt; ++i) {
- register struct lsinfo * lsisp;
- lsisp = &sp->lsis[i];
- lsisp->ls_trans = (stored == 4) ?
- detzcode(p) : detzcode64(p);
- p += stored;
- lsisp->ls_corr = detzcode(p);
- p += 4;
+ /* Read leap seconds, discarding those out of time_t range. */
+ leapcnt = 0;
+ for (i = 0; i < sp->leapcnt; ++i) {
+ int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
+ int_fast32_t corr = detzcode(p + stored);
+ p += stored + 4;
+ if (tr <= time_t_max) {
+ time_t trans
+ = ((TYPE_SIGNED(time_t) ? tr < time_t_min : tr < 0)
+ ? time_t_min : tr);
+ if (leapcnt && trans <= sp->lsis[leapcnt - 1].ls_trans) {
+ if (trans < sp->lsis[leapcnt - 1].ls_trans)
+ goto oops;
+ leapcnt--;
+ }
+ sp->lsis[leapcnt].ls_trans = trans;
+ sp->lsis[leapcnt].ls_corr = corr;
+ leapcnt++;
+ }
}
+ sp->leapcnt = leapcnt;
+
for (i = 0; i < sp->typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
if (ttisstdcnt == 0)
- ttisp->tt_ttisstd = FALSE;
+ ttisp->tt_ttisstd = false;
else {
- ttisp->tt_ttisstd = *p++;
- if (ttisp->tt_ttisstd != TRUE &&
- ttisp->tt_ttisstd != FALSE)
+ if (*p != true && *p != false)
goto oops;
+ ttisp->tt_ttisstd = *p++;
}
}
for (i = 0; i < sp->typecnt; ++i) {
@@ -490,12 +496,11 @@ tzload(register const char *name, register struct state *const sp,
ttisp = &sp->ttis[i];
if (ttisgmtcnt == 0)
- ttisp->tt_ttisgmt = FALSE;
+ ttisp->tt_ttisgmt = false;
else {
- ttisp->tt_ttisgmt = *p++;
- if (ttisp->tt_ttisgmt != TRUE &&
- ttisp->tt_ttisgmt != FALSE)
+ if (*p != true && *p != false)
goto oops;
+ ttisp->tt_ttisgmt = *p++;
}
}
/*
@@ -515,43 +520,42 @@ tzload(register const char *name, register struct state *const sp,
if (doextend && nread > 2 &&
up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
sp->typecnt + 2 <= TZ_MAX_TYPES) {
- struct state ts;
- register int result;
+ struct state *ts = &lsp->u.st;
up->buf[nread - 1] = '\0';
- result = tzparse(&up->buf[1], &ts, FALSE);
- if (result == 0 && ts.typecnt == 2 &&
- sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
+ if (tzparse(&up->buf[1], ts, false)
+ && ts->typecnt == 2
+ && sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
for (i = 0; i < 2; ++i)
- ts.ttis[i].tt_abbrind +=
+ ts->ttis[i].tt_abbrind +=
sp->charcnt;
- for (i = 0; i < ts.charcnt; ++i)
+ for (i = 0; i < ts->charcnt; ++i)
sp->chars[sp->charcnt++] =
- ts.chars[i];
+ ts->chars[i];
i = 0;
- while (i < ts.timecnt &&
- ts.ats[i] <=
+ while (i < ts->timecnt &&
+ ts->ats[i] <=
sp->ats[sp->timecnt - 1])
++i;
- while (i < ts.timecnt &&
+ while (i < ts->timecnt &&
sp->timecnt < TZ_MAX_TIMES) {
sp->ats[sp->timecnt] =
- ts.ats[i];
+ ts->ats[i];
sp->types[sp->timecnt] =
sp->typecnt +
- ts.types[i];
+ ts->types[i];
++sp->timecnt;
++i;
}
- sp->ttis[sp->typecnt++] = ts.ttis[0];
- sp->ttis[sp->typecnt++] = ts.ttis[1];
+ sp->ttis[sp->typecnt++] = ts->ttis[0];
+ sp->ttis[sp->typecnt++] = ts->ttis[1];
}
}
if (sp->timecnt > 1) {
for (i = 1; i < sp->timecnt; ++i)
if (typesequiv(sp, sp->types[i], sp->types[0]) &&
differ_by_repeat(sp->ats[i], sp->ats[0])) {
- sp->goback = TRUE;
+ sp->goback = true;
break;
}
for (i = sp->timecnt - 2; i >= 0; --i)
@@ -559,7 +563,7 @@ tzload(register const char *name, register struct state *const sp,
sp->types[i]) &&
differ_by_repeat(sp->ats[sp->timecnt - 1],
sp->ats[i])) {
- sp->goahead = TRUE;
+ sp->goahead = true;
break;
}
}
@@ -600,23 +604,23 @@ tzload(register const char *name, register struct state *const sp,
#ifdef ALL_STATE
free(up);
#endif /* defined ALL_STATE */
- return 0;
+ return true;
oops:
#ifdef ALL_STATE
free(up);
#endif /* defined ALL_STATE */
- return -1;
+ return false;
}
-static int
+static bool
typesequiv(const struct state *const sp, const int a, const int b)
{
- register int result;
+ register bool result;
if (sp == NULL ||
a < 0 || a >= sp->typecnt ||
b < 0 || b >= sp->typecnt)
- result = FALSE;
+ result = false;
else {
register const struct ttinfo * ap = &sp->ttis[a];
register const struct ttinfo * bp = &sp->ttis[b];
@@ -645,7 +649,7 @@ static const int year_lengths[2] = {
** character.
*/
-static const char *
+static const char * ATTRIBUTE_PURE
getzname(register const char *strp)
{
register char c;
@@ -665,7 +669,7 @@ getzname(register const char *strp)
** We don't do any checking here; checking is done later in common-case code.
*/
-static const char *
+static const char * ATTRIBUTE_PURE
getqzname(register const char *strp, const int delim)
{
register int c;
@@ -717,10 +721,10 @@ getsecs(register const char *strp, int_fast32_t *const secsp)
int num;
/*
- ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+ ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
** "M10.4.6/26", which does not conform to Posix,
** but which specifies the equivalent of
- ** ``02:00 on the first Sunday on or after 23 Oct''.
+ ** "02:00 on the first Sunday on or after 23 Oct".
*/
strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
if (strp == NULL)
@@ -734,7 +738,7 @@ getsecs(register const char *strp, int_fast32_t *const secsp)
*secsp += num * SECSPERMIN;
if (*strp == ':') {
++strp;
- /* `SECSPERMIN' allows for leap seconds. */
+ /* 'SECSPERMIN' allows for leap seconds. */
strp = getnum(strp, &num, 0, SECSPERMIN);
if (strp == NULL)
return NULL;
@@ -754,10 +758,10 @@ getsecs(register const char *strp, int_fast32_t *const secsp)
static const char *
getoffset(register const char *strp, int_fast32_t *const offsetp)
{
- register int neg = 0;
+ register bool neg = false;
if (*strp == '-') {
- neg = 1;
+ neg = true;
++strp;
} else if (*strp == '+')
++strp;
@@ -827,11 +831,11 @@ getrule(const char *strp, register struct rule *const rulep)
** effect, calculate the year-relative time that rule takes effect.
*/
-static int_fast32_t
+static int_fast32_t ATTRIBUTE_PURE
transtime(const int year, register const struct rule *const rulep,
const int_fast32_t offset)
{
- register int leapyear;
+ register bool leapyear;
register int_fast32_t value;
register int i;
int d, m1, yy0, yy1, yy2, dow;
@@ -918,9 +922,9 @@ transtime(const int year, register const struct rule *const rulep,
** appropriate.
*/
-static int
+static bool
tzparse(const char *name, register struct state *const sp,
- const int lastditch)
+ bool lastditch)
{
const char * stdname;
const char * dstname;
@@ -929,10 +933,9 @@ tzparse(const char *name, register struct state *const sp,
int_fast32_t stdoffset;
int_fast32_t dstoffset;
register char * cp;
- register int load_result;
+ register bool load_ok;
static struct ttinfo zttinfo;
- INITIALIZE(dstname);
stdname = name;
if (lastditch) {
stdlen = strlen(name); /* length of standard zone name */
@@ -946,7 +949,7 @@ tzparse(const char *name, register struct state *const sp,
stdname = name;
name = getqzname(name, '>');
if (*name != '>')
- return (-1);
+ return false;
stdlen = name - stdname;
name++;
} else {
@@ -954,20 +957,20 @@ tzparse(const char *name, register struct state *const sp,
stdlen = name - stdname;
}
if (*name == '\0')
- return -1;
+ return false;
name = getoffset(name, &stdoffset);
if (name == NULL)
- return -1;
+ return false;
}
- load_result = tzload(TZDEFRULES, sp, FALSE);
- if (load_result != 0)
+ load_ok = tzload(TZDEFRULES, sp, false);
+ if (!load_ok)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0') {
if (*name == '<') {
dstname = ++name;
name = getqzname(name, '>');
if (*name != '>')
- return -1;
+ return false;
dstlen = name - dstname;
name++;
} else {
@@ -978,9 +981,9 @@ tzparse(const char *name, register struct state *const sp,
if (*name != '\0' && *name != ',' && *name != ';') {
name = getoffset(name, &dstoffset);
if (name == NULL)
- return -1;
+ return false;
} else dstoffset = stdoffset - SECSPERHOUR;
- if (*name == '\0' && load_result != 0)
+ if (*name == '\0' && !load_ok)
name = TZDEFRULESTRING;
if (*name == ',' || *name == ';') {
struct rule start;
@@ -992,23 +995,23 @@ tzparse(const char *name, register struct state *const sp,
++name;
if ((name = getrule(name, &start)) == NULL)
- return -1;
+ return false;
if (*name++ != ',')
- return -1;
+ return false;
if ((name = getrule(name, &end)) == NULL)
- return -1;
+ return false;
if (*name != '\0')
- return -1;
+ return false;
sp->typecnt = 2; /* standard time and DST */
/*
** Two transitions per year, from EPOCH_YEAR forward.
*/
sp->ttis[0] = sp->ttis[1] = zttinfo;
sp->ttis[0].tt_gmtoff = -dstoffset;
- sp->ttis[0].tt_isdst = 1;
+ sp->ttis[0].tt_isdst = true;
sp->ttis[0].tt_abbrind = stdlen + 1;
sp->ttis[1].tt_gmtoff = -stdoffset;
- sp->ttis[1].tt_isdst = 0;
+ sp->ttis[1].tt_isdst = false;
sp->ttis[1].tt_abbrind = 0;
sp->defaulttype = 0;
timecnt = 0;
@@ -1021,7 +1024,7 @@ tzparse(const char *name, register struct state *const sp,
int_fast32_t
yearsecs = (year_lengths[isleap(year)]
* SECSPERDAY);
- int reversed = endtime < starttime;
+ bool reversed = endtime < starttime;
if (reversed) {
int_fast32_t swap = starttime;
starttime = endtime;
@@ -1056,12 +1059,12 @@ tzparse(const char *name, register struct state *const sp,
register int_fast32_t theirstdoffset;
register int_fast32_t theirdstoffset;
register int_fast32_t theiroffset;
- register int isdst;
+ register bool isdst;
register int i;
register int j;
if (*name != '\0')
- return -1;
+ return false;
/*
** Initial values of theirstdoffset and theirdstoffset.
*/
@@ -1086,7 +1089,7 @@ tzparse(const char *name, register struct state *const sp,
/*
** Initially we're assumed to be in standard time.
*/
- isdst = FALSE;
+ isdst = false;
theiroffset = theirstdoffset;
/*
** Now juggle transition times and types
@@ -1130,10 +1133,10 @@ tzparse(const char *name, register struct state *const sp,
*/
sp->ttis[0] = sp->ttis[1] = zttinfo;
sp->ttis[0].tt_gmtoff = -stdoffset;
- sp->ttis[0].tt_isdst = FALSE;
+ sp->ttis[0].tt_isdst = false;
sp->ttis[0].tt_abbrind = 0;
sp->ttis[1].tt_gmtoff = -dstoffset;
- sp->ttis[1].tt_isdst = TRUE;
+ sp->ttis[1].tt_isdst = true;
sp->ttis[1].tt_abbrind = stdlen + 1;
sp->typecnt = 2;
sp->defaulttype = 0;
@@ -1144,7 +1147,7 @@ tzparse(const char *name, register struct state *const sp,
sp->timecnt = 0;
sp->ttis[0] = zttinfo;
sp->ttis[0].tt_gmtoff = -stdoffset;
- sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_isdst = false;
sp->ttis[0].tt_abbrind = 0;
sp->defaulttype = 0;
}
@@ -1152,100 +1155,143 @@ tzparse(const char *name, register struct state *const sp,
if (dstlen != 0)
sp->charcnt += dstlen + 1;
if ((size_t) sp->charcnt > sizeof sp->chars)
- return -1;
+ return false;
cp = sp->chars;
- (void) strncpy(cp, stdname, stdlen);
+ memcpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0) {
- (void) strncpy(cp, dstname, dstlen);
+ memcpy(cp, dstname, dstlen);
*(cp + dstlen) = '\0';
}
- return 0;
+ return true;
}
static void
gmtload(struct state *const sp)
{
- if (tzload(gmt, sp, TRUE) != 0)
- (void) tzparse(gmt, sp, TRUE);
+ if (! tzload(gmt, sp, true))
+ tzparse(gmt, sp, true);
}
-#ifndef STD_INSPIRED
-/*
-** A non-static declaration of tzsetwall in a system header file
-** may cause a warning about this upcoming static declaration...
-*/
-static
-#endif /* !defined STD_INSPIRED */
-void
-tzsetwall(void)
+static struct state *
+zoneinit(struct state *sp, char const *name)
{
- if (lcl_is_set < 0)
- return;
- lcl_is_set = -1;
+ if (sp) {
+ if (name && ! name[0]) {
+ /*
+ ** User wants it fast rather than right.
+ */
+ sp->leapcnt = 0; /* so, we're off a little */
+ sp->timecnt = 0;
+ sp->typecnt = 0;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_gmtoff = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ strcpy(sp->chars, gmt);
+ } else if (! (tzload(name, sp, true)
+ || (name && name[0] != ':' && tzparse(name, sp, false))))
+ return NULL;
+ }
+ return sp;
+}
+static void
+tzsetlcl(char const *name)
+{
+ 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)
+ return;
+ if (0 < lcl)
+ strcpy(lcl_TZname, name);
#ifdef ALL_STATE
- if (lclptr == NULL) {
- lclptr = malloc(sizeof *lclptr);
- if (lclptr == NULL) {
- settzname(); /* all we can do */
- return;
- }
- }
+ if (! lclptr)
+ lclptr = malloc(sizeof *lclptr);
#endif /* defined ALL_STATE */
- if (tzload(NULL, lclptr, TRUE) != 0)
- gmtload(lclptr);
- settzname();
+ zoneinit(lclptr, name);
+ settzname();
+ lcl_is_set = lcl;
}
+#ifdef STD_INSPIRED
void
-tzset(void)
+tzsetwall(void)
{
- register const char * name;
+ if (lock() != 0)
+ return;
+ tzsetlcl(NULL);
+ unlock();
+}
+#endif
- name = getenv("TZ");
- if (name == NULL) {
- tzsetwall();
- return;
- }
+static void
+tzset_unlocked(void)
+{
+ tzsetlcl(getenv("TZ"));
+}
- if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
- return;
- lcl_is_set = strlen(name) < sizeof lcl_TZname;
- if (lcl_is_set)
- (void) strcpy(lcl_TZname, name);
+void
+tzset(void)
+{
+ if (lock() != 0)
+ return;
+ tzset_unlocked();
+ unlock();
+}
+static void
+gmtcheck(void)
+{
+ static bool VOLATILE gmt_is_set;
+ if (gmt_is_set)
+ return;
+ if (lock() != 0)
+ return;
#ifdef ALL_STATE
- if (lclptr == NULL) {
- lclptr = malloc(sizeof *lclptr);
- if (lclptr == NULL) {
- settzname(); /* all we can do */
- return;
- }
- }
-#endif /* defined ALL_STATE */
- if (*name == '\0') {
- /*
- ** User wants it fast rather than right.
- */
- lclptr->leapcnt = 0; /* so, we're off a little */
- lclptr->timecnt = 0;
- lclptr->typecnt = 0;
- lclptr->ttis[0].tt_isdst = 0;
- lclptr->ttis[0].tt_gmtoff = 0;
- lclptr->ttis[0].tt_abbrind = 0;
- (void) strcpy(lclptr->chars, gmt);
- } else if (tzload(name, lclptr, TRUE) != 0)
- if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
- (void) gmtload(lclptr);
- settzname();
+ gmtptr = malloc(sizeof *gmtptr);
+#endif
+ if (gmtptr)
+ gmtload(gmtptr);
+ gmt_is_set = true;
+ unlock();
+}
+
+#if NETBSD_INSPIRED
+
+timezone_t
+tzalloc(char const *name)
+{
+ timezone_t sp = malloc(sizeof *sp);
+ timezone_t tp = sp ? zoneinit(sp, name) : sp;
+ if (!tp)
+ free(sp);
+ return tp;
+}
+
+void
+tzfree(timezone_t sp)
+{
+ free(sp);
}
/*
+** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
+** ctime_r are obsolescent and have potential security problems that
+** ctime_rz would share. Callers can instead use localtime_rz + strftime.
+**
+** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
+** in zones with three or more time zone abbreviations.
+** Callers can instead use localtime_rz + strftime.
+*/
+
+#endif
+
+/*
** 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
-** freely called. (And no, the PANS doesn't require the above behavior--
+** is to not call it, so we drop its guts into "localsub", which can be
+** freely called. (And no, the PANS doesn't require the above behavior,
** but it *is* desirable.)
**
** The unused offset argument is for the benefit of mktime variants.
@@ -1253,18 +1299,16 @@ tzset(void)
/*ARGSUSED*/
static struct tm *
-localsub(const time_t *const timep, const int_fast32_t offset,
+localsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
struct tm *const tmp)
{
- register struct state * sp;
register const struct ttinfo * ttisp;
register int i;
register struct tm * result;
const time_t t = *timep;
- sp = lclptr;
if (sp == NULL)
- return gmtsub(timep, offset, tmp);
+ return gmtsub(gmtptr, timep, offset, tmp);
if ((sp->goback && t < sp->ats[0]) ||
(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
time_t newt = t;
@@ -1283,17 +1327,17 @@ localsub(const time_t *const timep, const int_fast32_t offset,
if (newt < sp->ats[0] ||
newt > sp->ats[sp->timecnt - 1])
return NULL; /* "cannot happen" */
- result = localsub(&newt, offset, tmp);
+ result = localsub(sp, &newt, offset, tmp);
if (result == tmp) {
- register time_t newy;
+ register int_fast64_t newy;
newy = tmp->tm_year;
if (t < sp->ats[0])
newy -= years;
else newy += years;
- tmp->tm_year = newy;
- if (tmp->tm_year != newy)
+ if (! (INT_MIN <= newy && newy <= INT_MAX))
return NULL;
+ tmp->tm_year = newy;
}
return result;
}
@@ -1321,28 +1365,43 @@ localsub(const time_t *const timep, const int_fast32_t offset,
*/
result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->tt_isdst;
- tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
#ifdef TM_ZONE
- tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+ tmp->TM_ZONE = (char *) &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */
return result;
}
+NETBSD_INSPIRED_EXTERN struct tm *
+localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
+{
+ return localsub(sp, timep, 0, tmp);
+}
+
+static struct tm *
+localtime_tzset(time_t const *timep, struct tm *tmp, bool skip_tzset)
+{
+ int err = lock();
+ if (err) {
+ errno = err;
+ return NULL;
+ }
+ if (!skip_tzset)
+ tzset_unlocked();
+ tmp = localtime_rz(lclptr, timep, tmp);
+ unlock();
+ return tmp;
+}
+
struct tm *
localtime(const time_t *const timep)
{
- tzset();
- return localsub(timep, 0L, &tm);
+ return localtime_tzset(timep, &tm, 0);
}
-/*
-** Re-entrant version of localtime.
-*/
-
struct tm *
localtime_r(const time_t *const timep, struct tm *tmp)
{
- return localsub(timep, 0L, tmp);
+ return localtime_tzset(timep, tmp, lcl_is_set != 0);
}
/*
@@ -1350,19 +1409,11 @@ localtime_r(const time_t *const timep, struct tm *tmp)
*/
static struct tm *
-gmtsub(const time_t *const timep, const int_fast32_t offset,
- struct tm *const tmp)
+gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
+ struct tm *tmp)
{
register struct tm * result;
- if (!gmt_is_set) {
- gmt_is_set = TRUE;
-#ifdef ALL_STATE
- gmtptr = malloc(sizeof *gmtptr);
-#endif /* defined ALL_STATE */
- if (gmtptr != NULL)
- gmtload(gmtptr);
- }
result = timesub(timep, offset, gmtptr, tmp);
#ifdef TM_ZONE
/*
@@ -1370,7 +1421,8 @@ gmtsub(const time_t *const timep, const int_fast32_t offset,
** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
- tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt;
+ tmp->TM_ZONE = ((char *)
+ (offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
#endif /* defined TM_ZONE */
return result;
}
@@ -1378,7 +1430,7 @@ gmtsub(const time_t *const timep, const int_fast32_t offset,
struct tm *
gmtime(const time_t *const timep)
{
- return gmtsub(timep, 0L, &tm);
+ return gmtime_r(timep, &tm);
}
/*
@@ -1388,7 +1440,9 @@ gmtime(const time_t *const timep)
struct tm *
gmtime_r(const time_t *const timep, struct tm *tmp)
{
- return gmtsub(timep, 0L, tmp);
+ gmtcheck();
+ tmp = gmtsub(gmtptr, timep, 0, tmp);
+ return tmp;
}
#ifdef STD_INSPIRED
@@ -1396,7 +1450,10 @@ gmtime_r(const time_t *const timep, struct tm *tmp)
struct tm *
offtime(const time_t *const timep, const long offset)
{
- return gmtsub(timep, offset, &tm);
+ struct tm *tmp;
+ gmtcheck();
+ tmp = gmtsub(gmtptr, timep, offset, &tm);
+ return tmp;
}
#endif /* defined STD_INSPIRED */
@@ -1406,7 +1463,7 @@ offtime(const time_t *const timep, const long offset)
** where, to make the math easy, the answer for year zero is defined as zero.
*/
-static int
+static int ATTRIBUTE_PURE
leaps_thru_end_of(register const int y)
{
return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
@@ -1425,11 +1482,11 @@ timesub(const time_t *const timep, const int_fast32_t offset,
int y;
register const int * ip;
register int_fast64_t corr;
- register int hit;
+ register bool hit;
register int i;
corr = 0;
- hit = 0;
+ hit = false;
i = (sp == NULL) ? 0 : sp->leapcnt;
while (--i >= 0) {
lp = &sp->lsis[i];
@@ -1578,7 +1635,7 @@ ctime_r(const time_t *const timep, char *buf)
** Normalize logic courtesy Paul Eggert.
*/
-static int
+static bool
increment_overflow(int *const ip, int j)
{
register int const i = *ip;
@@ -1590,23 +1647,23 @@ increment_overflow(int *const ip, int j)
** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
*/
if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
- return TRUE;
+ return true;
*ip += j;
- return FALSE;
+ return false;
}
-static int
+static bool
increment_overflow32(int_fast32_t *const lp, int const m)
{
register int_fast32_t const l = *lp;
if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
- return TRUE;
+ return true;
*lp += m;
- return FALSE;
+ return false;
}
-static int
+static bool
increment_overflow_time(time_t *tp, int_fast32_t j)
{
/*
@@ -1617,12 +1674,12 @@ increment_overflow_time(time_t *tp, int_fast32_t j)
if (! (j < 0
? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
: *tp <= time_t_max - j))
- return TRUE;
+ return true;
*tp += j;
- return FALSE;
+ return false;
}
-static int
+static bool
normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
{
register int tensdelta;
@@ -1634,7 +1691,7 @@ normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
return increment_overflow(tensptr, tensdelta);
}
-static int
+static bool
normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
const int base)
{
@@ -1665,12 +1722,13 @@ tmcomp(register const struct tm *const atmp,
static time_t
time2sub(struct tm *const tmp,
- struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *),
+ struct tm *(*funcp)(struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
+ struct state const *sp,
const int_fast32_t offset,
- int *const okayp,
- const int do_norm_secs)
+ bool *okayp,
+ bool do_norm_secs)
{
- register const struct state * sp;
register int dir;
register int i, j;
register int saved_seconds;
@@ -1682,7 +1740,7 @@ time2sub(struct tm *const tmp,
time_t t;
struct tm yourtm, mytm;
- *okayp = FALSE;
+ *okayp = false;
yourtm = *tmp;
if (do_norm_secs) {
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
@@ -1727,9 +1785,9 @@ time2sub(struct tm *const tmp,
}
if (increment_overflow32(&y, -TM_YEAR_BASE))
return WRONG;
- yourtm.tm_year = y;
- if (yourtm.tm_year != y)
+ if (! (INT_MIN <= y && y <= INT_MAX))
return WRONG;
+ yourtm.tm_year = y;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
@@ -1767,7 +1825,7 @@ time2sub(struct tm *const tmp,
t = lo;
else if (t > hi)
t = hi;
- if ((*funcp)(&t, offset, &mytm) == NULL) {
+ if (! funcp(sp, &t, offset, &mytm)) {
/*
** Assume that t is too extreme to be represented in
** a struct tm; arrange things so that it is less
@@ -1794,6 +1852,35 @@ time2sub(struct tm *const tmp,
else lo = t;
continue;
}
+#if defined TM_GMTOFF && ! UNINIT_TRAP
+ if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
+ && (yourtm.TM_GMTOFF < 0
+ ? (-SECSPERDAY <= yourtm.TM_GMTOFF
+ && (mytm.TM_GMTOFF <=
+ (SMALLEST (INT_FAST32_MAX, LONG_MAX)
+ + yourtm.TM_GMTOFF)))
+ : (yourtm.TM_GMTOFF <= SECSPERDAY
+ && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
+ + yourtm.TM_GMTOFF)
+ <= mytm.TM_GMTOFF)))) {
+ /* MYTM matches YOURTM except with the wrong UTC offset.
+ YOURTM.TM_GMTOFF is plausible, so try it instead.
+ It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
+ since the guess gets checked. */
+ time_t altt = t;
+ int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
+ if (!increment_overflow_time(&altt, diff)) {
+ struct tm alttm;
+ if (funcp(sp, &altt, offset, &alttm)
+ && alttm.tm_isdst == mytm.tm_isdst
+ && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
+ && tmcomp(&alttm, &yourtm) == 0) {
+ t = altt;
+ mytm = alttm;
+ }
+ }
+ }
+#endif
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
break;
/*
@@ -1802,8 +1889,6 @@ time2sub(struct tm *const tmp,
** It's okay to guess wrong since the guess
** gets checked.
*/
- sp = (const struct state *)
- ((funcp == localsub) ? lclptr : gmtptr);
if (sp == NULL)
return WRONG;
for (i = sp->typecnt - 1; i >= 0; --i) {
@@ -1814,7 +1899,7 @@ time2sub(struct tm *const tmp,
continue;
newt = t + sp->ttis[j].tt_gmtoff -
sp->ttis[i].tt_gmtoff;
- if ((*funcp)(&newt, offset, &mytm) == NULL)
+ if (! funcp(sp, &newt, offset, &mytm))
continue;
if (tmcomp(&mytm, &yourtm) != 0)
continue;
@@ -1834,16 +1919,18 @@ label:
if ((newt < t) != (saved_seconds < 0))
return WRONG;
t = newt;
- if ((*funcp)(&t, offset, tmp))
- *okayp = TRUE;
+ if (funcp(sp, &t, offset, tmp))
+ *okayp = true;
return t;
}
static time_t
time2(struct tm * const tmp,
- struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *),
+ struct tm *(*funcp)(struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
+ struct state const *sp,
const int_fast32_t offset,
- int *const okayp)
+ bool *okayp)
{
time_t t;
@@ -1852,24 +1939,25 @@ time2(struct tm * const tmp,
** (in case tm_sec contains a value associated with a leap second).
** If that fails, try with normalization of seconds.
*/
- t = time2sub(tmp, funcp, offset, okayp, FALSE);
- return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
+ t = time2sub(tmp, funcp, sp, offset, okayp, false);
+ return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
}
static time_t
time1(struct tm *const tmp,
- struct tm *(*const funcp) (const time_t *, int_fast32_t, struct tm *),
+ struct tm *(*funcp) (struct state const *, time_t const *,
+ int_fast32_t, struct tm *),
+ struct state const *sp,
const int_fast32_t offset)
{
register time_t t;
- register const struct state * sp;
register int samei, otheri;
register int sameind, otherind;
register int i;
register int nseen;
- int seen[TZ_MAX_TYPES];
- int types[TZ_MAX_TYPES];
- int okay;
+ char seen[TZ_MAX_TYPES];
+ unsigned char types[TZ_MAX_TYPES];
+ bool okay;
if (tmp == NULL) {
errno = EINVAL;
@@ -1877,7 +1965,7 @@ time1(struct tm *const tmp,
}
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
- t = time2(tmp, funcp, offset, &okay);
+ t = time2(tmp, funcp, sp, offset, &okay);
if (okay)
return t;
if (tmp->tm_isdst < 0)
@@ -1895,15 +1983,14 @@ time1(struct tm *const tmp,
** We try to divine the type they started from and adjust to the
** type they need.
*/
- sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
if (sp == NULL)
return WRONG;
for (i = 0; i < sp->typecnt; ++i)
- seen[i] = FALSE;
+ seen[i] = false;
nseen = 0;
for (i = sp->timecnt - 1; i >= 0; --i)
if (!seen[sp->types[i]]) {
- seen[sp->types[i]] = TRUE;
+ seen[sp->types[i]] = true;
types[nseen++] = sp->types[i];
}
for (sameind = 0; sameind < nseen; ++sameind) {
@@ -1917,7 +2004,7 @@ time1(struct tm *const tmp,
tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
sp->ttis[samei].tt_gmtoff;
tmp->tm_isdst = !tmp->tm_isdst;
- t = time2(tmp, funcp, offset, &okay);
+ t = time2(tmp, funcp, sp, offset, &okay);
if (okay)
return t;
tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
@@ -1928,11 +2015,30 @@ time1(struct tm *const tmp,
return WRONG;
}
+NETBSD_INSPIRED_EXTERN time_t
+mktime_z(struct state *sp, struct tm *tmp)
+{
+ if (sp)
+ return time1(tmp, localsub, sp, 0);
+ else {
+ gmtcheck();
+ return time1(tmp, gmtsub, gmtptr, 0);
+ }
+}
+
time_t
mktime(struct tm *const tmp)
{
- tzset();
- return time1(tmp, localsub, 0L);
+ time_t t;
+ int err = lock();
+ if (err) {
+ errno = err;
+ return -1;
+ }
+ tzset_unlocked();
+ t = mktime_z(lclptr, tmp);
+ unlock();
+ return t;
}
#ifdef STD_INSPIRED
@@ -1948,40 +2054,22 @@ timelocal(struct tm *const tmp)
time_t
timegm(struct tm *const tmp)
{
- if (tmp != NULL)
- tmp->tm_isdst = 0;
- return time1(tmp, gmtsub, 0L);
+ return timeoff(tmp, 0);
}
time_t
timeoff(struct tm *const tmp, const long offset)
{
- if (tmp != NULL)
- tmp->tm_isdst = 0;
- return time1(tmp, gmtsub, offset);
+ time_t t;
+ if (tmp)
+ tmp->tm_isdst = 0;
+ gmtcheck();
+ t = time1(tmp, gmtsub, gmtptr, offset);
+ return t;
}
#endif /* defined STD_INSPIRED */
-#ifdef CMUCS
-
-/*
-** The following is supplied for compatibility with
-** previous versions of the CMUCS runtime library.
-*/
-
-long
-gtime(struct tm *const tmp)
-{
- const time_t t = mktime(tmp);
-
- if (t == WRONG)
- return -1;
- return t;
-}
-
-#endif /* defined CMUCS */
-
/*
** XXX--is the below the right way to conditionalize??
*/
@@ -1997,60 +2085,102 @@ gtime(struct tm *const tmp)
*/
static int_fast64_t
-leapcorr(time_t *timep)
+leapcorr(struct state const *sp, time_t t)
{
- register struct state * sp;
- register struct lsinfo * lp;
+ register struct lsinfo const * lp;
register int i;
sp = lclptr;
i = sp->leapcnt;
while (--i >= 0) {
lp = &sp->lsis[i];
- if (*timep >= lp->ls_trans)
+ if (t >= lp->ls_trans)
return lp->ls_corr;
}
return 0;
}
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+time2posix_z(struct state *sp, time_t t)
+{
+ return t - leapcorr(sp, t);
+}
+
time_t
time2posix(time_t t)
{
- tzset();
- return t - leapcorr(&t);
+ int err = lock();
+ if (err) {
+ errno = err;
+ return -1;
+ }
+ if (!lcl_is_set)
+ tzset_unlocked();
+ if (lclptr)
+ t = time2posix_z(lclptr, t);
+ unlock();
+ return t;
}
-time_t
-posix2time(time_t t)
+NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
+posix2time_z(struct state *sp, time_t t)
{
time_t x;
time_t y;
-
- tzset();
/*
** For a positive leap second hit, the result
** is not unique. For a negative leap second
** hit, the corresponding time doesn't exist,
** so we return an adjacent second.
*/
- x = t + leapcorr(&t);
- y = x - leapcorr(&x);
+ x = t + leapcorr(sp, t);
+ y = x - leapcorr(sp, x);
if (y < t) {
do {
x++;
- y = x - leapcorr(&x);
+ y = x - leapcorr(sp, x);
} while (y < t);
- if (t != y)
- return x - 1;
+ x -= y != t;
} else if (y > t) {
do {
--x;
- y = x - leapcorr(&x);
+ y = x - leapcorr(sp, x);
} while (y > t);
- if (t != y)
- return x + 1;
+ x += y != t;
}
return x;
}
+time_t
+posix2time(time_t t)
+{
+ int err = lock();
+ if (err) {
+ errno = err;
+ return -1;
+ }
+ if (!lcl_is_set)
+ tzset_unlocked();
+ if (lclptr)
+ t = posix2time_z(lclptr, t);
+ unlock();
+ return t;
+}
+
#endif /* defined STD_INSPIRED */
+
+#ifdef time_tz
+
+/* Convert from the underlying system's time_t to the ersatz time_tz,
+ which is called 'time_t' in this file. */
+
+time_t
+time(time_t *p)
+{
+ time_t r = sys_time(0);
+ if (p)
+ *p = r;
+ return r;
+}
+
+#endif