Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/localtime.cc')
-rw-r--r--winsup/cygwin/localtime.cc1703
1 files changed, 1010 insertions, 693 deletions
diff --git a/winsup/cygwin/localtime.cc b/winsup/cygwin/localtime.cc
index 239aaffdd..19eef6759 100644
--- a/winsup/cygwin/localtime.cc
+++ b/winsup/cygwin/localtime.cc
@@ -1,6 +1,14 @@
+/* $NetBSD: localtime.c,v 1.72 2012/10/28 19:02:29 christos Exp $ */
+
+/* Don't reformat the code arbitrarily.
+
+ It uses in wide parts the exact formatting as the upstream NetBSD
+ versions. The purpose is to simplify subsequent diffs to the NetBSD
+ version, should the need arise again at one point. */
+
/*
** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson.
*/
/* Temporarily merged private.h and tzfile.h for ease of management - DJ */
@@ -15,16 +23,17 @@
#ifndef lint
#ifndef NOID
-static char elsieid[] = "@(#)localtime.c 7.66";
+static char elsieid[] = "@(#)localtime.c 8.17";
#endif /* !defined NOID */
#endif /* !defined lint */
/*
-** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
-** POSIX-style TZ environment variable handling from Guy Harris
-** (guy@auspex.com).
+** Leap second handling from Bradley White.
+** POSIX-style TZ environment variable handling from Guy Harris.
*/
+#define NO_ERROR_IN_DST_GAP
+
/*LINTLIBRARY*/
#ifndef PRIVATE_H
@@ -33,7 +42,7 @@ static char elsieid[] = "@(#)localtime.c 7.66";
/*
** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson
*/
/*
@@ -55,145 +64,33 @@ static char privatehid[] = "@(#)private.h 7.48";
#endif /* !defined lint */
/*
-** Defaults for preprocessor symbols.
-** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
-*/
-
-#ifndef HAVE_ADJTIME
-#define HAVE_ADJTIME 1
-#endif /* !defined HAVE_ADJTIME */
-
-#ifndef HAVE_GETTEXT
-#define HAVE_GETTEXT 0
-#endif /* !defined HAVE_GETTEXT */
-
-#ifndef HAVE_SETTIMEOFDAY
-#define HAVE_SETTIMEOFDAY 3
-#endif /* !defined HAVE_SETTIMEOFDAY */
-
-#ifndef HAVE_STRERROR
-#define HAVE_STRERROR 0
-#endif /* !defined HAVE_STRERROR */
-
-#ifndef HAVE_SYMLINK
-#define HAVE_SYMLINK 1
-#endif /* !defined HAVE_SYMLINK */
-
-#ifndef HAVE_UNISTD_H
-#define HAVE_UNISTD_H 1
-#endif /* !defined HAVE_UNISTD_H */
-
-#ifndef HAVE_UTMPX_H
-#define HAVE_UTMPX_H 0
-#endif /* !defined HAVE_UTMPX_H */
-
-#ifndef LOCALE_HOME
-#define LOCALE_HOME "/usr/lib/locale"
-#endif /* !defined LOCALE_HOME */
-
-/*
** Nested includes
*/
#include "stdio.h"
#include "limits.h" /* for CHAR_BIT */
#include "stdlib.h"
-
-#if HAVE_GETTEXT - 0
-#endif /* HAVE_GETTEXT - 0 */
-
-#if HAVE_UNISTD_H - 0
#include "unistd.h" /* for F_OK and R_OK */
-#endif /* HAVE_UNISTD_H - 0 */
-
-#if !(HAVE_UNISTD_H - 0)
-#ifndef F_OK
-#define F_OK 0
-#endif /* !defined F_OK */
-#ifndef R_OK
-#define R_OK 4
-#endif /* !defined R_OK */
-#endif /* !(HAVE_UNISTD_H - 0) */
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
-/*
-** Workarounds for compilers/systems.
-*/
-
-/*
-** SunOS 4.1.1 cc lacks const.
-*/
-
-#ifndef const
-#ifndef __STDC__
-#define const
-#endif /* !defined __STDC__ */
-#endif /* !defined const */
-
-/*
-** SunOS 4.1.1 cc lacks prototypes.
-*/
-
-#ifndef P
-#ifdef __STDC__
-#define P(x) x
-#endif /* defined __STDC__ */
-#ifndef __STDC__
-#define P(x) ()
-#endif /* !defined __STDC__ */
-#endif /* !defined P */
-
-/*
-** SunOS 4.1.1 headers lack EXIT_SUCCESS.
-*/
-
-#ifndef EXIT_SUCCESS
-#define EXIT_SUCCESS 0
-#endif /* !defined EXIT_SUCCESS */
-
-/*
-** SunOS 4.1.1 headers lack EXIT_FAILURE.
-*/
-
-#ifndef EXIT_FAILURE
-#define EXIT_FAILURE 1
-#endif /* !defined EXIT_FAILURE */
-
-/*
-** SunOS 4.1.1 headers lack FILENAME_MAX.
-*/
-
-#ifndef FILENAME_MAX
-
-#ifndef MAXPATHLEN
-#ifdef unix
-#endif /* defined unix */
-#endif /* !defined MAXPATHLEN */
-
-#ifdef MAXPATHLEN
-#define FILENAME_MAX MAXPATHLEN
-#endif /* defined MAXPATHLEN */
-#ifndef MAXPATHLEN
-#define FILENAME_MAX 1024 /* Pure guesswork */
-#endif /* !defined MAXPATHLEN */
-
-#endif /* !defined FILENAME_MAX */
-
-/*
-** SunOS 4.1.1 libraries lack remove.
-*/
-
-#ifndef remove
-extern int unlink P((const char * filename));
-#define remove unlink
-#endif /* !defined remove */
+#ifndef __pure
+#if 2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)
+# define __pure __attribute__ ((__pure__))
+#else
+# define __pure /* empty */
+#endif
+#endif
/*
** Finally, some convenience items.
*/
+#ifndef TYPE_INTEGRAL
+#define TYPE_INTEGRAL(type) (/*CONSTCOND*/((type) 0.5) != 0.5)
+#endif /* !defined TYPE_INTEGRAL */
+
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
@@ -237,23 +134,29 @@ extern int unlink P((const char * filename));
#endif /* !defined GNUC_or_lint */
#endif /* !defined INITIALIZE */
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#ifndef YEARSPERREPEAT
+#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+#endif /* !defined YEARSPERREPEAT */
+
/*
-** For the benefit of GNU folk...
-** `_(MSGID)' uses the current locale's message library string for MSGID.
-** The default is to use gettext if available, and use MSGID otherwise.
+** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
*/
-#ifndef _
-#if HAVE_GETTEXT - 0
-#define _(msgid) gettext(msgid)
-#else /* !(HAVE_GETTEXT - 0) */
-#define _(msgid) msgid
-#endif /* !(HAVE_GETTEXT - 0) */
-#endif /* !defined _ */
+#ifndef AVGSECSPERYEAR
+#define AVGSECSPERYEAR 31556952L
+#endif /* !defined AVGSECSPERYEAR */
-#ifndef TZ_DOMAIN
-#define TZ_DOMAIN "tz"
-#endif /* !defined TZ_DOMAIN */
+#ifndef SECSPERREPEAT
+#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+#endif /* !defined SECSPERREPEAT */
+
+#ifndef SECSPERREPEAT_BITS
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+#endif /* !defined SECSPERREPEAT_BITS */
/*
** UNIX was a registered trademark of UNIX System Laboratories in 1993.
@@ -267,7 +170,7 @@ extern int unlink P((const char * filename));
/*
** This file is in the public domain, so clarified as of
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+** 1996-06-05 by Arthur David Olson.
*/
/*
@@ -312,7 +215,8 @@ static char tzfilehid[] = "@(#)tzfile.h 7.14";
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
- char tzh_reserved[16]; /* reserved for future use */
+ char tzh_version[1]; /* '\0' or '2' as of 2005 */
+ char tzh_reserved[15]; /* reserved for future use */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
@@ -334,19 +238,29 @@ struct tzhead {
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
** one (char [4]) total correction after above
-** tzh_ttisstdcnt (char)s indexed by type; if true, transition
-** time is standard time, if false,
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
** transition time is wall clock time
** if absent, transition times are
** assumed to be wall clock time
-** tzh_ttisgmtcnt (char)s indexed by type; if true, transition
-** time is UTC, if false,
+** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
+** time is UTC, if FALSE,
** transition time is local time
** if absent, transition times are
** assumed to be local time
*/
/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+*/
+
+/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
@@ -358,7 +272,7 @@ struct tzhead {
** 138 years of Pacific Presidential Election time
** (where there are three time zone transitions every fourth year).
*/
-#define TZ_MAX_TIMES 370
+#define TZ_MAX_TIMES 1200
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
@@ -368,7 +282,7 @@ struct tzhead {
#ifdef NOSOLAR
/*
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
-** as noted by Earl Chew <earl@hpato.aus.hp.com>.
+** as noted by Earl Chew.
*/
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif /* !defined NOSOLAR */
@@ -426,28 +340,6 @@ struct tzhead {
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-#ifndef USG
-
-/*
-** Use of the underscored variants may cause problems if you move your code to
-** certain System-V-based systems; for maximum portability, use the
-** underscore-free variants. The underscored variants are provided for
-** backward compatibility only; they may disappear from future versions of
-** this file.
-*/
-
-#define SECS_PER_MIN SECSPERMIN
-#define MINS_PER_HOUR MINSPERHOUR
-#define HOURS_PER_DAY HOURSPERDAY
-#define DAYS_PER_WEEK DAYSPERWEEK
-#define DAYS_PER_NYEAR DAYSPERNYEAR
-#define DAYS_PER_LYEAR DAYSPERLYEAR
-#define SECS_PER_HOUR SECSPERHOUR
-#define SECS_PER_DAY SECSPERDAY
-#define MONS_PER_YEAR MONSPERYEAR
-
-#endif /* !defined USG */
-
#endif /* !defined TZFILE_H */
#include "fcntl.h"
@@ -477,25 +369,36 @@ struct tzhead {
** 5. They might reference tm.TM_ZONE after calling offtime.
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
-** WILDABBR is used. Another possibility: initialize tzname[0] to the
+** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
-** And another: initialize tzname[0] to "ERA", with an explanation in the
+** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
*/
#define WILDABBR " "
#endif /* !defined WILDABBR */
-static char wildabbr[] NO_COPY = WILDABBR;
+static const char wildabbr[] = WILDABBR;
-static char gmt[] NO_COPY = "GMT";
+static const char gmt[] = "GMT";
+
+/*
+** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** We default to US rules as of 1999-08-17.
+** POSIX 1003.1 section 8.1.1 says that the default DST rules are
+** implementation dependent; for historical reasons, US rules are a
+** common default.
+*/
+#ifndef TZDEFRULESTRING
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#endif /* !defined TZDEFDST */
struct ttinfo { /* time type information */
long tt_gmtoff; /* UTC offset in seconds */
int 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 UTC */
+ int tt_ttisstd; /* TRUE if transition is std time */
+ int tt_ttisgmt; /* TRUE if transition is UTC */
};
struct lsinfo { /* leap second information */
@@ -512,19 +415,23 @@ struct lsinfo { /* leap second information */
#define MY_TZNAME_MAX 255
#endif /* !defined TZNAME_MAX */
-struct state {
+struct __state {
int leapcnt;
int timecnt;
int typecnt;
int charcnt;
+ int goback;
+ int goahead;
time_t ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
- char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
- (2 * (MY_TZNAME_MAX + 1)))];
+ char chars[/*CONSTCOND*/BIGGEST(BIGGEST(TZ_MAX_CHARS + 1,
+ sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))];
struct lsinfo lsis[TZ_MAX_LEAPS];
};
+typedef struct __state *timezone_t;
+
struct rule {
int r_type; /* type of rule--see below */
int r_day; /* day number of rule */
@@ -537,59 +444,60 @@ struct rule {
#define DAY_OF_YEAR 1 /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
+typedef struct tm *(*subfun_t)(const timezone_t sp, const time_t *timep,
+ long offset, struct tm *tmp);
+
/*
** Prototypes for static functions.
*/
-static long detzcode P((const char * codep));
-static const char * getzname P((const char * strp));
-static const char * getnum P((const char * strp, int * nump, int min,
- int max));
-static const char * getsecs P((const char * strp, long * secsp));
-static const char * getoffset P((const char * strp, long * offsetp));
-static const char * getrule P((const char * strp, struct rule * rulep));
-static void gmtload P((struct state * sp));
-static void gmtsub P((const time_t * timep, long offset,
- struct tm * tmp));
-static void localsub P((const time_t * timep, long offset,
- struct tm * tmp));
-static int increment_overflow P((int * number, int delta));
-static int normalize_overflow P((int * tensptr, int * unitsptr,
- int base));
-static void settzname P((void));
-static time_t time1 P((struct tm * tmp,
- void(*funcp) P((const time_t *,
- long, struct tm *)),
- long offset));
-static time_t time2 P((struct tm *tmp,
- void(*funcp) P((const time_t *,
- long, struct tm*)),
- long offset, int * okayp));
-static time_t time2sub P((struct tm *tmp,
- void(*funcp) P((const time_t *,
- long, struct tm*)),
- long offset, int * okayp, int do_norm_secs));
-static void timesub P((const time_t * timep, long offset,
- const struct state * sp, struct tm * tmp));
-static int tmcomp P((const struct tm * atmp,
- const struct tm * btmp));
-static time_t transtime P((time_t janfirst, int year,
- const struct rule * rulep, long offset));
-static int tzload P((const char * name, struct state * sp));
-static int tzparse P((const char * name, struct state * sp,
- int lastditch));
-
-#ifdef ALL_STATE
-static struct state * lclptr;
-static struct state * gmtptr;
-#endif /* defined ALL_STATE */
-
-#ifndef ALL_STATE
-static struct state lclmem;
-static struct state gmtmem;
-#define lclptr (&lclmem)
-#define gmtptr (&gmtmem)
-#endif /* State Farm */
+static long detzcode(const char * codep);
+static time_t detzcode64(const char * codep);
+static int differ_by_repeat(time_t t1, time_t t0);
+static const char * getzname(const char * strp) __pure;
+static const char * getqzname(const char * strp, const int delim) __pure;
+static const char * getnum(const char * strp, int * nump, int min,
+ int max);
+static const char * getsecs(const char * strp, long * secsp);
+static const char * getoffset(const char * strp, long * offsetp);
+static const char * getrule(const char * strp, struct rule * rulep);
+static void gmtload(timezone_t sp);
+static struct tm * gmtsub(const timezone_t sp, const time_t *timep,
+ long offset, struct tm * tmp);
+static struct tm * localsub(const timezone_t sp, const time_t *timep,
+ long offset, struct tm *tmp);
+static int increment_overflow(int * number, int delta);
+static int leaps_thru_end_of(int y) __pure;
+static int long_increment_overflow(long * number, int delta);
+static int long_normalize_overflow(long * tensptr,
+ int * unitsptr, int base);
+static int normalize_overflow(int * tensptr, int * unitsptr,
+ int base);
+static void settzname(void);
+static time_t time1(const timezone_t sp, struct tm * const tmp,
+ subfun_t funcp, const long offset);
+static time_t time2(const timezone_t sp, struct tm * const tmp,
+ subfun_t funcp,
+ const long offset, int *const okayp);
+static time_t time2sub(const timezone_t sp, struct tm * const tmp,
+ subfun_t funcp, const long offset,
+ int *const okayp, const int do_norm_secs);
+static struct tm * timesub(const timezone_t sp, const time_t * timep,
+ long offset, struct tm * tmp);
+static int tmcomp(const struct tm * atmp,
+ const struct tm * btmp);
+static time_t transtime(time_t janfirst, int year,
+ const struct rule * rulep, long offset) __pure;
+static int typesequiv(const timezone_t sp, int a, int b);
+static int tzload(timezone_t sp, const char * name,
+ int doextend);
+static int tzparse(timezone_t sp, const char * name,
+ int lastditch);
+static void tzset_unlocked(void);
+static long leapcorr(const timezone_t sp, time_t * timep);
+
+static timezone_t lclptr;
+static timezone_t gmtptr;
#ifndef TZ_STRLEN_MAX
#define TZ_STRLEN_MAX 255
@@ -609,8 +517,8 @@ static int gmt_is_set;
#undef _tzname
char * tzname[2] = {
- wildabbr,
- wildabbr
+ (char *) wildabbr,
+ (char *) wildabbr
};
/*
@@ -618,12 +526,11 @@ char * tzname[2] = {
** Except for the strftime function, these functions [asctime,
** ctime, gmtime, localtime] return values in one of two static
** objects: a broken-down time structure and an array of char.
-** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
+** Thanks to Paul Eggert for noting this.
*/
static struct tm tm;
-
/* These variables are initialized by tzset. The macro versions are
defined in time.h, and indirect through the __imp_ pointers. */
@@ -633,34 +540,46 @@ static struct tm tm;
#undef _daylight
#ifdef USG_COMPAT
-long timezone; /* was time_t but POSIX requires long. */
-int daylight;
+long timezone = 0;
+int daylight;
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
-time_t altzone;
+time_t altzone = 0;
#endif /* defined ALTZONE */
static long
-detzcode(const char *codep)
+detzcode(const char *const codep)
{
- register long result;
- register int i;
+ long result;
+ int i;
- result = (codep[0] & 0x80) ? ~0L : 0L;
+ result = (codep[0] & 0x80) ? ~0L : 0;
for (i = 0; i < 4; ++i)
result = (result << 8) | (codep[i] & 0xff);
return result;
}
+static time_t
+detzcode64(const char *const codep)
+{
+ time_t result;
+ int i;
+
+ result = (time_t)((codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0);
+ for (i = 0; i < 8; ++i)
+ result = result * 256 + (codep[i] & 0xff);
+ return result;
+}
+
static void
-settzname P((void))
+settzname (void)
{
- register struct state * const sp = lclptr;
- register int i;
+ timezone_t const sp = lclptr;
+ int i;
- tzname[0] = wildabbr;
- tzname[1] = wildabbr;
+ tzname[0] = (char *) wildabbr;
+ tzname[1] = (char *) wildabbr;
#ifdef USG_COMPAT
daylight = 0;
timezone = 0;
@@ -668,25 +587,23 @@ settzname P((void))
#ifdef ALTZONE
altzone = 0;
#endif /* defined ALTZONE */
-#ifdef ALL_STATE
if (sp == NULL) {
- tzname[0] = tzname[1] = gmt;
+ tzname[0] = tzname[1] = (char *) gmt;
return;
}
-#endif /* defined ALL_STATE */
for (i = 0; i < sp->typecnt; ++i) {
- register const struct ttinfo * const ttisp = &sp->ttis[i];
+ const struct ttinfo * const ttisp = &sp->ttis[i];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
#ifdef USG_COMPAT
if (ttisp->tt_isdst)
daylight = 1;
- if (i == 0 || !ttisp->tt_isdst)
+ if (!ttisp->tt_isdst)
timezone = -(ttisp->tt_gmtoff);
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
- if (i == 0 || ttisp->tt_isdst)
+ if (ttisp->tt_isdst)
altzone = -(ttisp->tt_gmtoff);
#endif /* defined ALTZONE */
}
@@ -694,9 +611,7 @@ settzname P((void))
** And to get the latest zone names into tzname. . .
*/
for (i = 0; i < sp->timecnt; ++i) {
- register const struct ttinfo * const ttisp =
- &sp->ttis[
- sp->types[i]];
+ const struct ttinfo *const ttisp = &sp->ttis[sp->types[i]];
tzname[ttisp->tt_isdst] =
&sp->chars[ttisp->tt_abbrind];
@@ -706,17 +621,40 @@ settzname P((void))
#include "tz_posixrules.h"
static int
-tzload(const char *name, struct state *sp)
+differ_by_repeat(const time_t t1, const time_t t0)
{
- register const char * p;
- register int i;
- register int fid;
+ if (TYPE_INTEGRAL(time_t) &&
+ TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+ return 0;
+ return (int_fast64_t)t1 - (int_fast64_t)t0 == SECSPERREPEAT;
+}
+
+static int
+tzload(timezone_t sp, const char *name, const int doextend)
+{
+ const char * p;
+ int i;
+ int fid;
+ int stored;
+ ssize_t nread;
+ typedef union {
+ struct tzhead tzhead;
+ char buf[2 * sizeof(struct tzhead) +
+ 2 * sizeof *sp +
+ 4 * TZ_MAX_TIMES];
+ } u_t;
+ u_t * up;
save_errno save;
- if (name == NULL && (name = TZDEFAULT) == NULL)
+ up = (u_t *) calloc(1, sizeof *up);
+ if (up == NULL)
return -1;
+
+ sp->goback = sp->goahead = FALSE;
+ if (name == NULL && (name = TZDEFAULT) == NULL)
+ goto oops;
{
- register int doaccess;
+ int doaccess;
/*
** Section 4.9.1 of the C standard says that
** "FILENAME_MAX expands to an integral constant expression
@@ -731,24 +669,21 @@ tzload(const char *name, struct state *sp)
doaccess = name[0] == '/';
if (!doaccess) {
if ((p = TZDIR) == NULL)
- return -1;
+ goto oops;
if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
- return -1;
- strcpy(fullname, p);
- strcat(fullname, "/");
- strcat(fullname, name);
+ goto oops;
+ (void) strcpy(fullname, p); /* XXX strcpy is safe */
+ (void) strcat(fullname, "/"); /* XXX strcat is safe */
+ (void) strcat(fullname, name); /* XXX strcat is safe */
/*
** Set doaccess if '.' (as in "../") shows up in name.
*/
if (strchr(name, '.') != NULL)
- doaccess = true;
+ doaccess = TRUE;
name = fullname;
}
-#if 0
- if (doaccess && access(name, R_OK) != 0)
- return -1;
-#endif
- if ((fid = open(name, OPEN_MODE)) == -1)
+ if ((doaccess && access(name, R_OK) != 0)
+ || (fid = open(name, OPEN_MODE)) == -1)
{
const char *base = strrchr(name, '/');
if (base)
@@ -762,110 +697,202 @@ tzload(const char *name, struct state *sp)
fid = -2;
}
}
- {
- struct tzhead * tzhp;
- union {
- struct tzhead tzhead;
- char buf[sizeof *sp + sizeof *tzhp];
- } u;
+ if (fid == -2)
+ {
+ memcpy(up->buf, _posixrules_data, sizeof (_posixrules_data));
+ nread = sizeof (_posixrules_data);
+ }
+ else
+ {
+ 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;
- if (fid == -2)
- {
- memcpy(u.buf, _posixrules_data, sizeof (_posixrules_data));
- i = sizeof (_posixrules_data);
- }
- else
- {
- i = read(fid, u.buf, sizeof u.buf);
- if (close(fid) != 0)
- return -1;
- }
- ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
- ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
- sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
- sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
- sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
- sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
- p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+ 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);
+ 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))
- return -1;
- if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
+ goto oops;
+ if (nread - (p - up->buf) <
+ sp->timecnt * stored + /* ats */
sp->timecnt + /* types */
- sp->typecnt * (4 + 2) + /* ttinfos */
+ sp->typecnt * 6 + /* ttinfos */
sp->charcnt + /* chars */
- sp->leapcnt * (4 + 4) + /* lsinfos */
+ sp->leapcnt * (stored + 4) + /* lsinfos */
ttisstdcnt + /* ttisstds */
ttisgmtcnt) /* ttisgmts */
- return -1;
+ goto oops;
for (i = 0; i < sp->timecnt; ++i) {
- sp->ats[i] = detzcode(p);
- p += 4;
+ sp->ats[i] = (time_t)((stored == 4) ?
+ detzcode(p) : detzcode64(p));
+ p += stored;
}
for (i = 0; i < sp->timecnt; ++i) {
sp->types[i] = (unsigned char) *p++;
if (sp->types[i] >= sp->typecnt)
- return -1;
+ goto oops;
}
for (i = 0; i < sp->typecnt; ++i) {
- register struct ttinfo * ttisp;
+ struct ttinfo * ttisp;
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)
- return -1;
+ goto oops;
ttisp->tt_abbrind = (unsigned char) *p++;
if (ttisp->tt_abbrind < 0 ||
ttisp->tt_abbrind > sp->charcnt)
- return -1;
+ goto oops;
}
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;
+ struct lsinfo * lsisp;
lsisp = &sp->lsis[i];
- lsisp->ls_trans = detzcode(p);
- p += 4;
+ lsisp->ls_trans = (time_t)((stored == 4) ?
+ detzcode(p) : detzcode64(p));
+ p += stored;
lsisp->ls_corr = detzcode(p);
p += 4;
}
for (i = 0; i < sp->typecnt; ++i) {
- register struct ttinfo * ttisp;
+ 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)
- return -1;
+ if (ttisp->tt_ttisstd != TRUE &&
+ ttisp->tt_ttisstd != FALSE)
+ goto oops;
}
}
for (i = 0; i < sp->typecnt; ++i) {
- register struct ttinfo * ttisp;
+ struct ttinfo * ttisp;
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)
- return -1;
+ if (ttisp->tt_ttisgmt != TRUE &&
+ ttisp->tt_ttisgmt != FALSE)
+ goto oops;
}
}
+ /*
+ ** Out-of-sort ats should mean we're running on a
+ ** signed time_t system but using a data file with
+ ** unsigned values (or vice versa).
+ */
+ for (i = 0; i < sp->timecnt - 2; ++i)
+ if (sp->ats[i] > sp->ats[i + 1]) {
+ ++i;
+ if (TYPE_SIGNED(time_t)) {
+ /*
+ ** Ignore the end (easy).
+ */
+ sp->timecnt = i;
+ } else {
+ /*
+ ** Ignore the beginning (harder).
+ */
+ int j;
+
+ for (j = 0; j + i < sp->timecnt; ++j) {
+ sp->ats[j] = sp->ats[j + i];
+ sp->types[j] = sp->types[j + i];
+ }
+ sp->timecnt = j;
+ }
+ break;
+ }
+ /*
+ ** If this is an old file, we're done.
+ */
+ if (up->tzhead.tzh_version[0] == '\0')
+ break;
+ nread -= p - up->buf;
+ for (i = 0; i < nread; ++i)
+ up->buf[i] = p[i];
+ /*
+ ** If this is a narrow integer time_t system, we're done.
+ */
+ if (stored >= (int) sizeof(time_t)
+/* CONSTCOND */
+ && TYPE_INTEGRAL(time_t))
+ break;
+ }
+ if (doextend && nread > 2 &&
+ up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
+ sp->typecnt + 2 <= TZ_MAX_TYPES) {
+ struct __state ts;
+ int result;
+
+ up->buf[nread - 1] = '\0';
+ result = tzparse(&ts, &up->buf[1], FALSE);
+ if (result == 0 && ts.typecnt == 2 &&
+ sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
+ for (i = 0; i < 2; ++i)
+ ts.ttis[i].tt_abbrind +=
+ sp->charcnt;
+ for (i = 0; i < ts.charcnt; ++i)
+ sp->chars[sp->charcnt++] =
+ ts.chars[i];
+ i = 0;
+ while (i < ts.timecnt &&
+ ts.ats[i] <=
+ sp->ats[sp->timecnt - 1])
+ ++i;
+ while (i < ts.timecnt &&
+ sp->timecnt < TZ_MAX_TIMES) {
+ sp->ats[sp->timecnt] =
+ ts.ats[i];
+ sp->types[sp->timecnt] =
+ sp->typecnt +
+ ts.types[i];
+ ++sp->timecnt;
+ ++i;
+ }
+ 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;
+ break;
+ }
+ for (i = sp->timecnt - 2; i >= 0; --i)
+ if (typesequiv(sp, sp->types[sp->timecnt - 1],
+ sp->types[i]) &&
+ differ_by_repeat(sp->ats[sp->timecnt - 1],
+ sp->ats[i])) {
+ sp->goahead = TRUE;
+ break;
+ }
}
+ free(up);
if (sp == lclptr)
{
__gettzinfo ()->__tzrule[0].offset
@@ -874,6 +901,31 @@ tzload(const char *name, struct state *sp)
= -sp->ttis[0].tt_gmtoff;
}
return 0;
+oops:
+ free(up);
+ return -1;
+}
+
+static int
+typesequiv(const timezone_t sp, const int a, const int b)
+{
+ int result;
+
+ if (sp == NULL ||
+ a < 0 || a >= sp->typecnt ||
+ b < 0 || b >= sp->typecnt)
+ result = FALSE;
+ else {
+ const struct ttinfo * ap = &sp->ttis[a];
+ const struct ttinfo * bp = &sp->ttis[b];
+ result = ap->tt_gmtoff == bp->tt_gmtoff &&
+ ap->tt_isdst == bp->tt_isdst &&
+ ap->tt_ttisstd == bp->tt_ttisstd &&
+ ap->tt_ttisgmt == bp->tt_ttisgmt &&
+ strcmp(&sp->chars[ap->tt_abbrind],
+ &sp->chars[bp->tt_abbrind]) == 0;
+ }
+ return result;
}
static const int mon_lengths[2][MONSPERYEAR] = {
@@ -887,14 +939,14 @@ static const int year_lengths[2] = {
/*
** Given a pointer into a time zone string, scan until a character that is not
-** a valid character in a zone name is found. Return a pointer to that
+** a valid character in a zone name is found. Return a pointer to that
** character.
*/
static const char *
getzname(const char *strp)
{
- register char c;
+ char c;
while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
c != '+')
@@ -903,6 +955,25 @@ getzname(const char *strp)
}
/*
+** Given a pointer into an extended time zone string, scan until the ending
+** delimiter of the zone name is located. Return a pointer to the delimiter.
+**
+** As with getzname above, the legal character set is actually quite
+** restricted, with other characters producing undefined results.
+** We don't do any checking here; checking is done later in common-case code.
+*/
+
+static const char *
+getqzname(const char *strp, const int delim)
+{
+ int c;
+
+ while ((c = *strp) != '\0' && c != delim)
+ ++strp;
+ return strp;
+}
+
+/*
** Given a pointer into a time zone string, extract a number from that string.
** Check that the number is within a specified range; if it is not, return
** NULL.
@@ -910,22 +981,28 @@ getzname(const char *strp)
*/
static const char *
-getnum(const char *strp, int *nump, const int min, const int max)
+getnum(const char *strp, int *const nump, const int min, const int max)
{
- register char c;
- register int num;
+ char c;
+ int num;
- if (strp == NULL || !is_digit(c = *strp))
+ if (strp == NULL || !is_digit(c = *strp)) {
+ errno = EINVAL;
return NULL;
+ }
num = 0;
do {
num = num * 10 + (c - '0');
- if (num > max)
+ if (num > max) {
+ errno = EOVERFLOW;
return NULL; /* illegal value */
+ }
c = *++strp;
} while (is_digit(c));
- if (num < min)
+ if (num < min) {
+ errno = EINVAL;
return NULL; /* illegal value */
+ }
*nump = num;
return strp;
}
@@ -939,7 +1016,7 @@ getnum(const char *strp, int *nump, const int min, const int max)
*/
static const char *
-getsecs(const char *strp, long *secsp)
+getsecs(const char *strp, long *const secsp)
{
int num;
@@ -961,7 +1038,7 @@ getsecs(const char *strp, long *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;
@@ -979,9 +1056,9 @@ getsecs(const char *strp, long *secsp)
*/
static const char *
-getoffset(const char *strp, long *offsetp)
+getoffset(const char *strp, long *const offsetp)
{
- register int neg = 0;
+ int neg = 0;
if (*strp == '-') {
neg = 1;
@@ -998,13 +1075,13 @@ getoffset(const char *strp, long *offsetp)
/*
** Given a pointer into a time zone string, extract a rule in the form
-** date[/time]. See POSIX section 8 for the format of "date" and "time".
+** date[/time]. See POSIX section 8 for the format of "date" and "time".
** If a valid rule is not found, return NULL.
** Otherwise, return a pointer to the first character not part of the rule.
*/
static const char *
-getrule(const char *strp, struct rule *rulep)
+getrule(const char *strp, struct rule *const rulep)
{
if (*strp == 'J') {
/*
@@ -1056,12 +1133,12 @@ getrule(const char *strp, struct rule *rulep)
*/
static time_t
-transtime(const time_t janfirst, const int year, const struct rule *rulep,
- long offset)
+transtime(const time_t janfirst, const int year, const struct rule *const rulep,
+ const long offset)
{
- register int leapyear;
- register time_t value;
- register int i;
+ int leapyear;
+ time_t value;
+ int i;
int d, m1, yy0, yy1, yy2, dow;
INITIALIZE(value);
@@ -1076,7 +1153,7 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
** add SECSPERDAY times the day number-1 to the time of
** January 1, midnight, to get the day.
*/
- value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+ value = (time_t)(janfirst + (rulep->r_day - 1) * SECSPERDAY);
if (leapyear && rulep->r_day >= 60)
value += SECSPERDAY;
break;
@@ -1087,7 +1164,7 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
** Just add SECSPERDAY times the day number to the time of
** January 1, midnight, to get the day.
*/
- value = janfirst + rulep->r_day * SECSPERDAY;
+ value = (time_t)(janfirst + rulep->r_day * SECSPERDAY);
break;
case MONTH_NTH_DAY_OF_WEEK:
@@ -1096,7 +1173,7 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
*/
value = janfirst;
for (i = 0; i < rulep->r_mon - 1; ++i)
- value += mon_lengths[leapyear][i] * SECSPERDAY;
+ value += (time_t)(mon_lengths[leapyear][i] * SECSPERDAY);
/*
** Use Zeller's Congruence to get day-of-week of first day of
@@ -1112,7 +1189,7 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
dow += DAYSPERWEEK;
/*
- ** "dow" is the day-of-week of the first day of the month. Get
+ ** "dow" is the day-of-week of the first day of the month. Get
** the day-of-month (zero-origin) of the first "dow" day of the
** month.
*/
@@ -1129,17 +1206,17 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
/*
** "d" is the day-of-month (zero-origin) of the day we want.
*/
- value += d * SECSPERDAY;
+ value += (time_t)(d * SECSPERDAY);
break;
}
/*
** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
- ** question. To get the Epoch-relative time of the specified local
+ ** question. To get the Epoch-relative time of the specified local
** time on that day, add the transition time and the current offset
** from UTC.
*/
- return value + rulep->r_time + offset;
+ return (time_t)(value + rulep->r_time + offset);
}
/*
@@ -1148,7 +1225,7 @@ transtime(const time_t janfirst, const int year, const struct rule *rulep,
*/
static int
-tzparse(const char *name, struct state *sp, const int lastditch)
+tzparse(timezone_t sp, const char *name, const int lastditch)
{
const char * stdname;
const char * dstname;
@@ -1156,10 +1233,10 @@ tzparse(const char *name, struct state *sp, const int lastditch)
size_t dstlen;
long stdoffset;
long dstoffset;
- register time_t * atp;
- register unsigned char * typep;
- register char * cp;
- register int load_result;
+ time_t * atp;
+ unsigned char * typep;
+ char * cp;
+ int load_result;
INITIALIZE(dstname);
stdname = name;
@@ -1170,35 +1247,52 @@ tzparse(const char *name, struct state *sp, const int lastditch)
stdlen = (sizeof sp->chars) - 1;
stdoffset = 0;
} else {
- name = getzname(name);
- stdlen = name - stdname;
- if (stdlen < 3)
- return -1;
+ if (*name == '<') {
+ name++;
+ stdname = name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return (-1);
+ stdlen = name - stdname;
+ name++;
+ } else {
+ name = getzname(name);
+ stdlen = name - stdname;
+ }
if (*name == '\0')
return -1;
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
}
- load_result = tzload(TZDEFRULES, sp);
+ load_result = tzload(sp, TZDEFRULES, FALSE);
if (load_result != 0)
sp->leapcnt = 0; /* so, we're off a little */
if (*name != '\0') {
- dstname = name;
- name = getzname(name);
- dstlen = name - dstname; /* length of DST zone name */
- if (dstlen < 3)
- return -1;
+ if (*name == '<') {
+ dstname = ++name;
+ name = getqzname(name, '>');
+ if (*name != '>')
+ return -1;
+ dstlen = name - dstname;
+ name++;
+ } else {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ }
if (*name != '\0' && *name != ',' && *name != ';') {
name = getoffset(name, &dstoffset);
if (name == NULL)
return -1;
} else dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0' && load_result != 0)
+ name = TZDEFRULESTRING;
if (*name == ',' || *name == ';') {
struct rule start;
struct rule end;
- register int year;
- register time_t janfirst;
+ int year;
+ time_t janfirst;
time_t starttime;
time_t endtime;
@@ -1213,21 +1307,24 @@ tzparse(const char *name, struct state *sp, const int lastditch)
return -1;
sp->typecnt = 2; /* standard time and DST */
/*
- ** Two transitions per year, from EPOCH_YEAR to 2037.
+ ** Two transitions per year, from EPOCH_YEAR forward.
*/
- sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
- if (sp->timecnt > TZ_MAX_TIMES)
- return -1;
+ memset(sp->ttis, 0, sizeof(sp->ttis));
sp->ttis[0].tt_gmtoff = -dstoffset;
sp->ttis[0].tt_isdst = 1;
- sp->ttis[0].tt_abbrind = stdlen + 1;
+ sp->ttis[0].tt_abbrind = (int)(stdlen + 1);
sp->ttis[1].tt_gmtoff = -stdoffset;
sp->ttis[1].tt_isdst = 0;
sp->ttis[1].tt_abbrind = 0;
atp = sp->ats;
typep = sp->types;
janfirst = 0;
- for (year = EPOCH_YEAR; year <= 2037; ++year) {
+ sp->timecnt = 0;
+ for (year = EPOCH_YEAR;
+ sp->timecnt + 2 <= TZ_MAX_TIMES;
+ ++year) {
+ time_t newfirst;
+
starttime = transtime(janfirst, year, &start,
stdoffset);
endtime = transtime(janfirst, year, &end,
@@ -1243,8 +1340,13 @@ tzparse(const char *name, struct state *sp, const int lastditch)
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
- janfirst += year_lengths[isleap(year)] *
- SECSPERDAY;
+ sp->timecnt += 2;
+ newfirst = janfirst;
+ newfirst += (time_t)
+ (year_lengths[isleap(year)] * SECSPERDAY);
+ if (newfirst <= janfirst)
+ break;
+ janfirst = newfirst;
}
if (sp == lclptr)
{
@@ -1254,17 +1356,15 @@ tzparse(const char *name, struct state *sp, const int lastditch)
= -sp->ttis[0].tt_gmtoff;
}
} else {
- register long theirstdoffset;
- register long theirdstoffset;
- register long theiroffset;
- register int isdst;
- register int i;
- register int j;
+ long theirstdoffset;
+ long theirdstoffset;
+ long theiroffset;
+ int isdst;
+ int i;
+ int j;
if (*name != '\0')
return -1;
- if (load_result != 0)
- return -1;
/*
** Initial values of theirstdoffset and theirdstoffset.
*/
@@ -1289,7 +1389,7 @@ tzparse(const char *name, struct state *sp, const int lastditch)
/*
** Initially we're assumed to be in standard time.
*/
- isdst = false;
+ isdst = FALSE;
theiroffset = theirstdoffset;
/*
** Now juggle transition times and types
@@ -1316,28 +1416,29 @@ tzparse(const char *name, struct state *sp, const int lastditch)
** offset.
*/
if (isdst && !sp->ttis[j].tt_ttisstd) {
- sp->ats[i] += dstoffset -
- theirdstoffset;
+ sp->ats[i] += (time_t)
+ (dstoffset - theirdstoffset);
} else {
- sp->ats[i] += stdoffset -
- theirstdoffset;
+ sp->ats[i] += (time_t)
+ (stdoffset - theirstdoffset);
}
}
theiroffset = -sp->ttis[j].tt_gmtoff;
- if (sp->ttis[j].tt_isdst)
- theirdstoffset = theiroffset;
- else theirstdoffset = theiroffset;
+ if (!sp->ttis[j].tt_isdst)
+ theirstdoffset = theiroffset;
+ else theirdstoffset = theiroffset;
}
/*
** Finally, fill in ttis.
- ** ttisstd and ttisgmt need not be handled.
+ ** ttisstd and ttisgmt need not be handled
*/
+ memset(sp->ttis, 0, sizeof(sp->ttis));
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_abbrind = stdlen + 1;
+ sp->ttis[1].tt_isdst = TRUE;
+ sp->ttis[1].tt_abbrind = (int)(stdlen + 1);
sp->typecnt = 2;
if (sp == lclptr)
{
@@ -1351,6 +1452,7 @@ tzparse(const char *name, struct state *sp, const int lastditch)
dstlen = 0;
sp->typecnt = 1; /* only standard time */
sp->timecnt = 0;
+ memset(sp->ttis, 0, sizeof(sp->ttis));
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = 0;
sp->ttis[0].tt_abbrind = 0;
@@ -1360,27 +1462,27 @@ tzparse(const char *name, struct state *sp, const int lastditch)
__gettzinfo ()->__tzrule[1].offset = -sp->ttis[0].tt_gmtoff;
}
}
- sp->charcnt = stdlen + 1;
+ sp->charcnt = (int)(stdlen + 1);
if (dstlen != 0)
- sp->charcnt += dstlen + 1;
+ sp->charcnt += (int)(dstlen + 1);
if ((size_t) sp->charcnt > sizeof sp->chars)
return -1;
cp = sp->chars;
- strncpy(cp, stdname, stdlen);
+ (void) strncpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0) {
- strncpy(cp, dstname, dstlen);
+ (void) strncpy(cp, dstname, dstlen);
*(cp + dstlen) = '\0';
}
return 0;
}
static void
-gmtload(struct state *sp)
+gmtload(timezone_t sp)
{
- if (tzload(gmt, sp) != 0)
- tzparse(gmt, sp, true);
+ if (tzload(sp, gmt, TRUE) != 0)
+ (void) tzparse(sp, gmt, TRUE);
}
#ifndef STD_INSPIRED
@@ -1391,21 +1493,20 @@ gmtload(struct state *sp)
static
#endif /* !defined STD_INSPIRED */
void
-tzsetwall P((void))
+tzsetwall (void)
{
if (lcl_is_set == lcl_setting)
return;
lcl_is_set = lcl_setting;
-#ifdef ALL_STATE
if (lclptr == NULL) {
- lclptr = (struct state *) malloc(sizeof *lclptr);
+ save_errno save;
+ lclptr = (timezone_t) calloc(1, sizeof *lclptr);
if (lclptr == NULL) {
settzname(); /* all we can do */
return;
}
}
-#endif /* defined ALL_STATE */
#if defined (__CYGWIN__)
{
TIME_ZONE_INFORMATION tz;
@@ -1470,7 +1571,7 @@ tzsetwall P((void))
sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wSecond);
}
/* printf("TZ deduced as `%s'\n", buf); */
- if (tzparse(buf, lclptr, false) == 0) {
+ if (tzparse(lclptr, buf, FALSE) == 0) {
settzname();
lcl_is_set = lcl_from_default;
strlcpy(lcl_TZname, buf, sizeof (lcl_TZname));
@@ -1483,85 +1584,130 @@ tzsetwall P((void))
}
}
#endif
- if (tzload((char *) NULL, lclptr) != 0)
+ if (tzload(lclptr, NULL, TRUE) != 0)
gmtload(lclptr);
settzname();
}
static NO_COPY muto tzset_guard;
-extern "C" void
-tzset P((void))
+#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
+tzset_unlocked(void)
{
- tzset_guard.init ("tzset_guard")->acquire ();
- const char * name = getenv("TZ");
+ const char * name;
+ name = getenv("TZ");
if (name == NULL) {
if (lcl_is_set != lcl_from_default)
tzsetwall();
- goto out;
+ return;
}
- if (lcl_is_set > 0 && strncmp(lcl_TZname, name, sizeof(lcl_TZname) - 1) == 0)
- goto out;
+ if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
+ return;
lcl_is_set = (strlen(name) < sizeof (lcl_TZname)) ? lcl_from_environment : lcl_unset;
if (lcl_is_set != lcl_unset)
- strlcpy(lcl_TZname, name, sizeof (lcl_TZname));
+ (void)strlcpy(lcl_TZname, name, sizeof (lcl_TZname));
-#ifdef ALL_STATE
if (lclptr == NULL) {
- lclptr = (struct state *) malloc(sizeof *lclptr);
+ save_errno save;
+ lclptr = (timezone_t) calloc(1, sizeof *lclptr);
if (lclptr == NULL) {
settzname(); /* all we can do */
- goto out;
+ 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;
- strcpy(lclptr->chars, gmt);
- } else if (tzload(name, lclptr) != 0) {
- if (name[0] == ':' || tzparse(name, lclptr, false) != 0)
- gmtload(lclptr);
- }
+ (void) strlcpy(lclptr->chars, gmt, sizeof(lclptr->chars));
+ } else if (tzload(lclptr, name, TRUE) != 0)
+ if (name[0] == ':' || tzparse(lclptr, name, FALSE) != 0)
+ (void) gmtload(lclptr);
settzname();
-out:
+}
+
+extern "C" void
+tzset(void)
+{
+ tzset_guard.init ("tzset_guard")->acquire ();
+ tzset_unlocked();
tzset_guard.release ();
}
/*
** 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--
+** 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.
*/
/*ARGSUSED*/
-static void
-localsub (const time_t * const timep,
- const long offset,
- struct tm * const tmp)
+static struct tm *
+localsub(const timezone_t sp, const time_t * const timep, const long offset,
+ struct tm *const tmp)
{
- register struct state * sp;
- register const struct ttinfo * ttisp;
- register int i;
+ const struct ttinfo * ttisp;
+ int i;
+ struct tm * result;
const time_t t = *timep;
- sp = lclptr;
-#ifdef ALL_STATE
- if (sp == NULL) {
- gmtsub(timep, offset, tmp);
- return;
+ if ((sp->goback && t < sp->ats[0]) ||
+ (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
+ time_t newt = t;
+ time_t seconds;
+ time_t tcycles;
+ int_fast64_t icycles;
+
+ if (t < sp->ats[0])
+ seconds = sp->ats[0] - t;
+ else seconds = t - sp->ats[sp->timecnt - 1];
+ --seconds;
+ tcycles = (time_t)
+ (seconds / YEARSPERREPEAT / AVGSECSPERYEAR);
+ ++tcycles;
+ icycles = tcycles;
+ if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ return NULL;
+ seconds = (time_t) icycles;
+ seconds *= YEARSPERREPEAT;
+ seconds *= AVGSECSPERYEAR;
+ if (t < sp->ats[0])
+ newt += seconds;
+ else newt -= seconds;
+ if (newt < sp->ats[0] ||
+ newt > sp->ats[sp->timecnt - 1])
+ return NULL; /* "cannot happen" */
+ result = localsub(sp, &newt, offset, tmp);
+ if (result == tmp) {
+ time_t newy;
+
+ newy = tmp->tm_year;
+ if (t < sp->ats[0])
+ newy -= (time_t)icycles * YEARSPERREPEAT;
+ else newy += (time_t)icycles * YEARSPERREPEAT;
+ tmp->tm_year = (int)newy;
+ if (tmp->tm_year != newy)
+ return NULL;
+ }
+ return result;
}
-#endif /* defined ALL_STATE */
if (sp->timecnt == 0 || t < sp->ats[0]) {
i = 0;
while (sp->ttis[i].tt_isdst)
@@ -1570,10 +1716,17 @@ localsub (const time_t * const timep,
break;
}
} else {
- for (i = 1; i < sp->timecnt; ++i)
- if (t < sp->ats[i])
- break;
- i = sp->types[i - 1];
+ int lo = 1;
+ int hi = sp->timecnt;
+
+ while (lo < hi) {
+ int mid = (lo + hi) / 2;
+
+ if (t < sp->ats[mid])
+ hi = mid;
+ else lo = mid + 1;
+ }
+ i = (int) sp->types[lo - 1];
}
ttisp = &sp->ttis[i];
/*
@@ -1582,49 +1735,58 @@ localsub (const time_t * const timep,
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
*/
- timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ result = timesub(sp, &t, ttisp->tt_gmtoff, tmp);
tmp->tm_isdst = ttisp->tt_isdst;
- tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+ if (sp == lclptr)
+ tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
#ifdef TM_ZONE
tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */
+ return result;
}
+/*
+** Re-entrant version of localtime.
+*/
extern "C" struct tm *
-localtime(const time_t *timep)
+localtime_r(const time_t *timep, struct tm *tmp)
{
- tzset();
- localsub(timep, 0L, &tm);
- return &tm;
+ tzset_guard.init ("tzset_guard")->acquire ();
+ tzset_unlocked();
+ tmp = localsub(lclptr, timep, 0L, tmp);
+ tzset_guard.release ();
+ if (tmp == NULL)
+ errno = EOVERFLOW;
+ return tmp;
}
-/*
- * Re-entrant version of localtime
- */
extern "C" struct tm *
-localtime_r(const time_t *timep, struct tm *tm)
+localtime(const time_t *const timep)
{
- tzset();
- localsub(timep, 0L, tm);
- return tm;
+ return localtime_r(timep, &tm);
}
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
+static NO_COPY muto gmt_guard;
-static void
-gmtsub(const time_t *timep, const long offset, struct tm *tmp)
+static struct tm *
+gmtsub(const timezone_t sp, const time_t *const timep, const long offset,
+ struct tm *tmp)
{
+ struct tm * result;
+
+ gmt_guard.init ("gmt_guard")->acquire ();
if (!gmt_is_set) {
- gmt_is_set = true;
-#ifdef ALL_STATE
- gmtptr = (struct state *) malloc(sizeof *gmtptr);
+ save_errno save;
+ gmt_is_set = TRUE;
+ gmtptr = (timezone_t) calloc(1, sizeof *gmtptr);
if (gmtptr != NULL)
-#endif /* defined ALL_STATE */
gmtload(gmtptr);
}
- timesub(timep, offset, gmtptr, tmp);
+ gmt_guard.release ();
+ result = timesub(gmtptr, timep, offset, tmp);
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
@@ -1634,68 +1796,84 @@ gmtsub(const time_t *timep, const long offset, struct tm *tmp)
if (offset != 0)
tmp->TM_ZONE = wildabbr;
else {
-#ifdef ALL_STATE
if (gmtptr == NULL)
tmp->TM_ZONE = gmt;
else tmp->TM_ZONE = gmtptr->chars;
-#endif /* defined ALL_STATE */
-#ifndef ALL_STATE
- tmp->TM_ZONE = gmtptr->chars;
-#endif /* State Farm */
}
#endif /* defined TM_ZONE */
+ return result;
}
extern "C" struct tm *
-gmtime(const time_t *timep)
+gmtime(const time_t *const timep)
{
- gmtsub(timep, 0L, &tm);
- return &tm;
+ struct tm *tmp = gmtsub(NULL, timep, 0L, &tm);
+
+ if (tmp == NULL)
+ errno = EOVERFLOW;
+
+ return tmp;
}
/*
- * Re-entrant version of gmtime
- */
+** Re-entrant version of gmtime.
+*/
+
extern "C" struct tm *
-gmtime_r(const time_t *timep, struct tm *tm)
+gmtime_r(const time_t * const timep, struct tm *tmp)
{
- gmtsub(timep, 0L, tm);
- return tm;
+ tmp = gmtsub(NULL, timep, 0L, tmp);
+
+ if (tmp == NULL)
+ errno = EOVERFLOW;
+
+ return tmp;
}
#ifdef STD_INSPIRED
extern "C" struct tm *
-offtime(const time_t *timep, const long offset)
+offtime(const time_t *const timep, long offset)
{
- gmtsub(timep, offset, &tm);
- return &tm;
+ struct tm *tmp = gmtsub(NULL, timep, offset, &tm);
+
+ if (tmp == NULL)
+ errno = EOVERFLOW;
+
+ return tmp;
}
#endif /* defined STD_INSPIRED */
-static void
-timesub(const time_t *timep, const long offset, const struct state *sp,
- struct tm *tmp)
+/*
+** Return the number of leap years through the end of the given year
+** where, to make the math easy, the answer for year zero is defined as zero.
+*/
+
+static int
+leaps_thru_end_of(const int y)
{
- register const struct lsinfo * lp;
- register long days;
- register long rem;
- register int y;
- register int yleap;
- register const int * ip;
- register long corr;
- register int hit;
- register int i;
+ return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
+ -(leaps_thru_end_of(-(y + 1)) + 1);
+}
+
+static struct tm *
+timesub(const timezone_t sp, const time_t *const timep, const long offset,
+ struct tm *const tmp)
+{
+ const struct lsinfo * lp;
+ time_t tdays;
+ int idays; /* unsigned would be so 2003 */
+ long rem;
+ int y;
+ const int * ip;
+ long corr;
+ int hit;
+ int i;
corr = 0;
hit = 0;
-#ifdef ALL_STATE
i = (sp == NULL) ? 0 : sp->leapcnt;
-#endif /* defined ALL_STATE */
-#ifndef ALL_STATE
- i = sp->leapcnt;
-#endif /* State Farm */
while (--i >= 0) {
lp = &sp->lsis[i];
if (*timep >= lp->ls_trans) {
@@ -1716,115 +1894,170 @@ timesub(const time_t *timep, const long offset, const struct state *sp,
break;
}
}
- days = *timep / SECSPERDAY;
- rem = *timep % SECSPERDAY;
-#ifdef mc68k
- if (*timep == 0x80000000) {
- /*
- ** A 3B1 muffs the division on the most negative number.
- */
- days = -24855;
- rem = -11648;
+ y = EPOCH_YEAR;
+ tdays = (time_t)(*timep / SECSPERDAY);
+ rem = (long) (*timep - tdays * SECSPERDAY);
+ while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
+ int newy;
+ time_t tdelta;
+ int idelta;
+ int leapdays;
+
+ tdelta = tdays / DAYSPERLYEAR;
+ idelta = (int) tdelta;
+ if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
+ return NULL;
+ if (idelta == 0)
+ idelta = (tdays < 0) ? -1 : 1;
+ newy = y;
+ if (increment_overflow(&newy, idelta))
+ return NULL;
+ leapdays = leaps_thru_end_of(newy - 1) -
+ leaps_thru_end_of(y - 1);
+ tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
+ tdays -= leapdays;
+ y = newy;
+ }
+ {
+ long seconds;
+
+ seconds = tdays * SECSPERDAY + 0.5;
+ tdays = (time_t)(seconds / SECSPERDAY);
+ rem += (long) (seconds - tdays * SECSPERDAY);
}
-#endif /* defined mc68k */
- rem += (offset - corr);
+ /*
+ ** Given the range, we can now fearlessly cast...
+ */
+ idays = (int) tdays;
+ rem += offset - corr;
while (rem < 0) {
rem += SECSPERDAY;
- --days;
+ --idays;
}
while (rem >= SECSPERDAY) {
rem -= SECSPERDAY;
- ++days;
+ ++idays;
+ }
+ while (idays < 0) {
+ if (increment_overflow(&y, -1))
+ return NULL;
+ idays += year_lengths[isleap(y)];
}
+ while (idays >= year_lengths[isleap(y)]) {
+ idays -= year_lengths[isleap(y)];
+ if (increment_overflow(&y, 1))
+ return NULL;
+ }
+ tmp->tm_year = y;
+ if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+ return NULL;
+ tmp->tm_yday = idays;
+ /*
+ ** The "extra" mods below avoid overflow problems.
+ */
+ tmp->tm_wday = EPOCH_WDAY +
+ ((y - EPOCH_YEAR) % DAYSPERWEEK) *
+ (DAYSPERNYEAR % DAYSPERWEEK) +
+ leaps_thru_end_of(y - 1) -
+ leaps_thru_end_of(EPOCH_YEAR - 1) +
+ idays;
+ tmp->tm_wday %= DAYSPERWEEK;
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
tmp->tm_hour = (int) (rem / SECSPERHOUR);
- rem = rem % SECSPERHOUR;
+ rem %= SECSPERHOUR;
tmp->tm_min = (int) (rem / SECSPERMIN);
/*
** A positive leap second requires a special
- ** representation. This uses "... ??:59:60" et seq.
+ ** representation. This uses "... ??:59:60" et seq.
*/
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
- tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
- if (tmp->tm_wday < 0)
- tmp->tm_wday += DAYSPERWEEK;
- y = EPOCH_YEAR;
-#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
- while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
- register int newy;
-
- newy = y + days / DAYSPERNYEAR;
- if (days < 0)
- --newy;
- days -= (newy - y) * DAYSPERNYEAR +
- LEAPS_THRU_END_OF(newy - 1) -
- LEAPS_THRU_END_OF(y - 1);
- y = newy;
- }
- tmp->tm_year = y - TM_YEAR_BASE;
- tmp->tm_yday = (int) days;
- ip = mon_lengths[yleap];
- for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
- days = days - (long) ip[tmp->tm_mon];
- tmp->tm_mday = (int) (days + 1);
+ ip = mon_lengths[isleap(y)];
+ for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
+ idays -= ip[tmp->tm_mon];
+ tmp->tm_mday = (int) (idays + 1);
tmp->tm_isdst = 0;
#ifdef TM_GMTOFF
tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */
+ return tmp;
}
extern "C" char *
-ctime(const time_t *timep)
+ctime(const time_t *const timep)
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
** The ctime function converts the calendar time pointed to by timer
-** to local time in the form of a string. It is equivalent to
+** to local time in the form of a string. It is equivalent to
** asctime(localtime(timer))
*/
- return asctime(localtime(timep));
+ struct tm *rtm = localtime(timep);
+ if (rtm == NULL)
+ return NULL;
+ return asctime(rtm);
}
extern "C" char *
-ctime_r(const time_t *timep, char *buf)
+ctime_r(const time_t *const timep, char *buf)
{
- struct tm tm;
+ struct tm mytm, *rtm;
- return asctime_r(localtime_r(timep, &tm), buf);
+ rtm = localtime_r(timep, &mytm);
+ if (rtm == NULL)
+ return NULL;
+ return asctime_r(rtm, buf);
}
/*
** Adapted from code provided by Robert Elz, who writes:
** The "best" way to do mktime I think is based on an idea of Bob
** Kridle's (so its said...) from a long time ago.
-** [kridle@xinet.com as of 1996-01-16.]
-** It does a binary search of the time_t space. Since time_t's are
+** It does a binary search of the time_t space. Since time_t's are
** just 32 bits, its a max of 32 iterations (even at 64 bits it
** would still be very reasonable).
*/
#ifndef WRONG
-#define WRONG (-1)
+#define WRONG ((time_t)-1)
#endif /* !defined WRONG */
/*
-** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
+** Simplified normalize logic courtesy Paul Eggert.
*/
-/* Mark as noinline to prevent a compiler warning. */
-static int __attribute__((noinline))
-increment_overflow(int *number, int delta)
+static int
+increment_overflow(int *const ip, int j)
{
- int number0;
+ int i = *ip;
- number0 = *number;
- *number += delta;
- return (*number < number0) != (delta < 0);
+ /*
+ ** If i >= 0 there can only be overflow if i + j > INT_MAX
+ ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
+ ** If i < 0 there can only be overflow if i + j < INT_MIN
+ ** 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;
+ *ip += j;
+ return FALSE;
+}
+
+static int
+long_increment_overflow(long *const lp, int m)
+{
+ long l = *lp;
+
+ if ((l >= 0) ? (m > LONG_MAX - l) : (m < LONG_MIN - l))
+ return TRUE;
+ *lp += m;
+ return FALSE;
}
static int
-normalize_overflow(int *tensptr, int *unitsptr, const int base)
+normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
{
- register int tensdelta;
+ int tensdelta;
tensdelta = (*unitsptr >= 0) ?
(*unitsptr / base) :
@@ -1834,9 +2067,22 @@ normalize_overflow(int *tensptr, int *unitsptr, const int base)
}
static int
-tmcomp(register const struct tm *atmp, register const struct tm *btmp)
+long_normalize_overflow(long *const tensptr, int *const unitsptr,
+ const int base)
{
- register int result;
+ int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ?
+ (*unitsptr / base) :
+ (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return long_increment_overflow(tensptr, tensdelta);
+}
+
+static int
+tmcomp(const struct tm *const atmp, const struct tm *const btmp)
+{
+ int result;
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
@@ -1848,63 +2094,77 @@ tmcomp(register const struct tm *atmp, register const struct tm *btmp)
}
static time_t
-time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
- const long offset, int *okayp, const int do_norm_secs)
+time2sub(const timezone_t sp, struct tm *const tmp, subfun_t funcp,
+ const long offset, int *const okayp, const int do_norm_secs)
{
- register const struct state * sp;
- register int dir;
- register int bits;
- register int i, j ;
- register int saved_seconds;
+ int dir;
+ int i, j;
+ int saved_seconds;
+ long li;
+ time_t lo;
+ time_t hi;
+#ifdef NO_ERROR_IN_DST_GAP
+ time_t ilo;
+#endif
+ long y;
time_t newt;
time_t t;
struct tm yourtm, mytm;
- *okayp = false;
+ *okayp = FALSE;
yourtm = *tmp;
+#ifdef NO_ERROR_IN_DST_GAP
+again:
+#endif
if (do_norm_secs) {
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
- SECSPERMIN))
- return WRONG;
+ SECSPERMIN))
+ goto overflow;
}
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
- return WRONG;
+ goto overflow;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
- return WRONG;
- if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
- return WRONG;
+ goto overflow;
+ y = yourtm.tm_year;
+ if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
+ goto overflow;
/*
- ** Turn yourtm.tm_year into an actual year number for now.
+ ** Turn y into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
- if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
- return WRONG;
+ if (long_increment_overflow(&y, TM_YEAR_BASE))
+ goto overflow;
while (yourtm.tm_mday <= 0) {
- if (increment_overflow(&yourtm.tm_year, -1))
- return WRONG;
- i = yourtm.tm_year + (1 < yourtm.tm_mon);
- yourtm.tm_mday += year_lengths[isleap(i)];
+ if (long_increment_overflow(&y, -1))
+ goto overflow;
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday += year_lengths[isleap(li)];
}
while (yourtm.tm_mday > DAYSPERLYEAR) {
- i = yourtm.tm_year + (1 < yourtm.tm_mon);
- yourtm.tm_mday -= year_lengths[isleap(i)];
- if (increment_overflow(&yourtm.tm_year, 1))
- return WRONG;
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday -= year_lengths[isleap(li)];
+ if (long_increment_overflow(&y, 1))
+ goto overflow;
}
for ( ; ; ) {
- i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
+ i = mon_lengths[isleap(y)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
- if (increment_overflow(&yourtm.tm_year, 1))
- return WRONG;
+ if (long_increment_overflow(&y, 1))
+ goto overflow;
}
}
- if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
- return WRONG;
- if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
+ if (long_increment_overflow(&y, -TM_YEAR_BASE))
+ goto overflow;
+ yourtm.tm_year = (int)y;
+ if (yourtm.tm_year != y)
+ goto overflow;
+ if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+ saved_seconds = 0;
+ else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
/*
** We can't set tm_sec to 0, because that might push the
** time below the minimum representable time.
@@ -1914,7 +2174,7 @@ time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
** which is a safer assumption than using 58 would be.
*/
if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
- return WRONG;
+ goto overflow;
saved_seconds = yourtm.tm_sec;
yourtm.tm_sec = SECSPERMIN - 1;
} else {
@@ -1922,27 +2182,71 @@ time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
yourtm.tm_sec = 0;
}
/*
- ** Divide the search space in half
- ** (this works whether time_t is signed or unsigned).
+ ** Do a binary search (this works whatever time_t's type is).
*/
- bits = TYPE_BIT(time_t) - 1;
- /*
- ** If time_t is signed, then 0 is just above the median,
- ** assuming two's complement arithmetic.
- ** If time_t is unsigned, then (1 << bits) is just above the median.
- */
- t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+ /* LINTED const not */
+ if (!TYPE_SIGNED(time_t)) {
+ lo = 0;
+ hi = lo - 1;
+ /* LINTED const not */
+ } else {
+ lo = 1;
+ for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+ lo *= 2;
+ hi = -(lo + 1);
+ }
+#ifdef NO_ERROR_IN_DST_GAP
+ ilo = lo;
+#endif
for ( ; ; ) {
- (*funcp)(&t, offset, &mytm);
- dir = tmcomp(&mytm, &yourtm);
+ t = lo / 2 + hi / 2;
+ if (t < lo)
+ t = lo;
+ else if (t > hi)
+ t = hi;
+ if ((*funcp)(sp, &t, offset, &mytm) == NULL) {
+ /*
+ ** Assume that t is too extreme to be represented in
+ ** a struct tm; arrange things so that it is less
+ ** extreme on the next pass.
+ */
+ dir = (t > 0) ? 1 : -1;
+ } else dir = tmcomp(&mytm, &yourtm);
if (dir != 0) {
- if (bits-- < 0)
- return WRONG;
- if (bits < 0)
- --t; /* may be needed if new t is minimal */
- else if (dir > 0)
- t -= ((time_t) 1) << bits;
- else t += ((time_t) 1) << bits;
+ if (t == lo) {
+ ++t;
+ if (t <= lo)
+ goto overflow;
+ ++lo;
+ } else if (t == hi) {
+ --t;
+ if (t >= hi)
+ goto overflow;
+ --hi;
+ }
+#ifdef NO_ERROR_IN_DST_GAP
+ if (ilo != lo && lo - 1 == hi && yourtm.tm_isdst < 0 &&
+ do_norm_secs) {
+ for (i = sp->typecnt - 1; i >= 0; --i) {
+ for (j = sp->typecnt - 1; j >= 0; --j) {
+ time_t off;
+ if (sp->ttis[j].tt_isdst ==
+ sp->ttis[i].tt_isdst)
+ continue;
+ off = sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff;
+ yourtm.tm_sec += off < 0 ?
+ -off : off;
+ goto again;
+ }
+ }
+ }
+#endif
+ if (lo > hi)
+ goto invalid;
+ if (dir > 0)
+ hi = t;
+ else lo = t;
continue;
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
@@ -1953,25 +2257,18 @@ time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
** It's okay to guess wrong since the guess
** gets checked.
*/
- /*
- ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
- */
- sp = (const struct state *)
- (((void *) funcp == (void *) localsub) ?
- lclptr : gmtptr);
-#ifdef ALL_STATE
if (sp == NULL)
- return WRONG;
-#endif /* defined ALL_STATE */
+ goto invalid;
for (i = sp->typecnt - 1; i >= 0; --i) {
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
continue;
for (j = sp->typecnt - 1; j >= 0; --j) {
if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
continue;
- newt = t + sp->ttis[j].tt_gmtoff -
- sp->ttis[i].tt_gmtoff;
- (*funcp)(&newt, offset, &mytm);
+ newt = (time_t)(t + sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff);
+ if ((*funcp)(sp, &newt, offset, &mytm) == NULL)
+ continue;
if (tmcomp(&mytm, &yourtm) != 0)
continue;
if (mytm.tm_isdst != yourtm.tm_isdst)
@@ -1983,21 +2280,28 @@ time2sub(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
goto label;
}
}
- return WRONG;
+ goto invalid;
}
label:
newt = t + saved_seconds;
if ((newt < t) != (saved_seconds < 0))
- return WRONG;
+ goto overflow;
t = newt;
- (*funcp)(&t, offset, tmp);
- *okayp = true;
- return t;
+ if ((*funcp)(sp, &t, offset, tmp)) {
+ *okayp = TRUE;
+ return t;
+ }
+overflow:
+ errno = EOVERFLOW;
+ return WRONG;
+invalid:
+ errno = EINVAL;
+ return WRONG;
}
static time_t
-time2(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
- const long offset, int *okayp)
+time2(const timezone_t sp, struct tm *const tmp, subfun_t funcp,
+ const long offset, int *const okayp)
{
time_t t;
@@ -2006,46 +2310,33 @@ time2(struct tm *tmp, void (*funcp) P((const time_t*, long, struct tm*)),
** (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);
- if (*okayp)
- return t;
- t = time2sub(tmp, funcp, offset, okayp, true);
- if (*okayp)
- return t;
- /* Workaround for the spring forward gap problem which results in
- the autoconf mktime usability test failing.
- What we do here is this: The gap has 3600 seconds. If we
- subtract 3600 from the tm_sec value and get a valid result,
- then we can simply add 3600 to the return value and are done.
- If the result is still not valid, the problem is not the
- spring forward gap and we can give up. */
- struct tm tmp2 = *tmp;
- tmp2.tm_sec -= 3600;
- t = time2sub(&tmp2, funcp, offset, okayp, true);
- if (*okayp)
- {
- if (t + 3600 < 0) /* Sanity check */
- return WRONG;
- return t + 3600;
- }
- return t;
+ t = time2sub(sp, tmp, funcp, offset, okayp, FALSE);
+ return *okayp ? t : time2sub(sp, tmp, funcp, offset, okayp, TRUE);
}
static time_t
-time1(struct tm *tmp, void (*funcp) P((const time_t *, long, struct tm *)),
- const long offset)
+time1(const timezone_t sp, struct tm *const tmp, subfun_t funcp,
+ const long offset)
{
- register time_t t;
- register const struct state * sp;
- register int samei, otheri;
+ time_t t;
+ int samei, otheri;
+ int sameind, otherind;
+ int i;
+ int nseen;
+ int seen[TZ_MAX_TYPES];
+ int types[TZ_MAX_TYPES];
int okay;
+ if (tmp == NULL) {
+ errno = EINVAL;
+ return WRONG;
+ }
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
- t = time2(tmp, funcp, offset, &okay);
+ t = time2(sp, tmp, funcp, offset, &okay);
#ifdef PCTS
/*
- ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+ ** PCTS code courtesy Grant Sullivan.
*/
if (okay)
return t;
@@ -2062,63 +2353,83 @@ time1(struct tm *tmp, void (*funcp) P((const time_t *, long, struct tm *)),
** We try to divine the type they started from and adjust to the
** type they need.
*/
- /*
- ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
- */
- sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
- lclptr : gmtptr);
-#ifdef ALL_STATE
- if (sp == NULL)
+ if (sp == NULL) {
+ errno = EINVAL;
return WRONG;
-#endif /* defined ALL_STATE */
- for (samei = sp->typecnt - 1; samei >= 0; --samei) {
+ }
+ for (i = 0; i < sp->typecnt; ++i)
+ seen[i] = FALSE;
+ nseen = 0;
+ for (i = sp->timecnt - 1; i >= 0; --i)
+ if (!seen[sp->types[i]]) {
+ seen[sp->types[i]] = TRUE;
+ types[nseen++] = sp->types[i];
+ }
+ for (sameind = 0; sameind < nseen; ++sameind) {
+ samei = types[sameind];
if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
continue;
- for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
+ for (otherind = 0; otherind < nseen; ++otherind) {
+ otheri = types[otherind];
if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
continue;
- tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
- sp->ttis[samei].tt_gmtoff;
+ tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff);
tmp->tm_isdst = !tmp->tm_isdst;
- t = time2(tmp, funcp, offset, &okay);
+ t = time2(sp, tmp, funcp, offset, &okay);
if (okay)
return t;
- tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
- sp->ttis[samei].tt_gmtoff;
+ tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff);
tmp->tm_isdst = !tmp->tm_isdst;
}
}
+ errno = EOVERFLOW;
return WRONG;
}
extern "C" time_t
-mktime(struct tm *tmp)
+mktime(struct tm *const tmp)
{
- tzset();
- return time1(tmp, localsub, 0L);
+ time_t result;
+
+ tzset_guard.init ("tzset_guard")->acquire ();
+ tzset_unlocked();
+ result = time1(lclptr, tmp, localsub, 0L);
+ tzset_guard.release ();
+ return result;
}
#ifdef STD_INSPIRED
extern "C" time_t
-timelocal(struct tm *tmp)
+timelocal(struct tm *const tmp)
{
- tmp->tm_isdst = -1; /* in case it wasn't initialized */
+ if (tmp != NULL)
+ tmp->tm_isdst = -1; /* in case it wasn't initialized */
return mktime(tmp);
}
extern "C" time_t
-timegm(struct tm *tmp)
+timegm(struct tm *const tmp)
{
- tmp->tm_isdst = 0;
- return time1(tmp, gmtsub, 0L);
+ time_t t;
+
+ if (tmp != NULL)
+ tmp->tm_isdst = 0;
+ t = time1(gmtptr, tmp, gmtsub, 0L);
+ return t;
}
extern "C" time_t
-timeoff(struct tm *tmp, const long offset)
+timeoff(struct tm *const tmp, const long offset)
{
- tmp->tm_isdst = 0;
- return time1(tmp, gmtsub, offset);
+ time_t t;
+
+ if (tmp != NULL)
+ tmp->tm_isdst = 0;
+ t = time1(gmtptr, tmp, gmtsub, offset);
+ return t;
}
#endif /* defined STD_INSPIRED */
@@ -2131,9 +2442,9 @@ timeoff(struct tm *tmp, const long offset)
*/
extern "C" long
-gtime(struct tm *tmp)
+gtime(struct tm *const tmp)
{
- const time_t t = mktime(tmp);
+ const time_t t = mktime(tmp);
if (t == WRONG)
return -1;
@@ -2157,13 +2468,11 @@ gtime(struct tm *tmp)
*/
static long
-leapcorr(time_t *timep)
+leapcorr(const timezone_t sp, time_t *timep)
{
- register struct state * sp;
- register struct lsinfo * lp;
- register int i;
+ struct lsinfo * lp;
+ int i;
- sp = lclptr;
i = sp->leapcnt;
while (--i >= 0) {
lp = &sp->lsis[i];
@@ -2176,8 +2485,12 @@ leapcorr(time_t *timep)
extern "C" time_t
time2posix(time_t t)
{
- tzset();
- return t - leapcorr(&t);
+ time_t result;
+ tzset_guard.init ("tzset_guard")->acquire ();
+ tzset_unlocked();
+ result = t - leapcorr(lclptr, &t);
+ tzset_guard.release ();
+ return (result);
}
extern "C" time_t
@@ -2186,30 +2499,34 @@ posix2time(time_t t)
time_t x;
time_t y;
- tzset();
+ tzset_guard.init ("tzset_guard")->acquire ();
+ tzset_unlocked();
/*
** For a positive leap second hit, the result
- ** is not unique. For a negative leap second
+ ** 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 = (time_t)(t + leapcorr(lclptr, &t));
+ y = (time_t)(x - leapcorr(lclptr, &x));
if (y < t) {
do {
x++;
- y = x - leapcorr(&x);
+ y = (time_t)(x - leapcorr(lclptr, &x));
} while (y < t);
- if (t != y)
+ if (t != y) {
return x - 1;
+ }
} else if (y > t) {
do {
--x;
- y = x - leapcorr(&x);
+ y = (time_t)(x - leapcorr(lclptr, &x));
} while (y > t);
- if (t != y)
+ if (t != y) {
return x + 1;
+ }
}
+ tzset_guard.release ();
return x;
}