delorie.com/archives/browse.cgi   search  
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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019