Mail Archives: djgpp-workers/2013/08/17/12:44:52
X-Authentication-Warning: | delorie.com: mail set sender to djgpp-workers-bounces using -f
|
X-Recipient: | djgpp-workers AT delorie DOT com
|
Message-ID: | <520FA8C9.40909@gmx.de>
|
Date: | Sat, 17 Aug 2013 18:46:01 +0200
|
From: | Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
|
User-Agent: | Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2
|
MIME-Version: | 1.0
|
To: | djgpp-workers AT delorie DOT com
|
Subject: | Re: zoneinfo not able to recognize if daylight saving time is in
|
| effect.
|
References: | <51F2C9B5 DOT 3090202 AT gmx DOT de>
|
In-Reply-To: | <51F2C9B5.3090202@gmx.de>
|
X-Provags-ID: | V03:K0:X8QHEcScmYsdfis2TPg6GIlcIGz6mfxoyeHatMttWZs4xZCtpws
|
| ZhB6w/C78Y1yvYzUam5OtX1nh0l/UJhknZGHq0nJO34j9Bx7aIFispO0Eaew9vw03PvUDNB
|
| ma1IW7IgdwhF12k4K/gYCXFHhZdCw6ui5vGS1DeDe8krN90f5awoF+guYe8hIhNIDZEDFKQ
|
| LiGihouzESTeiZHI9U9nA==
|
Reply-To: | djgpp-workers AT delorie DOT com
|
Am 26.07.2013 21:10, schrieb Juan Manuel Guerrero:
[snip]
With the original djgpp code of djgpp/src/libc/ansi/time/ctime.c and
zic with date before 2013-01-30 (aka djdev204 and previous) I was not
able to compile the tzdata2006d tz-database and later. I got error
messages like this:
./host-zic -y ./yearistype -d ../../zoneinfo -L /dev/null africa antarctica asi
a australasia europe northamerica southamerica pacificnew etcetera factory backw
ard systemv solar87 solar88 solar89
"northamerica", line 1638: can't determine time zone abbreviation to use just af
ter until time
"northamerica", line 1646: can't determine time zone abbreviation to use just af
ter until time
make.exe: *** [posix_only] Error 1
I was not willing to waste my time investigating this issue and to figure out
how that very old code works, so I preferred to invested the time to update
djgpp/src/libc/ansi/time/ctime.c and djgpp/src/libc/ansi/time/posixrul.h to the
functionality provided by tz[code|data]2013d. I have also updated all the code
in /djgpp/zoneinfo/src to tz[code|data]2013d so that the new zic and ctime and
family of functions use the same set of auxiliary functions to encode and decode
the zoneinfo database. I have also added a small test program that checks for
some TZ that I am aware of. This test program is based on the sample code I
send in my first post and if someone wants to contribute with test data it will
be welcome. The new djgpp port of zic does not create the version 2 of data
base files that support 64 bit time_t. This makes no sense for djgpp and
bloats the zoneinfo files to be installed. It has been adjusted to continue
producing the old version 0 (32 bit time_t) tz database files.
Regards,
Juan M. Guerrero
2013-08-17 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/tests/libc/ansi/time/makefile: Added tzinfo2.c
* djgpp/tests/libc/ansi/time/tzinfo2.c: Checks for timezone files.
2013-08-09 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/include/tzfile.h: Update to tzcode2013d functionality.
* djgpp/src/libc/ansi/time/ctime.c: Update to tzcode2013d functionality.
* djgpp/src/libc/ansi/time/posixrul.h: Update to tzdata2013d posix rules
as default.
diff -aprNU5 djgpp.orig/include/tzfile.h djgpp/include/tzfile.h
--- djgpp.orig/include/tzfile.h 2012-09-23 07:49:12 +0100
+++ djgpp/include/tzfile.h 2013-08-17 16:02:38 +0100
@@ -1,5 +1,6 @@
+/* Copyright (C) 2013 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#ifndef __dj_include_tzfile_h__
#define __dj_include_tzfile_h__
@@ -45,34 +46,39 @@ extern "C" {
/*
** Information about time zone files.
*/
/* Time zone object file directory */
-#define TZDIR "/usr/share/zoneinfo"
-#define TZDEFAULT "/etc/localtime"
+#define TZDIR "/dev/env/DJDIR/share/zoneinfo"
+#define TZDEFAULT "/dev/env/DJDIR/etc/localtime"
#define TZDEFRULES "posixrules"
/*
** Each file begins with. . .
*/
+#define TZ_MAGIC "TZif"
+
struct tzhead {
- char tzh_reserved[24]; /* reserved for future use */
- char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
- char tzh_leapcnt[4]; /* coded number of leap seconds */
- char tzh_timecnt[4]; /* coded number of transition times */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_version[1]; /* '\0' or '2' as of 2005 */
+ char tzh_reserved[15]; /* reserved--must be zero */
+ 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 */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
** tzh_timecnt (char [4])s coded transition times a la time(2)
** tzh_timecnt (unsigned char)s types of local time starting at above
** tzh_typecnt repetitions of
-** one (char [4]) coded GMT offset in seconds
+** one (char [4]) coded UTC offset in seconds
** one (unsigned char) used to set tm_isdst
** one (unsigned char) that's an abbreviation list index
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
@@ -80,24 +86,34 @@ struct tzhead {
** 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,
+** transition time is local time
+** if absent, transition times are
+** assumed to be local time
*/
/*
-** In the current implementation, "tzset()" refuses to deal with files that
-** exceed any of the limits below.
+** 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).
+** DJGPP does not support version 2 or higher.
*/
/*
-** The TZ_MAX_TIMES value below is enough to handle a bit more than a
-** year's worth of solar time (corrected daily to the nearest second) or
-** 138 years of Pacific Presidential Election time
-** (where there are three time zone transitions every fourth year).
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
*/
-#define TZ_MAX_TIMES 370
+
+#define TZ_MAX_TIMES 1200
#define NOSOLAR /* 4BSD doesn't currently handle solar time */
#ifndef NOSOLAR
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
diff -aprNU5 djgpp.orig/src/libc/ansi/time/ctime.c djgpp/src/libc/ansi/time/ctime.c
--- djgpp.orig/src/libc/ansi/time/ctime.c 2005-01-09 14:56:12 +0100
+++ djgpp/src/libc/ansi/time/ctime.c 2013-08-17 16:02:38 +0100
@@ -1,5 +1,6 @@
+/* Copyright (C) 2013 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2005 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
/* This file has been modified by DJ Delorie. These modifications are
@@ -38,209 +39,259 @@ static char sccsid[] = "@(#)ctime.c 5.23
** POSIX-style TZ environment variable handling from Guy Harris
** (guy AT auspex DOT com).
*/
#include <libc/stubs.h>
+#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <unistd.h>
+#include <limits.h>
+#include <float.h>
#include <tzfile.h>
#include <libc/unconst.h>
#include <libc/bss.h>
#include <libc/environ.h>
#include "posixrul.h"
-#define P(s) s
-#define alloc_size_t size_t
-#define qsort_size_t size_t
-#define fread_size_t size_t
-#define fwrite_size_t size_t
+#if ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 96)) || (__GNUC__ >= 3)
+# define ATTRIBUTE_CONST __attribute__ ((const))
+# define ATTRIBUTE_PURE __attribute__ ((__pure__))
+#else
+# define ATTRIBUTE_CONST /* empty */
+# define ATTRIBUTE_PURE /* empty */
+#endif
+
+#define GRANDPARENTED "Local time zone must be set--see zic manual page"
+#define TZ_ABBR_MAX_LEN 16
+#define TZ_ABBR_CHAR_SET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
+#define TZ_ABBR_ERR_CHAR '_'
+
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
+
+#define AVGSECSPERYEAR 31556952L /* The Gregorian year averages 365.2425 days, which is 31556952 seconds. */
+#define YEARSPERREPEAT 400 /* Years before a Gregorian repeat */
+#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+
+#define ACCESS_MODE (O_RDONLY|O_BINARY)
+#define OPEN_MODE (O_RDONLY|O_BINARY)
+#define IS_ABSOLUTE(n) ((n)[0] == '/' || (n)[0] == '\\' || (n)[1] == ':')
+#define INITIALIZE(x) ((x) = 0)
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
-#define ACCESS_MODE O_RDONLY|O_BINARY
-#define OPEN_MODE O_RDONLY|O_BINARY
/*
** Someone might make incorrect use of a time zone abbreviation:
-** 1. They might reference tzname[0] before calling tzset (explicitly
-** or implicitly).
-** 2. They might reference tzname[1] before calling tzset (explicitly
-** or implicitly).
-** 3. They might reference tzname[1] after setting to a time zone
-** in which Daylight Saving Time is never observed.
-** 4. They might reference tzname[0] after setting to a time zone
-** in which Standard Time is never observed.
-** 5. They might reference tm.TM_ZONE after calling offtime.
+** 1. They might reference tzname[0] before calling tzset (explicitly
+** or implicitly).
+** 2. They might reference tzname[1] before calling tzset (explicitly
+** or implicitly).
+** 3. They might reference tzname[1] after setting to a time zone
+** in which Daylight Saving Time is never observed.
+** 4. They might reference tzname[0] after setting to a time zone
+** in which Standard Time is never observed.
+** 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
** string "tzname[0] used before set", and similarly for the other cases.
** 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).
*/
-static char WILDABBR[] = " ";
+static char wildabbr[] = " ";
#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
+#define TRUE 1
+#define FALSE 0
#endif /* !defined TRUE */
-static const char GMT[] = "GMT";
+static const char gmt[] = "GMT";
-struct ttinfo { /* time type information */
- long tt_gmtoff; /* GMT 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 */
+/*
+** 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 */
+ int_fast32_t 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 */
};
-struct lsinfo { /* leap second information */
- time_t ls_trans; /* transition time */
- long ls_corr; /* correction to apply */
+struct lsinfo { /* leap second information */
+ time_t ls_trans; /* transition time */
+ int_fast64_t ls_corr; /* correction to apply */
};
+#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef TZNAME_MAX
+#define MY_TZNAME_MAX TZNAME_MAX
+#endif /* defined TZNAME_MAX */
+#ifndef TZNAME_MAX
+#define MY_TZNAME_MAX 255
+#endif /* !defined TZNAME_MAX */
+
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[(TZ_MAX_CHARS + 1 > sizeof GMT) ? TZ_MAX_CHARS + 1 : sizeof GMT];
+ char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))];
struct lsinfo lsis[TZ_MAX_LEAPS];
+ int defaulttype; /* for early times or if no transitions */
};
struct rule {
- 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 */
- long r_time; /* transition time of rule */
+ 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 */
+#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.
*/
-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 void normalize P((int * tensptr, int * unitsptr, int base));
-static void settzname P((void));
-static time_t time1 P((struct tm * tmp, void (* funcp)(const time_t * const, const long, struct tm * const),
- long offset));
-static time_t time2 P((struct tm *tmp, void (* funcp)(const time_t * const, const long, struct tm * const),
- long offset, int * okayp));
-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 void tmnormalize P((struct tm * tmp));
-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 */
+static int_fast32_t detzcode(const char *codep);
+static int differ_by_repeat(time_t t1, time_t t0);
+static const char *getnum(const char *strp, int *nump, int min, int max);
+static const char *getqzname(const char * strp, const int delim) ATTRIBUTE_PURE;
+static const char *getzname(const char *strp) ATTRIBUTE_PURE;
+static const char *getsecs(const char *strp, int_fast32_t *const secsp);
+static const char *getoffset(const char *strp, int_fast32_t *const offsetp);
+static const char *getrule(const char *strp, struct rule *rulep);
+static void gmtload(struct state *sp);
+static struct tm *gmtsub(const time_t *const timep, const int_fast32_t offset, struct tm *const tmp);
+static int increment_overflow(int *const ip, int j);
+static struct tm *localsub(const time_t *const timep, const int_fast32_t offset, struct tm *const tmp);
+static void settzname(void);
+static time_t time1(struct tm *const tmp, struct tm *(*const funcp) (const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset);
+static time_t time2(struct tm *const tmp, struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset, int *const okayp);
+static struct tm *timesub(const time_t *const timep, const int_fast32_t offset, register const struct state *const sp, register struct tm *const 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, int_fast32_t offset) ATTRIBUTE_PURE;
+static int typesequiv(const struct state *const sp, const int a, const int b);
+static int tzload(const char *name, struct state *const sp, const int doextend);
+static int tzparse(const char *name, struct state *sp, int lastditch);
-#ifndef ALL_STATE
static struct state lclmem;
static struct state gmtmem;
#define lclptr (&lclmem)
#define gmtptr (&gmtmem)
-#endif /* State Farm */
-static int lcl_is_set; /* 0: no, 1: set by tzset, -1: set by tzsetwall */
+#ifndef TZ_STRLEN_MAX
+#define TZ_STRLEN_MAX 255
+#endif /* !defined TZ_STRLEN_MAX */
+
+static char lcl_TZname[TZ_STRLEN_MAX + 1];
+static int lcl_is_set; /* 0: no, 1: set by tzset, -1: set by tzsetwall */
static int gmt_is_set;
-static char lcl_tzstr[512];
-char * tzname[2] = {
- WILDABBR,
- WILDABBR
+char *tzname[2] = {
+ wildabbr,
+ wildabbr
};
-static long
-detzcode(const char * const codep)
+static int_fast32_t
+detzcode(const char *const codep)
{
- long result;
- int i;
+ register int_fast32_t result;
+ register int i;
- result = 0;
+ result = (codep[0] & 0x80) ? -1 : 0;
for (i = 0; i < 4; ++i)
result = (result << 8) | (codep[i] & 0xff);
return result;
}
static void
settzname(void)
{
- const struct state * const sp = lclptr;
+ register struct state *const sp = lclptr;
int i;
- tzname[0] = WILDABBR;
- tzname[1] = WILDABBR;
-#ifdef ALL_STATE
- if (sp == NULL)
- {
- tzname[0] = tzname[1] = GMT;
- return;
- }
-#endif /* defined ALL_STATE */
- for (i = 0; i < sp->typecnt; ++i)
- {
- register const struct ttinfo * const ttisp = &sp->ttis[i];
+ tzname[0] = wildabbr;
+ tzname[1] = wildabbr;
- tzname[ttisp->tt_isdst] =
- unconst(&sp->chars[ttisp->tt_abbrind], char *);
-#if 0
- if (ttisp->tt_isdst)
- _daylight = 1;
- if (i == 0 || !ttisp->tt_isdst)
- _timezone = -(ttisp->tt_gmtoff);
- if (i == 0 || ttisp->tt_isdst)
- _altzone = -(ttisp->tt_gmtoff);
-#endif
- }
/*
** And to get the latest zone names into tzname. . .
*/
+ for (i = 0; i < sp->typecnt; ++i)
+ {
+ register const struct ttinfo *const ttisp = &sp->ttis[i];
+
+ tzname[ttisp->tt_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *);
+ }
for (i = 0; i < sp->timecnt; ++i)
{
- const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]];
+ register const struct ttinfo *const ttisp = &sp->ttis[sp->types[i]];
tzname[ttisp->tt_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *);
}
+ /*
+ ** Finally, scrub the abbreviations.
+ ** First, replace bogus characters.
+ */
+ for (i = 0; i < sp->charcnt; ++i)
+ if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+ sp->chars[i] = TZ_ABBR_ERR_CHAR;
+ /*
+ ** Second, truncate long abbreviations.
+ */
+ for (i = 0; i < sp->typecnt; ++i)
+ {
+ register const struct ttinfo *const ttisp = &sp->ttis[i];
+ register char *cp = unconst(&sp->chars[ttisp->tt_abbrind], char *);
+ if (strlen(cp) > TZ_ABBR_MAX_LEN && strcmp(cp, GRANDPARENTED) != 0)
+ *(cp + TZ_ABBR_MAX_LEN) = '\0';
+ }
+}
+
+static int
+differ_by_repeat(const time_t t1, const time_t t0)
+{
+ if (TYPE_INTEGRAL(time_t) && TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+ return 0;
+ return t1 - t0 == SECSPERREPEAT;
}
static char *
tzdir(void)
{
- static char dir[FILENAME_MAX + 1]={0}, *cp;
+ static char *cp, dir[FILENAME_MAX + 1] = {0};
static int tzdir_bss_count = -1;
/* Force recomputation of cached values (Emacs). */
if (tzdir_bss_count != __bss_count)
{
@@ -263,26 +314,28 @@ tzdir(void)
}
return dir;
}
static int
-tzload(const char *name, struct state * const sp)
+tzload(const char *name, struct state *const sp, const int doextend)
{
- const char * p;
+ const char *p;
int i;
int fid;
+ int nread = 0;
char fullname[FILENAME_MAX + 1];
- const struct tzhead * tzhp;
- char buf[sizeof *sp + sizeof *tzhp];
- int ttisstdcnt;
+ const struct tzhead *tzhp;
+ char buf[sizeof *tzhp + sizeof *sp + 2 * TZ_MAX_TIMES];
+ int ttisgmtcnt, ttisstdcnt;
+ sp->goback = sp->goahead = FALSE;
if (name == NULL && (name = TZDEFAULT) == NULL)
return -1;
if (name[0] == ':')
++name;
- if (name[0] && name[0] != '/' && name[0] != '\\' && name[1] != ':')
+ if (name[0] && !IS_ABSOLUTE(name))
{
if ((p = tzdir()) == NULL)
return -1;
if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
return -1;
@@ -311,33 +364,37 @@ tzload(const char *name, struct state *
memcpy(buf, _posixrules_data, sizeof(_posixrules_data));
i = sizeof(_posixrules_data);
}
else
{
- i = read(fid, buf, sizeof buf);
- if (close(fid) != 0 || i < (int)sizeof *tzhp)
+ nread = read(fid, buf, sizeof buf);
+ if (close(fid) != 0 || nread < (int)sizeof *tzhp)
return -1;
}
tzhp = (struct tzhead *) buf;
+ ttisgmtcnt = (int) detzcode(tzhp->tzh_ttisgmtcnt);
ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
sp->charcnt = (int) detzcode(tzhp->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))
+ (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
+ (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
- if (i < (int)( sizeof *tzhp +
- sp->timecnt * (4 + sizeof (char)) +
- sp->typecnt * (4 + 2 * sizeof (char)) +
- sp->charcnt * sizeof (char) +
- sp->leapcnt * 2 * 4 +
- ttisstdcnt * sizeof (char) ))
+ if (nread < (int)(sizeof *tzhp +
+ sp->timecnt * 4 + /* ats */
+ sp->timecnt * sizeof(char) + /* types */
+ sp->typecnt * (4 + 2 * sizeof(char)) + /* ttinfos */
+ sp->charcnt * sizeof(char) + /* chars */
+ sp->leapcnt * 2 * 4 + /* lsinfos */
+ ttisstdcnt * sizeof(char) + /* ttisstds */
+ ttisgmtcnt * sizeof(char))) /* ttisgmts */
return -1;
p = buf + sizeof *tzhp;
for (i = 0; i < sp->timecnt; ++i)
{
sp->ats[i] = detzcode(p);
@@ -349,67 +406,227 @@ tzload(const char *name, struct state *
if (sp->types[i] >= sp->typecnt)
return -1;
}
for (i = 0; i < sp->typecnt; ++i)
{
- struct ttinfo * ttisp;
+ register 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;
ttisp->tt_abbrind = (unsigned char) *p++;
- if (ttisp->tt_abbrind < 0 ||
- ttisp->tt_abbrind > sp->charcnt)
+ if (ttisp->tt_abbrind < 0 || ttisp->tt_abbrind > sp->charcnt)
return -1;
}
for (i = 0; i < sp->charcnt; ++i)
sp->chars[i] = *p++;
- sp->chars[i] = '\0'; /* ensure '\0' at end */
+ sp->chars[i] = '\0'; /* ensure '\0' at end */
for (i = 0; i < sp->leapcnt; ++i)
{
- struct lsinfo * lsisp;
+ register struct lsinfo *lsisp;
lsisp = &sp->lsis[i];
lsisp->ls_trans = detzcode(p);
p += 4;
lsisp->ls_corr = detzcode(p);
p += 4;
}
for (i = 0; i < sp->typecnt; ++i)
{
- struct ttinfo * ttisp;
+ register struct ttinfo *ttisp;
ttisp = &sp->ttis[i];
if (ttisstdcnt == 0)
ttisp->tt_ttisstd = FALSE;
else
{
ttisp->tt_ttisstd = *p++;
if (ttisp->tt_ttisstd != TRUE &&
- ttisp->tt_ttisstd != FALSE)
- return -1;
+ ttisp->tt_ttisstd != FALSE)
+ return -1;
+ }
+ }
+ for (i = 0; i < sp->typecnt; ++i)
+ {
+ register struct ttinfo *ttisp;
+
+ ttisp = &sp->ttis[i];
+ if (ttisgmtcnt == 0)
+ ttisp->tt_ttisgmt = FALSE;
+ else
+ {
+ ttisp->tt_ttisgmt = *p++;
+ if (ttisp->tt_ttisgmt != TRUE &&
+ ttisp->tt_ttisgmt != FALSE)
+ return -1;
}
}
+ /*
+ ** 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; ++i)
+ if ((i < sp->timecnt - 1 && sp->ats[i] > sp->ats[i + 1]) ||
+ (i == sp->timecnt - 1 && !TYPE_SIGNED(time_t) && sp->ats[i] > INT32_MAX))
+ {
+ if (TYPE_SIGNED(time_t))
+ {
+ /*
+ ** Ignore the end (easy).
+ */
+ sp->timecnt = i + 1;
+ }
+ else
+ {
+ /*
+ ** Ignore the beginning (harder).
+ */
+ register int j;
+
+ /*
+ ** Keep the record right before the
+ ** epoch boundary,
+ ** but tweak it so that it starts
+ ** right with the epoch
+ ** (thanks to Doug Bailey).
+ */
+ sp->ats[i] = 0;
+ 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;
+ }
+
+ /*
+ ** DJGPP only supports old files (version 0).
+ */
+#if 0
+ if (tzhp->tzh_version[0] != '\0')
+ return -1;
+#endif
+
+ if (doextend && nread > 2 &&
+ buf[0] == '\n' && buf[nread - 1] == '\n' &&
+ sp->typecnt + 2 <= TZ_MAX_TYPES)
+ {
+ struct state ts;
+ register int result;
+
+ buf[nread - 1] = '\0';
+ result = tzparse(&buf[1], &ts, 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;
+ }
+ }
+ /*
+ ** If type 0 is unused in transitions,
+ ** it's the type to use for early times.
+ */
+ for (i = 0; i < sp->typecnt; ++i)
+ if (sp->types[i] == 0)
+ break;
+ i = (i >= sp->typecnt) ? 0 : -1;
+ /*
+ ** Absent the above,
+ ** if there are transition times
+ ** and the first transition is to a daylight time
+ ** find the standard type less than and closest to
+ ** the type of the first transition.
+ */
+ if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst)
+ {
+ i = sp->types[0];
+ while (--i > -1)
+ if (!sp->ttis[i].tt_isdst)
+ break;
+ }
+ /*
+ ** If no result yet, find the first standard type.
+ ** If there is none, punt to type zero.
+ */
+ if (i < 0)
+ {
+ i = 0;
+ while (sp->ttis[i].tt_isdst)
+ if (++i >= sp->typecnt)
+ {
+ i = 0;
+ break;
+ }
+ }
+ sp->defaulttype = i;
return 0;
}
+static int
+typesequiv(const struct state *const sp, const int a, const int b)
+{
+ register int result;
+
+ if (sp == NULL || a < 0 || a >= sp->typecnt || b < 0 || b >= sp->typecnt)
+ result = FALSE;
+ else
+ {
+ register const struct ttinfo *ap = &sp->ttis[a];
+ register 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] = {
-{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
static const int year_lengths[2] = {
-DAYSPERNYEAR, DAYSPERLYEAR
-};
-
-static const long n_year_lengths[3] = {
- 3*DAYSPERNYEAR + DAYSPERLYEAR, /* 4-year cycle length */
- 25*(3*DAYSPERNYEAR + DAYSPERLYEAR) - 1, /* 100-year cycle length */
- 4*(25*(3*DAYSPERNYEAR + DAYSPERLYEAR) - 1) + 1 /* 400-year cycle length */
+ DAYSPERNYEAR, DAYSPERLYEAR
};
/*
** 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
@@ -419,12 +636,30 @@ static const long n_year_lengths[3] = {
static const char *
getzname(const char *strp)
{
unsigned char c;
- while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
- c != '+')
+ while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+')
+ ++strp;
+ return 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)
+{
+ register int c;
+
+ while ((c = *strp) != '\0' && c != delim)
++strp;
return strp;
}
/*
@@ -433,27 +668,27 @@ getzname(const char *strp)
** NULL.
** Otherwise, return a pointer to the first character not part of the number.
*/
static const char *
-getnum(const char *strp, int * const nump, const int min, const int max)
+getnum(const char *strp, int *const nump, const int min, const int max)
{
unsigned char c;
int num;
- if (strp == NULL || !isdigit((unsigned char)*strp))
+ if (strp == NULL || !is_digit((unsigned char)*strp))
return NULL;
num = 0;
- while ((c = *strp) != '\0' && isdigit(c))
+ while ((c = *strp) != '\0' && is_digit(c))
{
num = num * 10 + (c - '0');
if (num > max)
- return NULL;
+ return NULL; /* illegal value */
++strp;
}
if (num < min)
- return NULL;
+ return NULL; /* illegal value */
*nump = num;
return strp;
}
/*
@@ -463,31 +698,38 @@ getnum(const char *strp, int * const num
** Otherwise, return a pointer to the first character not part of the number
** of seconds.
*/
static const char *
-getsecs(const char *strp, long * const secsp)
+getsecs(const char *strp, int_fast32_t *const secsp)
{
int num;
- strp = getnum(strp, &num, 0, HOURSPERDAY);
+ /*
+ ** `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''.
+ */
+ strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
if (strp == NULL)
return NULL;
- *secsp = num * SECSPERHOUR;
+ *secsp = num * (int_fast32_t)SECSPERHOUR;
if (*strp == ':')
{
++strp;
strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
if (strp == NULL)
return NULL;
*secsp += num * SECSPERMIN;
if (*strp == ':')
{
++strp;
- strp = getnum(strp, &num, 0, SECSPERMIN - 1);
+ /* `SECSPERMIN' allows for leap seconds. */
+ strp = getnum(strp, &num, 0, SECSPERMIN);
if (strp == NULL)
- return NULL;
+ return NULL;
*secsp += num;
}
}
return strp;
}
@@ -498,23 +740,21 @@ getsecs(const char *strp, long * const s
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the time.
*/
static const char *
-getoffset(const char *strp, long * const offsetp)
+getoffset(const char *strp, int_fast32_t *const offsetp)
{
- int neg;
+ int neg = 0;
if (*strp == '-')
{
neg = 1;
++strp;
}
- else if (isdigit((unsigned char)*strp) || *strp++ == '+')
- neg = 0;
- else
- return NULL; /* illegal offset */
+ else if (*strp == '+')
+ ++strp;
strp = getsecs(strp, offsetp);
if (strp == NULL)
return NULL; /* illegal time */
if (neg)
*offsetp = -*offsetp;
@@ -527,11 +767,11 @@ getoffset(const char *strp, long * const
** 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 * const rulep)
+getrule(const char *strp, struct rule *const rulep)
{
if (*strp == 'J')
{
/*
** Julian day.
@@ -557,20 +797,20 @@ getrule(const char *strp, struct rule *
return NULL;
if (*strp++ != '.')
return NULL;
strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
}
- else if (isdigit((unsigned char)*strp))
+ else if (is_digit((unsigned char)*strp))
{
/*
** Day of year.
*/
rulep->r_type = DAY_OF_YEAR;
strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
}
else
- return NULL; /* invalid format */
+ return NULL; /* invalid format */
if (strp == NULL)
return NULL;
if (*strp == '/')
{
/*
@@ -578,28 +818,29 @@ getrule(const char *strp, struct rule *
*/
++strp;
strp = getsecs(strp, &rulep->r_time);
}
else
- rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
+ rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
return strp;
}
/*
-** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
-** year, a rule, and the offset from GMT at the time that rule takes effect,
+** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
+** year, a rule, and the offset from UTC at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect.
*/
static time_t
-transtime(const time_t janfirst, const int year, const struct rule * const rulep, const long offset)
+transtime(const time_t janfirst, const int year, const struct rule *const rulep, const int_fast32_t offset)
{
int leapyear;
- time_t value=0;
+ time_t value;
int i;
int d, m1, yy0, yy1, yy2, dow;
+ INITIALIZE(value);
leapyear = isleap(year);
switch (rulep->r_type)
{
case JULIAN_DAY:
@@ -638,12 +879,11 @@ transtime(const time_t janfirst, const i
*/
m1 = (rulep->r_mon + 9) % 12 + 1;
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
yy1 = yy0 / 100;
yy2 = yy0 % 100;
- dow = ((26 * m1 - 2) / 10 +
- 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+ dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
if (dow < 0)
dow += DAYSPERWEEK;
/*
** "dow" is the day-of-week of the first day of the month. Get
@@ -653,13 +893,12 @@ transtime(const time_t janfirst, const i
d = rulep->r_day - dow;
if (d < 0)
d += DAYSPERWEEK;
for (i = 1; i < rulep->r_week; ++i)
{
- if (d + DAYSPERWEEK >=
- mon_lengths[leapyear][rulep->r_mon - 1])
- break;
+ if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
+ break;
d += DAYSPERWEEK;
}
/*
** "d" is the day-of-month (zero-origin) of the day we want.
@@ -667,78 +906,100 @@ transtime(const time_t janfirst, const i
value += d * SECSPERDAY;
break;
}
/*
- ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
+ ** "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
** time on that day, add the transition time and the current offset
- ** from GMT.
+ ** from UTC.
*/
return value + rulep->r_time + offset;
}
/*
** Given a POSIX section 8-style TZ string, fill in the rule tables as
** appropriate.
*/
static int
-tzparse(const char *name, struct state * const sp, const int lastditch)
+tzparse(const char *name, struct state *const sp, const int lastditch)
{
- const char * stdname;
- const char * dstname=0;
+ const char *stdname;
+ const char *dstname;
size_t stdlen;
- int dstlen;
- long stdoffset;
- long dstoffset;
- time_t * atp;
- unsigned char * typep;
- char * cp;
+ size_t dstlen;
+ int_fast32_t stdoffset;
+ int_fast32_t dstoffset;
+ time_t *atp;
+ unsigned char *typep;
+ char *cp;
int load_result;
+ static struct ttinfo zttinfo;
+ INITIALIZE(dstname);
stdname = name;
if (lastditch)
{
- stdlen = strlen(name); /* length of standard zone name */
+ stdlen = strlen(name); /* length of standard zone name */
name += stdlen;
if (stdlen >= sizeof sp->chars)
stdlen = (sizeof sp->chars) - 1;
}
else
{
- name = getzname(name);
- stdlen = name - stdname;
- if (stdlen < 3)
+ 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;
- }
- if (*name == '\0')
- return -1;
- else
- {
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
}
- load_result = tzload(TZDEFRULES, sp);
+ load_result = tzload(TZDEFRULES, sp, FALSE);
if (load_result != 0)
- sp->leapcnt = 0; /* so, we're off a little */
+ 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;
+ return -1;
}
else
dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0' && load_result != 0)
+ name = TZDEFRULESTRING;
if (*name == ',' || *name == ';')
{
struct rule start;
struct rule end;
int year;
@@ -746,146 +1007,153 @@ tzparse(const char *name, struct state *
time_t starttime;
time_t endtime;
++name;
if ((name = getrule(name, &start)) == NULL)
- return -1;
+ return -1;
if (*name++ != ',')
- return -1;
+ return -1;
if ((name = getrule(name, &end)) == NULL)
- return -1;
+ return -1;
if (*name != '\0')
- return -1;
- sp->typecnt = 2; /* standard time and DST */
+ return -1;
+ sp->typecnt = 2; /* standard time and DST */
/*
- ** Two transitions per year, from EPOCH_YEAR to 2037.
- */
- sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
- if (sp->timecnt > TZ_MAX_TIMES)
- return -1;
+ ** 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_abbrind = 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)
{
- starttime = transtime(janfirst, year, &start,
- stdoffset);
- endtime = transtime(janfirst, year, &end,
- dstoffset);
- if (starttime > endtime)
- {
- *atp++ = endtime;
- *typep++ = 1; /* DST ends */
- *atp++ = starttime;
- *typep++ = 0; /* DST begins */
- }
- else
- {
- *atp++ = starttime;
- *typep++ = 0; /* DST begins */
- *atp++ = endtime;
- *typep++ = 1; /* DST ends */
- }
- janfirst +=
- year_lengths[isleap(year)] * SECSPERDAY;
+ time_t newfirst;
+ starttime = transtime(janfirst, year, &start, stdoffset);
+ endtime = transtime(janfirst, year, &end, dstoffset);
+ if (starttime > endtime)
+ {
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ }
+ else
+ {
+ *atp++ = starttime;
+ *typep++ = 0; /* DST begins */
+ *atp++ = endtime;
+ *typep++ = 1; /* DST ends */
+ }
+ sp->timecnt += 2;
+ newfirst = janfirst;
+ newfirst += year_lengths[isleap(year)] * SECSPERDAY;
+ if (newfirst <= janfirst)
+ break;
+ janfirst = newfirst;
}
}
else
{
- int sawstd;
- int sawdst;
- long stdfix;
- long dstfix;
- long oldfix;
+ register int_fast32_t theirstdoffset;
+ register int_fast32_t theirdstoffset;
+ register int_fast32_t theiroffset;
int isdst;
- int i;
+ int i, j;
if (*name != '\0')
- return -1;
- if (load_result != 0)
- return -1;
+ return -1;
/*
- ** Compute the difference between the real and
- ** prototype standard and summer time offsets
- ** from GMT, and put the real standard and summer
- ** time offsets into the rules in place of the
- ** prototype offsets.
- */
- sawstd = FALSE;
- sawdst = FALSE;
- stdfix = 0;
- dstfix = 0;
- for (i = 0; i < sp->typecnt; ++i)
+ ** Initial values of theirstdoffset and theirdstoffset.
+ */
+ theirstdoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i)
+ {
+ j = sp->types[i];
+ if (!sp->ttis[j].tt_isdst)
+ {
+ theirstdoffset = -sp->ttis[j].tt_gmtoff;
+ break;
+ }
+ }
+ theirdstoffset = 0;
+ for (i = 0; i < sp->timecnt; ++i)
{
- if (sp->ttis[i].tt_isdst)
- {
- oldfix = dstfix;
- dstfix =
- sp->ttis[i].tt_gmtoff + dstoffset;
- if (sawdst && (oldfix != dstfix))
- return -1;
- sp->ttis[i].tt_gmtoff = -dstoffset;
- sp->ttis[i].tt_abbrind = stdlen + 1;
- sawdst = TRUE;
- }
- else
- {
- oldfix = stdfix;
- stdfix =
- sp->ttis[i].tt_gmtoff + stdoffset;
- if (sawstd && (oldfix != stdfix))
- return -1;
- sp->ttis[i].tt_gmtoff = -stdoffset;
- sp->ttis[i].tt_abbrind = 0;
- sawstd = TRUE;
- }
+ j = sp->types[i];
+ if (sp->ttis[j].tt_isdst)
+ {
+ theirdstoffset = -sp->ttis[j].tt_gmtoff;
+ break;
+ }
}
/*
- ** Make sure we have both standard and summer time.
- */
- if (!sawdst || !sawstd)
- return -1;
+ ** Initially we're assumed to be in standard time.
+ */
+ isdst = FALSE;
+ theiroffset = theirstdoffset;
/*
- ** Now correct the transition times by shifting
- ** them by the difference between the real and
- ** prototype offsets. Note that this difference
- ** can be different in standard and summer time;
- ** the prototype probably has a 1-hour difference
- ** between standard and summer time, but a different
- ** difference can be specified in TZ.
- */
- isdst = FALSE; /* we start in standard time */
+ ** Now juggle transition times and types
+ ** tracking offsets as you do.
+ */
for (i = 0; i < sp->timecnt; ++i)
{
- const struct ttinfo * ttisp;
-
- /*
- ** If summer time is in effect, and the
- ** transition time was not specified as
- ** standard time, add the summer time
- ** offset to the transition time;
- ** otherwise, add the standard time offset
- ** to the transition time.
- */
- ttisp = &sp->ttis[sp->types[i]];
- sp->ats[i] +=
- (isdst && !ttisp->tt_ttisstd) ?
- dstfix : stdfix;
- isdst = ttisp->tt_isdst;
+ j = sp->types[i];
+ sp->types[i] = sp->ttis[j].tt_isdst;
+ if (sp->ttis[j].tt_ttisgmt)
+ {
+ /* No adjustment to transition time */
+ }
+ else
+ {
+ /*
+ ** If summer time is in effect, and the
+ ** transition time was not specified as
+ ** standard time, add the summer time
+ ** offset to the transition time;
+ ** otherwise, add the standard time
+ ** offset to the transition time.
+ */
+ /*
+ ** Transitions from DST to DDST
+ ** will effectively disappear since
+ ** POSIX provides for only one DST
+ ** offset.
+ */
+ if (isdst && !sp->ttis[j].tt_ttisstd)
+ sp->ats[i] += dstoffset - theirdstoffset;
+ else
+ sp->ats[i] += stdoffset - theirstdoffset;
+ }
+ theiroffset = -sp->ttis[j].tt_gmtoff;
+ if (sp->ttis[j].tt_isdst)
+ theirdstoffset = theiroffset;
+ else
+ theirstdoffset = theiroffset;
}
+ /*
+ ** Finally, fill in ttis.
+ */
+ sp->ttis[0] = sp->ttis[1] = zttinfo;
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ 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->typecnt = 2;
}
}
else
{
dstlen = 0;
- sp->typecnt = 1; /* only standard time */
+ sp->typecnt = 1; /* only standard time */
sp->timecnt = 0;
sp->ttis[0].tt_gmtoff = -stdoffset;
sp->ttis[0].tt_isdst = 0;
sp->ttis[0].tt_abbrind = 0;
}
@@ -905,14 +1173,25 @@ tzparse(const char *name, struct state *
}
return 0;
}
static void
-gmtload(struct state * const sp)
+gmtload(struct state *const sp)
+{
+ if (tzload(gmt, sp, TRUE) != 0)
+ (void) tzparse(gmt, sp, TRUE);
+}
+
+void
+tzsetwall(void)
{
- if (tzload(GMT, sp) != 0)
- (void) tzparse(GMT, sp, TRUE);
+ if (lcl_is_set == -1)
+ return;
+ lcl_is_set = -1;
+ if (tzload((char *) NULL, lclptr, TRUE) != 0)
+ gmtload(lclptr);
+ settzname();
}
void
tzset(void)
{
@@ -928,328 +1207,331 @@ tzset(void)
were called, we are all done here. */
last_env_changed = __environ_changed;
name = getenv("TZ");
/* Use stricmp, since if TZ points to a file name, we need to be
case-insensitive. */
- if (lcl_is_set > 0 && (name == NULL || stricmp(name, lcl_tzstr) == 0))
+ if (lcl_is_set > 0 && (name == NULL || stricmp(name, lcl_TZname) == 0))
return;
/* On to some *real* work... */
if (name == NULL)
{
tzsetwall();
lcl_is_set = 1;
return;
}
- if (strlen(name) < sizeof(lcl_tzstr))
- {
- lcl_is_set = 1;
- strcpy(lcl_tzstr, name);
- }
- else
- lcl_is_set = 0;
-#ifdef ALL_STATE
- if (lclptr == NULL)
- {
- lclptr = (struct state *) malloc(sizeof *lclptr);
- if (lclptr == NULL)
- {
- settzname(); /* all we can do */
- return;
- }
- }
-#endif /* defined ALL_STATE */
+ lcl_is_set = strlen(name) < sizeof lcl_TZname;
+ if (lcl_is_set)
+ strcpy(lcl_TZname, name);
+
if (*name == '\0')
{
/*
** User wants it fast rather than right.
*/
- lclptr->leapcnt = 0; /* so, we're off a little */
+ lclptr->leapcnt = 0; /* so, we're off a little */
lclptr->timecnt = 0;
+ lclptr->ttis[0].tt_isdst = 0;
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
- (void) strcpy(lclptr->chars, GMT);
+ (void) strcpy(lclptr->chars, gmt);
}
- else if (tzload(name, lclptr) != 0)
+ else if (tzload(name, lclptr, TRUE) != 0)
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
gmtload(lclptr);
settzname();
}
-void
-tzsetwall(void)
-{
- if (lcl_is_set == -1)
- return;
- lcl_is_set = -1;
-#ifdef ALL_STATE
- if (lclptr == NULL)
- {
- lclptr = (struct state *) malloc(sizeof *lclptr);
- if (lclptr == NULL)
- {
- settzname(); /* all we can do */
- return;
- }
- }
-#endif /* defined ALL_STATE */
- if (tzload((char *) NULL, lclptr) != 0)
- gmtload(lclptr);
- settzname();
-}
-
/*
** 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--
** 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 time_t *const timep, const int_fast32_t offset, struct tm *const tmp)
{
- const struct state * sp;
- const struct ttinfo * ttisp;
+ const struct state *sp;
+ const struct ttinfo *ttisp;
int i;
+ struct tm *result;
const time_t t = *timep;
- tzset();
sp = lclptr;
-#ifdef ALL_STATE
- if (sp == NULL)
+ if ((sp->goback && t < sp->ats[0]) ||
+ (sp->goahead && t > sp->ats[sp->timecnt - 1]))
{
- gmtsub(timep, offset, tmp);
- return;
+ time_t newt = t;
+ register time_t seconds;
+ register time_t tcycles;
+ register int_fast64_t icycles;
+
+ if (t < sp->ats[0])
+ seconds = sp->ats[0] - t;
+ else
+ seconds = t - sp->ats[sp->timecnt - 1];
+ --seconds;
+ tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
+ ++tcycles;
+ icycles = tcycles;
+ if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
+ return NULL;
+ seconds = 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(&newt, offset, tmp);
+ if (result == tmp)
+ {
+ register time_t newy;
+
+ newy = tmp->tm_year;
+ if (t < sp->ats[0])
+ newy -= icycles * YEARSPERREPEAT;
+ else
+ newy += icycles * YEARSPERREPEAT;
+ tmp->tm_year = newy;
+ if (tmp->tm_year != (int)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)
- if (++i >= sp->typecnt)
- {
- i = 0;
- break;
- }
- }
+ i = sp->defaulttype;
else
{
- for (i = 1; i < sp->timecnt; ++i)
- if (t < sp->ats[i])
- break;
- i = sp->types[i - 1];
+ register int lo = 1;
+ register int hi = sp->timecnt;
+
+ while (lo < hi)
+ {
+ register int mid = (lo + hi) >> 1;
+
+ if (t < sp->ats[mid])
+ hi = mid;
+ else
+ lo = mid + 1;
+ }
+ i = (int) sp->types[lo - 1];
}
ttisp = &sp->ttis[i];
/*
** To get (wrong) behavior that's compatible with System V Release 2.0
** you'd replace the statement below with
** t += ttisp->tt_gmtoff;
** timesub(&t, 0L, sp, tmp);
*/
- timesub(&t, ttisp->tt_gmtoff, sp, tmp);
+ result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->tt_isdst;
tzname[tmp->tm_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *);
tmp->tm_zone = unconst(&sp->chars[ttisp->tt_abbrind], char *);
+ return result;
}
struct tm *
-localtime_r( const time_t * __restrict__ timep, struct tm * __restrict__ tm)
+localtime(const time_t *const timep)
{
+ static struct tm tm;
- localsub(timep, 0L, tm);
- return tm;
+ tzset();
+ return localtime_r(timep, &tm);
}
struct tm *
-localtime(const time_t * const timep)
+localtime_r( const time_t * __restrict__ timep, struct tm * __restrict__ tm)
{
- static struct tm tm;
-
- return localtime_r(timep, &tm);
+ return localsub(timep, 0L, tm);;
}
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
-static void
-gmtsub(const time_t * const timep, const long offset, struct tm * const tmp)
+static struct tm *
+gmtsub(const time_t *const timep, const int_fast32_t offset, struct tm *const tmp)
{
+ register struct tm *result;
+
if (!gmt_is_set)
{
gmt_is_set = TRUE;
-#ifdef ALL_STATE
- gmtptr = (struct state *) malloc(sizeof *gmtptr);
- if (gmtptr != NULL)
-#endif /* defined ALL_STATE */
- gmtload(gmtptr);
+ gmtload(gmtptr);
}
- timesub(timep, offset, gmtptr, tmp);
+ result = timesub(timep, offset, gmtptr, tmp);
/*
** Could get fancy here and deliver something such as
- ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
+ ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
if (offset != 0)
- tmp->tm_zone = WILDABBR;
+ 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 */
- }
+ return result;
}
struct tm *
-gmtime_r(const time_t * __restrict__ timep, struct tm * __restrict__ tm)
+gmtime(const time_t *const timep)
{
+ static struct tm tm;
- gmtsub(timep, 0L, tm);
- return tm;
+ return gmtime_r(timep, &tm);
}
struct tm *
-gmtime(const time_t * const timep)
+gmtime_r(const time_t * __restrict__ timep, struct tm * __restrict__ tm)
{
- static struct tm tm;
-
- return gmtime_r(timep, &tm);
+ return gmtsub(timep, 0L, tm);
}
-/* Return the year which is DAYS away from the year Y0. */
+/*
+** 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
-days_to_years(int y0, long *days)
+leaps_thru_end_of(register const int y)
{
- int y, dir, yleap;
-
- y = y0;
- dir = *days >= 0 ? 1 : -1;
-
- /* We move by 400, 100, and 4 years at a time, to quickly reduce
- DAYS to a reasonable value. */
- while (*days*dir > n_year_lengths[2])
- {
- y += dir*400;
- *days -= dir*n_year_lengths[2];
- }
- while (*days*dir > n_year_lengths[1])
- {
- y += dir*100;
- *days -= dir*n_year_lengths[1];
- }
- while (*days*dir > n_year_lengths[0])
- {
- y += dir*4;
- *days -= dir*n_year_lengths[0];
- }
- if (dir == 1)
- for ( ; ; )
- {
- yleap = isleap(y);
- if (*days < (long) year_lengths[yleap])
- break;
- ++y;
- *days = *days - (long) year_lengths[yleap];
- }
- else
- do {
- --y;
- yleap = isleap(y);
- *days = *days + (long) year_lengths[yleap];
- } while (*days < 0);
-
- return y;
+ return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1);
}
-static void
-timesub(const time_t * const timep, const long offset, const struct state * const sp, struct tm * const tmp)
+static struct tm *
+timesub(const time_t *const timep, const int_fast32_t offset, register const struct state *const sp, register struct tm *const tmp)
{
- const struct lsinfo * lp;
- long days;
- long rem;
+ const struct lsinfo *lp;
+ time_t tdays;
+ int idays; /* unsigned would be so 2003 */
+ int_fast64_t rem;
int y;
- int yleap;
- const int * ip;
- long corr;
+ const int *ip;
+ int_fast64_t corr;
int hit;
int i;
corr = 0;
- hit = FALSE;
-#ifdef ALL_STATE
- i = (sp == NULL) ? 0 : sp->leapcnt;
-#endif /* defined ALL_STATE */
-#ifndef ALL_STATE
+ hit = 0;
i = sp->leapcnt;
-#endif /* State Farm */
- while (--i >= 0)
+ while (--i > -1)
{
lp = &sp->lsis[i];
if (*timep >= lp->ls_trans)
{
if (*timep == lp->ls_trans)
- hit = ((i == 0 && lp->ls_corr > 0) ||
- lp->ls_corr > sp->lsis[i - 1].ls_corr);
+ {
+ hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr);
+ if (hit)
+ while (i > 0 &&
+ sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&
+ sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1)
+ {
+ ++hit;
+ --i;
+ }
+ }
corr = lp->ls_corr;
break;
}
}
- days = *timep / SECSPERDAY;
- rem = *timep % SECSPERDAY;
-#ifdef mc68k
- if (*timep == 0x80000000)
+ y = EPOCH_YEAR;
+ tdays = *timep / SECSPERDAY;
+ rem = *timep - tdays * SECSPERDAY;
+ while (tdays < 0 || tdays >= (time_t)year_lengths[isleap(y)])
+ {
+ int newy;
+ register time_t tdelta;
+ register int idelta;
+ register int leapdays;
+
+ tdelta = tdays / DAYSPERLYEAR;
+ idelta = 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;
+ }
{
- /*
- ** A 3B1 muffs the division on the most negative number.
- */
- days = -24855;
- rem = -11648;
+ register int_fast32_t seconds;
+ register time_t half_second = 0.5;
+
+ seconds = tdays * SECSPERDAY + half_second;
+ tdays = seconds / SECSPERDAY;
+ rem += seconds - tdays * SECSPERDAY;
}
-#endif /* mc68k */
- rem += (offset - corr);
+ /*
+ ** Given the range, we can now fearlessly cast...
+ */
+ idays = tdays;
+ rem += offset - corr;
while (rem < 0)
{
rem += SECSPERDAY;
- --days;
+ --idays;
}
while (rem >= SECSPERDAY)
{
rem -= SECSPERDAY;
- ++days;
+ ++idays;
}
- tmp->tm_hour = (int) (rem / SECSPERHOUR);
- rem = rem % SECSPERHOUR;
- tmp->tm_min = (int) (rem / SECSPERMIN);
- tmp->tm_sec = (int) (rem % SECSPERMIN);
- if (hit)
- /*
- ** A positive leap second requires a special
- ** representation. This uses "... ??:59:60".
- */
- ++(tmp->tm_sec);
- tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
+ 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;
- y = days_to_years(EPOCH_YEAR, &days);
- yleap = isleap(y);
- 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);
+ tmp->tm_hour = (int) (rem / SECSPERHOUR);
+ rem %= SECSPERHOUR;
+ tmp->tm_min = (int) (rem / SECSPERMIN);
+ /*
+ ** A positive leap second requires a special
+ ** representation. This uses "... ??:59:60" et seq.
+ */
+ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
+ 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;
tmp->tm_gmtoff = offset;
+ return tmp;
}
/*
** A la X3J11
*/
@@ -1264,15 +1546,15 @@ asctime_r(const struct tm * __restrict__
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
(void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
- wday_name[timeptr->tm_wday],
- mon_name[timeptr->tm_mon],
- timeptr->tm_mday, timeptr->tm_hour,
- timeptr->tm_min, timeptr->tm_sec,
- TM_YEAR_BASE + timeptr->tm_year);
+ wday_name[timeptr->tm_wday],
+ mon_name[timeptr->tm_mon],
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec,
+ TM_YEAR_BASE + timeptr->tm_year);
return result;
}
char *
asctime(const struct tm *timeptr)
@@ -1289,50 +1571,82 @@ ctime_r(const time_t *timep, char *resul
return asctime_r(localtime_r(timep, &tm), result);
}
char *
-ctime(const time_t * const timep)
+ctime(const time_t *const timep)
{
return asctime(localtime(timep));
}
/*
** 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. (mtxinu!kridle now).
-** 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).
+** 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. (mtxinu!kridle now).
+** 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 (-1)
#endif /* !defined WRONG */
-static void
-normalize(int * const tensptr, int * const unitsptr, const int base)
+/*
+** Normalize logic courtesy Paul Eggert.
+*/
+
+static int
+increment_overflow(int *const ip, int j)
{
- if (*unitsptr >= base)
- {
- *tensptr += *unitsptr / base;
- *unitsptr %= base;
- }
- else if (*unitsptr < 0)
- {
- --*tensptr;
- *unitsptr += base;
- if (*unitsptr < 0)
- {
- *tensptr -= 1 + (-*unitsptr) / base;
- *unitsptr = base - (-*unitsptr) % base;
- }
- }
+ register int const i = *ip;
+
+ /*
+ ** 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
-tmcomp(const struct tm * const atmp, const struct tm * const btmp)
+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;
+ *lp += m;
+ return FALSE;
+}
+
+static int
+normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
+{
+ register int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return increment_overflow(tensptr, tensdelta);
+}
+
+static int
+normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr, const int base)
+{
+ register int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return increment_overflow32(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 &&
@@ -1341,220 +1655,283 @@ tmcomp(const struct tm * const atmp, con
(result = (atmp->tm_min - btmp->tm_min)) == 0)
result = atmp->tm_sec - btmp->tm_sec;
return result;
}
-static void
-tmnormalize(struct tm *tmp)
-{
- if (tmp->tm_sec >= SECSPERMIN + 2 || tmp->tm_sec < 0)
- normalize(&tmp->tm_min, &tmp->tm_sec, SECSPERMIN);
- normalize(&tmp->tm_hour, &tmp->tm_min, MINSPERHOUR);
- normalize(&tmp->tm_mday, &tmp->tm_hour, HOURSPERDAY);
- normalize(&tmp->tm_year, &tmp->tm_mon, MONSPERYEAR);
-
- /* If tm_mday is negative, or positive and too large, bring it back
- to the reasonable range [1..366]. */
- if (tmp->tm_mday <= 0 || tmp->tm_mday > DAYSPERLYEAR)
- {
- long days = tmp->tm_mday;
- int yleap = isleap(tmp->tm_year + TM_YEAR_BASE);
-
- while (tmp->tm_mon--)
- days += mon_lengths[yleap][tmp->tm_mon];
- tmp->tm_year =
- days_to_years(tmp->tm_year + TM_YEAR_BASE, &days) - TM_YEAR_BASE;
- tmp->tm_mday = days;
- tmp->tm_mon = 0;
- }
-
- /* Now correct tm_mon and tm_mday so that they are within their
- normal ranges [0..11] and [1..mon_length[tm_mon]], respectively. */
- for ( ; ; )
- {
- int i = mon_lengths[isleap(tmp->tm_year + TM_YEAR_BASE)][tmp->tm_mon];
- if (tmp->tm_mday <= i)
- break;
- tmp->tm_mday -= i;
- if (++tmp->tm_mon >= MONSPERYEAR)
- {
- tmp->tm_mon = 0;
- ++tmp->tm_year;
- }
- }
-}
-
static time_t
-time2(struct tm *tmp, void (*const funcp)(const time_t *const,const long,struct tm *), const long offset, int * const okayp)
+time2sub(struct tm *const tmp, struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset, int *const okayp, const int do_norm_secs)
{
- const struct state * sp;
- int dir;
- int bits;
- int i, j ;
- int saved_seconds;
+ register const struct state *sp;
+ register int dir;
+ register int i, j;
+ register int saved_seconds;
+ register int_fast32_t li;
+ register time_t lo;
+ register time_t hi;
+ int_fast32_t y;
time_t newt;
time_t t;
struct tm yourtm, mytm;
*okayp = FALSE;
- tmnormalize(tmp);
yourtm = *tmp;
- saved_seconds = yourtm.tm_sec;
- yourtm.tm_sec = 0;
+ if (do_norm_secs)
+ {
+ if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN))
+ return WRONG;
+ }
+ if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
+ return WRONG;
+ if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
+ return WRONG;
+ y = yourtm.tm_year;
+ if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
+ return WRONG;
/*
- ** Calculate the number of magnitude bits in a time_t
- ** (this works regardless of whether time_t is
- ** signed or unsigned, though lint complains if unsigned).
- */
- for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
- ;
+ ** Turn y into an actual year number for now.
+ ** It is converted back to an offset from TM_YEAR_BASE later.
+ */
+ if (increment_overflow32(&y, TM_YEAR_BASE))
+ return WRONG;
+ while (yourtm.tm_mday <= 0)
+ {
+ if (increment_overflow32(&y, -1))
+ return WRONG;
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday += year_lengths[isleap(li)];
+ }
+ while (yourtm.tm_mday > DAYSPERLYEAR)
+ {
+ li = y + (1 < yourtm.tm_mon);
+ yourtm.tm_mday -= year_lengths[isleap(li)];
+ if (increment_overflow32(&y, 1))
+ return WRONG;
+ }
+ for ( ; ; )
+ {
+ 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_overflow32(&y, 1))
+ return WRONG;
+ }
+ }
+ if (increment_overflow32(&y, -TM_YEAR_BASE))
+ return WRONG;
+ yourtm.tm_year = y;
+ if (yourtm.tm_year != y)
+ return WRONG;
+ 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.
+ ** Set tm_sec to 59 instead.
+ ** This assumes that the minimum representable time is
+ ** not in the same minute that a leap second was deleted from,
+ ** which is a safer assumption than using 58 would be.
+ */
+ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
+ return WRONG;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = SECSPERMIN - 1;
+ }
+ else
+ {
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ }
/*
- ** If time_t is signed, then 0 is the median value,
- ** if time_t is unsigned, then 1 << bits is median.
- */
- t = (time_t) 1 << bits;
+ ** Do a binary search (this works whatever time_t's type is).
+ */
+ if (!TYPE_SIGNED(time_t))
+ {
+ lo = 0;
+ hi = lo - 1;
+ }
+ else if (!TYPE_INTEGRAL(time_t))
+ {
+ if (sizeof(time_t) > sizeof(float))
+ hi = (time_t) DBL_MAX;
+ else
+ hi = (time_t) FLT_MAX;
+ lo = -hi;
+ }
+ else
+ {
+ lo = 1;
+ for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
+ lo *= 2;
+ hi = -(lo + 1);
+ }
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)(&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;
- else if (dir > 0)
- t -= (time_t) 1 << bits;
- else t += (time_t) 1 << bits;
+ if (t == lo)
+ {
+ ++t;
+ if (t <= lo)
+ return WRONG;
+ ++lo;
+ }
+ else if (t == hi)
+ {
+ --t;
+ if (t >= hi)
+ return WRONG;
+ --hi;
+ }
+ if (lo > hi)
+ return WRONG;
+ if (dir > 0)
+ hi = t;
+ else
+ lo = t;
continue;
}
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
break;
/*
- ** Right time, wrong type.
- ** Hunt for right time, right type.
- ** It's okay to guess wrong since the guess
- ** gets checked.
- */
- sp = (const struct state *)
- ((funcp == localsub) ? lclptr : gmtptr);
-#ifdef ALL_STATE
- if (sp == NULL)
- return WRONG;
-#endif /* defined ALL_STATE */
- for (i = 0; i < sp->typecnt; ++i)
+ ** Right time, wrong type.
+ ** Hunt for right time, right type.
+ ** It's okay to guess wrong since the guess
+ ** gets checked.
+ */
+ sp = (const struct state *)((funcp == localsub) ? lclptr : gmtptr);
+ for (i = sp->typecnt - 1; i >= 0; --i)
{
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
- continue;
- for (j = 0; j < sp->typecnt; ++j)
+ 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);
- if (tmcomp(&mytm, &yourtm) != 0)
- continue;
- if (mytm.tm_isdst != yourtm.tm_isdst)
- continue;
- /*
- ** We have a match.
- */
- t = newt;
- goto label;
+ if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+ continue;
+ newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff;
+ if ((*funcp)(&newt, offset, &mytm) == NULL)
+ continue;
+ if (tmcomp(&mytm, &yourtm) != 0)
+ continue;
+ if (mytm.tm_isdst != yourtm.tm_isdst)
+ continue;
+ /*
+ ** We have a match.
+ */
+ t = newt;
+ goto label;
}
}
return WRONG;
}
- label:
- t += saved_seconds;
- (*funcp)(&t, offset, tmp);
- *okayp = TRUE;
+label:
+ newt = t + saved_seconds;
+ if ((newt < t) != (saved_seconds < 0))
+ return WRONG;
+ t = newt;
+ if ((*funcp)(&t, offset, tmp))
+ *okayp = TRUE;
return t;
}
static time_t
-time1(struct tm * const tmp, void (*const funcp)(const time_t * const, const long, struct tm *), const long offset)
+time2(struct tm *const tmp, struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *), const int_fast32_t offset, int *const okayp)
{
time_t t;
- const struct state * sp;
- int samei, otheri;
+
+ /*
+ ** First try without normalization of seconds
+ ** (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);
+}
+
+static time_t
+time1(struct tm *const tmp, struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *), 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;
+ if (tmp == NULL)
+ {
+ errno = EINVAL;
+ return WRONG;
+ }
if (tmp->tm_isdst > 1)
tmp->tm_isdst = 1;
t = time2(tmp, funcp, offset, &okay);
if (okay || tmp->tm_isdst < 0)
return t;
/*
- ** We're supposed to assume that somebody took a time of one type
- ** and did some math on it that yielded a "struct tm" that's bad.
- ** We try to divine the type they started from and adjust to the
- ** type they need.
- */
- sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
-#ifdef ALL_STATE
- if (sp == NULL)
- return WRONG;
-#endif /* defined ALL_STATE */
- for (samei = 0; samei < sp->typecnt; ++samei)
+ ** We're supposed to assume that somebody took a time of one type
+ ** and did some math on it that yielded a "struct tm" that's bad.
+ ** We try to divine the type they started from and adjust to the
+ ** type they need.
+ */
+ sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
+ 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 = 0; otheri < sp->typecnt; ++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;
+ continue;
+ 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);
if (okay)
- return t;
- tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
- sp->ttis[samei].tt_gmtoff;
+ return t;
+ tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff;
tmp->tm_isdst = !tmp->tm_isdst;
}
}
return WRONG;
}
time_t
mktime(struct tm * tmp)
{
- struct tm save_tm = *tmp;
- int rv = time1(tmp, localsub, 0L);
- if (rv == -1)
- {
- /* Try again, off a few hours. This may get us out of the DST
- switch zone (which has two valid time_t's) and into a "normal"
- range, and we'll compensate the return value afterwards. */
- int delta = 12;
- if (tmp->tm_hour > 12)
- delta = -12;
-
- tmp->tm_hour += delta;
- rv = time1(tmp, localsub, 0L);
- tmp->tm_hour -= delta;
- if (rv != -1)
- rv -= delta*60*60;
- else
- {
- /* tmp might point to a time structure that's before 1/1/1970.
- This can happen if tmp is a result of a call to localtime(0)
- issued in a timezone with a negative offset, like PST8.
- Adding the timezone offset will bring the time structure into
- the valid range. */
- delta = 24 - tmp->tm_hour;
- tmp->tm_hour += delta;
- rv = time1(tmp, localsub, 0L);
- tmp->tm_hour -= delta;
- if (rv != -1)
- rv -= delta*60*60;
- }
- if (rv == -1)
- *tmp = save_tm;
- else
- tmnormalize(tmp);
- }
- return rv;
+ tzset();
+ return time1(tmp, localsub, 0L);
}
diff -aprNU5 djgpp.orig/src/libc/ansi/time/posixrul.h djgpp/src/libc/ansi/time/posixrul.h
--- djgpp.orig/src/libc/ansi/time/posixrul.h 1995-08-27 04:52:08 +0100
+++ djgpp/src/libc/ansi/time/posixrul.h 2013-08-17 16:02:38 +0100
@@ -1,49 +1,44 @@
+/* Copyright (C) 2013 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
/* generated with bin2h from DJGPP/zoneinfo/posixrules */
unsigned char _posixrules_data[] = {
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,
-0,1,16,0,0,0,2,0,0,0,8,0,151,254,240,1,135,225,224,2,119,224,240,3,112,254,96,4,96,253,112,5,80,
+84,90,105,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,
+0,0,235,0,0,0,4,0,0,0,16,158,166,30,112,159,186,235,96,160,134,0,112,161,154,205,96,162,101,226,112,163,131,
+233,224,164,106,174,112,165,53,167,96,166,83,202,240,167,21,137,96,168,51,172,240,168,254,165,224,170,19,142,240,170,222,135,
+224,171,243,112,240,172,190,105,224,173,211,82,240,174,158,75,224,175,179,52,240,176,126,45,224,177,156,81,112,178,103,74,96,
+179,124,51,112,180,71,44,96,181,92,21,112,182,39,14,96,183,59,247,112,184,6,240,96,185,27,217,112,185,230,210,96,187,
+4,245,240,187,198,180,96,188,228,215,240,189,175,208,224,190,196,185,240,191,143,178,224,192,164,155,240,193,111,148,224,194,132,
+125,240,195,79,118,224,196,100,95,240,197,47,88,224,198,77,124,112,199,15,58,224,200,45,94,112,200,248,87,96,202,13,64,
+112,202,216,57,96,203,136,240,112,210,35,244,112,210,96,251,224,211,117,228,240,212,64,221,224,213,85,198,240,214,32,191,224,
+215,53,168,240,216,0,161,224,217,21,138,240,217,224,131,224,218,254,167,112,219,192,101,224,220,222,137,112,221,169,130,96,222,
+190,107,112,223,137,100,96,224,158,77,112,225,105,70,96,226,126,47,112,227,73,40,96,228,94,17,112,229,87,46,224,230,71,
+45,240,231,55,16,224,232,39,15,240,233,22,242,224,234,6,241,240,234,246,212,224,235,230,211,240,236,214,182,224,237,198,181,
+240,238,191,211,96,239,175,210,112,240,159,181,96,241,143,180,112,242,127,151,96,243,111,150,112,244,95,121,96,245,79,120,112,
+246,63,91,96,247,47,90,112,248,40,119,224,249,15,60,112,250,8,89,224,250,248,88,240,251,232,59,224,252,216,58,240,253,
+200,29,224,254,184,28,240,255,167,255,224,0,151,254,240,1,135,225,224,2,119,224,240,3,112,254,96,4,96,253,112,5,80,
224,96,6,64,223,112,7,48,194,96,7,141,25,112,9,16,164,96,9,173,148,240,10,240,134,96,11,224,133,112,12,217,162,
224,13,192,103,112,14,185,132,224,15,169,131,240,16,153,102,224,17,137,101,240,18,121,72,224,19,105,71,240,20,89,42,224,
21,73,41,240,22,57,12,224,23,41,11,240,24,34,41,96,25,8,237,240,26,2,11,96,26,242,10,112,27,225,237,96,28,
209,236,112,29,193,207,96,30,177,206,112,31,161,177,96,32,118,0,240,33,129,147,96,34,85,226,240,35,106,175,224,36,53,
196,240,37,74,145,224,38,21,166,240,39,42,115,224,39,254,195,112,41,10,85,224,41,222,165,112,42,234,55,224,43,190,135,
112,44,211,84,96,45,158,105,112,46,179,54,96,47,126,75,112,48,147,24,96,49,103,103,240,50,114,250,96,51,71,73,240,
52,82,220,96,53,39,43,240,54,50,190,96,55,7,13,240,56,27,218,224,56,230,239,240,57,251,188,224,58,198,209,240,59,
219,158,224,60,175,238,112,61,187,128,224,62,143,208,112,63,155,98,224,64,111,178,112,65,132,127,96,66,79,148,112,67,100,
-97,96,68,47,118,112,69,68,67,96,70,15,88,112,71,36,37,96,71,248,116,240,73,4,7,96,73,216,86,240,74,227,233,
-96,75,184,56,240,76,205,5,224,77,152,26,240,78,172,231,224,79,119,252,240,80,140,201,224,81,97,25,112,82,108,171,224,
-83,64,251,112,84,76,141,224,85,32,221,112,86,44,111,224,87,0,191,112,88,21,140,96,88,224,161,112,89,245,110,96,90,
-192,131,112,91,213,80,96,92,169,159,240,93,181,50,96,94,137,129,240,95,149,20,96,96,105,99,240,97,126,48,224,98,73,
-69,240,99,94,18,224,100,41,39,240,101,61,244,224,102,18,68,112,103,29,214,224,103,242,38,112,104,253,184,224,105,210,8,
-112,106,221,154,224,107,177,234,112,108,198,183,96,109,145,204,112,110,166,153,96,111,113,174,112,112,134,123,96,113,90,202,240,
-114,102,93,96,115,58,172,240,116,70,63,96,117,26,142,240,118,47,91,224,118,250,112,240,120,15,61,224,120,218,82,240,121,
-239,31,224,122,186,52,240,123,207,1,224,124,163,81,112,125,174,227,224,126,131,51,112,127,142,197,224,128,99,21,112,129,119,
-226,96,130,66,247,112,131,87,196,96,132,34,217,112,133,55,166,96,134,11,245,240,135,23,136,96,135,235,215,240,136,247,106,
-96,137,203,185,240,138,215,76,96,139,171,155,240,140,192,104,224,141,139,125,240,142,160,74,224,143,107,95,240,144,128,44,224,
-145,84,124,112,146,96,14,224,147,52,94,112,148,63,240,224,149,20,64,112,150,41,13,96,150,244,34,112,152,8,239,96,152,
-212,4,112,153,232,209,96,154,189,32,240,155,200,179,96,156,157,2,240,157,168,149,96,158,124,228,240,159,136,119,96,160,92,
-198,240,161,113,147,224,162,60,168,240,163,81,117,224,164,28,138,240,165,49,87,224,166,5,167,112,167,17,57,224,167,229,137,
-112,168,241,27,224,169,197,107,112,170,218,56,96,171,165,77,112,172,186,26,96,173,133,47,112,174,153,252,96,175,101,17,112,
-176,121,222,96,177,78,45,240,178,89,192,96,179,46,15,240,180,57,162,96,181,13,241,240,182,34,190,224,182,237,211,240,184,
-2,160,224,184,205,181,240,185,226,130,224,186,182,210,112,187,194,100,224,188,150,180,112,189,162,70,224,190,118,150,112,191,130,
-40,224,192,86,120,112,193,107,69,96,194,54,90,112,195,75,39,96,196,22,60,112,197,43,9,96,197,255,88,240,199,10,235,
-96,199,223,58,240,200,234,205,96,201,191,28,240,202,211,233,224,203,158,254,240,204,179,203,224,205,126,224,240,206,147,173,224,
-207,103,253,112,208,115,143,224,209,71,223,112,210,83,113,224,211,39,193,112,212,51,83,224,213,7,163,112,214,28,112,96,214,
-231,133,112,215,252,82,96,216,199,103,112,217,220,52,96,218,176,131,240,219,188,22,96,220,144,101,240,221,155,248,96,222,112,
-71,240,223,133,20,224,224,80,41,240,225,100,246,224,226,48,11,240,227,68,216,224,228,15,237,240,229,36,186,224,229,249,10,
-112,231,4,156,224,231,216,236,112,232,228,126,224,233,184,206,112,234,205,155,96,235,152,176,112,236,173,125,96,237,120,146,112,
-238,141,95,96,239,97,174,240,240,109,65,96,241,65,144,240,242,77,35,96,243,33,114,240,244,45,5,96,245,1,84,240,246,
-22,33,224,246,225,54,240,247,246,3,224,248,193,24,240,249,213,229,224,250,160,250,240,251,181,199,224,252,138,23,112,253,149,
-169,224,254,105,249,112,255,117,139,224,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
-1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
+97,96,68,47,118,112,69,68,67,96,69,243,168,240,71,45,95,224,71,211,138,240,73,13,65,224,73,179,108,240,74,237,35,
+224,75,156,137,112,76,214,64,96,77,124,107,112,78,182,34,96,79,92,77,112,80,150,4,96,81,60,47,112,82,117,230,96,
+83,28,17,112,84,85,200,96,84,251,243,112,86,53,170,96,86,229,15,240,88,30,198,224,88,196,241,240,89,254,168,224,90,
+164,211,240,91,222,138,224,92,132,181,240,93,190,108,224,94,100,151,240,95,158,78,224,96,77,180,112,97,135,107,96,98,45,
+150,112,99,103,77,96,100,13,120,112,101,71,47,96,101,237,90,112,103,39,17,96,103,205,60,112,105,6,243,96,105,173,30,
+112,106,230,213,96,107,150,58,240,108,207,241,224,109,118,28,240,110,175,211,224,111,85,254,240,112,143,181,224,113,53,224,240,
+114,111,151,224,115,21,194,240,116,79,121,224,116,254,223,112,118,56,150,96,118,222,193,112,120,24,120,96,120,190,163,112,121,
+248,90,96,122,158,133,112,123,216,60,96,124,126,103,112,125,184,30,96,126,94,73,112,127,152,0,96,0,1,0,1,0,1,
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
+1,0,1,0,1,0,1,0,1,2,3,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
-1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
-0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,255,255,199,192,1,0,255,255,185,176,0,4,69,68,84,
-0,69,83,84,0,0,0
-};
+1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,255,255,
+199,192,1,0,255,255,185,176,0,4,255,255,199,192,1,8,255,255,199,192,1,12,69,68,84,0,69,83,84,0,69,87,84,
+0,69,80,84,0,0,0,0,1,0,0,0,1,};
diff -aprNU5 djgpp.orig/tests/libc/ansi/time/makefile djgpp/tests/libc/ansi/time/makefile
--- djgpp.orig/tests/libc/ansi/time/makefile 2005-01-09 15:55:52 +0100
+++ djgpp/tests/libc/ansi/time/makefile 2013-08-17 16:02:38 +0100
@@ -2,9 +2,10 @@ TOP=../..
SRC += ctime.c # There's a warning when compiling this with gcc 2.953.
SRC += mktime.c
SRC += strftime.c
SRC += tzinfo.c
+SRC += tzinfo2.c
SRC += xstrftm.c # There's a warning when compiling this with gcc 2.953.
include $(TOP)/../makefile.inc
diff -aprNU5 djgpp.orig/tests/libc/ansi/time/tzinfo2.c djgpp/tests/libc/ansi/time/tzinfo2.c
--- djgpp.orig/tests/libc/ansi/time/tzinfo2.c 1970-01-01 01:00:00 +0100
+++ djgpp/tests/libc/ansi/time/tzinfo2.c 2013-08-17 15:57:12 +0100
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <libc/unconst.h>
+
+#define buflen 80
+
+void timetest(int *fail, time_t t, const char er[buflen])
+{
+ char or[buflen];
+
+ if (!strftime (or, buflen, "%Y-%m-%d %H:%M:%S %Z", localtime(&t)))
+ {
+ fprintf(stderr, "strftime failed FAIL\n");
+ exit(-1);
+ }
+
+ printf("time_t %ld expected %s\n", (long)t, er);
+ printf(" got %s", or);
+ if (strcmp(er, or)) *fail = 1, printf(" FAIL");
+ printf ("\n");
+}
+
+int main (int argc, char **argv)
+{
+ int fail = 0;
+ static const char *env_string[] = {"TZ=:America/New_York", "TZ=:Europe/Berlin", "TZ=:America/Buenos_Aires"};
+ char *tz;
+
+ if (tz = unconst(env_string[0], char *), putenv(tz))
+ {
+ fprintf(stderr, "putenv failed FAIL\n");
+ exit(-1);
+ }
+ tzset();
+
+ timetest(&fail, 1357016400, "2013-01-01 00:00:00 EST");
+ timetest(&fail, 1362898799, "2013-03-10 01:59:59 EST");
+ timetest(&fail, 1362898800, "2013-03-10 03:00:00 EDT");
+ timetest(&fail, 1372780800, "2013-07-02 12:00:00 EDT");
+ timetest(&fail, 1383454800, "2013-11-03 01:00:00 EDT");
+ timetest(&fail, 1383458400, "2013-11-03 01:00:00 EST");
+ timetest(&fail, 1388552399, "2013-12-31 23:59:59 EST");
+ printf("Test #1 %s\n", (fail ? "FAILED" : "passed"));
+
+
+ printf("\n\n\n");
+
+
+ if (tz = unconst(env_string[1], char *), putenv(tz))
+ {
+ fprintf(stderr, "putenv failed FAIL\n");
+ exit(-1);
+ }
+ tzset();
+
+ timetest(&fail, 1356998461, "2013-01-01 01:01:01 CET");
+ timetest(&fail, 1359766922, "2013-02-02 02:02:02 CET");
+ timetest(&fail, 1370491566, "2013-06-06 06:06:06 CEST");
+ timetest(&fail, 1376701904, "2013-08-17 03:11:44 CEST");
+ timetest(&fail, 1379401749, "2013-09-17 09:09:09 CEST");
+ timetest(&fail, 1384164692, "2013-11-11 11:11:32 CET");
+ timetest(&fail, 1388530799, "2013-12-31 23:59:59 CET");
+ printf("Test #2 %s\n", (fail ? "FAILED" : "passed"));
+
+
+ printf("\n\n\n");
+
+
+ if (tz = unconst(env_string[2], char *), putenv(tz))
+ {
+ fprintf(stderr, "putenv failed FAIL\n");
+ exit(-1);
+ }
+ tzset();
+
+ timetest(&fail, 1357012861, "2013-01-01 01:01:01 ART");
+ timetest(&fail, 1359781322, "2013-02-02 02:02:02 ART");
+ timetest(&fail, 1370509566, "2013-06-06 06:06:06 ART");
+ timetest(&fail, 1376738799, "2013-08-17 08:26:39 ART");
+ timetest(&fail, 1379417277, "2013-09-17 08:27:57 ART");
+ timetest(&fail, 1384179071, "2013-11-11 11:11:11 ART");
+ timetest(&fail, 1388545199, "2013-12-31 23:59:59 ART");
+ printf("Test #3 %s\n", (fail ? "FAILED" : "passed"));
+
+ return 0;
+}
Diffs against tz[code|data]2013d.tar.gz
2013-08-17 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/zoneinfo/src/date.c [OLD_TIME]: Only if OLD_TIME defined
include utmp.h.
[__MSDOS__]: For MSDOS do not declare and do not define oops().
(main): Cast variable to time_t.
[TSP_SETDATE]: Only if TSP_SETDATE defined include syslog.h,
sys/socket.h, netinet/in.h, netdb.h and protocols/timed.h and
define TSPTYPES.
(reset) [__MSDOS__]: MSDOS does not support TSP_SETDATE.
Fix -Wunused-but-set-variable.
(convert): Cast variable to time_t.
(nondigit): Use ATTRIBUTE_PURE macro.
(main): Fix -Wunused-but-set-variable.
2013-08-16 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/zoneinfo/src/zic.c [__DJGPP__]: Define ZIC_VERSION to 0.
[IS_SLASH, IS_ABSOLUTE]: If not defined define them.
(dolink): Use IS_ABSOLUTE for portable testing of absolute file
names. Replace '+' by '%' in file names or directory names.
(itsdir) [D_OK]: On MSDOS/WINDOWS use access() to check if it is
a directory.
(writezone): Replace '+' by '%' in file names or directory names.
Make only the first pass and do not print the newline-enclosed,
POSIX-TZ-environment-variable-style string to create a version 0 file.
(mkdirs): Use HAS_DEVICE and IS_SLASH to handle directory craetiong
in a portable way.
2013-08-14 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
* djgpp/zoneinfo/src/makefile: Support building with gcc 3.4.4 and
from gcc 4.0.0 up to gcc 4.8.3.
Install formated man pages into /share/man/catN.
* djgpp/zoneinfo/src/private.h [__MSDOS__]: Define IS_SLASH(c),
HAS_DEVICE, IS_ABSOLUTE and TZDIR macros.
* djgpp/zoneinfo/src/localtime.c: Define IS_SLASH and IS_ABSOLUTE
for portable testing of absolute file names.
[STD_INSPIRED]: Provide function declarations.
[!__DJGPP__]: Use DJGPP's own libc implementations of localtime,
localtime_r, gmtime, gmtime_r, ctime, ctime_r and mktime.
(tzload): Use IS_ABSOLUTE for portable testing of absolute file
names.
* djgpp/zoneinfo/src/strftime.c [!__DJGPP__]: Use DJGPP's libc
implementations of asctime and asctime_r.
* djgpp/zoneinfo/src/asctime.c [!__DJGPP__]: Use DJGPP's libc
implementations of asctime and asctime_r.
* djgpp/distrib/p/djtzn204/files: Man pages will be stored in
/share/man/catN.
diff -aprNU5 djgpp.orig/distrib/p/djtzn204/files djgpp/distrib/p/djtzn204/files
--- djgpp.orig/distrib/p/djtzn204/files 2013-01-31 22:35:24 +0000
+++ djgpp/distrib/p/djtzn204/files 2013-08-17 14:34:22 +0000
@@ -1,14 +1,14 @@
etc/date.exe
etc/tzselect
etc/zdump.exe
etc/zic.exe
-share/man/man1/date.1
-share/man/man3/newctime.3
-share/man/man3/newtzset.3
-share/man/man3/time2posix.3
-share/man/man5/tzfile.5
-share/man/man8/tzselect.8
-share/man/man8/zdump.8
-share/man/man8/zic.8
+share/man/cat1/date.1
+share/man/cat3/newctime.3
+share/man/cat3/newtzset.3
+share/man/cat3/time2posix.3
+share/man/cat5/tzfile.5
+share/man/cat8/tzselect.8
+share/man/cat8/zdump.8
+share/man/cat8/zic.8
lib/libtz.a
zoneinfo
diff -aprNU5 djgpp.orig/zoneinfo/src/asctime.c djgpp/zoneinfo/src/asctime.c
--- djgpp.orig/zoneinfo/src/asctime.c 2012-10-26 23:37:42 +0000
+++ djgpp/zoneinfo/src/asctime.c 2013-08-17 14:34:22 +0000
@@ -1,5 +1,9 @@
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of asctime and asctime_r. */
+
+
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/
@@ -128,5 +132,6 @@ asctime_r(register const struct tm *time
char *
asctime(register const struct tm *timeptr)
{
return asctime_r(timeptr, buf_asctime);
}
+#endif /* !__DJGPP__ */
diff -aprNU5 djgpp.orig/zoneinfo/src/date.c djgpp/zoneinfo/src/date.c
--- djgpp.orig/zoneinfo/src/date.c 2013-05-28 03:26:18 +0000
+++ djgpp/zoneinfo/src/date.c 2013-08-17 14:34:22 +0000
@@ -28,11 +28,13 @@ static char sccsid[] = "@(#)date.c 4.23
#include "private.h"
#if HAVE_ADJTIME || HAVE_SETTIMEOFDAY
#include "sys/time.h" /* for struct timeval, struct timezone */
#endif /* HAVE_ADJTIME || HAVE_SETTIMEOFDAY */
#include "locale.h"
+#ifdef OLD_TIME
#include "utmp.h" /* for OLD_TIME (or its absence) */
+#endif
#if HAVE_UTMPX_H
#include "utmpx.h"
#endif
#ifndef OTIME_MSG
@@ -52,18 +54,18 @@ static char sccsid[] = "@(#)date.c 4.23
#ifndef SECSPERMIN
#define SECSPERMIN 60
#endif /* !defined SECSPERMIN */
-extern double atof();
+extern double atof(const char *s);
extern char ** environ;
-extern char * getlogin();
-extern time_t mktime();
+extern char * getlogin(void);
+extern time_t mktime(struct tm *tptr);
extern char * optarg;
extern int optind;
-extern char * strchr();
-extern time_t time();
+extern char * strchr(const char *s, int c);
+extern time_t time(time_t *t);
extern char * tzname[2];
static int retval = EXIT_SUCCESS;
static void checkfinal(const char *, int, time_t, time_t);
@@ -72,11 +74,13 @@ static void display(const char *);
static void dogmt(void);
static void errensure(void);
static void iffy(time_t, time_t, const char *, const char *);
int main(int, char**);
static const char * nondigit(const char *);
+#ifndef __MSDOS__
static void oops(const char *);
+#endif /* __MSDOS__ */
static void reset(time_t, int);
static int sametm(const struct tm *, const struct tm *);
static void timeout(FILE *, const char *, const struct tm *);
static void usage(void);
static void wildinput(const char *, const char *,
@@ -92,19 +96,23 @@ main(const int argc, char *argv[])
register int dousg;
register int aflag = 0;
register int dflag = 0;
register int nflag = 0;
register int tflag = 0;
+#if HAVE_SETTIMEOFDAY == 2
register int minuteswest;
register int dsttime;
+#endif /* HAVE_SETTIMEOFDAY == 2 */
register double adjust;
time_t now;
time_t t;
INITIALIZE(dousg);
+#if HAVE_SETTIMEOFDAY == 2
INITIALIZE(minuteswest);
INITIALIZE(dsttime);
+#endif /* HAVE_SETTIMEOFDAY == 2 */
INITIALIZE(adjust);
INITIALIZE(t);
#ifdef LC_ALL
(void) setlocale(LC_ALL, "");
#endif /* defined(LC_ALL) */
@@ -133,11 +141,13 @@ main(const int argc, char *argv[])
_("date: error: multiple -d's used"));
usage();
}
dflag = 1;
cp = optarg;
+#if HAVE_SETTIMEOFDAY == 2
dsttime = atoi(cp);
+#endif /* HAVE_SETTIMEOFDAY == 2 */
if (*cp == '\0' || *nondigit(cp) != '\0')
wildinput(_("-t value"), optarg,
_("must be a non-negative number"));
break;
case 't': /* minutes west of UTC */
@@ -146,11 +156,13 @@ main(const int argc, char *argv[])
_("date: error: multiple -t's used"));
usage();
}
tflag = 1;
cp = optarg;
+#if HAVE_SETTIMEOFDAY == 2
minuteswest = atoi(cp);
+#endif /* HAVE_SETTIMEOFDAY == 2 */
if (*cp == '+' || *cp == '-')
++cp;
if (*cp == '\0' || *nondigit(cp) != '\0')
wildinput(_("-d value"), optarg,
_("must be a number"));
@@ -424,18 +436,20 @@ reset(const time_t newt, const int nflag
#ifndef BSD4_4
#define TIME_NAME ""
#endif /* !defined BSD4_4 */
#endif /* !defined TIME_NAME */
+#ifdef TSP_SETDATE
#include "syslog.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "netdb.h"
#define TSPTYPES
#include "protocols/timed.h"
+#endif
-extern int logwtmp();
+extern int logwtmp(char *line, char *name, char *host);
#if HAVE_SETTIMEOFDAY == 1
#define settimeofday(t, tz) (settimeofday)(t)
#endif /* HAVE_SETTIMEOFDAY == 1 */
@@ -448,18 +462,21 @@ static int netsettime(struct timeval);
#endif /* !defined TSP_SETDATE */
static void
reset(const time_t newt, const int nflag)
{
register const char * username;
+#ifndef __MSDOS__
static struct timeval tv; /* static so tv_usec is 0 */
+#endif /* __MSDOS__ */
#ifdef EBUG
return;
#endif /* defined EBUG */
username = getlogin();
if (username == NULL || *username == '\0') /* single-user or no tty */
username = "root";
+#ifndef __MSDOS__
tv.tv_sec = newt;
#ifdef TSP_SETDATE
if (nflag || !netsettime(tv))
#endif /* defined TSP_SETDATE */
{
@@ -471,10 +488,11 @@ reset(const time_t newt, const int nflag
logwtmp("{", TIME_NAME, ""); /* } */
syslog(LOG_AUTH | LOG_NOTICE, _("date set by %s"),
username);
} else oops("settimeofday");
}
+#endif /* __MSDOS__ */
}
#endif /* !defined OLD_TIME */
static void
@@ -509,10 +527,11 @@ usage(void)
[-t min-west] [-a sss.fff] [[yyyy]mmddhhmm[yyyy][.ss]] [+format]\n"));
errensure();
exit(retval);
}
+#ifndef __MSDOS__
static void
oops(const char *const string)
{
int e = errno;
@@ -520,10 +539,11 @@ oops(const char *const string)
errno = e;
(void) perror(string);
errensure();
display(NULL);
}
+#endif /* __MSDOS__ */
static void
display(const char *const format)
{
struct tm tm;
@@ -541,11 +561,11 @@ display(const char *const format)
errensure();
}
exit(retval);
}
-extern size_t strftime();
+extern size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *t);
#define INCR 1024
static void
timeout(FILE *const fp, const char *const format, const struct tm *const tmp)
diff -aprNU5 djgpp.orig/zoneinfo/src/localtime.c djgpp/zoneinfo/src/localtime.c
--- djgpp.orig/zoneinfo/src/localtime.c 2013-08-10 21:33:40 +0000
+++ djgpp/zoneinfo/src/localtime.c 2013-08-17 14:34:22 +0000
@@ -27,10 +27,21 @@
#ifndef TZ_ABBR_ERR_CHAR
#define TZ_ABBR_ERR_CHAR '_'
#endif /* !defined TZ_ABBR_ERR_CHAR */
/*
+** Portable testing for absolute file names.
+*/
+
+#ifndef IS_SLASH
+#define IS_SLASH(c) ((c) == '/')
+#endif
+#ifndef IS_ABSOLUTE
+#define IS_ABSOLUTE(n) (IS_SLASH((n)[0]))
+#endif
+
+/*
** SunOS 4.1.1 headers lack O_BINARY.
*/
#ifdef O_BINARY
#define OPEN_MODE (O_RDONLY | O_BINARY)
@@ -155,10 +166,19 @@ static struct tm * timesub(const time_t
static int tmcomp(const struct tm * atmp, const struct tm * btmp);
static time_t transtime(time_t janfirst, 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);
+#ifdef STD_INSPIRED
+static int_fast64_t leapcorr(time_t *timep);
+time_t time2posix(time_t t);
+time_t posix2time(time_t t);
+struct tm * offtime(const time_t *const timep, const int_fast32_t offset);
+time_t timelocal(struct tm *const tmp);
+time_t timegm(struct tm *const tmp);
+time_t timeoff(struct tm *const tmp, const int_fast32_t offset);
+#endif /* defined STD_INSPIRED */
#ifdef ALL_STATE
static struct state * lclptr;
static struct state * gmtptr;
#endif /* defined ALL_STATE */
@@ -176,14 +196,17 @@ static struct state gmtmem;
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
static int gmt_is_set;
+#ifndef __DJGPP__
+/* Use DJGPP's own definition of tzname. */
char * tzname[2] = {
wildabbr,
wildabbr
};
+#endif /* !__DJGPP__ */
/*
** Section 4.12.3 of X3.159-1989 requires that
** Except for the strftime function, these functions [asctime,
** ctime, gmtime, localtime] return values in one of two static
@@ -341,11 +364,11 @@ tzload(register const char *name, regist
*/
char fullname[FILENAME_MAX + 1];
if (name[0] == ':')
++name;
- doaccess = name[0] == '/';
+ doaccess = IS_ABSOLUTE(name);
if (!doaccess) {
if ((p = TZDIR) == NULL)
goto oops;
if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
goto oops;
@@ -1320,10 +1343,12 @@ localsub(const time_t *const timep, cons
tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
#endif /* defined TM_ZONE */
return result;
}
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of localtime and localtime_r. */
struct tm *
localtime(const time_t *const timep)
{
tzset();
return localsub(timep, 0L, &tm);
@@ -1336,10 +1361,11 @@ localtime(const time_t *const timep)
struct tm *
localtime_r(const time_t *const timep, struct tm *tmp)
{
return localsub(timep, 0L, tmp);
}
+#endif /* !__DJGPP__ */
/*
** gmtsub is to gmtime as localsub is to localtime.
*/
@@ -1377,10 +1403,12 @@ gmtsub(const time_t *const timep, const
}
#endif /* defined TM_ZONE */
return result;
}
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of gmtime and gmtime_r. */
struct tm *
gmtime(const time_t *const timep)
{
return gmtsub(timep, 0L, &tm);
}
@@ -1392,10 +1420,11 @@ gmtime(const time_t *const timep)
struct tm *
gmtime_r(const time_t *const timep, struct tm *tmp)
{
return gmtsub(timep, 0L, tmp);
}
+#endif /* !__DJGPP__ */
#ifdef STD_INSPIRED
struct tm *
offtime(const time_t *const timep, const int_fast32_t offset)
@@ -1548,10 +1577,12 @@ timesub(const time_t *const timep, const
tmp->TM_GMTOFF = offset;
#endif /* defined TM_GMTOFF */
return tmp;
}
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of ctime and ctime_r. */
char *
ctime(const time_t *const timep)
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
@@ -1567,10 +1598,11 @@ ctime_r(const time_t *const timep, char
{
struct tm mytm;
return asctime_r(localtime_r(timep, &mytm), buf);
}
+#endif /* !__DJGPP__ */
/*
** 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.
@@ -1929,16 +1961,19 @@ time1(struct tm *const tmp,
}
}
return WRONG;
}
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of mktime. */
time_t
mktime(struct tm *const tmp)
{
tzset();
return time1(tmp, localsub, 0L);
}
+#endif /* !__DJGPP__ */
#ifdef STD_INSPIRED
time_t
timelocal(struct tm *const tmp)
diff -aprNU5 djgpp.orig/zoneinfo/src/makefile djgpp/zoneinfo/src/makefile
--- djgpp.orig/zoneinfo/src/makefile 2013-07-05 13:38:00 +0000
+++ djgpp/zoneinfo/src/makefile 2013-08-17 15:13:10 +0000
@@ -43,38 +43,56 @@ POSIXRULES= America/New_York
# Also see TZDEFRULESTRING below, which takes effect only
# if the time zone files cannot be accessed.
# Everything gets put in subdirectories of. . .
-TOPDIR= /usr/local
+TOPDIR= ../..
# "Compiled" time zone information is placed in the "TZDIR" directory
# (and subdirectories).
# Use an absolute path name for TZDIR unless you're just testing the software.
-TZDIR= $(TOPDIR)/etc/zoneinfo
+TZDIR= $(TOPDIR)/zoneinfo
# Types to try, as an alternative to time_t. int64_t should be first.
TIME_T_ALTERNATIVES= int64_t int32_t uint32_t uint64_t
# The "tzselect", "zic", and "zdump" commands get installed in. . .
ETCDIR= $(TOPDIR)/etc
# If you "make INSTALL", the "date" command gets installed in. . .
-BINDIR= $(TOPDIR)/bin
+BINDIR= $(TOPDIR)/etc
# Manual pages go in subdirectories of. . .
-MANDIR= $(TOPDIR)/man
+SHAREDIR= $(TOPDIR)/share
+MANDIR= $(SHAREDIR)/man
# Library functions are put in an archive in LIBDIR.
LIBDIR= $(TOPDIR)/lib
TZLIB= $(LIBDIR)/libtz.a
+# This defines several variables that enable zoneinfo/src/* files to be
+# built both natively and with cross-tools on Unix.
+
+include $(TOPDIR)/src/makefile.def
+export CROSS_BUILD
+
+# If cross compiling the native and cross-compiler versions may not match.
+# Allow different flag settings accrording the compiler version.
+GCC_MAJOR := $(word 3, $(shell ../../src/misc.exe | $(GCC) -E -dD -x c - | egrep 'define\ *__GNUC__'))
+GCC_MINOR := $(word 3, $(shell ../../src/misc.exe | $(GCC) -E -dD -x c - | egrep 'define\ *__GNUC_MINOR__'))
+CROSS_GCC_MAJOR := $(word 3, $(shell ../../src/misc.exe | $(CROSS_GCC) -E -dD -x c - | egrep 'define\ *__GNUC__'))
+CROSS_GCC_MINOR := $(word 3, $(shell ../../src/misc.exe | $(CROSS_GCC) -E -dD -x c - | egrep 'define\ *__GNUC_MINOR__'))
+
+# A replacement for (possibly missing) Unix programs:
+
+UTIL= $(TOPDIR)/src/misc.exe
+
# If you always want time values interpreted as "seconds since the epoch
# (not counting leap seconds)", use
# REDO= posix_only
# below. If you always want right time values interpreted as "seconds since
# the epoch" (counting leap seconds)", use
@@ -87,11 +105,11 @@ TZLIB= $(LIBDIR)/libtz.a
# REDO= right_posix
# below.
# POSIX mandates that leap seconds not be counted; for compatibility with it,
# use either "posix_only" or "posix_right".
-REDO= posix_right
+REDO= posix_only
# Since "." may not be in PATH...
YEARISTYPE= ./yearistype
@@ -129,22 +147,115 @@ LDLIBS=
# DST transitions if the time zone files cannot be accessed
# -DZIC_MAX_ABBR_LEN_WO_WARN=3
# (or some other number) to set the maximum time zone abbreviation length
# that zic will accept without a warning (the default is 6)
# $(GCC_DEBUG_FLAGS) if you are using GCC and want lots of checking
-GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \
+#GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-common -fstrict-aliasing \
+# -Wall -Wextra \
+# -Wbad-function-cast -Wcast-align -Wcast-qual \
+# -Wformat=2 -Winit-self \
+# -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes \
+# -Wnested-externs \
+# -Wno-format-nonliteral -Wno-sign-compare -Wno-sign-conversion \
+# -Wno-type-limits \
+# -Wno-unused-parameter -Woverlength-strings -Wpointer-arith \
+# -Wshadow -Wstrict-prototypes -Wsuggest-attribute=const \
+# -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines \
+# -Wwrite-strings
+
+# Cross compiler debug flags.
+CROSS_GCC_DEBUG_FLAGS_FOR_ALL = -Dlint -g2 -fno-common -fstrict-aliasing \
-Wall -Wextra \
-Wbad-function-cast -Wcast-align -Wcast-qual \
-Wformat=2 -Winit-self \
-Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes \
- -Wnested-externs \
- -Wno-format-nonliteral -Wno-sign-compare -Wno-sign-conversion \
- -Wno-type-limits \
- -Wno-unused-parameter -Woverlength-strings -Wpointer-arith \
- -Wshadow -Wstrict-prototypes -Wsuggest-attribute=const \
- -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines \
+ -Wnested-externs -Wno-format-nonliteral -Wno-sign-compare \
+ -Wno-unused-parameter -Wpointer-arith -Wshadow -Wstrict-prototypes \
-Wwrite-strings
+
+ifeq ($(CROSS_GCC_MAJOR),3)
+ifeq ($(CROSS_GCC_MINOR),4)
+CROSS_GCC_DEBUG_FLAGS = $(CROSS_GCC_DEBUG_FLAGS_FOR_ALL) -Wconversion -Wtraditional
+endif
+endif
+
+ifeq ($(CROSS_GCC_MAJOR),4)
+ ifeq ($(CROSS_GCC_MINOR),0)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL =
+ else
+ ifeq ($(CROSS_GCC_MINOR),1)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL =
+ else
+ ifeq ($(CROSS_GCC_MINOR),2)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings
+ else
+ ifeq ($(CROSS_GCC_MINOR),3)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+ ifeq ($(CROSS_GCC_MINOR),4)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+ ifeq ($(CROSS_GCC_MINOR),5)
+CROSS_GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+# gcc 4.6 and later works.
+CROSS_GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits -Wsuggest-attribute=const -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines
+ endif
+ endif
+ endif
+ endif
+ endif
+CROSS_GCC_DEBUG_FLAGS = $(CROSS_GCC_DEBUG_FLAGS_FOR_ALL) $(CROSS_GCC_DEBUG_FLAGS_SPECIAL)
+ endif
+endif
+
+# Native compiler debug flags.
+GCC_DEBUG_FLAGS_FOR_ALL = -Dlint -g2 -fno-common -fstrict-aliasing \
+ -Wall -Wextra \
+ -Wbad-function-cast -Wcast-align -Wcast-qual \
+ -Wformat=2 -Winit-self \
+ -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes \
+ -Wnested-externs -Wno-format-nonliteral -Wno-sign-compare \
+ -Wno-unused-parameter -Wpointer-arith -Wshadow -Wstrict-prototypes \
+ -Wwrite-strings
+
+ifeq ($(GCC_MAJOR),3)
+ifeq ($(GCC_MINOR),4)
+GCC_DEBUG_FLAGS = $(GCC_DEBUG_FLAGS_FOR_ALL) -Wconversion -Wtraditional
+endif
+endif
+
+ifeq ($(GCC_MAJOR),4)
+ ifeq ($(GCC_MINOR),0)
+GCC_DEBUG_FLAGS_SPECIAL =
+ else
+ ifeq ($(GCC_MINOR),1)
+GCC_DEBUG_FLAGS_SPECIAL =
+ else
+ ifeq ($(GCC_MINOR),2)
+GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings
+ else
+ ifeq ($(GCC_MINOR),3)
+GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+ ifeq ($(GCC_MINOR),4)
+GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+ ifeq ($(GCC_MINOR),5)
+GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits
+ else
+# gcc 4.6 and later works.
+GCC_DEBUG_FLAGS_SPECIAL = -Woverlength-strings -Wno-sign-conversion -Wno-type-limits -Wsuggest-attribute=const -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure -Wtrampolines
+ endif
+ endif
+ endif
+ endif
+ endif
+GCC_DEBUG_FLAGS = $(GCC_DEBUG_FLAGS_FOR_ALL) $(GCC_DEBUG_FLAGS_SPECIAL)
+ endif
+endif
+
#
# If you want to use System V compatibility code, add
# -DUSG_COMPAT
# to the end of the "CFLAGS=" line. This arrange for "timezone" and "daylight"
# variables to be kept up-to-date by the time conversion functions. Neither
@@ -229,22 +340,41 @@ GCC_DEBUG_FLAGS = -Dlint -g3 -O3 -fno-co
# to the end of the "CFLAGS=" line. This causes "strftime" to always return
# 53 as a week number (rather than 52 or 53) for those days in January that
# before the first Monday in January when a "%V" format is used and January 1
# falls on a Friday, Saturday, or Sunday.
-CFLAGS=
+# If cross compiling the native and cross-compiler versions may not match.
+# Allow different flag settings accrording the compiler version.
+# Flags for cross compiler
+CFLAGS= -DHAVE_ADJTIME=0 -DHAVE_LONG_DOUBLE=1 -DHAVE_SETTIMEOFDAY=1 \
+ -DHAVE_STRERROR=1 -DHAVE_SYMLINK=0 -DHAVE_STDINT_H=1\
+ -DSTD_INSPIRED \
+ -DLOCALE_HOME=\"/dev/env/DJDIR~c:/djgpp~/share/locale\" \
+ $(CROSS_GCC_DEBUG_FLAGS) -O2
+
+# Flags for native compiler
+GCCFLAGS= -DHAVE_ADJTIME=0 -DHAVE_LONG_DOUBLE=1 -DHAVE_SETTIMEOFDAY=1 \
+ -DHAVE_STRERROR=1 -DHAVE_SYMLINK=0 -DHAVE_STDINT_H=1 \
+ -DSTD_INSPIRED \
+ -DLOCALE_HOME=\"/dev/env/DJDIR~c:/djgpp~/share/locale\" \
+ $(GCC_DEBUG_FLAGS) -O2
+
+# Don't use -s here, since "gcc -s" on DJ's Irix machine dumps core
+# when invoked with -s. To work around, we use strip explicitly.
+LFLAGS=
# Linker flags. Default to $(LFLAGS) for backwards compatibility
# to tzcode2012h and earlier.
LDFLAGS= $(LFLAGS)
-zic= ./zic
+EXEEXT= .exe
+zic= ./host-zic
ZIC= $(zic) $(ZFLAGS)
# The name of a Posix-compliant `awk' on your system.
-AWK= awk
+AWK= gawk
# The full path name of a Posix-compliant shell that supports the Korn shell's
# 'select' statement, as an extension. These days, Bash is the most popular.
KSHELL= /bin/bash
@@ -290,24 +420,24 @@ TARFLAGS= `if tar $(GNUTARFLAGS) --versi
# Flags to give 'gzip' when making a distribution.
GZIPFLAGS= -9n
###############################################################################
-cc= cc
-CC= $(cc) -DTZDIR=\"$(TZDIR)\"
+cc= $(CROSS_GCC)
+CC= $(cc) -DTZDIR=\"/dev/env/DJDIR~c:/djgpp~/zoneinfo\"
TZCSRCS= zic.c localtime.c asctime.c scheck.c ialloc.c
TZCOBJS= zic.o localtime.o asctime.o scheck.o ialloc.o
TZDSRCS= zdump.c localtime.c ialloc.c
TZDOBJS= zdump.o localtime.o ialloc.o
-DATESRCS= date.c localtime.c strftime.c asctime.c
-DATEOBJS= date.o localtime.o strftime.o asctime.o
+DATESRCS= date.c localtime.c logwtmp.c strftime.c asctime.c
+DATEOBJS= date.o localtime.o logwtmp.o strftime.o asctime.o
LIBSRCS= localtime.c asctime.c difftime.c
LIBOBJS= localtime.o asctime.o difftime.o
HEADERS= tzfile.h private.h
NONLIBSRCS= zic.c zdump.c scheck.c ialloc.c
-NEWUCBSRCS= date.c strftime.c
+NEWUCBSRCS= date.c logwtmp.c strftime.c
SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) tzselect.ksh
MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \
tzfile.5 tzselect.8 zic.8 zdump.8
COMMON= Makefile
DOCS= README Theory $(MANS) date.1
@@ -328,59 +458,87 @@ ENCHILADA= $(COMMON) $(DOCS) $(SOURCES)
# And for the benefit of csh users on systems that assume the user
# shell should be used to handle commands in Makefiles. . .
SHELL= /bin/sh
-all: tzselect zic zdump $(LIBOBJS)
-
-ALL: all date
+INSTALL: ALL install date.1
+ -$(UTIL) mkdir $(TOPDIR)
+ -$(UTIL) mkdir $(BINDIR)
+ $(UTIL) cp date$(EXEEXT) $(BINDIR)/date$(EXEEXT)
+ -$(UTIL) mkdir $(SHAREDIR)
+ -$(UTIL) mkdir $(MANDIR)
+ -$(UTIL) mkdir $(MANDIR)/cat1
+ -$(UTIL) rm $(MANDIR)/cat1/date.1
+ groff -mman -Tascii date.1 > date.man
+ $(UTIL) cp date.man $(MANDIR)/cat1/date.1
install: all $(DATA) $(REDO) $(TZLIB) $(MANS) $(TABDATA)
$(ZIC) -y $(YEARISTYPE) \
-d $(TZDIR) -l $(LOCALTIME) -p $(POSIXRULES)
- -rm -f $(TZDIR)/iso3166.tab $(TZDIR)/zone.tab
- cp iso3166.tab zone.tab $(TZDIR)/.
- -mkdir $(TOPDIR) $(ETCDIR)
- cp tzselect zic zdump $(ETCDIR)/.
- -mkdir $(TOPDIR) $(MANDIR) \
- $(MANDIR)/man3 $(MANDIR)/man5 $(MANDIR)/man8
- -rm -f $(MANDIR)/man3/newctime.3 \
- $(MANDIR)/man3/newtzset.3 \
- $(MANDIR)/man5/tzfile.5 \
- $(MANDIR)/man8/tzselect.8 \
- $(MANDIR)/man8/zdump.8 \
- $(MANDIR)/man8/zic.8
- cp newctime.3 newtzset.3 $(MANDIR)/man3/.
- cp tzfile.5 $(MANDIR)/man5/.
- cp tzselect.8 zdump.8 zic.8 $(MANDIR)/man8/.
+ -$(UTIL) rm -f $(TZDIR)/iso3166.tab $(TZDIR)/zone.tab
+ $(UTIL) cp iso3166.tab $(TZDIR)/iso3166.tab
+ $(UTIL) cp zone.tab $(TZDIR)/zone.tab
+ -$(UTIL) mkdir $(TOPDIR)
+ -$(UTIL) mkdir $(ETCDIR)
+ $(UTIL) cp zic$(EXEEXT) $(ETCDIR)/zic$(EXEEXT)
+ $(UTIL) cp zdump$(EXEEXT) $(ETCDIR)/zdump$(EXEEXT)
+ $(UTIL) cp tzselect $(ETCDIR)/tzselect
+ -$(UTIL) mkdir $(SHAREDIR)
+ -$(UTIL) mkdir $(MANDIR)
+ -$(UTIL) mkdir $(MANDIR)/cat3
+ -$(UTIL) mkdir $(MANDIR)/cat5
+ -$(UTIL) mkdir $(MANDIR)/cat8
+ -$(UTIL) rm -f $(MANDIR)/cat3/newctime.3 \
+ $(MANDIR)/cat3/newtzset.3 \
+ $(MANDIR)/cat5/tzfile.5 \
+ $(MANDIR)/cat8/tzselect.8 \
+ $(MANDIR)/cat8/zdump.8 \
+ $(MANDIR)/cat8/zic.8
+ groff -mman -Tascii newctime.3 > newctime.man
+ groff -mman -Tascii newtzset.3 > newtzset.man
+ groff -mman -Tascii time2posix.3 > time2posix.man
+ groff -mman -Tascii tzfile.5 > tzfile.man
+ groff -mman -Tascii tzselect.8 > tzselect.man
+ groff -mman -Tascii zdump.8 > zdump.man
+ groff -mman -Tascii zic.8 > zic.man
+ $(UTIL) cp newctime.man $(MANDIR)/cat3/newctime.3
+ $(UTIL) cp newtzset.man $(MANDIR)/cat3/newtzset.3
+ $(UTIL) cp time2posix.man $(MANDIR)/cat3/time2posix.3
+ $(UTIL) cp tzfile.man $(MANDIR)/cat5/tzfile.5
+ $(UTIL) cp tzselect.man $(MANDIR)/cat8/tzselect.8
+ $(UTIL) cp zdump.man $(MANDIR)/cat8/zdump.8
+ $(UTIL) cp zic.man $(MANDIR)/cat8/zic.8
-INSTALL: ALL install date.1
- -mkdir $(TOPDIR) $(BINDIR)
- cp date $(BINDIR)/.
- -mkdir $(TOPDIR) $(MANDIR) $(MANDIR)/man1
- -rm -f $(MANDIR)/man1/date.1
- cp date.1 $(MANDIR)/man1/.
+all: tzselect host-zic zic$(EXEEXT) zdump$(EXEEXT) $(LIBOBJS)
+
+ALL: all date$(EXEEXT)
version.h:
(echo 'static char const PKGVERSION[]="($(PACKAGE)) ";' && \
echo 'static char const TZVERSION[]="$(VERSION)";' && \
echo 'static char const REPORT_BUGS_TO[]="$(BUGEMAIL)";') >$@
-zdump: $(TZDOBJS)
+zdump$(EXEEXT): $(TZDOBJS)
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZDOBJS) $(LDLIBS)
+ $(CROSS_STRIP) $@
-zic: $(TZCOBJS) yearistype
+host-zic: $(TZCSRCS) yearistype version.h
+ $(GCC) -DTZDIR=\"/dev/env/DJDIR~c:/djgpp~/zoneinfo\" \
+ $(GCCFLAGS) $(LDFLAGS) $(TZCSRCS) $(LDLIBS) -o $@
+ $(STRIP) $@
+
+zic$(EXEEXT): $(TZCOBJS) yearistype
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(TZCOBJS) $(LDLIBS)
+ $(CROSS_STRIP) $@
yearistype: yearistype.sh
- cp yearistype.sh yearistype
- chmod +x yearistype
+ $(UTIL) cp yearistype.sh yearistype
-posix_only: zic $(TDATA)
+posix_only: $(zic) $(TDATA)
$(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L /dev/null $(TDATA)
-right_only: zic leapseconds $(TDATA)
+right_only: $(zic) leapseconds $(TDATA)
$(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L leapseconds $(TDATA)
# In earlier versions of this makefile, the other two directories were
# subdirectories of $(TZDIR). However, this led to configuration errors.
# For example, with posix_right under the earlier scheme,
@@ -388,11 +546,11 @@ right_only: zic leapseconds $(TDATA)
# but gmtime without leap seconds, which led to problems with applications
# like sendmail that subtract gmtime from localtime.
# Therefore, the other two directories are now siblings of $(TZDIR).
# You must replace all of $(TZDIR) to switch from not using leap seconds
# to using them, or vice versa.
-other_two: zic leapseconds $(TDATA)
+other_two: $(zic) leapseconds $(TDATA)
$(ZIC) -y $(YEARISTYPE) -d $(TZDIR)-posix -L /dev/null $(TDATA)
$(ZIC) -y $(YEARISTYPE) \
-d $(TZDIR)-leaps -L leapseconds $(TDATA)
posix_right: posix_only other_two
@@ -400,25 +558,30 @@ posix_right: posix_only other_two
right_posix: right_only other_two
zones: $(REDO)
$(TZLIB): $(LIBOBJS)
- -mkdir $(TOPDIR) $(LIBDIR)
- ar ru $@ $(LIBOBJS)
- if [ -x /usr/ucb/ranlib ] || [ -x /usr/bin/ranlib ]; \
- then ranlib $@ ; fi
-
-date: $(DATEOBJS)
- $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DATEOBJS) $(LDLIBS)
+ -$(UTIL) mkdir $(TOPDIR)
+ -$(UTIL) mkdir $(LIBDIR)
+ $(CROSS_AR) rus $@ $(LIBOBJS)
+
+# We use the system's logwtmp in preference to ours if available.
+
+date$(EXEEXT): $(DATEOBJS)
+ $(CROSS_AR) rs logwtmpl.a logwtmp.o
+ $(CC) $(CFLAGS) date.o localtime.o asctime.o strftime.o \
+ $(LDLIBS) -lc logwtmpl.a -o $@
+ $(CROSS_STRIP) $@
+ $(UTIL) rm logwtmpl.a
+ $(CROSS_STRIP) $@
tzselect: tzselect.ksh
sed \
- -e 's|#!/bin/bash|#!$(KSHELL)|g' \
-e 's|AWK=[^}]*|AWK=$(AWK)|g' \
-e 's|\(PKGVERSION\)=.*|\1='\''($(PACKAGE)) '\''|' \
-e 's|\(REPORT_BUGS_TO\)=.*|\1=$(BUGEMAIL)|' \
- -e 's|TZDIR=[^}]*|TZDIR=$(TZDIR)|' \
+ -e 's|TZDIR=[^}]*|TZDIR=/dev/env/DJDIR/zoneinfo|' \
-e 's|\(TZVERSION\)=.*|\1=$(VERSION)|' \
<$? >$@
chmod +x $@
check: check_character_set check_tables check_web
@@ -431,22 +594,22 @@ check_tables: checktab.awk $(PRIMARY_YDA
check_web: $(WEB_PAGES)
$(VALIDATE_ENV) $(VALIDATE) $(VALIDATE_FLAGS) $(WEB_PAGES)
clean_misc:
- rm -f core *.o *.out \
- date tzselect version.h zdump zic yearistype
+ $(UTIL) rm core *.o *.out tzselect zdump$(EXEEXT) zic$(EXEEXT) \
+ yearistype date$(EXEEXT) logwtmpl* *.tar.gz host-zic *.exe *.man
clean: clean_misc
- rm -f -r tzpublic
+ $(UTIL) rm -f -r tzpublic
maintainer-clean: clean
@echo 'This command is intended for maintainers to use; it'
@echo 'deletes files that may need special tools to rebuild.'
rm -f *.[1-8].txt *.asc *.tar.gz
names:
- @echo $(ENCHILADA)
+ @$(UTIL) echo $(ENCHILADA)
public: check check_public check_time_t_alternatives \
set-timestamps tarballs signatures
# Set the time stamps to those of the git repository, if available,
@@ -468,11 +631,11 @@ set-timestamps:
# The zics below ensure that each data file can stand on its own.
# We also do an all-files run to catch links to links.
check_public: $(ENCHILADA)
make maintainer-clean
- make "CFLAGS=$(GCC_DEBUG_FLAGS)"
+ make "CFLAGS=$(CROSS_GCC_DEBUG_FLAGS)"
mkdir tzpublic
for i in $(TDATA) ; do \
$(zic) -v -d tzpublic $$i 2>&1 || exit; \
done
$(zic) -v -d tzpublic $(TDATA)
diff -aprNU5 djgpp.orig/zoneinfo/src/private.h djgpp/zoneinfo/src/private.h
--- djgpp.orig/zoneinfo/src/private.h 2013-05-28 03:26:18 +0000
+++ djgpp/zoneinfo/src/private.h 2013-08-17 14:34:22 +0000
@@ -347,10 +347,20 @@ const char * scheck(const char * string,
#ifndef GNUC_or_lint
#define INITIALIZE(x)
#endif /* !defined GNUC_or_lint */
#endif /* !defined INITIALIZE */
+#ifdef __MSDOS__
+#define IS_SLASH(c) ((c) == '/' || (c) == '\\')
+#define HAS_DEVICE(n) ((n)[0] && (n)[1] == ':')
+#define IS_ABSOLUTE(n) (IS_SLASH((n)[0]) || HAS_DEVICE(n))
+#undef TZDIR
+#define TZDIR (getenv("TZDIR") ? getenv("TZDIR") : "/dev/env/DJDIR/zoneinfo")
+#else /* !__MSDOS__ */
+#define HAS_DEVICE(n) 0
+#endif /* !__MSDOS__ */
+
/*
** 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.
*/
diff -aprNU5 djgpp.orig/zoneinfo/src/strftime.c djgpp/zoneinfo/src/strftime.c
--- djgpp.orig/zoneinfo/src/strftime.c 2013-05-28 03:26:18 +0000
+++ djgpp/zoneinfo/src/strftime.c 2013-08-17 14:34:22 +0000
@@ -3,10 +3,14 @@
** appearing below.
**
** This is ANSIish only when "multibyte character == plain character".
*/
+#ifndef __DJGPP__
+/* Use DJGPP's own implementation of strftime. */
+
+
#include "private.h"
/*
** Copyright (c) 1989 The Regents of the University of California.
** All rights reserved.
@@ -736,5 +740,6 @@ no_locale:
localebuf = C_time_locale;
locale_buf = NULL;
return &localebuf;
}
#endif /* defined LOCALE_HOME */
+#endif /* !__DJGPP__ */
diff -aprNU5 djgpp.orig/zoneinfo/src/zic.c djgpp/zoneinfo/src/zic.c
--- djgpp.orig/zoneinfo/src/zic.c 2013-05-28 03:26:18 +0000
+++ djgpp/zoneinfo/src/zic.c 2013-08-17 14:34:22 +0000
@@ -5,12 +5,15 @@
#include "version.h"
#include "private.h"
#include "locale.h"
#include "tzfile.h"
-
+#ifdef __DJGPP__
+#define ZIC_VERSION '\0'
+#else
#define ZIC_VERSION '2'
+#endif
typedef int_fast64_t zic_t;
#define ZIC_MIN INT_FAST64_MIN
#define ZIC_MAX INT_FAST64_MAX
#define SCNdZIC SCNdFAST64
@@ -27,10 +30,21 @@ typedef int_fast64_t zic_t;
#else
#define MKDIR_UMASK 0755
#endif
/*
+** Portable testing for absolute file names.
+*/
+
+#ifndef IS_SLASH
+#define IS_SLASH(c) ((c) == '/')
+#endif
+#ifndef IS_ABSOLUTE
+#define IS_ABSOLUTE(n) (IS_SLASH((n)[0]))
+#endif
+
+/*
** On some ancient hosts, predicates like `isspace(C)' are defined
** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
** which says they are defined only if C == ((unsigned char) C) || C == EOF.
** Neither the C Standard nor Posix require that `isascii' exist.
** For portability, we check both ancient and modern requirements.
@@ -579,24 +593,37 @@ static void
dolink(const char *const fromfield, const char *const tofield)
{
register char * fromname;
register char * toname;
- if (fromfield[0] == '/')
+ if (IS_ABSOLUTE(fromfield))
fromname = ecpyalloc(fromfield);
else {
fromname = ecpyalloc(directory);
fromname = ecatalloc(fromname, "/");
fromname = ecatalloc(fromname, fromfield);
}
- if (tofield[0] == '/')
+ if (IS_ABSOLUTE(tofield))
toname = ecpyalloc(tofield);
else {
toname = ecpyalloc(directory);
toname = ecatalloc(toname, "/");
toname = ecatalloc(toname, tofield);
}
+ /* Some zone names use `+' as part of their names, but DOS
+ doesn't allow `+' in file names. Replace with a `%'. */
+ if (getenv ("COMSPEC") || getenv ("CROSS_BUILD"))
+ {
+ char *p;
+
+ for (p = fromname; *p; p++)
+ if (*p == '+')
+ *p = '%';
+ for (p = toname; *p; p++)
+ if (*p == '+')
+ *p = '%';
+ }
/*
** We get to be careful here since
** there's a fair chance of root running us.
*/
if (!itsdir(toname))
@@ -648,17 +675,24 @@ static const zic_t min_time = (zic_t) -1
static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1));
static int
itsdir(const char *const name)
{
- register char * myname;
register int accres;
+#ifdef D_OK
+ /* MS-DOS/MS-Windows normalize "foo/." to "foo" before testing,
+ so we think foo is a directory. Use D_OK instead. */
+ accres = access(name, D_OK);
+#else
+ register char * myname;
+
myname = ecpyalloc(name);
myname = ecatalloc(myname, "/.");
accres = access(myname, F_OK);
free(myname);
+#endif
return accres == 0;
}
/*
** Associate sets of rules with zones.
@@ -1473,10 +1507,24 @@ writezone(const char *const name, const
++leapi32;
}
fullname = erealloc(fullname,
strlen(directory) + 1 + strlen(name) + 1);
(void) sprintf(fullname, "%s/%s", directory, name);
+ /* Some zone names use `+' as part of their names, but DOS
+ doesn't allow `+' in file names. Replace with a `%'. */
+ if (getenv ("COMSPEC") || getenv ("CROSS_BUILD"))
+ {
+ char new_name[FILENAME_MAX + 1], *p;
+
+ strcpy(new_name, name);
+ for (p = new_name; *p; p++)
+ if (*p == '+')
+ *p = '%';
+ (void) sprintf(fullname, "%s/%s", directory, new_name);
+ }
+ else
+ (void) sprintf(fullname, "%s/%s", directory, name);
/*
** Remove old file, if any, to snap links.
*/
if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
const char *e = strerror(errno);
@@ -1494,11 +1542,15 @@ writezone(const char *const name, const
(void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
progname, fullname, e);
exit(EXIT_FAILURE);
}
}
+#if defined(ZIC_VERSION) && ZIC_VERSION == 2
for (pass = 1; pass <= 2; ++pass) {
+#else /* ZIC_VERSION == 0 */
+ for (pass = 1; pass < 2; ++pass) {
+#endif /* ZIC_VERSION == 0 */
register int thistimei, thistimecnt;
register int thisleapi, thisleapcnt;
register int thistimelim, thisleaplim;
int writetype[TZ_MAX_TIMES];
int typemap[TZ_MAX_TYPES];
@@ -1704,11 +1756,13 @@ writezone(const char *const name, const
(void) putc(ttisstds[i], fp);
for (i = 0; i < typecnt; ++i)
if (writetype[i])
(void) putc(ttisgmts[i], fp);
}
+#if defined(ZIC_VERSION) && ZIC_VERSION == 2
(void) fprintf(fp, "\n%s\n", string);
+#endif /* ZIC_VERSION */
if (ferror(fp) || fclose(fp)) {
(void) fprintf(stderr, _("%s: Error writing %s\n"),
progname, fullname);
exit(EXIT_FAILURE);
}
@@ -2608,42 +2662,40 @@ mkdirs(char *argname)
register char * cp;
if (argname == NULL || *argname == '\0')
return 0;
cp = name = ecpyalloc(argname);
- while ((cp = strchr(cp + 1, '/')) != 0) {
- *cp = '\0';
-#ifdef HAVE_DOS_FILE_NAMES
- /*
- ** DOS drive specifier?
- */
- if (isalpha((unsigned char) name[0]) &&
- name[1] == ':' && name[2] == '\0') {
- *cp = '/';
- continue;
- }
-#endif
- if (!itsdir(name)) {
- /*
- ** It doesn't seem to exist, so we try to create it.
- ** Creation may fail because of the directory being
- ** created by some other multiprocessor, so we get
- ** to do extra checking.
- */
- if (mkdir(name, MKDIR_UMASK) != 0) {
- const char *e = strerror(errno);
-
- if (errno != EEXIST || !itsdir(name)) {
- (void) fprintf(stderr,
-_("%s: Can't create directory %s: %s\n"),
- progname, name, e);
- free(name);
- return -1;
- }
- }
- }
- *cp = '/';
+ /*
+ ** Get past a DOS-style drive specifier, if any.
+ */
+ if (HAS_DEVICE(name))
+ cp += 2;
+ while (*cp++) {
+ if (IS_SLASH(*cp)) {
+ *cp = '\0';
+ if (!itsdir(name)) {
+ /*
+ ** It doesn't seem to exist, so we try to
+ ** create it. Creation may fail because
+ ** of the directory being created by some
+ ** other multiprocessor, so we get to do
+ ** extra checking.
+ */
+ if (mkdir(name, MKDIR_UMASK) != 0) {
+ const char *e = strerror(errno);
+
+ if (errno != EEXIST || !itsdir(name)) {
+ (void) fprintf(stderr,
+ _("%s: Can't create directory %s: %s\n"),
+ progname, name, e);
+ free(name);
+ return -1;
+ }
+ }
+ }
+ *cp = '/';
+ }
}
free(name);
return 0;
}
- Raw text -