Convert DOS newlines to Unix newlines.
authorBruce Momjian <bruce@momjian.us>
Fri, 30 Apr 2004 04:44:06 +0000 (04:44 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 30 Apr 2004 04:44:06 +0000 (04:44 +0000)
src/timezone/asctime.c
src/timezone/difftime.c
src/timezone/ialloc.c
src/timezone/localtime.c
src/timezone/pgtz.h
src/timezone/private.h
src/timezone/scheck.c
src/timezone/tzfile.h
src/timezone/zic.c

index 31a6275edc933596eb5f4881c128bb126f73b2db..d19e1dc1925052f21a35420adb84c66ba524058e 100644 (file)
@@ -1,75 +1,75 @@
-#include "pgtz.h"\r
-/*\r
-** This file is in the public domain, so clarified as of\r
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
-*/\r
-\r
-#ifndef lint\r
-#ifndef NOID\r
-static char    elsieid[] = "@(#)asctime.c  7.9";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*LINTLIBRARY*/\r
-\r
-#include "private.h"\r
-#include "tzfile.h"\r
-\r
-/*\r
-** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.\r
-*/\r
-\r
-char *\r
-asctime_r(timeptr, buf)\r
-register const struct tm * timeptr;\r
-char *             buf;\r
-{\r
-   static const char   wday_name[][3] = {\r
-       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\r
-   };\r
-   static const char   mon_name[][3] = {\r
-       "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
-       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"\r
-   };\r
-   register const char *   wn;\r
-   register const char *   mn;\r
-\r
-   if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)\r
-       wn = "???";\r
-   else    wn = wday_name[timeptr->tm_wday];\r
-   if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)\r
-       mn = "???";\r
-   else    mn = mon_name[timeptr->tm_mon];\r
-   /*\r
-   ** The X3J11-suggested format is\r
-   **  "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"\r
-   ** Since the .2 in 02.2d is ignored, we drop it.\r
-   */\r
-   (void) sprintf(buf, "%.3s %.3s%3d %02d:%02d:%02d %d\n",\r
-       wn, mn,\r
-       timeptr->tm_mday, timeptr->tm_hour,\r
-       timeptr->tm_min, timeptr->tm_sec,\r
-       TM_YEAR_BASE + timeptr->tm_year);\r
-   return buf;\r
-}\r
-\r
-/*\r
-** A la X3J11, with core dump avoidance.\r
-*/\r
-\r
-char *\r
-asctime(timeptr)\r
-register const struct tm * timeptr;\r
-{\r
-   /*\r
-   ** Big enough for something such as\r
-   ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n\r
-   ** (two three-character abbreviations, five strings denoting integers,\r
-   ** three explicit spaces, two explicit colons, a newline,\r
-   ** and a trailing ASCII nul).\r
-   */\r
-   static char     result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +\r
-                   3 + 2 + 1 + 1];\r
-\r
-   return asctime_r(timeptr, result);\r
-}\r
+#include "pgtz.h"
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)asctime.c  7.9";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+#include "tzfile.h"
+
+/*
+** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.
+*/
+
+char *
+asctime_r(timeptr, buf)
+register const struct tm * timeptr;
+char *             buf;
+{
+   static const char   wday_name[][3] = {
+       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+   };
+   static const char   mon_name[][3] = {
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+   };
+   register const char *   wn;
+   register const char *   mn;
+
+   if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
+       wn = "???";
+   else    wn = wday_name[timeptr->tm_wday];
+   if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
+       mn = "???";
+   else    mn = mon_name[timeptr->tm_mon];
+   /*
+   ** The X3J11-suggested format is
+   **  "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
+   ** Since the .2 in 02.2d is ignored, we drop it.
+   */
+   (void) sprintf(buf, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+       wn, mn,
+       timeptr->tm_mday, timeptr->tm_hour,
+       timeptr->tm_min, timeptr->tm_sec,
+       TM_YEAR_BASE + timeptr->tm_year);
+   return buf;
+}
+
+/*
+** A la X3J11, with core dump avoidance.
+*/
+
+char *
+asctime(timeptr)
+register const struct tm * timeptr;
+{
+   /*
+   ** Big enough for something such as
+   ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
+   ** (two three-character abbreviations, five strings denoting integers,
+   ** three explicit spaces, two explicit colons, a newline,
+   ** and a trailing ASCII nul).
+   */
+   static char     result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +
+                   3 + 2 + 1 + 1];
+
+   return asctime_r(timeptr, result);
+}
index 636640d6f572e0ba02a8c33fd6066cbd0ae8099b..57b88deafee79848714e80ceec7c6c13b19bea5f 100644 (file)
@@ -1,84 +1,84 @@
-#include "pgtz.h"\r
-/*\r
-** This file is in the public domain, so clarified as of\r
-** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).\r
-*/\r
-\r
-#ifndef lint\r
-#ifndef NOID\r
-static char    elsieid[] = "@(#)difftime.c 7.9";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*LINTLIBRARY*/\r
-\r
-#include "private.h"\r
-\r
-/*\r
-** Algorithm courtesy Paul Eggert (eggert@twinsun.com).\r
-*/\r
-\r
-#ifdef HAVE_LONG_DOUBLE\r
-#define long_double    long double\r
-#endif /* defined HAVE_LONG_DOUBLE */\r
-#ifndef HAVE_LONG_DOUBLE\r
-#define long_double    double\r
-#endif /* !defined HAVE_LONG_DOUBLE */\r
-\r
-double\r
-difftime(time1, time0)\r
-const time_t   time1;\r
-const time_t   time0;\r
-{\r
-   time_t  delta;\r
-   time_t  hibit;\r
-\r
-   {\r
-       time_t      tt;\r
-       double      d;\r
-       long_double ld;\r
-\r
-       if (sizeof tt < sizeof d)\r
-           return (double) time1 - (double) time0;\r
-       if (sizeof tt < sizeof ld)\r
-           return (long_double) time1 - (long_double) time0;\r
-   }\r
-   if (time1 < time0)\r
-       return -difftime(time0, time1);\r
-   /*\r
-   ** As much as possible, avoid loss of precision\r
-   ** by computing the difference before converting to double.\r
-   */\r
-   delta = time1 - time0;\r
-   if (delta >= 0)\r
-       return delta;\r
-   /*\r
-   ** Repair delta overflow.\r
-   */\r
-   hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1);\r
-   /*\r
-   ** The following expression rounds twice, which means\r
-   ** the result may not be the closest to the true answer.\r
-   ** For example, suppose time_t is 64-bit signed int,\r
-   ** long_double is IEEE 754 double with default rounding,\r
-   ** time1 = 9223372036854775807 and time0 = -1536.\r
-   ** Then the true difference is 9223372036854777343,\r
-   ** which rounds to 9223372036854777856\r
-   ** with a total error of 513.\r
-   ** But delta overflows to -9223372036854774273,\r
-   ** which rounds to -9223372036854774784, and correcting\r
-   ** this by subtracting 2 * (long_double) hibit\r
-   ** (i.e. by adding 2**64 = 18446744073709551616)\r
-   ** yields 9223372036854776832, which\r
-   ** rounds to 9223372036854775808\r
-   ** with a total error of 1535 instead.\r
-   ** This problem occurs only with very large differences.\r
-   ** It's too painful to fix this portably.\r
-   ** We are not alone in this problem;\r
-   ** some C compilers round twice when converting\r
-   ** large unsigned types to small floating types,\r
-   ** so if time_t is unsigned the "return delta" above\r
-   ** has the same double-rounding problem with those compilers.\r
-   */\r
-   return delta - 2 * (long_double) hibit;\r
-}\r
+#include "pgtz.h"
+/*
+** This file is in the public domain, so clarified as of
+** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)difftime.c 7.9";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+/*
+** Algorithm courtesy Paul Eggert (eggert@twinsun.com).
+*/
+
+#ifdef HAVE_LONG_DOUBLE
+#define long_double    long double
+#endif /* defined HAVE_LONG_DOUBLE */
+#ifndef HAVE_LONG_DOUBLE
+#define long_double    double
+#endif /* !defined HAVE_LONG_DOUBLE */
+
+double
+difftime(time1, time0)
+const time_t   time1;
+const time_t   time0;
+{
+   time_t  delta;
+   time_t  hibit;
+
+   {
+       time_t      tt;
+       double      d;
+       long_double ld;
+
+       if (sizeof tt < sizeof d)
+           return (double) time1 - (double) time0;
+       if (sizeof tt < sizeof ld)
+           return (long_double) time1 - (long_double) time0;
+   }
+   if (time1 < time0)
+       return -difftime(time0, time1);
+   /*
+   ** As much as possible, avoid loss of precision
+   ** by computing the difference before converting to double.
+   */
+   delta = time1 - time0;
+   if (delta >= 0)
+       return delta;
+   /*
+   ** Repair delta overflow.
+   */
+   hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1);
+   /*
+   ** The following expression rounds twice, which means
+   ** the result may not be the closest to the true answer.
+   ** For example, suppose time_t is 64-bit signed int,
+   ** long_double is IEEE 754 double with default rounding,
+   ** time1 = 9223372036854775807 and time0 = -1536.
+   ** Then the true difference is 9223372036854777343,
+   ** which rounds to 9223372036854777856
+   ** with a total error of 513.
+   ** But delta overflows to -9223372036854774273,
+   ** which rounds to -9223372036854774784, and correcting
+   ** this by subtracting 2 * (long_double) hibit
+   ** (i.e. by adding 2**64 = 18446744073709551616)
+   ** yields 9223372036854776832, which
+   ** rounds to 9223372036854775808
+   ** with a total error of 1535 instead.
+   ** This problem occurs only with very large differences.
+   ** It's too painful to fix this portably.
+   ** We are not alone in this problem;
+   ** some C compilers round twice when converting
+   ** large unsigned types to small floating types,
+   ** so if time_t is unsigned the "return delta" above
+   ** has the same double-rounding problem with those compilers.
+   */
+   return delta - 2 * (long_double) hibit;
+}
index ea457aeb6646f9d85d40594b8f6205f08d1d591b..8a0c7015789022a3dbf82bdf2257bd8fb0512975 100644 (file)
@@ -1,81 +1,81 @@
-#ifndef lint\r
-#ifndef NOID\r
-static char    elsieid[] = "@(#)ialloc.c   8.29";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*LINTLIBRARY*/\r
-\r
-#include "private.h"\r
-\r
-#define nonzero(n) (((n) == 0) ? 1 : (n))\r
-\r
-char *\r
-imalloc(n)\r
-const int  n;\r
-{\r
-   return malloc((size_t) nonzero(n));\r
-}\r
-\r
-char *\r
-icalloc(nelem, elsize)\r
-int    nelem;\r
-int    elsize;\r
-{\r
-   if (nelem == 0 || elsize == 0)\r
-       nelem = elsize = 1;\r
-   return calloc((size_t) nelem, (size_t) elsize);\r
-}\r
-\r
-void *\r
-irealloc(pointer, size)\r
-void * const   pointer;\r
-const int  size;\r
-{\r
-   if (pointer == NULL)\r
-       return imalloc(size);\r
-   return realloc((void *) pointer, (size_t) nonzero(size));\r
-}\r
-\r
-char *\r
-icatalloc(old, new)\r
-char * const       old;\r
-const char * const new;\r
-{\r
-   register char * result;\r
-   register int    oldsize, newsize;\r
-\r
-   newsize = (new == NULL) ? 0 : strlen(new);\r
-   if (old == NULL)\r
-       oldsize = 0;\r
-   else if (newsize == 0)\r
-       return old;\r
-   else    oldsize = strlen(old);\r
-   if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)\r
-       if (new != NULL)\r
-           (void) strcpy(result + oldsize, new);\r
-   return result;\r
-}\r
-\r
-char *\r
-icpyalloc(string)\r
-const char * const string;\r
-{\r
-   return icatalloc((char *) NULL, string);\r
-}\r
-\r
-void\r
-ifree(p)\r
-char * const   p;\r
-{\r
-   if (p != NULL)\r
-       (void) free(p);\r
-}\r
-\r
-void\r
-icfree(p)\r
-char * const   p;\r
-{\r
-   if (p != NULL)\r
-       (void) free(p);\r
-}\r
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)ialloc.c   8.29";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+#define nonzero(n) (((n) == 0) ? 1 : (n))
+
+char *
+imalloc(n)
+const int  n;
+{
+   return malloc((size_t) nonzero(n));
+}
+
+char *
+icalloc(nelem, elsize)
+int    nelem;
+int    elsize;
+{
+   if (nelem == 0 || elsize == 0)
+       nelem = elsize = 1;
+   return calloc((size_t) nelem, (size_t) elsize);
+}
+
+void *
+irealloc(pointer, size)
+void * const   pointer;
+const int  size;
+{
+   if (pointer == NULL)
+       return imalloc(size);
+   return realloc((void *) pointer, (size_t) nonzero(size));
+}
+
+char *
+icatalloc(old, new)
+char * const       old;
+const char * const new;
+{
+   register char * result;
+   register int    oldsize, newsize;
+
+   newsize = (new == NULL) ? 0 : strlen(new);
+   if (old == NULL)
+       oldsize = 0;
+   else if (newsize == 0)
+       return old;
+   else    oldsize = strlen(old);
+   if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
+       if (new != NULL)
+           (void) strcpy(result + oldsize, new);
+   return result;
+}
+
+char *
+icpyalloc(string)
+const char * const string;
+{
+   return icatalloc((char *) NULL, string);
+}
+
+void
+ifree(p)
+char * const   p;
+{
+   if (p != NULL)
+       (void) free(p);
+}
+
+void
+icfree(p)
+char * const   p;
+{
+   if (p != NULL)
+       (void) free(p);
+}
index 4f389b52dee13dff7bc433058417a29637902403..6936cd674be050bf0cd32a317f0847230c86e9b4 100644 (file)
-#include "pgtz.h"\r
-#undef open\r
-#define timezone pg_timezone\r
-#define USG_COMPAT\r
-extern time_t pg_timezone;\r
-/*\r
-** This file is in the public domain, so clarified as of\r
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
-*/\r
-\r
-#ifndef lint\r
-#ifndef NOID\r
-static char    elsieid[] = "@(#)localtime.c    7.78";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*\r
-** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).\r
-** POSIX-style TZ environment variable handling from Guy Harris\r
-** (guy@auspex.com).\r
-*/\r
-\r
-/*LINTLIBRARY*/\r
-\r
-#include "private.h"\r
-#include "tzfile.h"\r
-#include "fcntl.h"\r
-\r
-/*\r
-** SunOS 4.1.1 headers lack O_BINARY.\r
-*/\r
-\r
-#ifdef O_BINARY\r
-#define OPEN_MODE  (O_RDONLY | O_BINARY)\r
-#endif /* defined O_BINARY */\r
-#ifndef O_BINARY\r
-#define OPEN_MODE  O_RDONLY\r
-#endif /* !defined O_BINARY */\r
-\r
-#ifndef WILDABBR\r
-/*\r
-** Someone might make incorrect use of a time zone abbreviation:\r
-** 1.  They might reference tzname[0] before calling tzset (explicitly\r
-**     or implicitly).\r
-** 2.  They might reference tzname[1] before calling tzset (explicitly\r
-**     or implicitly).\r
-** 3.  They might reference tzname[1] after setting to a time zone\r
-**     in which Daylight Saving Time is never observed.\r
-** 4.  They might reference tzname[0] after setting to a time zone\r
-**     in which Standard Time is never observed.\r
-** 5.  They might reference tm.TM_ZONE after calling offtime.\r
-** What's best to do in the above cases is open to debate;\r
-** for now, we just set things up so that in any of the five cases\r
-** WILDABBR is used.  Another possibility:  initialize tzname[0] to the\r
-** string "tzname[0] used before set", and similarly for the other cases.\r
-** And another:  initialize tzname[0] to "ERA", with an explanation in the\r
-** manual page of what this "time zone abbreviation" means (doing this so\r
-** that tzname[0] has the "normal" length of three characters).\r
-*/\r
-#define WILDABBR   "   "\r
-#endif /* !defined WILDABBR */\r
-\r
-static char        wildabbr[] = "WILDABBR";\r
-\r
-static const char  gmt[] = "GMT";\r
-\r
-/*\r
-** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.\r
-** We default to US rules as of 1999-08-17.\r
-** POSIX 1003.1 section 8.1.1 says that the default DST rules are\r
-** implementation dependent; for historical reasons, US rules are a\r
-** common default.\r
-*/\r
-#ifndef TZDEFRULESTRING\r
-#define TZDEFRULESTRING ",M4.1.0,M10.5.0"\r
-#endif /* !defined TZDEFDST */\r
-\r
-struct ttinfo {                /* time type information */\r
-   long        tt_gmtoff;  /* UTC offset in seconds */\r
-   int     tt_isdst;   /* used to set tm_isdst */\r
-   int     tt_abbrind; /* abbreviation list index */\r
-   int     tt_ttisstd; /* TRUE if transition is std time */\r
-   int     tt_ttisgmt; /* TRUE if transition is UTC */\r
-};\r
-\r
-struct lsinfo {                /* leap second information */\r
-   time_t      ls_trans;   /* transition time */\r
-   long        ls_corr;    /* correction to apply */\r
-};\r
-\r
-#define BIGGEST(a, b)  (((a) > (b)) ? (a) : (b))\r
-\r
-#ifdef TZNAME_MAX\r
-#define MY_TZNAME_MAX  TZNAME_MAX\r
-#endif /* defined TZNAME_MAX */\r
-#ifndef TZNAME_MAX\r
-#define MY_TZNAME_MAX  255\r
-#endif /* !defined TZNAME_MAX */\r
-\r
-struct state {\r
-   int     leapcnt;\r
-   int     timecnt;\r
-   int     typecnt;\r
-   int     charcnt;\r
-   time_t      ats[TZ_MAX_TIMES];\r
-   unsigned char   types[TZ_MAX_TIMES];\r
-   struct ttinfo   ttis[TZ_MAX_TYPES];\r
-   char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),\r
-               (2 * (MY_TZNAME_MAX + 1)))];\r
-   struct lsinfo   lsis[TZ_MAX_LEAPS];\r
-};\r
-\r
-struct rule {\r
-   int     r_type;     /* type of rule--see below */\r
-   int     r_day;      /* day number of rule */\r
-   int     r_week;     /* week number of rule */\r
-   int     r_mon;      /* month number of rule */\r
-   long        r_time;     /* transition time of rule */\r
-};\r
-\r
-#define JULIAN_DAY     0   /* Jn - Julian day */\r
-#define DAY_OF_YEAR        1   /* n - day of year */\r
-#define MONTH_NTH_DAY_OF_WEEK  2   /* Mm.n.d - month, week, day of week */\r
-\r
-/*\r
-** Prototypes for static functions.\r
-*/\r
-\r
-static long        detzcode P((const char * codep));\r
-static const char *    getzname P((const char * strp));\r
-static const char *    getnum P((const char * strp, int * nump, int min,\r
-               int max));\r
-static const char *    getsecs P((const char * strp, long * secsp));\r
-static const char *    getoffset P((const char * strp, long * offsetp));\r
-static const char *    getrule P((const char * strp, struct rule * rulep));\r
-static void        gmtload P((struct state * sp));\r
-static void        gmtsub P((const time_t * timep, long offset,\r
-               struct tm * tmp));\r
-static void        localsub P((const time_t * timep, long offset,\r
-               struct tm * tmp));\r
-static int     increment_overflow P((int * number, int delta));\r
-static int     normalize_overflow P((int * tensptr, int * unitsptr,\r
-               int base));\r
-static void        settzname P((void));\r
-static time_t      time1 P((struct tm * tmp,\r
-               void(*funcp) P((const time_t *,\r
-               long, struct tm *)),\r
-               long offset));\r
-static time_t      time2 P((struct tm *tmp,\r
-               void(*funcp) P((const time_t *,\r
-               long, struct tm*)),\r
-               long offset, int * okayp));\r
-static time_t      time2sub P((struct tm *tmp,\r
-               void(*funcp) P((const time_t *,\r
-               long, struct tm*)),\r
-               long offset, int * okayp, int do_norm_secs));\r
-static void        timesub P((const time_t * timep, long offset,\r
-               const struct state * sp, struct tm * tmp));\r
-static int     tmcomp P((const struct tm * atmp,\r
-               const struct tm * btmp));\r
-static time_t      transtime P((time_t janfirst, int year,\r
-               const struct rule * rulep, long offset));\r
-static int     tzload P((const char * name, struct state * sp));\r
-static int     tzparse P((const char * name, struct state * sp,\r
-               int lastditch));\r
-\r
-#ifdef ALL_STATE\r
-static struct state *  lclptr;\r
-static struct state *  gmtptr;\r
-#endif /* defined ALL_STATE */\r
-\r
-#ifndef ALL_STATE\r
-static struct state    lclmem;\r
-static struct state    gmtmem;\r
-#define lclptr     (&lclmem)\r
-#define gmtptr     (&gmtmem)\r
-#endif /* State Farm */\r
-\r
-#ifndef TZ_STRLEN_MAX\r
-#define TZ_STRLEN_MAX 255\r
-#endif /* !defined TZ_STRLEN_MAX */\r
-\r
-static char        lcl_TZname[TZ_STRLEN_MAX + 1];\r
-static int     lcl_is_set;\r
-static int     gmt_is_set;\r
-\r
-char *         tzname[2] = {\r
-   wildabbr,\r
-   wildabbr\r
-};\r
-\r
-/*\r
-** Section 4.12.3 of X3.159-1989 requires that\r
-** Except for the strftime function, these functions [asctime,\r
-** ctime, gmtime, localtime] return values in one of two static\r
-** objects: a broken-down time structure and an array of char.\r
-** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.\r
-*/\r
-\r
-static struct tm   tm;\r
-\r
-#ifdef USG_COMPAT\r
-time_t         timezone = 0;\r
-int            daylight = 0;\r
-#endif /* defined USG_COMPAT */\r
-\r
-#ifdef ALTZONE\r
-time_t         altzone = 0;\r
-#endif /* defined ALTZONE */\r
-\r
-static long\r
-detzcode(codep)\r
-const char * const codep;\r
-{\r
-   register long   result;\r
-   register int    i;\r
-\r
-   result = (codep[0] & 0x80) ? ~0L : 0L;\r
-   for (i = 0; i < 4; ++i)\r
-       result = (result << 8) | (codep[i] & 0xff);\r
-   return result;\r
-}\r
-\r
-static void\r
-settzname P((void))\r
-{\r
-   register struct state * const   sp = lclptr;\r
-   register int            i;\r
-\r
-   tzname[0] = wildabbr;\r
-   tzname[1] = wildabbr;\r
-#ifdef USG_COMPAT\r
-   daylight = 0;\r
-   timezone = 0;\r
-#endif /* defined USG_COMPAT */\r
-#ifdef ALTZONE\r
-   altzone = 0;\r
-#endif /* defined ALTZONE */\r
-#ifdef ALL_STATE\r
-   if (sp == NULL) {\r
-       tzname[0] = tzname[1] = gmt;\r
-       return;\r
-   }\r
-#endif /* defined ALL_STATE */\r
-   for (i = 0; i < sp->typecnt; ++i) {\r
-       register const struct ttinfo * const    ttisp = &sp->ttis[i];\r
-\r
-       tzname[ttisp->tt_isdst] =\r
-           &sp->chars[ttisp->tt_abbrind];\r
-#ifdef USG_COMPAT\r
-       if (ttisp->tt_isdst)\r
-           daylight = 1;\r
-       if (i == 0 || !ttisp->tt_isdst)\r
-           timezone = -(ttisp->tt_gmtoff);\r
-#endif /* defined USG_COMPAT */\r
-#ifdef ALTZONE\r
-       if (i == 0 || ttisp->tt_isdst)\r
-           altzone = -(ttisp->tt_gmtoff);\r
-#endif /* defined ALTZONE */\r
-   }\r
-   /*\r
-   ** And to get the latest zone names into tzname. . .\r
-   */\r
-   for (i = 0; i < sp->timecnt; ++i) {\r
-       register const struct ttinfo * const    ttisp =\r
-                           &sp->ttis[\r
-                               sp->types[i]];\r
-\r
-       tzname[ttisp->tt_isdst] =\r
-           &sp->chars[ttisp->tt_abbrind];\r
-   }\r
-}\r
-\r
-static int\r
-tzload(name, sp)\r
-register const char *      name;\r
-register struct state * const  sp;\r
-{\r
-   register const char *   p;\r
-   register int        i;\r
-   register int        fid;\r
-\r
-   if (name == NULL && (name = TZDEFAULT) == NULL)\r
-       return -1;\r
-   {\r
-       register int    doaccess;\r
-       /*\r
-       ** Section 4.9.1 of the C standard says that\r
-       ** "FILENAME_MAX expands to an integral constant expression\r
-       ** that is the size needed for an array of char large enough\r
-       ** to hold the longest file name string that the implementation\r
-       ** guarantees can be opened."\r
-       */\r
-       char        fullname[FILENAME_MAX + 1];\r
-\r
-       if (name[0] == ':')\r
-           ++name;\r
-       doaccess = name[0] == '/';\r
-       if (!doaccess) {\r
-           if ((p = TZDIR) == NULL)\r
-               return -1;\r
-           if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)\r
-               return -1;\r
-           (void) strcpy(fullname, p);\r
-           (void) strcat(fullname, "/");\r
-           (void) strcat(fullname, name);\r
-           /*\r
-           ** Set doaccess if '.' (as in "../") shows up in name.\r
-           */\r
-           if (strchr(name, '.') != NULL)\r
-               doaccess = TRUE;\r
-           name = fullname;\r
-       }\r
-       if (doaccess && access(name, R_OK) != 0)\r
-           return -1;\r
-       if ((fid = open(name, OPEN_MODE)) == -1)\r
-           return -1;\r
-   }\r
-   {\r
-       struct tzhead * tzhp;\r
-       union {\r
-           struct tzhead   tzhead;\r
-           char        buf[sizeof *sp + sizeof *tzhp];\r
-       } u;\r
-       int     ttisstdcnt;\r
-       int     ttisgmtcnt;\r
-\r
-       i = read(fid, u.buf, sizeof u.buf);\r
-       if (close(fid) != 0)\r
-           return -1;\r
-       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);\r
-       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);\r
-       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);\r
-       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);\r
-       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);\r
-       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);\r
-       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;\r
-       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||\r
-           sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||\r
-           sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||\r
-           sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||\r
-           (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||\r
-           (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))\r
-               return -1;\r
-       if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */\r
-           sp->timecnt +           /* types */\r
-           sp->typecnt * (4 + 2) +     /* ttinfos */\r
-           sp->charcnt +           /* chars */\r
-           sp->leapcnt * (4 + 4) +     /* lsinfos */\r
-           ttisstdcnt +            /* ttisstds */\r
-           ttisgmtcnt)         /* ttisgmts */\r
-               return -1;\r
-       for (i = 0; i < sp->timecnt; ++i) {\r
-           sp->ats[i] = detzcode(p);\r
-           p += 4;\r
-       }\r
-       for (i = 0; i < sp->timecnt; ++i) {\r
-           sp->types[i] = (unsigned char) *p++;\r
-           if (sp->types[i] >= sp->typecnt)\r
-               return -1;\r
-       }\r
-       for (i = 0; i < sp->typecnt; ++i) {\r
-           register struct ttinfo *    ttisp;\r
-\r
-           ttisp = &sp->ttis[i];\r
-           ttisp->tt_gmtoff = detzcode(p);\r
-           p += 4;\r
-           ttisp->tt_isdst = (unsigned char) *p++;\r
-           if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)\r
-               return -1;\r
-           ttisp->tt_abbrind = (unsigned char) *p++;\r
-           if (ttisp->tt_abbrind < 0 ||\r
-               ttisp->tt_abbrind > sp->charcnt)\r
-                   return -1;\r
-       }\r
-       for (i = 0; i < sp->charcnt; ++i)\r
-           sp->chars[i] = *p++;\r
-       sp->chars[i] = '\0';    /* ensure '\0' at end */\r
-       for (i = 0; i < sp->leapcnt; ++i) {\r
-           register struct lsinfo *    lsisp;\r
-\r
-           lsisp = &sp->lsis[i];\r
-           lsisp->ls_trans = detzcode(p);\r
-           p += 4;\r
-           lsisp->ls_corr = detzcode(p);\r
-           p += 4;\r
-       }\r
-       for (i = 0; i < sp->typecnt; ++i) {\r
-           register struct ttinfo *    ttisp;\r
-\r
-           ttisp = &sp->ttis[i];\r
-           if (ttisstdcnt == 0)\r
-               ttisp->tt_ttisstd = FALSE;\r
-           else {\r
-               ttisp->tt_ttisstd = *p++;\r
-               if (ttisp->tt_ttisstd != TRUE &&\r
-                   ttisp->tt_ttisstd != FALSE)\r
-                       return -1;\r
-           }\r
-       }\r
-       for (i = 0; i < sp->typecnt; ++i) {\r
-           register struct ttinfo *    ttisp;\r
-\r
-           ttisp = &sp->ttis[i];\r
-           if (ttisgmtcnt == 0)\r
-               ttisp->tt_ttisgmt = FALSE;\r
-           else {\r
-               ttisp->tt_ttisgmt = *p++;\r
-               if (ttisp->tt_ttisgmt != TRUE &&\r
-                   ttisp->tt_ttisgmt != FALSE)\r
-                       return -1;\r
-           }\r
-       }\r
-   }\r
-   return 0;\r
-}\r
-\r
-static const int   mon_lengths[2][MONSPERYEAR] = {\r
-   { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },\r
-   { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }\r
-};\r
-\r
-static const int   year_lengths[2] = {\r
-   DAYSPERNYEAR, DAYSPERLYEAR\r
-};\r
-\r
-/*\r
-** Given a pointer into a time zone string, scan until a character that is not\r
-** a valid character in a zone name is found.  Return a pointer to that\r
-** character.\r
-*/\r
-\r
-static const char *\r
-getzname(strp)\r
-register const char *  strp;\r
-{\r
-   register char   c;\r
-\r
-   while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&\r
-       c != '+')\r
-           ++strp;\r
-   return strp;\r
-}\r
-\r
-/*\r
-** Given a pointer into a time zone string, extract a number from that string.\r
-** Check that the number is within a specified range; if it is not, return\r
-** NULL.\r
-** Otherwise, return a pointer to the first character not part of the number.\r
-*/\r
-\r
-static const char *\r
-getnum(strp, nump, min, max)\r
-register const char *  strp;\r
-int * const        nump;\r
-const int      min;\r
-const int      max;\r
-{\r
-   register char   c;\r
-   register int    num;\r
-\r
-   if (strp == NULL || !is_digit(c = *strp))\r
-       return NULL;\r
-   num = 0;\r
-   do {\r
-       num = num * 10 + (c - '0');\r
-       if (num > max)\r
-           return NULL;    /* illegal value */\r
-       c = *++strp;\r
-   } while (is_digit(c));\r
-   if (num < min)\r
-       return NULL;        /* illegal value */\r
-   *nump = num;\r
-   return strp;\r
-}\r
-\r
-/*\r
-** Given a pointer into a time zone string, extract a number of seconds,\r
-** in hh[:mm[:ss]] form, from the string.\r
-** If any error occurs, return NULL.\r
-** Otherwise, return a pointer to the first character not part of the number\r
-** of seconds.\r
-*/\r
-\r
-static const char *\r
-getsecs(strp, secsp)\r
-register const char *  strp;\r
-long * const       secsp;\r
-{\r
-   int num;\r
-\r
-   /*\r
-   ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like\r
-   ** "M10.4.6/26", which does not conform to Posix,\r
-   ** but which specifies the equivalent of\r
-   ** ``02:00 on the first Sunday on or after 23 Oct''.\r
-   */\r
-   strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);\r
-   if (strp == NULL)\r
-       return NULL;\r
-   *secsp = num * (long) SECSPERHOUR;\r
-   if (*strp == ':') {\r
-       ++strp;\r
-       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);\r
-       if (strp == NULL)\r
-           return NULL;\r
-       *secsp += num * SECSPERMIN;\r
-       if (*strp == ':') {\r
-           ++strp;\r
-           /* `SECSPERMIN' allows for leap seconds.  */\r
-           strp = getnum(strp, &num, 0, SECSPERMIN);\r
-           if (strp == NULL)\r
-               return NULL;\r
-           *secsp += num;\r
-       }\r
-   }\r
-   return strp;\r
-}\r
-\r
-/*\r
-** Given a pointer into a time zone string, extract an offset, in\r
-** [+-]hh[:mm[:ss]] form, from the string.\r
-** If any error occurs, return NULL.\r
-** Otherwise, return a pointer to the first character not part of the time.\r
-*/\r
-\r
-static const char *\r
-getoffset(strp, offsetp)\r
-register const char *  strp;\r
-long * const       offsetp;\r
-{\r
-   register int    neg = 0;\r
-\r
-   if (*strp == '-') {\r
-       neg = 1;\r
-       ++strp;\r
-   } else if (*strp == '+')\r
-       ++strp;\r
-   strp = getsecs(strp, offsetp);\r
-   if (strp == NULL)\r
-       return NULL;        /* illegal time */\r
-   if (neg)\r
-       *offsetp = -*offsetp;\r
-   return strp;\r
-}\r
-\r
-/*\r
-** Given a pointer into a time zone string, extract a rule in the form\r
-** date[/time].  See POSIX section 8 for the format of "date" and "time".\r
-** If a valid rule is not found, return NULL.\r
-** Otherwise, return a pointer to the first character not part of the rule.\r
-*/\r
-\r
-static const char *\r
-getrule(strp, rulep)\r
-const char *           strp;\r
-register struct rule * const   rulep;\r
-{\r
-   if (*strp == 'J') {\r
-       /*\r
-       ** Julian day.\r
-       */\r
-       rulep->r_type = JULIAN_DAY;\r
-       ++strp;\r
-       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);\r
-   } else if (*strp == 'M') {\r
-       /*\r
-       ** Month, week, day.\r
-       */\r
-       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;\r
-       ++strp;\r
-       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);\r
-       if (strp == NULL)\r
-           return NULL;\r
-       if (*strp++ != '.')\r
-           return NULL;\r
-       strp = getnum(strp, &rulep->r_week, 1, 5);\r
-       if (strp == NULL)\r
-           return NULL;\r
-       if (*strp++ != '.')\r
-           return NULL;\r
-       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);\r
-   } else if (is_digit(*strp)) {\r
-       /*\r
-       ** Day of year.\r
-       */\r
-       rulep->r_type = DAY_OF_YEAR;\r
-       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);\r
-   } else  return NULL;        /* invalid format */\r
-   if (strp == NULL)\r
-       return NULL;\r
-   if (*strp == '/') {\r
-       /*\r
-       ** Time specified.\r
-       */\r
-       ++strp;\r
-       strp = getsecs(strp, &rulep->r_time);\r
-   } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */\r
-   return strp;\r
-}\r
-\r
-/*\r
-** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the\r
-** year, a rule, and the offset from UTC at the time that rule takes effect,\r
-** calculate the Epoch-relative time that rule takes effect.\r
-*/\r
-\r
-static time_t\r
-transtime(janfirst, year, rulep, offset)\r
-const time_t               janfirst;\r
-const int              year;\r
-register const struct rule * const rulep;\r
-const long             offset;\r
-{\r
-   register int    leapyear;\r
-   register time_t value;\r
-   register int    i;\r
-   int     d, m1, yy0, yy1, yy2, dow;\r
-\r
-   INITIALIZE(value);\r
-   leapyear = isleap(year);\r
-   switch (rulep->r_type) {\r
-\r
-   case JULIAN_DAY:\r
-       /*\r
-       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap\r
-       ** years.\r
-       ** In non-leap years, or if the day number is 59 or less, just\r
-       ** add SECSPERDAY times the day number-1 to the time of\r
-       ** January 1, midnight, to get the day.\r
-       */\r
-       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;\r
-       if (leapyear && rulep->r_day >= 60)\r
-           value += SECSPERDAY;\r
-       break;\r
-\r
-   case DAY_OF_YEAR:\r
-       /*\r
-       ** n - day of year.\r
-       ** Just add SECSPERDAY times the day number to the time of\r
-       ** January 1, midnight, to get the day.\r
-       */\r
-       value = janfirst + rulep->r_day * SECSPERDAY;\r
-       break;\r
-\r
-   case MONTH_NTH_DAY_OF_WEEK:\r
-       /*\r
-       ** Mm.n.d - nth "dth day" of month m.\r
-       */\r
-       value = janfirst;\r
-       for (i = 0; i < rulep->r_mon - 1; ++i)\r
-           value += mon_lengths[leapyear][i] * SECSPERDAY;\r
-\r
-       /*\r
-       ** Use Zeller's Congruence to get day-of-week of first day of\r
-       ** month.\r
-       */\r
-       m1 = (rulep->r_mon + 9) % 12 + 1;\r
-       yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;\r
-       yy1 = yy0 / 100;\r
-       yy2 = yy0 % 100;\r
-       dow = ((26 * m1 - 2) / 10 +\r
-           1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;\r
-       if (dow < 0)\r
-           dow += DAYSPERWEEK;\r
-\r
-       /*\r
-       ** "dow" is the day-of-week of the first day of the month.  Get\r
-       ** the day-of-month (zero-origin) of the first "dow" day of the\r
-       ** month.\r
-       */\r
-       d = rulep->r_day - dow;\r
-       if (d < 0)\r
-           d += DAYSPERWEEK;\r
-       for (i = 1; i < rulep->r_week; ++i) {\r
-           if (d + DAYSPERWEEK >=\r
-               mon_lengths[leapyear][rulep->r_mon - 1])\r
-                   break;\r
-           d += DAYSPERWEEK;\r
-       }\r
-\r
-       /*\r
-       ** "d" is the day-of-month (zero-origin) of the day we want.\r
-       */\r
-       value += d * SECSPERDAY;\r
-       break;\r
-   }\r
-\r
-   /*\r
-   ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in\r
-   ** question.  To get the Epoch-relative time of the specified local\r
-   ** time on that day, add the transition time and the current offset\r
-   ** from UTC.\r
-   */\r
-   return value + rulep->r_time + offset;\r
-}\r
-\r
-/*\r
-** Given a POSIX section 8-style TZ string, fill in the rule tables as\r
-** appropriate.\r
-*/\r
-\r
-static int\r
-tzparse(name, sp, lastditch)\r
-const char *           name;\r
-register struct state * const  sp;\r
-const int          lastditch;\r
-{\r
-   const char *            stdname;\r
-   const char *            dstname;\r
-   size_t              stdlen;\r
-   size_t              dstlen;\r
-   long                stdoffset;\r
-   long                dstoffset;\r
-   register time_t *       atp;\r
-   register unsigned char *    typep;\r
-   register char *         cp;\r
-   register int            load_result;\r
-\r
-   INITIALIZE(dstname);\r
-   stdname = name;\r
-   if (lastditch) {\r
-       stdlen = strlen(name);  /* length of standard zone name */\r
-       name += stdlen;\r
-       if (stdlen >= sizeof sp->chars)\r
-           stdlen = (sizeof sp->chars) - 1;\r
-       stdoffset = 0;\r
-   } else {\r
-       name = getzname(name);\r
-       stdlen = name - stdname;\r
-       if (stdlen < 3)\r
-           return -1;\r
-       if (*name == '\0')\r
-           return -1;\r
-       name = getoffset(name, &stdoffset);\r
-       if (name == NULL)\r
-           return -1;\r
-   }\r
-   load_result = tzload(TZDEFRULES, sp);\r
-   if (load_result != 0)\r
-       sp->leapcnt = 0;        /* so, we're off a little */\r
-   if (*name != '\0') {\r
-       dstname = name;\r
-       name = getzname(name);\r
-       dstlen = name - dstname;    /* length of DST zone name */\r
-       if (dstlen < 3)\r
-           return -1;\r
-       if (*name != '\0' && *name != ',' && *name != ';') {\r
-           name = getoffset(name, &dstoffset);\r
-           if (name == NULL)\r
-               return -1;\r
-       } else  dstoffset = stdoffset - SECSPERHOUR;\r
-       if (*name == '\0' && load_result != 0)\r
-           name = TZDEFRULESTRING;\r
-       if (*name == ',' || *name == ';') {\r
-           struct rule start;\r
-           struct rule end;\r
-           register int    year;\r
-           register time_t janfirst;\r
-           time_t      starttime;\r
-           time_t      endtime;\r
-\r
-           ++name;\r
-           if ((name = getrule(name, &start)) == NULL)\r
-               return -1;\r
-           if (*name++ != ',')\r
-               return -1;\r
-           if ((name = getrule(name, &end)) == NULL)\r
-               return -1;\r
-           if (*name != '\0')\r
-               return -1;\r
-           sp->typecnt = 2;    /* standard time and DST */\r
-           /*\r
-           ** Two transitions per year, from EPOCH_YEAR to 2037.\r
-           */\r
-           sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);\r
-           if (sp->timecnt > TZ_MAX_TIMES)\r
-               return -1;\r
-           sp->ttis[0].tt_gmtoff = -dstoffset;\r
-           sp->ttis[0].tt_isdst = 1;\r
-           sp->ttis[0].tt_abbrind = stdlen + 1;\r
-           sp->ttis[1].tt_gmtoff = -stdoffset;\r
-           sp->ttis[1].tt_isdst = 0;\r
-           sp->ttis[1].tt_abbrind = 0;\r
-           atp = sp->ats;\r
-           typep = sp->types;\r
-           janfirst = 0;\r
-           for (year = EPOCH_YEAR; year <= 2037; ++year) {\r
-               starttime = transtime(janfirst, year, &start,\r
-                   stdoffset);\r
-               endtime = transtime(janfirst, year, &end,\r
-                   dstoffset);\r
-               if (starttime > endtime) {\r
-                   *atp++ = endtime;\r
-                   *typep++ = 1;   /* DST ends */\r
-                   *atp++ = starttime;\r
-                   *typep++ = 0;   /* DST begins */\r
-               } else {\r
-                   *atp++ = starttime;\r
-                   *typep++ = 0;   /* DST begins */\r
-                   *atp++ = endtime;\r
-                   *typep++ = 1;   /* DST ends */\r
-               }\r
-               janfirst += year_lengths[isleap(year)] *\r
-                   SECSPERDAY;\r
-           }\r
-       } else {\r
-           register long   theirstdoffset;\r
-           register long   theirdstoffset;\r
-           register long   theiroffset;\r
-           register int    isdst;\r
-           register int    i;\r
-           register int    j;\r
-\r
-           if (*name != '\0')\r
-               return -1;\r
-           /*\r
-           ** Initial values of theirstdoffset and theirdstoffset.\r
-           */\r
-           theirstdoffset = 0;\r
-           for (i = 0; i < sp->timecnt; ++i) {\r
-               j = sp->types[i];\r
-               if (!sp->ttis[j].tt_isdst) {\r
-                   theirstdoffset =\r
-                       -sp->ttis[j].tt_gmtoff;\r
-                   break;\r
-               }\r
-           }\r
-           theirdstoffset = 0;\r
-           for (i = 0; i < sp->timecnt; ++i) {\r
-               j = sp->types[i];\r
-               if (sp->ttis[j].tt_isdst) {\r
-                   theirdstoffset =\r
-                       -sp->ttis[j].tt_gmtoff;\r
-                   break;\r
-               }\r
-           }\r
-           /*\r
-           ** Initially we're assumed to be in standard time.\r
-           */\r
-           isdst = FALSE;\r
-           theiroffset = theirstdoffset;\r
-           /*\r
-           ** Now juggle transition times and types\r
-           ** tracking offsets as you do.\r
-           */\r
-           for (i = 0; i < sp->timecnt; ++i) {\r
-               j = sp->types[i];\r
-               sp->types[i] = sp->ttis[j].tt_isdst;\r
-               if (sp->ttis[j].tt_ttisgmt) {\r
-                   /* No adjustment to transition time */\r
-               } else {\r
-                   /*\r
-                   ** If summer time is in effect, and the\r
-                   ** transition time was not specified as\r
-                   ** standard time, add the summer time\r
-                   ** offset to the transition time;\r
-                   ** otherwise, add the standard time\r
-                   ** offset to the transition time.\r
-                   */\r
-                   /*\r
-                   ** Transitions from DST to DDST\r
-                   ** will effectively disappear since\r
-                   ** POSIX provides for only one DST\r
-                   ** offset.\r
-                   */\r
-                   if (isdst && !sp->ttis[j].tt_ttisstd) {\r
-                       sp->ats[i] += dstoffset -\r
-                           theirdstoffset;\r
-                   } else {\r
-                       sp->ats[i] += stdoffset -\r
-                           theirstdoffset;\r
-                   }\r
-               }\r
-               theiroffset = -sp->ttis[j].tt_gmtoff;\r
-               if (sp->ttis[j].tt_isdst)\r
-                   theirdstoffset = theiroffset;\r
-               else    theirstdoffset = theiroffset;\r
-           }\r
-           /*\r
-           ** Finally, fill in ttis.\r
-           ** ttisstd and ttisgmt need not be handled.\r
-           */\r
-           sp->ttis[0].tt_gmtoff = -stdoffset;\r
-           sp->ttis[0].tt_isdst = FALSE;\r
-           sp->ttis[0].tt_abbrind = 0;\r
-           sp->ttis[1].tt_gmtoff = -dstoffset;\r
-           sp->ttis[1].tt_isdst = TRUE;\r
-           sp->ttis[1].tt_abbrind = stdlen + 1;\r
-           sp->typecnt = 2;\r
-       }\r
-   } else {\r
-       dstlen = 0;\r
-       sp->typecnt = 1;        /* only standard time */\r
-       sp->timecnt = 0;\r
-       sp->ttis[0].tt_gmtoff = -stdoffset;\r
-       sp->ttis[0].tt_isdst = 0;\r
-       sp->ttis[0].tt_abbrind = 0;\r
-   }\r
-   sp->charcnt = stdlen + 1;\r
-   if (dstlen != 0)\r
-       sp->charcnt += dstlen + 1;\r
-   if ((size_t) sp->charcnt > sizeof sp->chars)\r
-       return -1;\r
-   cp = sp->chars;\r
-   (void) strncpy(cp, stdname, stdlen);\r
-   cp += stdlen;\r
-   *cp++ = '\0';\r
-   if (dstlen != 0) {\r
-       (void) strncpy(cp, dstname, dstlen);\r
-       *(cp + dstlen) = '\0';\r
-   }\r
-   return 0;\r
-}\r
-\r
-static void\r
-gmtload(sp)\r
-struct state * const   sp;\r
-{\r
-   if (tzload(gmt, sp) != 0)\r
-       (void) tzparse(gmt, sp, TRUE);\r
-}\r
-\r
-#ifndef STD_INSPIRED\r
-/*\r
-** A non-static declaration of tzsetwall in a system header file\r
-** may cause a warning about this upcoming static declaration...\r
-*/\r
-static\r
-#endif /* !defined STD_INSPIRED */\r
-void\r
-tzsetwall P((void))\r
-{\r
-   if (lcl_is_set < 0)\r
-       return;\r
-   lcl_is_set = -1;\r
-\r
-#ifdef ALL_STATE\r
-   if (lclptr == NULL) {\r
-       lclptr = (struct state *) malloc(sizeof *lclptr);\r
-       if (lclptr == NULL) {\r
-           settzname();    /* all we can do */\r
-           return;\r
-       }\r
-   }\r
-#endif /* defined ALL_STATE */\r
-   if (tzload((char *) NULL, lclptr) != 0)\r
-       gmtload(lclptr);\r
-   settzname();\r
-}\r
-\r
-void\r
-tzset P((void))\r
-{\r
-   register const char *   name;\r
-\r
-   name = getenv("TZ");\r
-   if (name == NULL) {\r
-       tzsetwall();\r
-       return;\r
-   }\r
-\r
-   if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)\r
-       return;\r
-   lcl_is_set = strlen(name) < sizeof lcl_TZname;\r
-   if (lcl_is_set)\r
-       (void) strcpy(lcl_TZname, name);\r
-\r
-#ifdef ALL_STATE\r
-   if (lclptr == NULL) {\r
-       lclptr = (struct state *) malloc(sizeof *lclptr);\r
-       if (lclptr == NULL) {\r
-           settzname();    /* all we can do */\r
-           return;\r
-       }\r
-   }\r
-#endif /* defined ALL_STATE */\r
-   if (*name == '\0') {\r
-       /*\r
-       ** User wants it fast rather than right.\r
-       */\r
-       lclptr->leapcnt = 0;        /* so, we're off a little */\r
-       lclptr->timecnt = 0;\r
-       lclptr->typecnt = 0;\r
-       lclptr->ttis[0].tt_isdst = 0;\r
-       lclptr->ttis[0].tt_gmtoff = 0;\r
-       lclptr->ttis[0].tt_abbrind = 0;\r
-       (void) strcpy(lclptr->chars, gmt);\r
-   } else if (tzload(name, lclptr) != 0)\r
-       if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)\r
-           (void) gmtload(lclptr);\r
-   settzname();\r
-}\r
-\r
-/*\r
-** The easy way to behave "as if no library function calls" localtime\r
-** is to not call it--so we drop its guts into "localsub", which can be\r
-** freely called.  (And no, the PANS doesn't require the above behavior--\r
-** but it *is* desirable.)\r
-**\r
-** The unused offset argument is for the benefit of mktime variants.\r
-*/\r
-\r
-/*ARGSUSED*/\r
-static void\r
-localsub(timep, offset, tmp)\r
-const time_t * const   timep;\r
-const long     offset;\r
-struct tm * const  tmp;\r
-{\r
-   register struct state *     sp;\r
-   register const struct ttinfo *  ttisp;\r
-   register int            i;\r
-   const time_t            t = *timep;\r
-\r
-   sp = lclptr;\r
-#ifdef ALL_STATE\r
-   if (sp == NULL) {\r
-       gmtsub(timep, offset, tmp);\r
-       return;\r
-   }\r
-#endif /* defined ALL_STATE */\r
-   if (sp->timecnt == 0 || t < sp->ats[0]) {\r
-       i = 0;\r
-       while (sp->ttis[i].tt_isdst)\r
-           if (++i >= sp->typecnt) {\r
-               i = 0;\r
-               break;\r
-           }\r
-   } else {\r
-       for (i = 1; i < sp->timecnt; ++i)\r
-           if (t < sp->ats[i])\r
-               break;\r
-       i = sp->types[i - 1];\r
-   }\r
-   ttisp = &sp->ttis[i];\r
-   /*\r
-   ** To get (wrong) behavior that's compatible with System V Release 2.0\r
-   ** you'd replace the statement below with\r
-   **  t += ttisp->tt_gmtoff;\r
-   **  timesub(&t, 0L, sp, tmp);\r
-   */\r
-   timesub(&t, ttisp->tt_gmtoff, sp, tmp);\r
-   tmp->tm_isdst = ttisp->tt_isdst;\r
-   tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];\r
-#ifdef TM_ZONE\r
-   tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];\r
-#endif /* defined TM_ZONE */\r
-}\r
-\r
-struct tm *\r
-localtime(timep)\r
-const time_t * const   timep;\r
-{\r
-   tzset();\r
-   localsub(timep, 0L, &tm);\r
-   return &tm;\r
-}\r
-\r
-/*\r
-** Re-entrant version of localtime.\r
-*/\r
-\r
-struct tm *\r
-localtime_r(timep, tm)\r
-const time_t * const   timep;\r
-struct tm *        tm;\r
-{\r
-   localsub(timep, 0L, tm);\r
-   return tm;\r
-}\r
-\r
-/*\r
-** gmtsub is to gmtime as localsub is to localtime.\r
-*/\r
-\r
-static void\r
-gmtsub(timep, offset, tmp)\r
-const time_t * const   timep;\r
-const long     offset;\r
-struct tm * const  tmp;\r
-{\r
-   if (!gmt_is_set) {\r
-       gmt_is_set = TRUE;\r
-#ifdef ALL_STATE\r
-       gmtptr = (struct state *) malloc(sizeof *gmtptr);\r
-       if (gmtptr != NULL)\r
-#endif /* defined ALL_STATE */\r
-           gmtload(gmtptr);\r
-   }\r
-   timesub(timep, offset, gmtptr, tmp);\r
-#ifdef TM_ZONE\r
-   /*\r
-   ** Could get fancy here and deliver something such as\r
-   ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,\r
-   ** but this is no time for a treasure hunt.\r
-   */\r
-   if (offset != 0)\r
-       tmp->TM_ZONE = wildabbr;\r
-   else {\r
-#ifdef ALL_STATE\r
-       if (gmtptr == NULL)\r
-           tmp->TM_ZONE = gmt;\r
-       else    tmp->TM_ZONE = gmtptr->chars;\r
-#endif /* defined ALL_STATE */\r
-#ifndef ALL_STATE\r
-       tmp->TM_ZONE = gmtptr->chars;\r
-#endif /* State Farm */\r
-   }\r
-#endif /* defined TM_ZONE */\r
-}\r
-\r
-struct tm *\r
-gmtime(timep)\r
-const time_t * const   timep;\r
-{\r
-   gmtsub(timep, 0L, &tm);\r
-   return &tm;\r
-}\r
-\r
-/*\r
-* Re-entrant version of gmtime.\r
-*/\r
-\r
-struct tm *\r
-gmtime_r(timep, tm)\r
-const time_t * const   timep;\r
-struct tm *        tm;\r
-{\r
-   gmtsub(timep, 0L, tm);\r
-   return tm;\r
-}\r
-\r
-#ifdef STD_INSPIRED\r
-\r
-struct tm *\r
-offtime(timep, offset)\r
-const time_t * const   timep;\r
-const long     offset;\r
-{\r
-   gmtsub(timep, offset, &tm);\r
-   return &tm;\r
-}\r
-\r
-#endif /* defined STD_INSPIRED */\r
-\r
-static void\r
-timesub(timep, offset, sp, tmp)\r
-const time_t * const           timep;\r
-const long             offset;\r
-register const struct state * const    sp;\r
-register struct tm * const     tmp;\r
-{\r
-   register const struct lsinfo *  lp;\r
-   register long           days;\r
-   register long           rem;\r
-   register int            y;\r
-   register int            yleap;\r
-   register const int *        ip;\r
-   register long           corr;\r
-   register int            hit;\r
-   register int            i;\r
-\r
-   corr = 0;\r
-   hit = 0;\r
-#ifdef ALL_STATE\r
-   i = (sp == NULL) ? 0 : sp->leapcnt;\r
-#endif /* defined ALL_STATE */\r
-#ifndef ALL_STATE\r
-   i = sp->leapcnt;\r
-#endif /* State Farm */\r
-   while (--i >= 0) {\r
-       lp = &sp->lsis[i];\r
-       if (*timep >= lp->ls_trans) {\r
-           if (*timep == lp->ls_trans) {\r
-               hit = ((i == 0 && lp->ls_corr > 0) ||\r
-                   lp->ls_corr > sp->lsis[i - 1].ls_corr);\r
-               if (hit)\r
-                   while (i > 0 &&\r
-                       sp->lsis[i].ls_trans ==\r
-                       sp->lsis[i - 1].ls_trans + 1 &&\r
-                       sp->lsis[i].ls_corr ==\r
-                       sp->lsis[i - 1].ls_corr + 1) {\r
-                           ++hit;\r
-                           --i;\r
-                   }\r
-           }\r
-           corr = lp->ls_corr;\r
-           break;\r
-       }\r
-   }\r
-   days = *timep / SECSPERDAY;\r
-   rem = *timep % SECSPERDAY;\r
-#ifdef mc68k\r
-   if (*timep == 0x80000000) {\r
-       /*\r
-       ** A 3B1 muffs the division on the most negative number.\r
-       */\r
-       days = -24855;\r
-       rem = -11648;\r
-   }\r
-#endif /* defined mc68k */\r
-   rem += (offset - corr);\r
-   while (rem < 0) {\r
-       rem += SECSPERDAY;\r
-       --days;\r
-   }\r
-   while (rem >= SECSPERDAY) {\r
-       rem -= SECSPERDAY;\r
-       ++days;\r
-   }\r
-   tmp->tm_hour = (int) (rem / SECSPERHOUR);\r
-   rem = rem % SECSPERHOUR;\r
-   tmp->tm_min = (int) (rem / SECSPERMIN);\r
-   /*\r
-   ** A positive leap second requires a special\r
-   ** representation.  This uses "... ??:59:60" et seq.\r
-   */\r
-   tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;\r
-   tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);\r
-   if (tmp->tm_wday < 0)\r
-       tmp->tm_wday += DAYSPERWEEK;\r
-   y = EPOCH_YEAR;\r
-#define LEAPS_THRU_END_OF(y)   ((y) / 4 - (y) / 100 + (y) / 400)\r
-   while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {\r
-       register int    newy;\r
-\r
-       newy = y + days / DAYSPERNYEAR;\r
-       if (days < 0)\r
-           --newy;\r
-       days -= (newy - y) * DAYSPERNYEAR +\r
-           LEAPS_THRU_END_OF(newy - 1) -\r
-           LEAPS_THRU_END_OF(y - 1);\r
-       y = newy;\r
-   }\r
-   tmp->tm_year = y - TM_YEAR_BASE;\r
-   tmp->tm_yday = (int) days;\r
-   ip = mon_lengths[yleap];\r
-   for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))\r
-       days = days - (long) ip[tmp->tm_mon];\r
-   tmp->tm_mday = (int) (days + 1);\r
-   tmp->tm_isdst = 0;\r
-#ifdef TM_GMTOFF\r
-   tmp->TM_GMTOFF = offset;\r
-#endif /* defined TM_GMTOFF */\r
-}\r
-\r
-char *\r
-ctime(timep)\r
-const time_t * const   timep;\r
-{\r
-/*\r
-** Section 4.12.3.2 of X3.159-1989 requires that\r
-** The ctime function converts the calendar time pointed to by timer\r
-** to local time in the form of a string.  It is equivalent to\r
-**     asctime(localtime(timer))\r
-*/\r
-   return asctime(localtime(timep));\r
-}\r
-\r
-char *\r
-ctime_r(timep, buf)\r
-const time_t * const   timep;\r
-char *         buf;\r
-{\r
-   struct tm   tm;\r
-\r
-   return asctime_r(localtime_r(timep, &tm), buf);\r
-}\r
-\r
-/*\r
-** Adapted from code provided by Robert Elz, who writes:\r
-** The "best" way to do mktime I think is based on an idea of Bob\r
-** Kridle's (so its said...) from a long time ago.\r
-** [kridle@xinet.com as of 1996-01-16.]\r
-** It does a binary search of the time_t space.  Since time_t's are\r
-** just 32 bits, its a max of 32 iterations (even at 64 bits it\r
-** would still be very reasonable).\r
-*/\r
-\r
-#ifndef WRONG\r
-#define WRONG  (-1)\r
-#endif /* !defined WRONG */\r
-\r
-/*\r
-** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).\r
-*/\r
-\r
-static int\r
-increment_overflow(number, delta)\r
-int *  number;\r
-int    delta;\r
-{\r
-   int number0;\r
-\r
-   number0 = *number;\r
-   *number += delta;\r
-   return (*number < number0) != (delta < 0);\r
-}\r
-\r
-static int\r
-normalize_overflow(tensptr, unitsptr, base)\r
-int * const    tensptr;\r
-int * const    unitsptr;\r
-const int  base;\r
-{\r
-   register int    tensdelta;\r
-\r
-   tensdelta = (*unitsptr >= 0) ?\r
-       (*unitsptr / base) :\r
-       (-1 - (-1 - *unitsptr) / base);\r
-   *unitsptr -= tensdelta * base;\r
-   return increment_overflow(tensptr, tensdelta);\r
-}\r
-\r
-static int\r
-tmcomp(atmp, btmp)\r
-register const struct tm * const atmp;\r
-register const struct tm * const btmp;\r
-{\r
-   register int    result;\r
-\r
-   if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&\r
-       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&\r
-       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&\r
-       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&\r
-       (result = (atmp->tm_min - btmp->tm_min)) == 0)\r
-           result = atmp->tm_sec - btmp->tm_sec;\r
-   return result;\r
-}\r
-\r
-static time_t\r
-time2sub(tmp, funcp, offset, okayp, do_norm_secs)\r
-struct tm * const  tmp;\r
-void (* const      funcp) P((const time_t*, long, struct tm*));\r
-const long     offset;\r
-int * const        okayp;\r
-const int      do_norm_secs;\r
-{\r
-   register const struct state *   sp;\r
-   register int            dir;\r
-   register int            bits;\r
-   register int            i, j ;\r
-   register int            saved_seconds;\r
-   time_t              newt;\r
-   time_t              t;\r
-   struct tm           yourtm, mytm;\r
-\r
-   *okayp = FALSE;\r
-   yourtm = *tmp;\r
-   if (do_norm_secs) {\r
-       if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,\r
-           SECSPERMIN))\r
-               return WRONG;\r
-   }\r
-   if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))\r
-       return WRONG;\r
-   if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))\r
-       return WRONG;\r
-   if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))\r
-       return WRONG;\r
-   /*\r
-   ** Turn yourtm.tm_year into an actual year number for now.\r
-   ** It is converted back to an offset from TM_YEAR_BASE later.\r
-   */\r
-   if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))\r
-       return WRONG;\r
-   while (yourtm.tm_mday <= 0) {\r
-       if (increment_overflow(&yourtm.tm_year, -1))\r
-           return WRONG;\r
-       i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
-       yourtm.tm_mday += year_lengths[isleap(i)];\r
-   }\r
-   while (yourtm.tm_mday > DAYSPERLYEAR) {\r
-       i = yourtm.tm_year + (1 < yourtm.tm_mon);\r
-       yourtm.tm_mday -= year_lengths[isleap(i)];\r
-       if (increment_overflow(&yourtm.tm_year, 1))\r
-           return WRONG;\r
-   }\r
-   for ( ; ; ) {\r
-       i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];\r
-       if (yourtm.tm_mday <= i)\r
-           break;\r
-       yourtm.tm_mday -= i;\r
-       if (++yourtm.tm_mon >= MONSPERYEAR) {\r
-           yourtm.tm_mon = 0;\r
-           if (increment_overflow(&yourtm.tm_year, 1))\r
-               return WRONG;\r
-       }\r
-   }\r
-   if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))\r
-       return WRONG;\r
-   if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)\r
-       saved_seconds = 0;\r
-   else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {\r
-       /*\r
-       ** We can't set tm_sec to 0, because that might push the\r
-       ** time below the minimum representable time.\r
-       ** Set tm_sec to 59 instead.\r
-       ** This assumes that the minimum representable time is\r
-       ** not in the same minute that a leap second was deleted from,\r
-       ** which is a safer assumption than using 58 would be.\r
-       */\r
-       if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))\r
-           return WRONG;\r
-       saved_seconds = yourtm.tm_sec;\r
-       yourtm.tm_sec = SECSPERMIN - 1;\r
-   } else {\r
-       saved_seconds = yourtm.tm_sec;\r
-       yourtm.tm_sec = 0;\r
-   }\r
-   /*\r
-   ** Divide the search space in half\r
-   ** (this works whether time_t is signed or unsigned).\r
-   */\r
-   bits = TYPE_BIT(time_t) - 1;\r
-   /*\r
-   ** If time_t is signed, then 0 is just above the median,\r
-   ** assuming two's complement arithmetic.\r
-   ** If time_t is unsigned, then (1 << bits) is just above the median.\r
-   */\r
-   t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);\r
-   for ( ; ; ) {\r
-       (*funcp)(&t, offset, &mytm);\r
-       dir = tmcomp(&mytm, &yourtm);\r
-       if (dir != 0) {\r
-           if (bits-- < 0)\r
-               return WRONG;\r
-           if (bits < 0)\r
-               --t; /* may be needed if new t is minimal */\r
-           else if (dir > 0)\r
-               t -= ((time_t) 1) << bits;\r
-           else    t += ((time_t) 1) << bits;\r
-           continue;\r
-       }\r
-       if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)\r
-           break;\r
-       /*\r
-       ** Right time, wrong type.\r
-       ** Hunt for right time, right type.\r
-       ** It's okay to guess wrong since the guess\r
-       ** gets checked.\r
-       */\r
-       /*\r
-       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
-       */\r
-       sp = (const struct state *)\r
-           (((void *) funcp == (void *) localsub) ?\r
-           lclptr : gmtptr);\r
-#ifdef ALL_STATE\r
-       if (sp == NULL)\r
-           return WRONG;\r
-#endif /* defined ALL_STATE */\r
-       for (i = sp->typecnt - 1; i >= 0; --i) {\r
-           if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)\r
-               continue;\r
-           for (j = sp->typecnt - 1; j >= 0; --j) {\r
-               if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)\r
-                   continue;\r
-               newt = t + sp->ttis[j].tt_gmtoff -\r
-                   sp->ttis[i].tt_gmtoff;\r
-               (*funcp)(&newt, offset, &mytm);\r
-               if (tmcomp(&mytm, &yourtm) != 0)\r
-                   continue;\r
-               if (mytm.tm_isdst != yourtm.tm_isdst)\r
-                   continue;\r
-               /*\r
-               ** We have a match.\r
-               */\r
-               t = newt;\r
-               goto label;\r
-           }\r
-       }\r
-       return WRONG;\r
-   }\r
-label:\r
-   newt = t + saved_seconds;\r
-   if ((newt < t) != (saved_seconds < 0))\r
-       return WRONG;\r
-   t = newt;\r
-   (*funcp)(&t, offset, tmp);\r
-   *okayp = TRUE;\r
-   return t;\r
-}\r
-\r
-static time_t\r
-time2(tmp, funcp, offset, okayp)\r
-struct tm * const  tmp;\r
-void (* const      funcp) P((const time_t*, long, struct tm*));\r
-const long     offset;\r
-int * const        okayp;\r
-{\r
-   time_t  t;\r
-\r
-   /*\r
-   ** First try without normalization of seconds\r
-   ** (in case tm_sec contains a value associated with a leap second).\r
-   ** If that fails, try with normalization of seconds.\r
-   */\r
-   t = time2sub(tmp, funcp, offset, okayp, FALSE);\r
-   return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);\r
-}\r
-\r
-static time_t\r
-time1(tmp, funcp, offset)\r
-struct tm * const  tmp;\r
-void (* const      funcp) P((const time_t *, long, struct tm *));\r
-const long     offset;\r
-{\r
-   register time_t         t;\r
-   register const struct state *   sp;\r
-   register int            samei, otheri;\r
-   register int            sameind, otherind;\r
-   register int            i;\r
-   register int            nseen;\r
-   int             seen[TZ_MAX_TYPES];\r
-   int             types[TZ_MAX_TYPES];\r
-   int             okay;\r
-\r
-   if (tmp->tm_isdst > 1)\r
-       tmp->tm_isdst = 1;\r
-   t = time2(tmp, funcp, offset, &okay);\r
-#ifdef PCTS\r
-   /*\r
-   ** PCTS code courtesy Grant Sullivan (grant@osf.org).\r
-   */\r
-   if (okay)\r
-       return t;\r
-   if (tmp->tm_isdst < 0)\r
-       tmp->tm_isdst = 0;  /* reset to std and try again */\r
-#endif /* defined PCTS */\r
-#ifndef PCTS\r
-   if (okay || tmp->tm_isdst < 0)\r
-       return t;\r
-#endif /* !defined PCTS */\r
-   /*\r
-   ** We're supposed to assume that somebody took a time of one type\r
-   ** and did some math on it that yielded a "struct tm" that's bad.\r
-   ** We try to divine the type they started from and adjust to the\r
-   ** type they need.\r
-   */\r
-   /*\r
-   ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.\r
-   */\r
-   sp = (const struct state *) (((void *) funcp == (void *) localsub) ?\r
-       lclptr : gmtptr);\r
-#ifdef ALL_STATE\r
-   if (sp == NULL)\r
-       return WRONG;\r
-#endif /* defined ALL_STATE */\r
-   for (i = 0; i < sp->typecnt; ++i)\r
-       seen[i] = FALSE;\r
-   nseen = 0;\r
-   for (i = sp->timecnt - 1; i >= 0; --i)\r
-       if (!seen[sp->types[i]]) {\r
-           seen[sp->types[i]] = TRUE;\r
-           types[nseen++] = sp->types[i];\r
-       }\r
-   for (sameind = 0; sameind < nseen; ++sameind) {\r
-       samei = types[sameind];\r
-       if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)\r
-           continue;\r
-       for (otherind = 0; otherind < nseen; ++otherind) {\r
-           otheri = types[otherind];\r
-           if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)\r
-               continue;\r
-           tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -\r
-                   sp->ttis[samei].tt_gmtoff;\r
-           tmp->tm_isdst = !tmp->tm_isdst;\r
-           t = time2(tmp, funcp, offset, &okay);\r
-           if (okay)\r
-               return t;\r
-           tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -\r
-                   sp->ttis[samei].tt_gmtoff;\r
-           tmp->tm_isdst = !tmp->tm_isdst;\r
-       }\r
-   }\r
-   return WRONG;\r
-}\r
-\r
-time_t\r
-mktime(tmp)\r
-struct tm * const  tmp;\r
-{\r
-   tzset();\r
-   return time1(tmp, localsub, 0L);\r
-}\r
-\r
-#ifdef STD_INSPIRED\r
-\r
-time_t\r
-timelocal(tmp)\r
-struct tm * const  tmp;\r
-{\r
-   tmp->tm_isdst = -1; /* in case it wasn't initialized */\r
-   return mktime(tmp);\r
-}\r
-\r
-time_t\r
-timegm(tmp)\r
-struct tm * const  tmp;\r
-{\r
-   tmp->tm_isdst = 0;\r
-   return time1(tmp, gmtsub, 0L);\r
-}\r
-\r
-time_t\r
-timeoff(tmp, offset)\r
-struct tm * const  tmp;\r
-const long     offset;\r
-{\r
-   tmp->tm_isdst = 0;\r
-   return time1(tmp, gmtsub, offset);\r
-}\r
-\r
-#endif /* defined STD_INSPIRED */\r
-\r
-#ifdef CMUCS\r
-\r
-/*\r
-** The following is supplied for compatibility with\r
-** previous versions of the CMUCS runtime library.\r
-*/\r
-\r
-long\r
-gtime(tmp)\r
-struct tm * const  tmp;\r
-{\r
-   const time_t    t = mktime(tmp);\r
-\r
-   if (t == WRONG)\r
-       return -1;\r
-   return t;\r
-}\r
-\r
-#endif /* defined CMUCS */\r
-\r
-/*\r
-** XXX--is the below the right way to conditionalize??\r
-*/\r
-\r
-#ifdef STD_INSPIRED\r
-\r
-/*\r
-** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599\r
-** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which\r
-** is not the case if we are accounting for leap seconds.\r
-** So, we provide the following conversion routines for use\r
-** when exchanging timestamps with POSIX conforming systems.\r
-*/\r
-\r
-static long\r
-leapcorr(timep)\r
-time_t *   timep;\r
-{\r
-   register struct state *     sp;\r
-   register struct lsinfo *    lp;\r
-   register int            i;\r
-\r
-   sp = lclptr;\r
-   i = sp->leapcnt;\r
-   while (--i >= 0) {\r
-       lp = &sp->lsis[i];\r
-       if (*timep >= lp->ls_trans)\r
-           return lp->ls_corr;\r
-   }\r
-   return 0;\r
-}\r
-\r
-time_t\r
-time2posix(t)\r
-time_t t;\r
-{\r
-   tzset();\r
-   return t - leapcorr(&t);\r
-}\r
-\r
-time_t\r
-posix2time(t)\r
-time_t t;\r
-{\r
-   time_t  x;\r
-   time_t  y;\r
-\r
-   tzset();\r
-   /*\r
-   ** For a positive leap second hit, the result\r
-   ** is not unique.  For a negative leap second\r
-   ** hit, the corresponding time doesn't exist,\r
-   ** so we return an adjacent second.\r
-   */\r
-   x = t + leapcorr(&t);\r
-   y = x - leapcorr(&x);\r
-   if (y < t) {\r
-       do {\r
-           x++;\r
-           y = x - leapcorr(&x);\r
-       } while (y < t);\r
-       if (t != y)\r
-           return x - 1;\r
-   } else if (y > t) {\r
-       do {\r
-           --x;\r
-           y = x - leapcorr(&x);\r
-       } while (y > t);\r
-       if (t != y)\r
-           return x + 1;\r
-   }\r
-   return x;\r
-}\r
-\r
-#endif /* defined STD_INSPIRED */\r
+#include "pgtz.h"
+#undef open
+#define timezone pg_timezone
+#define USG_COMPAT
+extern time_t pg_timezone;
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)localtime.c    7.78";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
+** POSIX-style TZ environment variable handling from Guy Harris
+** (guy@auspex.com).
+*/
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+#include "tzfile.h"
+#include "fcntl.h"
+
+/*
+** SunOS 4.1.1 headers lack O_BINARY.
+*/
+
+#ifdef O_BINARY
+#define OPEN_MODE  (O_RDONLY | O_BINARY)
+#endif /* defined O_BINARY */
+#ifndef O_BINARY
+#define OPEN_MODE  O_RDONLY
+#endif /* !defined O_BINARY */
+
+#ifndef WILDABBR
+/*
+** 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.
+** 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).
+*/
+#define WILDABBR   "   "
+#endif /* !defined WILDABBR */
+
+static char        wildabbr[] = "WILDABBR";
+
+static const char  gmt[] = "GMT";
+
+/*
+** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** We default to US rules as of 1999-08-17.
+** POSIX 1003.1 section 8.1.1 says that the default DST rules are
+** implementation dependent; for historical reasons, US rules are a
+** common default.
+*/
+#ifndef TZDEFRULESTRING
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#endif /* !defined TZDEFDST */
+
+struct ttinfo {                /* time type information */
+   long        tt_gmtoff;  /* UTC offset in seconds */
+   int     tt_isdst;   /* used to set tm_isdst */
+   int     tt_abbrind; /* abbreviation list index */
+   int     tt_ttisstd; /* TRUE if transition is std time */
+   int     tt_ttisgmt; /* TRUE if transition is UTC */
+};
+
+struct lsinfo {                /* leap second information */
+   time_t      ls_trans;   /* transition time */
+   long        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;
+   time_t      ats[TZ_MAX_TIMES];
+   unsigned char   types[TZ_MAX_TIMES];
+   struct ttinfo   ttis[TZ_MAX_TYPES];
+   char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
+               (2 * (MY_TZNAME_MAX + 1)))];
+   struct lsinfo   lsis[TZ_MAX_LEAPS];
+};
+
+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 */
+};
+
+#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 int     increment_overflow P((int * number, int delta));
+static int     normalize_overflow P((int * tensptr, int * unitsptr,
+               int base));
+static void        settzname P((void));
+static time_t      time1 P((struct tm * tmp,
+               void(*funcp) P((const time_t *,
+               long, struct tm *)),
+               long offset));
+static time_t      time2 P((struct tm *tmp,
+               void(*funcp) P((const time_t *,
+               long, struct tm*)),
+               long offset, int * okayp));
+static time_t      time2sub P((struct tm *tmp,
+               void(*funcp) P((const time_t *,
+               long, struct tm*)),
+               long offset, int * okayp, int do_norm_secs));
+static void        timesub P((const time_t * timep, long offset,
+               const struct state * sp, struct tm * tmp));
+static int     tmcomp P((const struct tm * atmp,
+               const struct tm * btmp));
+static time_t      transtime P((time_t janfirst, int year,
+               const struct rule * rulep, long offset));
+static int     tzload P((const char * name, struct state * sp));
+static int     tzparse P((const char * name, struct state * sp,
+               int lastditch));
+
+#ifdef ALL_STATE
+static struct state *  lclptr;
+static struct state *  gmtptr;
+#endif /* defined ALL_STATE */
+
+#ifndef ALL_STATE
+static struct state    lclmem;
+static struct state    gmtmem;
+#define lclptr     (&lclmem)
+#define gmtptr     (&gmtmem)
+#endif /* State Farm */
+
+#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;
+static int     gmt_is_set;
+
+char *         tzname[2] = {
+   wildabbr,
+   wildabbr
+};
+
+/*
+** 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
+** objects: a broken-down time structure and an array of char.
+** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
+*/
+
+static struct tm   tm;
+
+#ifdef USG_COMPAT
+time_t         timezone = 0;
+int            daylight = 0;
+#endif /* defined USG_COMPAT */
+
+#ifdef ALTZONE
+time_t         altzone = 0;
+#endif /* defined ALTZONE */
+
+static long
+detzcode(codep)
+const char * const codep;
+{
+   register long   result;
+   register int    i;
+
+   result = (codep[0] & 0x80) ? ~0L : 0L;
+   for (i = 0; i < 4; ++i)
+       result = (result << 8) | (codep[i] & 0xff);
+   return result;
+}
+
+static void
+settzname P((void))
+{
+   register struct state * const   sp = lclptr;
+   register int            i;
+
+   tzname[0] = wildabbr;
+   tzname[1] = wildabbr;
+#ifdef USG_COMPAT
+   daylight = 0;
+   timezone = 0;
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+   altzone = 0;
+#endif /* defined ALTZONE */
+#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[ttisp->tt_isdst] =
+           &sp->chars[ttisp->tt_abbrind];
+#ifdef USG_COMPAT
+       if (ttisp->tt_isdst)
+           daylight = 1;
+       if (i == 0 || !ttisp->tt_isdst)
+           timezone = -(ttisp->tt_gmtoff);
+#endif /* defined USG_COMPAT */
+#ifdef ALTZONE
+       if (i == 0 || ttisp->tt_isdst)
+           altzone = -(ttisp->tt_gmtoff);
+#endif /* defined ALTZONE */
+   }
+   /*
+   ** And to get the latest zone names into tzname. . .
+   */
+   for (i = 0; i < sp->timecnt; ++i) {
+       register const struct ttinfo * const    ttisp =
+                           &sp->ttis[
+                               sp->types[i]];
+
+       tzname[ttisp->tt_isdst] =
+           &sp->chars[ttisp->tt_abbrind];
+   }
+}
+
+static int
+tzload(name, sp)
+register const char *      name;
+register struct state * const  sp;
+{
+   register const char *   p;
+   register int        i;
+   register int        fid;
+
+   if (name == NULL && (name = TZDEFAULT) == NULL)
+       return -1;
+   {
+       register int    doaccess;
+       /*
+       ** Section 4.9.1 of the C standard says that
+       ** "FILENAME_MAX expands to an integral constant expression
+       ** that is the size needed for an array of char large enough
+       ** to hold the longest file name string that the implementation
+       ** guarantees can be opened."
+       */
+       char        fullname[FILENAME_MAX + 1];
+
+       if (name[0] == ':')
+           ++name;
+       doaccess = name[0] == '/';
+       if (!doaccess) {
+           if ((p = TZDIR) == NULL)
+               return -1;
+           if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
+               return -1;
+           (void) strcpy(fullname, p);
+           (void) strcat(fullname, "/");
+           (void) strcat(fullname, name);
+           /*
+           ** Set doaccess if '.' (as in "../") shows up in name.
+           */
+           if (strchr(name, '.') != NULL)
+               doaccess = TRUE;
+           name = fullname;
+       }
+       if (doaccess && access(name, R_OK) != 0)
+           return -1;
+       if ((fid = open(name, OPEN_MODE)) == -1)
+           return -1;
+   }
+   {
+       struct tzhead * tzhp;
+       union {
+           struct tzhead   tzhead;
+           char        buf[sizeof *sp + sizeof *tzhp];
+       } u;
+       int     ttisstdcnt;
+       int     ttisgmtcnt;
+
+       i = read(fid, u.buf, sizeof u.buf);
+       if (close(fid) != 0)
+           return -1;
+       ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
+       ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
+       sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
+       sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
+       sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
+       sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
+       p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+       if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
+           sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
+           sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
+           sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
+           (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
+           (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
+               return -1;
+       if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
+           sp->timecnt +           /* types */
+           sp->typecnt * (4 + 2) +     /* ttinfos */
+           sp->charcnt +           /* chars */
+           sp->leapcnt * (4 + 4) +     /* lsinfos */
+           ttisstdcnt +            /* ttisstds */
+           ttisgmtcnt)         /* ttisgmts */
+               return -1;
+       for (i = 0; i < sp->timecnt; ++i) {
+           sp->ats[i] = detzcode(p);
+           p += 4;
+       }
+       for (i = 0; i < sp->timecnt; ++i) {
+           sp->types[i] = (unsigned char) *p++;
+           if (sp->types[i] >= sp->typecnt)
+               return -1;
+       }
+       for (i = 0; i < sp->typecnt; ++i) {
+           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)
+                   return -1;
+       }
+       for (i = 0; i < sp->charcnt; ++i)
+           sp->chars[i] = *p++;
+       sp->chars[i] = '\0';    /* ensure '\0' at end */
+       for (i = 0; i < sp->leapcnt; ++i) {
+           register struct lsinfo *    lsisp;
+
+           lsisp = &sp->lsis[i];
+           lsisp->ls_trans = detzcode(p);
+           p += 4;
+           lsisp->ls_corr = detzcode(p);
+           p += 4;
+       }
+       for (i = 0; i < sp->typecnt; ++i) {
+           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;
+           }
+       }
+       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;
+           }
+       }
+   }
+   return 0;
+}
+
+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 }
+};
+
+static const int   year_lengths[2] = {
+   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
+** character.
+*/
+
+static const char *
+getzname(strp)
+register const char *  strp;
+{
+   register char   c;
+
+   while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+       c != '+')
+           ++strp;
+   return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number from that string.
+** Check that the number is within a specified range; if it is not, return
+** NULL.
+** Otherwise, return a pointer to the first character not part of the number.
+*/
+
+static const char *
+getnum(strp, nump, min, max)
+register const char *  strp;
+int * const        nump;
+const int      min;
+const int      max;
+{
+   register char   c;
+   register int    num;
+
+   if (strp == NULL || !is_digit(c = *strp))
+       return NULL;
+   num = 0;
+   do {
+       num = num * 10 + (c - '0');
+       if (num > max)
+           return NULL;    /* illegal value */
+       c = *++strp;
+   } while (is_digit(c));
+   if (num < min)
+       return NULL;        /* illegal value */
+   *nump = num;
+   return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a number of seconds,
+** in hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the number
+** of seconds.
+*/
+
+static const char *
+getsecs(strp, secsp)
+register const char *  strp;
+long * const       secsp;
+{
+   int num;
+
+   /*
+   ** `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 * (long) SECSPERHOUR;
+   if (*strp == ':') {
+       ++strp;
+       strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+       if (strp == NULL)
+           return NULL;
+       *secsp += num * SECSPERMIN;
+       if (*strp == ':') {
+           ++strp;
+           /* `SECSPERMIN' allows for leap seconds.  */
+           strp = getnum(strp, &num, 0, SECSPERMIN);
+           if (strp == NULL)
+               return NULL;
+           *secsp += num;
+       }
+   }
+   return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract an offset, in
+** [+-]hh[:mm[:ss]] form, from the string.
+** If any error occurs, return NULL.
+** Otherwise, return a pointer to the first character not part of the time.
+*/
+
+static const char *
+getoffset(strp, offsetp)
+register const char *  strp;
+long * const       offsetp;
+{
+   register int    neg = 0;
+
+   if (*strp == '-') {
+       neg = 1;
+       ++strp;
+   } else if (*strp == '+')
+       ++strp;
+   strp = getsecs(strp, offsetp);
+   if (strp == NULL)
+       return NULL;        /* illegal time */
+   if (neg)
+       *offsetp = -*offsetp;
+   return strp;
+}
+
+/*
+** Given a pointer into a time zone string, extract a rule in the form
+** date[/time].  See POSIX section 8 for the format of "date" and "time".
+** 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(strp, rulep)
+const char *           strp;
+register struct rule * const   rulep;
+{
+   if (*strp == 'J') {
+       /*
+       ** Julian day.
+       */
+       rulep->r_type = JULIAN_DAY;
+       ++strp;
+       strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+   } else if (*strp == 'M') {
+       /*
+       ** Month, week, day.
+       */
+       rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+       ++strp;
+       strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+       if (strp == NULL)
+           return NULL;
+       if (*strp++ != '.')
+           return NULL;
+       strp = getnum(strp, &rulep->r_week, 1, 5);
+       if (strp == NULL)
+           return NULL;
+       if (*strp++ != '.')
+           return NULL;
+       strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+   } else if (is_digit(*strp)) {
+       /*
+       ** Day of year.
+       */
+       rulep->r_type = DAY_OF_YEAR;
+       strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+   } else  return NULL;        /* invalid format */
+   if (strp == NULL)
+       return NULL;
+   if (*strp == '/') {
+       /*
+       ** Time specified.
+       */
+       ++strp;
+       strp = getsecs(strp, &rulep->r_time);
+   } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
+   return strp;
+}
+
+/*
+** 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(janfirst, year, rulep, offset)
+const time_t               janfirst;
+const int              year;
+register const struct rule * const rulep;
+const long             offset;
+{
+   register int    leapyear;
+   register time_t value;
+   register int    i;
+   int     d, m1, yy0, yy1, yy2, dow;
+
+   INITIALIZE(value);
+   leapyear = isleap(year);
+   switch (rulep->r_type) {
+
+   case JULIAN_DAY:
+       /*
+       ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+       ** years.
+       ** In non-leap years, or if the day number is 59 or less, just
+       ** add SECSPERDAY times the day number-1 to the time of
+       ** January 1, midnight, to get the day.
+       */
+       value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+       if (leapyear && rulep->r_day >= 60)
+           value += SECSPERDAY;
+       break;
+
+   case DAY_OF_YEAR:
+       /*
+       ** n - day of year.
+       ** Just add SECSPERDAY times the day number to the time of
+       ** January 1, midnight, to get the day.
+       */
+       value = janfirst + rulep->r_day * SECSPERDAY;
+       break;
+
+   case MONTH_NTH_DAY_OF_WEEK:
+       /*
+       ** Mm.n.d - nth "dth day" of month m.
+       */
+       value = janfirst;
+       for (i = 0; i < rulep->r_mon - 1; ++i)
+           value += mon_lengths[leapyear][i] * SECSPERDAY;
+
+       /*
+       ** Use Zeller's Congruence to get day-of-week of first day of
+       ** month.
+       */
+       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;
+       if (dow < 0)
+           dow += DAYSPERWEEK;
+
+       /*
+       ** "dow" is the day-of-week of the first day of the month.  Get
+       ** the day-of-month (zero-origin) of the first "dow" day of the
+       ** month.
+       */
+       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;
+           d += DAYSPERWEEK;
+       }
+
+       /*
+       ** "d" is the day-of-month (zero-origin) of the day we want.
+       */
+       value += d * SECSPERDAY;
+       break;
+   }
+
+   /*
+   ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+   ** question.  To get the Epoch-relative time of the specified local
+   ** time on that day, add the transition time and the current offset
+   ** 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(name, sp, lastditch)
+const char *           name;
+register struct state * const  sp;
+const int          lastditch;
+{
+   const char *            stdname;
+   const char *            dstname;
+   size_t              stdlen;
+   size_t              dstlen;
+   long                stdoffset;
+   long                dstoffset;
+   register time_t *       atp;
+   register unsigned char *    typep;
+   register char *         cp;
+   register int            load_result;
+
+   INITIALIZE(dstname);
+   stdname = name;
+   if (lastditch) {
+       stdlen = strlen(name);  /* length of standard zone name */
+       name += stdlen;
+       if (stdlen >= sizeof sp->chars)
+           stdlen = (sizeof sp->chars) - 1;
+       stdoffset = 0;
+   } else {
+       name = getzname(name);
+       stdlen = name - stdname;
+       if (stdlen < 3)
+           return -1;
+       if (*name == '\0')
+           return -1;
+       name = getoffset(name, &stdoffset);
+       if (name == NULL)
+           return -1;
+   }
+   load_result = tzload(TZDEFRULES, sp);
+   if (load_result != 0)
+       sp->leapcnt = 0;        /* so, we're off a little */
+   if (*name != '\0') {
+       dstname = name;
+       name = getzname(name);
+       dstlen = name - dstname;    /* length of DST zone name */
+       if (dstlen < 3)
+           return -1;
+       if (*name != '\0' && *name != ',' && *name != ';') {
+           name = getoffset(name, &dstoffset);
+           if (name == NULL)
+               return -1;
+       } else  dstoffset = stdoffset - SECSPERHOUR;
+       if (*name == '\0' && load_result != 0)
+           name = TZDEFRULESTRING;
+       if (*name == ',' || *name == ';') {
+           struct rule start;
+           struct rule end;
+           register int    year;
+           register time_t janfirst;
+           time_t      starttime;
+           time_t      endtime;
+
+           ++name;
+           if ((name = getrule(name, &start)) == NULL)
+               return -1;
+           if (*name++ != ',')
+               return -1;
+           if ((name = getrule(name, &end)) == NULL)
+               return -1;
+           if (*name != '\0')
+               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;
+           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) {
+               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;
+           }
+       } else {
+           register long   theirstdoffset;
+           register long   theirdstoffset;
+           register long   theiroffset;
+           register int    isdst;
+           register int    i;
+           register int    j;
+
+           if (*name != '\0')
+               return -1;
+           /*
+           ** 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) {
+               j = sp->types[i];
+               if (sp->ttis[j].tt_isdst) {
+                   theirdstoffset =
+                       -sp->ttis[j].tt_gmtoff;
+                   break;
+               }
+           }
+           /*
+           ** Initially we're assumed to be in standard time.
+           */
+           isdst = FALSE;
+           theiroffset = theirstdoffset;
+           /*
+           ** Now juggle transition times and types
+           ** tracking offsets as you do.
+           */
+           for (i = 0; i < sp->timecnt; ++i) {
+               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.
+           ** ttisstd and ttisgmt need not be handled.
+           */
+           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->timecnt = 0;
+       sp->ttis[0].tt_gmtoff = -stdoffset;
+       sp->ttis[0].tt_isdst = 0;
+       sp->ttis[0].tt_abbrind = 0;
+   }
+   sp->charcnt = stdlen + 1;
+   if (dstlen != 0)
+       sp->charcnt += dstlen + 1;
+   if ((size_t) sp->charcnt > sizeof sp->chars)
+       return -1;
+   cp = sp->chars;
+   (void) strncpy(cp, stdname, stdlen);
+   cp += stdlen;
+   *cp++ = '\0';
+   if (dstlen != 0) {
+       (void) strncpy(cp, dstname, dstlen);
+       *(cp + dstlen) = '\0';
+   }
+   return 0;
+}
+
+static void
+gmtload(sp)
+struct state * const   sp;
+{
+   if (tzload(gmt, sp) != 0)
+       (void) tzparse(gmt, sp, TRUE);
+}
+
+#ifndef STD_INSPIRED
+/*
+** A non-static declaration of tzsetwall in a system header file
+** may cause a warning about this upcoming static declaration...
+*/
+static
+#endif /* !defined STD_INSPIRED */
+void
+tzsetwall P((void))
+{
+   if (lcl_is_set < 0)
+       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();
+}
+
+void
+tzset P((void))
+{
+   register const char *   name;
+
+   name = getenv("TZ");
+   if (name == NULL) {
+       tzsetwall();
+       return;
+   }
+
+   if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
+       return;
+   lcl_is_set = strlen(name) < sizeof lcl_TZname;
+   if (lcl_is_set)
+       (void) strcpy(lcl_TZname, name);
+
+#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 (*name == '\0') {
+       /*
+       ** User wants it fast rather than right.
+       */
+       lclptr->leapcnt = 0;        /* so, we're off a little */
+       lclptr->timecnt = 0;
+       lclptr->typecnt = 0;
+       lclptr->ttis[0].tt_isdst = 0;
+       lclptr->ttis[0].tt_gmtoff = 0;
+       lclptr->ttis[0].tt_abbrind = 0;
+       (void) strcpy(lclptr->chars, gmt);
+   } else if (tzload(name, lclptr) != 0)
+       if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
+           (void) 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(timep, offset, tmp)
+const time_t * const   timep;
+const long     offset;
+struct tm * const  tmp;
+{
+   register struct state *     sp;
+   register const struct ttinfo *  ttisp;
+   register int            i;
+   const time_t            t = *timep;
+
+   sp = lclptr;
+#ifdef ALL_STATE
+   if (sp == NULL) {
+       gmtsub(timep, offset, tmp);
+       return;
+   }
+#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;
+           }
+   } else {
+       for (i = 1; i < sp->timecnt; ++i)
+           if (t < sp->ats[i])
+               break;
+       i = sp->types[i - 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);
+   tmp->tm_isdst = ttisp->tt_isdst;
+   tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
+#ifdef TM_ZONE
+   tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+localtime(timep)
+const time_t * const   timep;
+{
+   tzset();
+   localsub(timep, 0L, &tm);
+   return &tm;
+}
+
+/*
+** Re-entrant version of localtime.
+*/
+
+struct tm *
+localtime_r(timep, tm)
+const time_t * const   timep;
+struct tm *        tm;
+{
+   localsub(timep, 0L, tm);
+   return tm;
+}
+
+/*
+** gmtsub is to gmtime as localsub is to localtime.
+*/
+
+static void
+gmtsub(timep, offset, tmp)
+const time_t * const   timep;
+const long     offset;
+struct tm * const  tmp;
+{
+   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);
+   }
+   timesub(timep, offset, gmtptr, tmp);
+#ifdef TM_ZONE
+   /*
+   ** Could get fancy here and deliver something such as
+   ** "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;
+   else {
+#ifdef ALL_STATE
+       if (gmtptr == NULL)
+           tmp->TM_ZONE = gmt;
+       else    tmp->TM_ZONE = gmtptr->chars;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+       tmp->TM_ZONE = gmtptr->chars;
+#endif /* State Farm */
+   }
+#endif /* defined TM_ZONE */
+}
+
+struct tm *
+gmtime(timep)
+const time_t * const   timep;
+{
+   gmtsub(timep, 0L, &tm);
+   return &tm;
+}
+
+/*
+* Re-entrant version of gmtime.
+*/
+
+struct tm *
+gmtime_r(timep, tm)
+const time_t * const   timep;
+struct tm *        tm;
+{
+   gmtsub(timep, 0L, tm);
+   return tm;
+}
+
+#ifdef STD_INSPIRED
+
+struct tm *
+offtime(timep, offset)
+const time_t * const   timep;
+const long     offset;
+{
+   gmtsub(timep, offset, &tm);
+   return &tm;
+}
+
+#endif /* defined STD_INSPIRED */
+
+static void
+timesub(timep, offset, sp, tmp)
+const time_t * const           timep;
+const long             offset;
+register const struct state * const    sp;
+register struct tm * const     tmp;
+{
+   register const struct lsinfo *  lp;
+   register long           days;
+   register long           rem;
+   register int            y;
+   register int            yleap;
+   register const int *        ip;
+   register long           corr;
+   register int            hit;
+   register int            i;
+
+   corr = 0;
+   hit = 0;
+#ifdef ALL_STATE
+   i = (sp == NULL) ? 0 : sp->leapcnt;
+#endif /* defined ALL_STATE */
+#ifndef ALL_STATE
+   i = sp->leapcnt;
+#endif /* State Farm */
+   while (--i >= 0) {
+       lp = &sp->lsis[i];
+       if (*timep >= lp->ls_trans) {
+           if (*timep == lp->ls_trans) {
+               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) {
+       /*
+       ** A 3B1 muffs the division on the most negative number.
+       */
+       days = -24855;
+       rem = -11648;
+   }
+#endif /* defined mc68k */
+   rem += (offset - corr);
+   while (rem < 0) {
+       rem += SECSPERDAY;
+       --days;
+   }
+   while (rem >= SECSPERDAY) {
+       rem -= SECSPERDAY;
+       ++days;
+   }
+   tmp->tm_hour = (int) (rem / SECSPERHOUR);
+   rem = 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;
+   tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
+   if (tmp->tm_wday < 0)
+       tmp->tm_wday += DAYSPERWEEK;
+   y = EPOCH_YEAR;
+#define LEAPS_THRU_END_OF(y)   ((y) / 4 - (y) / 100 + (y) / 400)
+   while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+       register int    newy;
+
+       newy = y + days / DAYSPERNYEAR;
+       if (days < 0)
+           --newy;
+       days -= (newy - y) * DAYSPERNYEAR +
+           LEAPS_THRU_END_OF(newy - 1) -
+           LEAPS_THRU_END_OF(y - 1);
+       y = newy;
+   }
+   tmp->tm_year = y - TM_YEAR_BASE;
+   tmp->tm_yday = (int) days;
+   ip = mon_lengths[yleap];
+   for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
+       days = days - (long) ip[tmp->tm_mon];
+   tmp->tm_mday = (int) (days + 1);
+   tmp->tm_isdst = 0;
+#ifdef TM_GMTOFF
+   tmp->TM_GMTOFF = offset;
+#endif /* defined TM_GMTOFF */
+}
+
+char *
+ctime(timep)
+const time_t * const   timep;
+{
+/*
+** Section 4.12.3.2 of X3.159-1989 requires that
+** The ctime function converts the calendar time pointed to by timer
+** to local time in the form of a string.  It is equivalent to
+**     asctime(localtime(timer))
+*/
+   return asctime(localtime(timep));
+}
+
+char *
+ctime_r(timep, buf)
+const time_t * const   timep;
+char *         buf;
+{
+   struct tm   tm;
+
+   return asctime_r(localtime_r(timep, &tm), buf);
+}
+
+/*
+** Adapted from code provided by Robert Elz, who writes:
+** The "best" way to do mktime I think is based on an idea of Bob
+** Kridle's (so its said...) from a long time ago.
+** [kridle@xinet.com as of 1996-01-16.]
+** It does a binary search of the time_t space.  Since time_t's are
+** just 32 bits, its a max of 32 iterations (even at 64 bits it
+** would still be very reasonable).
+*/
+
+#ifndef WRONG
+#define WRONG  (-1)
+#endif /* !defined WRONG */
+
+/*
+** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
+*/
+
+static int
+increment_overflow(number, delta)
+int *  number;
+int    delta;
+{
+   int number0;
+
+   number0 = *number;
+   *number += delta;
+   return (*number < number0) != (delta < 0);
+}
+
+static int
+normalize_overflow(tensptr, unitsptr, base)
+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
+tmcomp(atmp, btmp)
+register const struct tm * const atmp;
+register const struct tm * const btmp;
+{
+   register int    result;
+
+   if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+       (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+       (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+       (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+       (result = (atmp->tm_min - btmp->tm_min)) == 0)
+           result = atmp->tm_sec - btmp->tm_sec;
+   return result;
+}
+
+static time_t
+time2sub(tmp, funcp, offset, okayp, do_norm_secs)
+struct tm * const  tmp;
+void (* const      funcp) P((const time_t*, long, struct tm*));
+const long     offset;
+int * const        okayp;
+const int      do_norm_secs;
+{
+   register const struct state *   sp;
+   register int            dir;
+   register int            bits;
+   register int            i, j ;
+   register int            saved_seconds;
+   time_t              newt;
+   time_t              t;
+   struct tm           yourtm, mytm;
+
+   *okayp = FALSE;
+   yourtm = *tmp;
+   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;
+   if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
+       return WRONG;
+   /*
+   ** Turn yourtm.tm_year into an actual year number for now.
+   ** It is converted back to an offset from TM_YEAR_BASE later.
+   */
+   if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
+       return WRONG;
+   while (yourtm.tm_mday <= 0) {
+       if (increment_overflow(&yourtm.tm_year, -1))
+           return WRONG;
+       i = yourtm.tm_year + (1 < yourtm.tm_mon);
+       yourtm.tm_mday += year_lengths[isleap(i)];
+   }
+   while (yourtm.tm_mday > DAYSPERLYEAR) {
+       i = yourtm.tm_year + (1 < yourtm.tm_mon);
+       yourtm.tm_mday -= year_lengths[isleap(i)];
+       if (increment_overflow(&yourtm.tm_year, 1))
+           return WRONG;
+   }
+   for ( ; ; ) {
+       i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
+       if (yourtm.tm_mday <= i)
+           break;
+       yourtm.tm_mday -= i;
+       if (++yourtm.tm_mon >= MONSPERYEAR) {
+           yourtm.tm_mon = 0;
+           if (increment_overflow(&yourtm.tm_year, 1))
+               return WRONG;
+       }
+   }
+   if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
+       return WRONG;
+   if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+       saved_seconds = 0;
+   else if (yourtm.tm_year + 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;
+   }
+   /*
+   ** Divide the search space in half
+   ** (this works whether time_t is signed or unsigned).
+   */
+   bits = TYPE_BIT(time_t) - 1;
+   /*
+   ** If time_t is signed, then 0 is just above the median,
+   ** assuming two's complement arithmetic.
+   ** If time_t is unsigned, then (1 << bits) is just above the median.
+   */
+   t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+   for ( ; ; ) {
+       (*funcp)(&t, offset, &mytm);
+       dir = tmcomp(&mytm, &yourtm);
+       if (dir != 0) {
+           if (bits-- < 0)
+               return WRONG;
+           if (bits < 0)
+               --t; /* may be needed if new t is minimal */
+           else if (dir > 0)
+               t -= ((time_t) 1) << bits;
+           else    t += ((time_t) 1) << bits;
+           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.
+       */
+       /*
+       ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+       */
+       sp = (const struct state *)
+           (((void *) funcp == (void *) localsub) ?
+           lclptr : gmtptr);
+#ifdef ALL_STATE
+       if (sp == NULL)
+           return WRONG;
+#endif /* defined ALL_STATE */
+       for (i = sp->typecnt - 1; i >= 0; --i) {
+           if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
+               continue;
+           for (j = sp->typecnt - 1; j >= 0; --j) {
+               if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
+                   continue;
+               newt = t + sp->ttis[j].tt_gmtoff -
+                   sp->ttis[i].tt_gmtoff;
+               (*funcp)(&newt, offset, &mytm);
+               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:
+   newt = t + saved_seconds;
+   if ((newt < t) != (saved_seconds < 0))
+       return WRONG;
+   t = newt;
+   (*funcp)(&t, offset, tmp);
+   *okayp = TRUE;
+   return t;
+}
+
+static time_t
+time2(tmp, funcp, offset, okayp)
+struct tm * const  tmp;
+void (* const      funcp) P((const time_t*, long, struct tm*));
+const long     offset;
+int * const        okayp;
+{
+   time_t  t;
+
+   /*
+   ** 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(tmp, funcp, offset)
+struct tm * const  tmp;
+void (* const      funcp) P((const time_t *, long, struct tm *));
+const long     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->tm_isdst > 1)
+       tmp->tm_isdst = 1;
+   t = time2(tmp, funcp, offset, &okay);
+#ifdef PCTS
+   /*
+   ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+   */
+   if (okay)
+       return t;
+   if (tmp->tm_isdst < 0)
+       tmp->tm_isdst = 0;  /* reset to std and try again */
+#endif /* defined PCTS */
+#ifndef PCTS
+   if (okay || tmp->tm_isdst < 0)
+       return t;
+#endif /* !defined PCTS */
+   /*
+   ** 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.
+   */
+   /*
+   ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
+   */
+   sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
+       lclptr : gmtptr);
+#ifdef ALL_STATE
+   if (sp == NULL)
+       return WRONG;
+#endif /* defined ALL_STATE */
+   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 (otherind = 0; otherind < nseen; ++otherind) {
+           otheri = types[otherind];
+           if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
+               continue;
+           tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+                   sp->ttis[samei].tt_gmtoff;
+           tmp->tm_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;
+           tmp->tm_isdst = !tmp->tm_isdst;
+       }
+   }
+   return WRONG;
+}
+
+time_t
+mktime(tmp)
+struct tm * const  tmp;
+{
+   tzset();
+   return time1(tmp, localsub, 0L);
+}
+
+#ifdef STD_INSPIRED
+
+time_t
+timelocal(tmp)
+struct tm * const  tmp;
+{
+   tmp->tm_isdst = -1; /* in case it wasn't initialized */
+   return mktime(tmp);
+}
+
+time_t
+timegm(tmp)
+struct tm * const  tmp;
+{
+   tmp->tm_isdst = 0;
+   return time1(tmp, gmtsub, 0L);
+}
+
+time_t
+timeoff(tmp, offset)
+struct tm * const  tmp;
+const long     offset;
+{
+   tmp->tm_isdst = 0;
+   return time1(tmp, gmtsub, offset);
+}
+
+#endif /* defined STD_INSPIRED */
+
+#ifdef CMUCS
+
+/*
+** The following is supplied for compatibility with
+** previous versions of the CMUCS runtime library.
+*/
+
+long
+gtime(tmp)
+struct tm * const  tmp;
+{
+   const time_t    t = mktime(tmp);
+
+   if (t == WRONG)
+       return -1;
+   return t;
+}
+
+#endif /* defined CMUCS */
+
+/*
+** XXX--is the below the right way to conditionalize??
+*/
+
+#ifdef STD_INSPIRED
+
+/*
+** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
+** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
+** is not the case if we are accounting for leap seconds.
+** So, we provide the following conversion routines for use
+** when exchanging timestamps with POSIX conforming systems.
+*/
+
+static long
+leapcorr(timep)
+time_t *   timep;
+{
+   register struct state *     sp;
+   register struct lsinfo *    lp;
+   register int            i;
+
+   sp = lclptr;
+   i = sp->leapcnt;
+   while (--i >= 0) {
+       lp = &sp->lsis[i];
+       if (*timep >= lp->ls_trans)
+           return lp->ls_corr;
+   }
+   return 0;
+}
+
+time_t
+time2posix(t)
+time_t t;
+{
+   tzset();
+   return t - leapcorr(&t);
+}
+
+time_t
+posix2time(t)
+time_t t;
+{
+   time_t  x;
+   time_t  y;
+
+   tzset();
+   /*
+   ** For a positive leap second hit, the result
+   ** is not unique.  For a negative leap second
+   ** hit, the corresponding time doesn't exist,
+   ** so we return an adjacent second.
+   */
+   x = t + leapcorr(&t);
+   y = x - leapcorr(&x);
+   if (y < t) {
+       do {
+           x++;
+           y = x - leapcorr(&x);
+       } while (y < t);
+       if (t != y)
+           return x - 1;
+   } else if (y > t) {
+       do {
+           --x;
+           y = x - leapcorr(&x);
+       } while (y > t);
+       if (t != y)
+           return x + 1;
+   }
+   return x;
+}
+
+#endif /* defined STD_INSPIRED */
index 17df71cbec9a84f3ef429d17ddf223ccad46f060..d30ac7aac3aece12180c0d2ad736941612866688 100644 (file)
@@ -1,8 +1,6 @@
 #include "postgres.h"
 
 #define NOID
-#define HAVE_SYMLINK 0
-#define HAVE_SYS_WAIT_H 0
 #define TZDIR pgwin32_TZDIR()
 
 char *pgwin32_TZDIR(void);
index 9333529bcc4445699604cb87aa5d3189f2c06845..c8f45486837f754d14f5974033afbca4d3a4a82a 100644 (file)
-#ifndef PRIVATE_H\r
-\r
-#define PRIVATE_H\r
-\r
-/*\r
-** This file is in the public domain, so clarified as of\r
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
-*/\r
-\r
-/*\r
-** This header is for use ONLY with the time conversion code.\r
-** There is no guarantee that it will remain unchanged,\r
-** or that it will remain at all.\r
-** Do NOT copy it to any system include directory.\r
-** Thank you!\r
-*/\r
-\r
-/*\r
-** ID\r
-*/\r
-\r
-#ifndef lint\r
-#ifndef NOID\r
-static char    privatehid[] = "@(#)private.h   7.53";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*\r
-** Defaults for preprocessor symbols.\r
-** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.\r
-*/\r
-\r
-#ifndef HAVE_ADJTIME\r
-#define HAVE_ADJTIME       1\r
-#endif /* !defined HAVE_ADJTIME */\r
-\r
-#ifndef HAVE_GETTEXT\r
-#define HAVE_GETTEXT       0\r
-#endif /* !defined HAVE_GETTEXT */\r
-\r
-#ifndef HAVE_INCOMPATIBLE_CTIME_R\r
-#define HAVE_INCOMPATIBLE_CTIME_R  0\r
-#endif /* !defined INCOMPATIBLE_CTIME_R */\r
-\r
-#ifndef HAVE_SETTIMEOFDAY\r
-#define HAVE_SETTIMEOFDAY  3\r
-#endif /* !defined HAVE_SETTIMEOFDAY */\r
-\r
-#ifndef HAVE_STRERROR\r
-#define HAVE_STRERROR      1\r
-#endif /* !defined HAVE_STRERROR */\r
-\r
-#ifndef HAVE_SYMLINK\r
-#define HAVE_SYMLINK       1\r
-#endif /* !defined HAVE_SYMLINK */\r
-\r
-#ifndef HAVE_SYS_STAT_H\r
-#define HAVE_SYS_STAT_H        1\r
-#endif /* !defined HAVE_SYS_STAT_H */\r
-\r
-#ifndef HAVE_SYS_WAIT_H\r
-#define HAVE_SYS_WAIT_H        1\r
-#endif /* !defined HAVE_SYS_WAIT_H */\r
-\r
-#ifndef HAVE_UNISTD_H\r
-#define HAVE_UNISTD_H      1\r
-#endif /* !defined HAVE_UNISTD_H */\r
-\r
-#ifndef HAVE_UTMPX_H\r
-#define HAVE_UTMPX_H       0\r
-#endif /* !defined HAVE_UTMPX_H */\r
-\r
-#ifndef LOCALE_HOME\r
-#define LOCALE_HOME        "/usr/lib/locale"\r
-#endif /* !defined LOCALE_HOME */\r
-\r
-#if HAVE_INCOMPATIBLE_CTIME_R\r
-#define asctime_r _incompatible_asctime_r\r
-#define ctime_r _incompatible_ctime_r\r
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */\r
-\r
-/*\r
-** Nested includes\r
-*/\r
-\r
-#include "sys/types.h" /* for time_t */\r
-#include "stdio.h"\r
-#include "errno.h"\r
-#include "string.h"\r
-#include "limits.h"    /* for CHAR_BIT */\r
-#include "time.h"\r
-#include "stdlib.h"\r
-\r
-#if HAVE_GETTEXT - 0\r
-#include "libintl.h"\r
-#endif /* HAVE_GETTEXT - 0 */\r
-\r
-#if HAVE_SYS_WAIT_H - 0\r
-#include <sys/wait.h>  /* for WIFEXITED and WEXITSTATUS */\r
-#endif /* HAVE_SYS_WAIT_H - 0 */\r
-\r
-#ifndef WIFEXITED\r
-#define WIFEXITED(status)  (((status) & 0xff) == 0)\r
-#endif /* !defined WIFEXITED */\r
-#ifndef WEXITSTATUS\r
-#define WEXITSTATUS(status)    (((status) >> 8) & 0xff)\r
-#endif /* !defined WEXITSTATUS */\r
-\r
-#if HAVE_UNISTD_H - 0\r
-#include "unistd.h"    /* for F_OK and R_OK */\r
-#endif /* HAVE_UNISTD_H - 0 */\r
-\r
-#if !(HAVE_UNISTD_H - 0)\r
-#ifndef F_OK\r
-#define F_OK   0\r
-#endif /* !defined F_OK */\r
-#ifndef R_OK\r
-#define R_OK   4\r
-#endif /* !defined R_OK */\r
-#endif /* !(HAVE_UNISTD_H - 0) */\r
-\r
-/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX.  */\r
-#define is_digit(c) ((unsigned)(c) - '0' <= 9)\r
-\r
-/*\r
-** Workarounds for compilers/systems.\r
-*/\r
-\r
-/*\r
-** SunOS 4.1.1 cc lacks prototypes.\r
-*/\r
-\r
-#ifndef P\r
-#ifdef __STDC__\r
-#define P(x)   x\r
-#endif /* defined __STDC__ */\r
-#ifndef __STDC__\r
-#define P(x)   ()\r
-#endif /* !defined __STDC__ */\r
-#endif /* !defined P */\r
-\r
-/*\r
-** SunOS 4.1.1 headers lack EXIT_SUCCESS.\r
-*/\r
-\r
-#ifndef EXIT_SUCCESS\r
-#define EXIT_SUCCESS   0\r
-#endif /* !defined EXIT_SUCCESS */\r
-\r
-/*\r
-** SunOS 4.1.1 headers lack EXIT_FAILURE.\r
-*/\r
-\r
-#ifndef EXIT_FAILURE\r
-#define EXIT_FAILURE   1\r
-#endif /* !defined EXIT_FAILURE */\r
-\r
-/*\r
-** SunOS 4.1.1 headers lack FILENAME_MAX.\r
-*/\r
-\r
-#ifndef FILENAME_MAX\r
-\r
-#ifndef MAXPATHLEN\r
-#ifdef unix\r
-#include "sys/param.h"\r
-#endif /* defined unix */\r
-#endif /* !defined MAXPATHLEN */\r
-\r
-#ifdef MAXPATHLEN\r
-#define FILENAME_MAX   MAXPATHLEN\r
-#endif /* defined MAXPATHLEN */\r
-#ifndef MAXPATHLEN\r
-#define FILENAME_MAX   1024        /* Pure guesswork */\r
-#endif /* !defined MAXPATHLEN */\r
-\r
-#endif /* !defined FILENAME_MAX */\r
-\r
-/*\r
-** SunOS 4.1.1 libraries lack remove.\r
-*/\r
-\r
-#ifndef remove\r
-extern int unlink P((const char * filename));\r
-#define remove unlink\r
-#endif /* !defined remove */\r
-\r
-/*\r
-** Some ancient errno.h implementations don't declare errno.\r
-** But some newer errno.h implementations define it as a macro.\r
-** Fix the former without affecting the latter.\r
-*/\r
-#ifndef errno\r
-extern int errno;\r
-#endif /* !defined errno */\r
-\r
-/*\r
-** Private function declarations.\r
-*/\r
-char * icalloc P((int nelem, int elsize));\r
-char * icatalloc P((char * old, const char * new));\r
-char * icpyalloc P((const char * string));\r
-char * imalloc P((int n));\r
-void * irealloc P((void * pointer, int size));\r
-void   icfree P((char * pointer));\r
-void   ifree P((char * pointer));\r
-char * scheck P((const char *string, const char *format));\r
-\r
-\r
-/*\r
-** Finally, some convenience items.\r
-*/\r
-\r
-#ifndef TRUE\r
-#define TRUE   1\r
-#endif /* !defined TRUE */\r
-\r
-#ifndef FALSE\r
-#define FALSE  0\r
-#endif /* !defined FALSE */\r
-\r
-#ifndef TYPE_BIT\r
-#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)\r
-#endif /* !defined TYPE_BIT */\r
-\r
-#ifndef TYPE_SIGNED\r
-#define TYPE_SIGNED(type) (((type) -1) < 0)\r
-#endif /* !defined TYPE_SIGNED */\r
-\r
-#ifndef INT_STRLEN_MAXIMUM\r
-/*\r
-** 302 / 1000 is log10(2.0) rounded up.\r
-** Subtract one for the sign bit if the type is signed;\r
-** add one for integer division truncation;\r
-** add one more for a minus sign if the type is signed.\r
-*/\r
-#define INT_STRLEN_MAXIMUM(type) \\r
-    ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))\r
-#endif /* !defined INT_STRLEN_MAXIMUM */\r
-\r
-/*\r
-** INITIALIZE(x)\r
-*/\r
-\r
-#ifndef GNUC_or_lint\r
-#ifdef lint\r
-#define GNUC_or_lint\r
-#endif /* defined lint */\r
-#ifndef lint\r
-#ifdef __GNUC__\r
-#define GNUC_or_lint\r
-#endif /* defined __GNUC__ */\r
-#endif /* !defined lint */\r
-#endif /* !defined GNUC_or_lint */\r
-\r
-#ifndef INITIALIZE\r
-#ifdef GNUC_or_lint\r
-#define INITIALIZE(x)  ((x) = 0)\r
-#endif /* defined GNUC_or_lint */\r
-#ifndef GNUC_or_lint\r
-#define INITIALIZE(x)\r
-#endif /* !defined GNUC_or_lint */\r
-#endif /* !defined INITIALIZE */\r
-\r
-/*\r
-** For the benefit of GNU folk...\r
-** `_(MSGID)' uses the current locale's message library string for MSGID.\r
-** The default is to use gettext if available, and use MSGID otherwise.\r
-*/\r
-\r
-#ifndef _\r
-#if HAVE_GETTEXT - 0\r
-#define _(msgid) gettext(msgid)\r
-#else /* !(HAVE_GETTEXT - 0) */\r
-#define _(msgid) msgid\r
-#endif /* !(HAVE_GETTEXT - 0) */\r
-#endif /* !defined _ */\r
-\r
-#ifndef TZ_DOMAIN\r
-#define TZ_DOMAIN "tz"\r
-#endif /* !defined TZ_DOMAIN */\r
-\r
-#if HAVE_INCOMPATIBLE_CTIME_R\r
-#undef asctime_r\r
-#undef ctime_r\r
-char *asctime_r P((struct tm const *, char *));\r
-char *ctime_r P((time_t const *, char *));\r
-#endif /* HAVE_INCOMPATIBLE_CTIME_R */\r
-\r
-/*\r
-** UNIX was a registered trademark of The Open Group in 2003.\r
-*/\r
-\r
-#endif /* !defined PRIVATE_H */\r
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    privatehid[] = "@(#)private.h   7.53";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_ADJTIME
+#define HAVE_ADJTIME       1
+#endif /* !defined HAVE_ADJTIME */
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT       0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_INCOMPATIBLE_CTIME_R
+#define HAVE_INCOMPATIBLE_CTIME_R  0
+#endif /* !defined INCOMPATIBLE_CTIME_R */
+
+#ifndef HAVE_SETTIMEOFDAY
+#define HAVE_SETTIMEOFDAY  3
+#endif /* !defined HAVE_SETTIMEOFDAY */
+
+#ifndef HAVE_STRERROR
+#define HAVE_STRERROR      1
+#endif /* !defined HAVE_STRERROR */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK       1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H        1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H        1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H      1
+#endif /* !defined HAVE_UNISTD_H */
+
+#ifndef HAVE_UTMPX_H
+#define HAVE_UTMPX_H       0
+#endif /* !defined HAVE_UTMPX_H */
+
+#ifndef LOCALE_HOME
+#define LOCALE_HOME        "/usr/lib/locale"
+#endif /* !defined LOCALE_HOME */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#define asctime_r _incompatible_asctime_r
+#define ctime_r _incompatible_ctime_r
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "limits.h"    /* for CHAR_BIT */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT - 0
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#if HAVE_SYS_WAIT_H - 0
+#include <sys/wait.h>  /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H - 0 */
+
+#ifndef WIFEXITED
+#define WIFEXITED(status)  (((status) & 0xff) == 0)
+#endif /* !defined WIFEXITED */
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(status)    (((status) >> 8) & 0xff)
+#endif /* !defined WEXITSTATUS */
+
+#if HAVE_UNISTD_H - 0
+#include "unistd.h"    /* for F_OK and R_OK */
+#endif /* HAVE_UNISTD_H - 0 */
+
+#if !(HAVE_UNISTD_H - 0)
+#ifndef F_OK
+#define F_OK   0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK   4
+#endif /* !defined R_OK */
+#endif /* !(HAVE_UNISTD_H - 0) */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX.  */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+/*
+** Workarounds for compilers/systems.
+*/
+
+/*
+** SunOS 4.1.1 cc lacks prototypes.
+*/
+
+#ifndef P
+#ifdef __STDC__
+#define P(x)   x
+#endif /* defined __STDC__ */
+#ifndef __STDC__
+#define P(x)   ()
+#endif /* !defined __STDC__ */
+#endif /* !defined P */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_SUCCESS.
+*/
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS   0
+#endif /* !defined EXIT_SUCCESS */
+
+/*
+** SunOS 4.1.1 headers lack EXIT_FAILURE.
+*/
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE   1
+#endif /* !defined EXIT_FAILURE */
+
+/*
+** SunOS 4.1.1 headers lack FILENAME_MAX.
+*/
+
+#ifndef FILENAME_MAX
+
+#ifndef MAXPATHLEN
+#ifdef unix
+#include "sys/param.h"
+#endif /* defined unix */
+#endif /* !defined MAXPATHLEN */
+
+#ifdef MAXPATHLEN
+#define FILENAME_MAX   MAXPATHLEN
+#endif /* defined MAXPATHLEN */
+#ifndef MAXPATHLEN
+#define FILENAME_MAX   1024        /* Pure guesswork */
+#endif /* !defined MAXPATHLEN */
+
+#endif /* !defined FILENAME_MAX */
+
+/*
+** SunOS 4.1.1 libraries lack remove.
+*/
+
+#ifndef remove
+extern int unlink P((const char * filename));
+#define remove unlink
+#endif /* !defined remove */
+
+/*
+** Some ancient errno.h implementations don't declare errno.
+** But some newer errno.h implementations define it as a macro.
+** Fix the former without affecting the latter.
+*/
+#ifndef errno
+extern int errno;
+#endif /* !defined errno */
+
+/*
+** Private function declarations.
+*/
+char * icalloc P((int nelem, int elsize));
+char * icatalloc P((char * old, const char * new));
+char * icpyalloc P((const char * string));
+char * imalloc P((int n));
+void * irealloc P((void * pointer, int size));
+void   icfree P((char * pointer));
+void   ifree P((char * pointer));
+char * scheck P((const char *string, const char *format));
+
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE   1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE  0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+    ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x)  ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** 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.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#if HAVE_INCOMPATIBLE_CTIME_R
+#undef asctime_r
+#undef ctime_r
+char *asctime_r P((struct tm const *, char *));
+char *ctime_r P((time_t const *, char *));
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+#endif /* !defined PRIVATE_H */
index 6bcfe87950a3e2bced544da695fe7be64ed9a622..39feeba701171ca6def94627ecb04016866efb2c 100644 (file)
@@ -1,59 +1,59 @@
-#ifndef lint\r
-#ifndef NOID\r
-static char    elsieid[] = "@(#)scheck.c   8.15";\r
-#endif /* !defined lint */\r
-#endif /* !defined NOID */\r
-\r
-/*LINTLIBRARY*/\r
-\r
-#include "private.h"\r
-\r
-char *\r
-scheck(string, format)\r
-const char * const string;\r
-const char * const format;\r
-{\r
-   register char *     fbuf;\r
-   register const char *   fp;\r
-   register char *     tp;\r
-   register int        c;\r
-   register char *     result;\r
-   char            dummy;\r
-   static char     nada;\r
-\r
-   result = &nada;\r
-   if (string == NULL || format == NULL)\r
-       return result;\r
-   fbuf = imalloc((int) (2 * strlen(format) + 4));\r
-   if (fbuf == NULL)\r
-       return result;\r
-   fp = format;\r
-   tp = fbuf;\r
-   while ((*tp++ = c = *fp++) != '\0') {\r
-       if (c != '%')\r
-           continue;\r
-       if (*fp == '%') {\r
-           *tp++ = *fp++;\r
-           continue;\r
-       }\r
-       *tp++ = '*';\r
-       if (*fp == '*')\r
-           ++fp;\r
-       while (is_digit(*fp))\r
-           *tp++ = *fp++;\r
-       if (*fp == 'l' || *fp == 'h')\r
-           *tp++ = *fp++;\r
-       else if (*fp == '[')\r
-           do *tp++ = *fp++;\r
-               while (*fp != '\0' && *fp != ']');\r
-       if ((*tp++ = *fp++) == '\0')\r
-           break;\r
-   }\r
-   *(tp - 1) = '%';\r
-   *tp++ = 'c';\r
-   *tp = '\0';\r
-   if (sscanf(string, fbuf, &dummy) != 1)\r
-       result = (char *) format;\r
-   ifree(fbuf);\r
-   return result;\r
-}\r
+#ifndef lint
+#ifndef NOID
+static char    elsieid[] = "@(#)scheck.c   8.15";
+#endif /* !defined lint */
+#endif /* !defined NOID */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+char *
+scheck(string, format)
+const char * const string;
+const char * const format;
+{
+   register char *     fbuf;
+   register const char *   fp;
+   register char *     tp;
+   register int        c;
+   register char *     result;
+   char            dummy;
+   static char     nada;
+
+   result = &nada;
+   if (string == NULL || format == NULL)
+       return result;
+   fbuf = imalloc((int) (2 * strlen(format) + 4));
+   if (fbuf == NULL)
+       return result;
+   fp = format;
+   tp = fbuf;
+   while ((*tp++ = c = *fp++) != '\0') {
+       if (c != '%')
+           continue;
+       if (*fp == '%') {
+           *tp++ = *fp++;
+           continue;
+       }
+       *tp++ = '*';
+       if (*fp == '*')
+           ++fp;
+       while (is_digit(*fp))
+           *tp++ = *fp++;
+       if (*fp == 'l' || *fp == 'h')
+           *tp++ = *fp++;
+       else if (*fp == '[')
+           do *tp++ = *fp++;
+               while (*fp != '\0' && *fp != ']');
+       if ((*tp++ = *fp++) == '\0')
+           break;
+   }
+   *(tp - 1) = '%';
+   *tp++ = 'c';
+   *tp = '\0';
+   if (sscanf(string, fbuf, &dummy) != 1)
+       result = (char *) format;
+   ifree(fbuf);
+   return result;
+}
index 2d07a867e2f014fe1d0fd8d3108a803225240e2b..0921c3c3396e8116ff749f3c8116011d09e00202 100644 (file)
-#ifndef TZFILE_H\r
-\r
-#define TZFILE_H\r
-\r
-/*\r
-** This file is in the public domain, so clarified as of\r
-** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).\r
-*/\r
-\r
-/*\r
-** This header is for use ONLY with the time conversion code.\r
-** There is no guarantee that it will remain unchanged,\r
-** or that it will remain at all.\r
-** Do NOT copy it to any system include directory.\r
-** Thank you!\r
-*/\r
-\r
-/*\r
-** ID\r
-*/\r
-\r
-#ifndef lint\r
-#ifndef NOID\r
-static char    tzfilehid[] = "@(#)tzfile.h 7.14";\r
-#endif /* !defined NOID */\r
-#endif /* !defined lint */\r
-\r
-/*\r
-** Information about time zone files.\r
-*/\r
-\r
-#ifndef TZDIR\r
-#define TZDIR  "/usr/local/etc/zoneinfo" /* Time zone object file directory */\r
-#endif /* !defined TZDIR */\r
-\r
-#ifndef TZDEFAULT\r
-#define TZDEFAULT  "localtime"\r
-#endif /* !defined TZDEFAULT */\r
-\r
-#ifndef TZDEFRULES\r
-#define TZDEFRULES "posixrules"\r
-#endif /* !defined TZDEFRULES */\r
-\r
-/*\r
-** Each file begins with. . .\r
-*/\r
-\r
-#define    TZ_MAGIC    "TZif"\r
-\r
-struct tzhead {\r
-   char    tzh_magic[4];       /* TZ_MAGIC */\r
-   char    tzh_reserved[16];   /* reserved for future use */\r
-   char    tzh_ttisgmtcnt[4];  /* coded number of trans. time flags */\r
-   char    tzh_ttisstdcnt[4];  /* coded number of trans. time flags */\r
-   char    tzh_leapcnt[4];     /* coded number of leap seconds */\r
-   char    tzh_timecnt[4];     /* coded number of transition times */\r
-   char    tzh_typecnt[4];     /* coded number of local time types */\r
-   char    tzh_charcnt[4];     /* coded number of abbr. chars */\r
-};\r
-\r
-/*\r
-** . . .followed by. . .\r
-**\r
-** tzh_timecnt (char [4])s     coded transition times a la time(2)\r
-** tzh_timecnt (unsigned char)s    types of local time starting at above\r
-** tzh_typecnt repetitions of\r
-**     one (char [4])      coded UTC offset in seconds\r
-**     one (unsigned char) used to set tm_isdst\r
-**     one (unsigned char) that's an abbreviation list index\r
-** tzh_charcnt (char)s     '\0'-terminated zone abbreviations\r
-** tzh_leapcnt repetitions of\r
-**     one (char [4])      coded leap second transition times\r
-**     one (char [4])      total correction after above\r
-** tzh_ttisstdcnt (char)s      indexed by type; if TRUE, transition\r
-**                 time is standard time, if FALSE,\r
-**                 transition time is wall clock time\r
-**                 if absent, transition times are\r
-**                 assumed to be wall clock time\r
-** tzh_ttisgmtcnt (char)s      indexed by type; if TRUE, transition\r
-**                 time is UTC, if FALSE,\r
-**                 transition time is local time\r
-**                 if absent, transition times are\r
-**                 assumed to be local time\r
-*/\r
-\r
-/*\r
-** In the current implementation, "tzset()" refuses to deal with files that\r
-** exceed any of the limits below.\r
-*/\r
-\r
-#ifndef TZ_MAX_TIMES\r
-/*\r
-** The TZ_MAX_TIMES value below is enough to handle a bit more than a\r
-** year's worth of solar time (corrected daily to the nearest second) or\r
-** 138 years of Pacific Presidential Election time\r
-** (where there are three time zone transitions every fourth year).\r
-*/\r
-#define TZ_MAX_TIMES   370\r
-#endif /* !defined TZ_MAX_TIMES */\r
-\r
-#ifndef TZ_MAX_TYPES\r
-#ifndef NOSOLAR\r
-#define TZ_MAX_TYPES   256 /* Limited by what (unsigned char)'s can hold */\r
-#endif /* !defined NOSOLAR */\r
-#ifdef NOSOLAR\r
-/*\r
-** Must be at least 14 for Europe/Riga as of Jan 12 1995,\r
-** as noted by Earl Chew <earl@hpato.aus.hp.com>.\r
-*/\r
-#define TZ_MAX_TYPES   20  /* Maximum number of local time types */\r
-#endif /* !defined NOSOLAR */\r
-#endif /* !defined TZ_MAX_TYPES */\r
-\r
-#ifndef TZ_MAX_CHARS\r
-#define TZ_MAX_CHARS   50  /* Maximum number of abbreviation characters */\r
-               /* (limited by what unsigned chars can hold) */\r
-#endif /* !defined TZ_MAX_CHARS */\r
-\r
-#ifndef TZ_MAX_LEAPS\r
-#define TZ_MAX_LEAPS   50  /* Maximum number of leap second corrections */\r
-#endif /* !defined TZ_MAX_LEAPS */\r
-\r
-#define SECSPERMIN 60\r
-#define MINSPERHOUR    60\r
-#define HOURSPERDAY    24\r
-#define DAYSPERWEEK    7\r
-#define DAYSPERNYEAR   365\r
-#define DAYSPERLYEAR   366\r
-#define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)\r
-#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)\r
-#define MONSPERYEAR    12\r
-\r
-#define TM_SUNDAY  0\r
-#define TM_MONDAY  1\r
-#define TM_TUESDAY 2\r
-#define TM_WEDNESDAY   3\r
-#define TM_THURSDAY    4\r
-#define TM_FRIDAY  5\r
-#define TM_SATURDAY    6\r
-\r
-#define TM_JANUARY 0\r
-#define TM_FEBRUARY    1\r
-#define TM_MARCH   2\r
-#define TM_APRIL   3\r
-#define TM_MAY     4\r
-#define TM_JUNE        5\r
-#define TM_JULY        6\r
-#define TM_AUGUST  7\r
-#define TM_SEPTEMBER   8\r
-#define TM_OCTOBER 9\r
-#define TM_NOVEMBER    10\r
-#define TM_DECEMBER    11\r
-\r
-#define TM_YEAR_BASE   1900\r
-\r
-#define EPOCH_YEAR 1970\r
-#define EPOCH_WDAY TM_THURSDAY\r
-\r
-/*\r
-** Accurate only for the past couple of centuries;\r
-** that will probably do.\r
-*/\r
-\r
-#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))\r
-\r
-#ifndef USG\r
-\r
-/*\r
-** Use of the underscored variants may cause problems if you move your code to\r
-** certain System-V-based systems; for maximum portability, use the\r
-** underscore-free variants.  The underscored variants are provided for\r
-** backward compatibility only; they may disappear from future versions of\r
-** this file.\r
-*/\r
-\r
-#define SECS_PER_MIN   SECSPERMIN\r
-#define MINS_PER_HOUR  MINSPERHOUR\r
-#define HOURS_PER_DAY  HOURSPERDAY\r
-#define DAYS_PER_WEEK  DAYSPERWEEK\r
-#define DAYS_PER_NYEAR DAYSPERNYEAR\r
-#define DAYS_PER_LYEAR DAYSPERLYEAR\r
-#define SECS_PER_HOUR  SECSPERHOUR\r
-#define SECS_PER_DAY   SECSPERDAY\r
-#define MONS_PER_YEAR  MONSPERYEAR\r
-\r
-#endif /* !defined USG */\r
-\r
-#endif /* !defined TZFILE_H */\r
+#ifndef TZFILE_H
+
+#define TZFILE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static char    tzfilehid[] = "@(#)tzfile.h 7.14";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR  "/usr/local/etc/zoneinfo" /* Time zone object file directory */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT  "localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define    TZ_MAGIC    "TZif"
+
+struct tzhead {
+   char    tzh_magic[4];       /* TZ_MAGIC */
+   char    tzh_reserved[16];   /* reserved for future use */
+   char    tzh_ttisgmtcnt[4];  /* coded number of trans. time flags */
+   char    tzh_ttisstdcnt[4];  /* coded number of trans. time flags */
+   char    tzh_leapcnt[4];     /* coded number of leap seconds */
+   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 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
+**     one (char [4])      total correction after above
+** 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.
+*/
+
+#ifndef TZ_MAX_TIMES
+/*
+** 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).
+*/
+#define TZ_MAX_TIMES   370
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES   256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined NOSOLAR */
+#ifdef NOSOLAR
+/*
+** Must be at least 14 for Europe/Riga as of Jan 12 1995,
+** as noted by Earl Chew <earl@hpato.aus.hp.com>.
+*/
+#define TZ_MAX_TYPES   20  /* Maximum number of local time types */
+#endif /* !defined NOSOLAR */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS   50  /* Maximum number of abbreviation characters */
+               /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS   50  /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR    60
+#define HOURSPERDAY    24
+#define DAYSPERWEEK    7
+#define DAYSPERNYEAR   365
+#define DAYSPERLYEAR   366
+#define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR    12
+
+#define TM_SUNDAY  0
+#define TM_MONDAY  1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY   3
+#define TM_THURSDAY    4
+#define TM_FRIDAY  5
+#define TM_SATURDAY    6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY    1
+#define TM_MARCH   2
+#define TM_APRIL   3
+#define TM_MAY     4
+#define TM_JUNE        5
+#define TM_JULY        6
+#define TM_AUGUST  7
+#define TM_SEPTEMBER   8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER    10
+#define TM_DECEMBER    11
+
+#define TM_YEAR_BASE   1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+** Accurate only for the past couple of centuries;
+** that will probably do.
+*/
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+#ifndef USG
+
+/*
+** Use of the underscored variants may cause problems if you move your code to
+** certain System-V-based systems; for maximum portability, use the
+** underscore-free variants.  The underscored variants are provided for
+** backward compatibility only; they may disappear from future versions of
+** this file.
+*/
+
+#define SECS_PER_MIN   SECSPERMIN
+#define MINS_PER_HOUR  MINSPERHOUR
+#define HOURS_PER_DAY  HOURSPERDAY
+#define DAYS_PER_WEEK  DAYSPERWEEK
+#define DAYS_PER_NYEAR DAYSPERNYEAR
+#define DAYS_PER_LYEAR DAYSPERLYEAR
+#define SECS_PER_HOUR  SECSPERHOUR
+#define SECS_PER_DAY   SECSPERDAY
+#define MONS_PER_YEAR  MONSPERYEAR
+
+#endif /* !defined USG */
+
+#endif /* !defined TZFILE_H */
index ec187addf3d061074646e76c319baf7366696f89..21d665c7150276d63666ae135463db6cd1bc6f7f 100644 (file)
-static char    elsieid[] = "@(#)zic.c  7.115";\r
-#include "pgtz.h"\r
-#undef unlink\r
-#undef TZDIR\r
-#define TZDIR "data"\r
-#ifdef WIN32\r
-#include <windows.h>\r
-#endif\r
-\r
-#include "private.h"\r
-#include "locale.h"\r
-#include "tzfile.h"\r
-\r
-#if HAVE_SYS_STAT_H\r
-#include "sys/stat.h"\r
-#endif\r
-#ifndef WIN32\r
-#ifdef S_IRUSR\r
-#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)\r
-#else\r
-#define MKDIR_UMASK 0755\r
-#endif\r
-#endif\r
-\r
-/*\r
-** On some ancient hosts, predicates like `isspace(C)' are defined\r
-** only if isascii(C) || C == EOF.  Modern hosts obey the C Standard,\r
-** which says they are defined only if C == ((unsigned char) C) || C == EOF.\r
-** Neither the C Standard nor Posix require that `isascii' exist.\r
-** For portability, we check both ancient and modern requirements.\r
-** If isascii is not defined, the isascii check succeeds trivially.\r
-*/\r
-#include "ctype.h"\r
-#ifndef isascii\r
-#define isascii(x) 1\r
-#endif\r
-\r
-struct rule {\r
-   const char *    r_filename;\r
-   int     r_linenum;\r
-   const char *    r_name;\r
-\r
-   int     r_loyear;   /* for example, 1986 */\r
-   int     r_hiyear;   /* for example, 1986 */\r
-   const char *    r_yrtype;\r
-\r
-   int     r_month;    /* 0..11 */\r
-\r
-   int     r_dycode;   /* see below */\r
-   int     r_dayofmonth;\r
-   int     r_wday;\r
-\r
-   long        r_tod;      /* time from midnight */\r
-   int     r_todisstd; /* above is standard time if TRUE */\r
-                   /* or wall clock time if FALSE */\r
-   int     r_todisgmt; /* above is GMT if TRUE */\r
-                   /* or local time if FALSE */\r
-   long        r_stdoff;   /* offset from standard time */\r
-   const char *    r_abbrvar;  /* variable part of abbreviation */\r
-\r
-   int     r_todo;     /* a rule to do (used in outzone) */\r
-   time_t      r_temp;     /* used in outzone */\r
-};\r
-\r
-/*\r
-** r_dycode        r_dayofmonth    r_wday\r
-*/\r
-\r
-#define DC_DOM     0   /* 1..31 */ /* unused */\r
-#define DC_DOWGEQ  1   /* 1..31 */ /* 0..6 (Sun..Sat) */\r
-#define DC_DOWLEQ  2   /* 1..31 */ /* 0..6 (Sun..Sat) */\r
-\r
-struct zone {\r
-   const char *    z_filename;\r
-   int     z_linenum;\r
-\r
-   const char *    z_name;\r
-   long        z_gmtoff;\r
-   const char *    z_rule;\r
-   const char *    z_format;\r
-\r
-   long        z_stdoff;\r
-\r
-   struct rule *   z_rules;\r
-   int     z_nrules;\r
-\r
-   struct rule z_untilrule;\r
-   time_t      z_untiltime;\r
-};\r
-\r
-extern int getopt P((int argc, char * const argv[],\r
-           const char * options));\r
-extern int link P((const char * fromname, const char * toname));\r
-extern char *  optarg;\r
-extern int optind;\r
-\r
-static void    addtt P((time_t starttime, int type));\r
-static int addtype P((long gmtoff, const char * abbr, int isdst,\r
-               int ttisstd, int ttisgmt));\r
-static void    leapadd P((time_t t, int positive, int rolling, int count));\r
-static void    adjleap P((void));\r
-static void    associate P((void));\r
-static int ciequal P((const char * ap, const char * bp));\r
-static void    convert P((long val, char * buf));\r
-static void    dolink P((const char * fromfile, const char * tofile));\r
-static void    doabbr P((char * abbr, const char * format,\r
-           const char * letters, int isdst));\r
-static void    eat P((const char * name, int num));\r
-static void    eats P((const char * name, int num,\r
-           const char * rname, int rnum));\r
-static long    eitol P((int i));\r
-static void    error P((const char * message));\r
-static char ** getfields P((char * buf));\r
-static long    gethms P((const char * string, const char * errstrng,\r
-           int signable));\r
-static void    infile P((const char * filename));\r
-static void    inleap P((char ** fields, int nfields));\r
-static void    inlink P((char ** fields, int nfields));\r
-static void    inrule P((char ** fields, int nfields));\r
-static int inzcont P((char ** fields, int nfields));\r
-static int inzone P((char ** fields, int nfields));\r
-static int inzsub P((char ** fields, int nfields, int iscont));\r
-static int itsabbr P((const char * abbr, const char * word));\r
-static int itsdir P((const char * name));\r
-static int lowerit P((int c));\r
-static char *  memcheck P((char * tocheck));\r
-static int mkdirs P((char * filename));\r
-static void    newabbr P((const char * abbr));\r
-static long    oadd P((long t1, long t2));\r
-static void    outzone P((const struct zone * zp, int ntzones));\r
-static void    puttzcode P((long code, FILE * fp));\r
-static int rcomp P((const void * leftp, const void * rightp));\r
-static time_t  rpytime P((const struct rule * rp, int wantedy));\r
-static void    rulesub P((struct rule * rp,\r
-           const char * loyearp, const char * hiyearp,\r
-           const char * typep, const char * monthp,\r
-           const char * dayp, const char * timep));\r
-static void    setboundaries P((void));\r
-static time_t  tadd P((time_t t1, long t2));\r
-static void    usage P((void));\r
-static void    writezone P((const char * name));\r
-static int yearistype P((int year, const char * type));\r
-\r
-#if !(HAVE_STRERROR - 0)\r
-static char *  strerror P((int));\r
-#endif /* !(HAVE_STRERROR - 0) */\r
-\r
-static int     charcnt;\r
-static int     errors;\r
-static const char *    filename;\r
-static int     leapcnt;\r
-static int     linenum;\r
-static time_t      max_time;\r
-static int     max_year;\r
-static int     max_year_representable;\r
-static time_t      min_time;\r
-static int     min_year;\r
-static int     min_year_representable;\r
-static int     noise;\r
-static const char *    rfilename;\r
-static int     rlinenum;\r
-static const char *    progname;\r
-static int     timecnt;\r
-static int     typecnt;\r
-\r
-/*\r
-** Line codes.\r
-*/\r
-\r
-#define LC_RULE        0\r
-#define LC_ZONE        1\r
-#define LC_LINK        2\r
-#define LC_LEAP        3\r
-\r
-/*\r
-** Which fields are which on a Zone line.\r
-*/\r
-\r
-#define ZF_NAME        1\r
-#define ZF_GMTOFF  2\r
-#define ZF_RULE        3\r
-#define ZF_FORMAT  4\r
-#define ZF_TILYEAR 5\r
-#define ZF_TILMONTH    6\r
-#define ZF_TILDAY  7\r
-#define ZF_TILTIME 8\r
-#define ZONE_MINFIELDS 5\r
-#define ZONE_MAXFIELDS 9\r
-\r
-/*\r
-** Which fields are which on a Zone continuation line.\r
-*/\r
-\r
-#define ZFC_GMTOFF 0\r
-#define ZFC_RULE   1\r
-#define ZFC_FORMAT 2\r
-#define ZFC_TILYEAR    3\r
-#define ZFC_TILMONTH   4\r
-#define ZFC_TILDAY 5\r
-#define ZFC_TILTIME    6\r
-#define ZONEC_MINFIELDS    3\r
-#define ZONEC_MAXFIELDS    7\r
-\r
-/*\r
-** Which files are which on a Rule line.\r
-*/\r
-\r
-#define RF_NAME        1\r
-#define RF_LOYEAR  2\r
-#define RF_HIYEAR  3\r
-#define RF_COMMAND 4\r
-#define RF_MONTH   5\r
-#define RF_DAY     6\r
-#define RF_TOD     7\r
-#define RF_STDOFF  8\r
-#define RF_ABBRVAR 9\r
-#define RULE_FIELDS    10\r
-\r
-/*\r
-** Which fields are which on a Link line.\r
-*/\r
-\r
-#define LF_FROM        1\r
-#define LF_TO      2\r
-#define LINK_FIELDS    3\r
-\r
-/*\r
-** Which fields are which on a Leap line.\r
-*/\r
-\r
-#define LP_YEAR        1\r
-#define LP_MONTH   2\r
-#define LP_DAY     3\r
-#define LP_TIME        4\r
-#define LP_CORR        5\r
-#define LP_ROLL        6\r
-#define LEAP_FIELDS    7\r
-\r
-/*\r
-** Year synonyms.\r
-*/\r
-\r
-#define YR_MINIMUM 0\r
-#define YR_MAXIMUM 1\r
-#define YR_ONLY        2\r
-\r
-static struct rule *   rules;\r
-static int     nrules; /* number of rules */\r
-\r
-static struct zone *   zones;\r
-static int     nzones; /* number of zones */\r
-\r
-struct link {\r
-   const char *    l_filename;\r
-   int     l_linenum;\r
-   const char *    l_from;\r
-   const char *    l_to;\r
-};\r
-\r
-static struct link *   links;\r
-static int     nlinks;\r
-\r
-struct lookup {\r
-   const char *    l_word;\r
-   const int   l_value;\r
-};\r
-\r
-static struct lookup const *   byword P((const char * string,\r
-                   const struct lookup * lp));\r
-\r
-static struct lookup const line_codes[] = {\r
-   { "Rule",   LC_RULE },\r
-   { "Zone",   LC_ZONE },\r
-   { "Link",   LC_LINK },\r
-   { "Leap",   LC_LEAP },\r
-   { NULL,     0}\r
-};\r
-\r
-static struct lookup const mon_names[] = {\r
-   { "January",    TM_JANUARY },\r
-   { "February",   TM_FEBRUARY },\r
-   { "March",  TM_MARCH },\r
-   { "April",  TM_APRIL },\r
-   { "May",    TM_MAY },\r
-   { "June",   TM_JUNE },\r
-   { "July",   TM_JULY },\r
-   { "August", TM_AUGUST },\r
-   { "September",  TM_SEPTEMBER },\r
-   { "October",    TM_OCTOBER },\r
-   { "November",   TM_NOVEMBER },\r
-   { "December",   TM_DECEMBER },\r
-   { NULL,     0 }\r
-};\r
-\r
-static struct lookup const wday_names[] = {\r
-   { "Sunday", TM_SUNDAY },\r
-   { "Monday", TM_MONDAY },\r
-   { "Tuesday",    TM_TUESDAY },\r
-   { "Wednesday",  TM_WEDNESDAY },\r
-   { "Thursday",   TM_THURSDAY },\r
-   { "Friday", TM_FRIDAY },\r
-   { "Saturday",   TM_SATURDAY },\r
-   { NULL,     0 }\r
-};\r
-\r
-static struct lookup const lasts[] = {\r
-   { "last-Sunday",    TM_SUNDAY },\r
-   { "last-Monday",    TM_MONDAY },\r
-   { "last-Tuesday",   TM_TUESDAY },\r
-   { "last-Wednesday", TM_WEDNESDAY },\r
-   { "last-Thursday",  TM_THURSDAY },\r
-   { "last-Friday",    TM_FRIDAY },\r
-   { "last-Saturday",  TM_SATURDAY },\r
-   { NULL,         0 }\r
-};\r
-\r
-static struct lookup const begin_years[] = {\r
-   { "minimum",    YR_MINIMUM },\r
-   { "maximum",    YR_MAXIMUM },\r
-   { NULL,     0 }\r
-};\r
-\r
-static struct lookup const end_years[] = {\r
-   { "minimum",    YR_MINIMUM },\r
-   { "maximum",    YR_MAXIMUM },\r
-   { "only",   YR_ONLY },\r
-   { NULL,     0 }\r
-};\r
-\r
-static struct lookup const leap_types[] = {\r
-   { "Rolling",    TRUE },\r
-   { "Stationary", FALSE },\r
-   { NULL,     0 }\r
-};\r
-\r
-static const int   len_months[2][MONSPERYEAR] = {\r
-   { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },\r
-   { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }\r
-};\r
-\r
-static const int   len_years[2] = {\r
-   DAYSPERNYEAR, DAYSPERLYEAR\r
-};\r
-\r
-static struct attype {\r
-   time_t      at;\r
-   unsigned char   type;\r
-}          attypes[TZ_MAX_TIMES];\r
-static long        gmtoffs[TZ_MAX_TYPES];\r
-static char        isdsts[TZ_MAX_TYPES];\r
-static unsigned char   abbrinds[TZ_MAX_TYPES];\r
-static char        ttisstds[TZ_MAX_TYPES];\r
-static char        ttisgmts[TZ_MAX_TYPES];\r
-static char        chars[TZ_MAX_CHARS];\r
-static time_t      trans[TZ_MAX_LEAPS];\r
-static long        corr[TZ_MAX_LEAPS];\r
-static char        roll[TZ_MAX_LEAPS];\r
-\r
-/*\r
-** Memory allocation.\r
-*/\r
-\r
-static char *\r
-memcheck(ptr)\r
-char * const   ptr;\r
-{\r
-   if (ptr == NULL) {\r
-       const char *e = strerror(errno);\r
-\r
-       (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),\r
-           progname, e);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   return ptr;\r
-}\r
-\r
-#define emalloc(size)      memcheck(imalloc(size))\r
-#define erealloc(ptr, size)    memcheck(irealloc((ptr), (size)))\r
-#define ecpyalloc(ptr)     memcheck(icpyalloc(ptr))\r
-#define ecatalloc(oldp, newp)  memcheck(icatalloc((oldp), (newp)))\r
-\r
-/*\r
-** Error handling.\r
-*/\r
-\r
-#if !(HAVE_STRERROR - 0)\r
-static char *\r
-strerror(errnum)\r
-int    errnum;\r
-{\r
-   extern char *   sys_errlist[];\r
-   extern int  sys_nerr;\r
-\r
-   return (errnum > 0 && errnum <= sys_nerr) ?\r
-       sys_errlist[errnum] : _("Unknown system error");\r
-}\r
-#endif /* !(HAVE_STRERROR - 0) */\r
-\r
-static void\r
-eats(name, num, rname, rnum)\r
-const char * const name;\r
-const int      num;\r
-const char * const rname;\r
-const int      rnum;\r
-{\r
-   filename = name;\r
-   linenum = num;\r
-   rfilename = rname;\r
-   rlinenum = rnum;\r
-}\r
-\r
-static void\r
-eat(name, num)\r
-const char * const name;\r
-const int      num;\r
-{\r
-   eats(name, num, (char *) NULL, -1);\r
-}\r
-\r
-static void\r
-error(string)\r
-const char * const string;\r
-{\r
-   /*\r
-   ** Match the format of "cc" to allow sh users to\r
-   **  zic ... 2>&1 | error -t "*" -v\r
-   ** on BSD systems.\r
-   */\r
-   (void) fprintf(stderr, _("\"%s\", line %d: %s"),\r
-       filename, linenum, string);\r
-   if (rfilename != NULL)\r
-       (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),\r
-           rfilename, rlinenum);\r
-   (void) fprintf(stderr, "\n");\r
-   ++errors;\r
-}\r
-\r
-static void\r
-warning(string)\r
-const char * const string;\r
-{\r
-   char *  cp;\r
-\r
-   cp = ecpyalloc(_("warning: "));\r
-   cp = ecatalloc(cp, string);\r
-   error(cp);\r
-   ifree(cp);\r
-   --errors;\r
-}\r
-\r
-static void\r
-usage P((void))\r
-{\r
-   (void) fprintf(stderr, _("%s: usage is %s [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),\r
-       progname, progname);\r
-   (void) exit(EXIT_FAILURE);\r
-}\r
-\r
-static const char *    psxrules;\r
-static const char *    lcltime;\r
-static const char *    directory;\r
-static const char *    leapsec;\r
-static const char *    yitcommand;\r
-static int     sflag = FALSE;\r
-\r
-int\r
-main(argc, argv)\r
-int    argc;\r
-char * argv[];\r
-{\r
-   register int    i;\r
-   register int    j;\r
-   register int    c;\r
-\r
-#ifdef unix\r
-   (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));\r
-#endif /* defined unix */\r
-#if HAVE_GETTEXT - 0\r
-   (void) setlocale(LC_MESSAGES, "");\r
-#ifdef TZ_DOMAINDIR\r
-   (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);\r
-#endif /* defined TEXTDOMAINDIR */\r
-   (void) textdomain(TZ_DOMAIN);\r
-#endif /* HAVE_GETTEXT - 0 */\r
-   progname = argv[0];\r
-   for (i = 1; i < argc; ++i)\r
-       if (strcmp(argv[i], "--version") == 0) {\r
-           (void) printf("%s\n", elsieid);\r
-           (void) exit(EXIT_SUCCESS);\r
-       }\r
-   while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)\r
-       switch (c) {\r
-           default:\r
-               usage();\r
-           case 'd':\r
-               if (directory == NULL)\r
-                   directory = optarg;\r
-               else {\r
-                   (void) fprintf(stderr,\r
-_("%s: More than one -d option specified\n"),\r
-                       progname);\r
-                   (void) exit(EXIT_FAILURE);\r
-               }\r
-               break;\r
-           case 'l':\r
-               if (lcltime == NULL)\r
-                   lcltime = optarg;\r
-               else {\r
-                   (void) fprintf(stderr,\r
-_("%s: More than one -l option specified\n"),\r
-                       progname);\r
-                   (void) exit(EXIT_FAILURE);\r
-               }\r
-               break;\r
-           case 'p':\r
-               if (psxrules == NULL)\r
-                   psxrules = optarg;\r
-               else {\r
-                   (void) fprintf(stderr,\r
-_("%s: More than one -p option specified\n"),\r
-                       progname);\r
-                   (void) exit(EXIT_FAILURE);\r
-               }\r
-               break;\r
-           case 'y':\r
-               if (yitcommand == NULL)\r
-                   yitcommand = optarg;\r
-               else {\r
-                   (void) fprintf(stderr,\r
-_("%s: More than one -y option specified\n"),\r
-                       progname);\r
-                   (void) exit(EXIT_FAILURE);\r
-               }\r
-               break;\r
-           case 'L':\r
-               if (leapsec == NULL)\r
-                   leapsec = optarg;\r
-               else {\r
-                   (void) fprintf(stderr,\r
-_("%s: More than one -L option specified\n"),\r
-                       progname);\r
-                   (void) exit(EXIT_FAILURE);\r
-               }\r
-               break;\r
-           case 'v':\r
-               noise = TRUE;\r
-               break;\r
-           case 's':\r
-               sflag = TRUE;\r
-               break;\r
-       }\r
-   if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)\r
-       usage();    /* usage message by request */\r
-   if (directory == NULL)\r
-       directory = TZDIR;\r
-   if (yitcommand == NULL)\r
-       yitcommand = "yearistype";\r
-\r
-   setboundaries();\r
-\r
-   if (optind < argc && leapsec != NULL) {\r
-       infile(leapsec);\r
-       adjleap();\r
-   }\r
-\r
-   for (i = optind; i < argc; ++i)\r
-       infile(argv[i]);\r
-   if (errors)\r
-       (void) exit(EXIT_FAILURE);\r
-   associate();\r
-   for (i = 0; i < nzones; i = j) {\r
-       /*\r
-       ** Find the next non-continuation zone entry.\r
-       */\r
-       for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)\r
-           continue;\r
-       outzone(&zones[i], j - i);\r
-   }\r
-   /*\r
-   ** Make links.\r
-   */\r
-   for (i = 0; i < nlinks; ++i) {\r
-       eat(links[i].l_filename, links[i].l_linenum);\r
-       dolink(links[i].l_from, links[i].l_to);\r
-   }\r
-   if (lcltime != NULL) {\r
-       eat("command line", 1);\r
-       dolink(lcltime, TZDEFAULT);\r
-   }\r
-   if (psxrules != NULL) {\r
-       eat("command line", 1);\r
-       dolink(psxrules, TZDEFRULES);\r
-   }\r
-   return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\r
-}\r
-\r
-static void\r
-dolink(fromfile, tofile)\r
-const char * const fromfile;\r
-const char * const tofile;\r
-{\r
-   register char * fromname;\r
-   register char * toname;\r
-\r
-   if (fromfile[0] == '/')\r
-       fromname = ecpyalloc(fromfile);\r
-   else {\r
-       fromname = ecpyalloc(directory);\r
-       fromname = ecatalloc(fromname, "/");\r
-       fromname = ecatalloc(fromname, fromfile);\r
-   }\r
-   if (tofile[0] == '/')\r
-       toname = ecpyalloc(tofile);\r
-   else {\r
-       toname = ecpyalloc(directory);\r
-       toname = ecatalloc(toname, "/");\r
-       toname = ecatalloc(toname, tofile);\r
-   }\r
-   /*\r
-   ** We get to be careful here since\r
-   ** there's a fair chance of root running us.\r
-   */\r
-   if (!itsdir(toname))\r
-       (void) remove(toname);\r
-   if (link(fromname, toname) != 0) {\r
-       int result;\r
-\r
-       if (mkdirs(toname) != 0)\r
-           (void) exit(EXIT_FAILURE);\r
-\r
-       result = link(fromname, toname);\r
-#if (HAVE_SYMLINK - 0)\r
-       if (result != 0 &&\r
-           access(fromname, F_OK) == 0 &&\r
-           !itsdir(fromname)) {\r
-               const char *s = tofile;\r
-               register char * symlinkcontents = NULL;\r
-               while ((s = strchr(s+1, '/')) != NULL)\r
-                   symlinkcontents = ecatalloc(symlinkcontents, "../");\r
-           symlinkcontents = ecatalloc(symlinkcontents, fromfile);\r
-\r
-           result = symlink(symlinkcontents, toname);\r
-           if (result == 0)\r
-warning(_("hard link failed, symbolic link used"));\r
-           ifree(symlinkcontents);\r
-       }\r
-#endif\r
-       if (result != 0) {\r
-           const char *e = strerror(errno);\r
-\r
-           (void) fprintf(stderr,\r
-               _("%s: Can't link from %s to %s: %s\n"),\r
-               progname, fromname, toname, e);\r
-           (void) exit(EXIT_FAILURE);\r
-       }\r
-   }\r
-   ifree(fromname);\r
-   ifree(toname);\r
-}\r
-\r
-#ifndef INT_MAX\r
-#define INT_MAX    ((int) (((unsigned)~0)>>1))\r
-#endif /* !defined INT_MAX */\r
-\r
-#ifndef INT_MIN\r
-#define INT_MIN    ((int) ~(((unsigned)~0)>>1))\r
-#endif /* !defined INT_MIN */\r
-\r
-/*\r
-** The tz file format currently allows at most 32-bit quantities.\r
-** This restriction should be removed before signed 32-bit values\r
-** wrap around in 2038, but unfortunately this will require a\r
-** change to the tz file format.\r
-*/\r
-\r
-#define MAX_BITS_IN_FILE   32\r
-#define TIME_T_BITS_IN_FILE    ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)\r
-\r
-static void\r
-setboundaries P((void))\r
-{\r
-   if (TYPE_SIGNED(time_t)) {\r
-       min_time = ~ (time_t) 0;\r
-       min_time <<= TIME_T_BITS_IN_FILE - 1;\r
-       max_time = ~ (time_t) 0 - min_time;\r
-       if (sflag)\r
-           min_time = 0;\r
-   } else {\r
-       min_time = 0;\r
-       max_time = 2 - sflag;\r
-       max_time <<= TIME_T_BITS_IN_FILE - 1;\r
-       --max_time;\r
-   }\r
-   min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;\r
-   max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;\r
-   min_year_representable = min_year;\r
-   max_year_representable = max_year;\r
-}\r
-\r
-static int\r
-itsdir(name)\r
-const char * const name;\r
-{\r
-   register char * myname;\r
-   register int    accres;\r
-\r
-   myname = ecpyalloc(name);\r
-   myname = ecatalloc(myname, "/.");\r
-   accres = access(myname, F_OK);\r
-   ifree(myname);\r
-   return accres == 0;\r
-}\r
-\r
-/*\r
-** Associate sets of rules with zones.\r
-*/\r
-\r
-/*\r
-** Sort by rule name.\r
-*/\r
-\r
-static int\r
-rcomp(cp1, cp2)\r
-const void *   cp1;\r
-const void *   cp2;\r
-{\r
-   return strcmp(((const struct rule *) cp1)->r_name,\r
-       ((const struct rule *) cp2)->r_name);\r
-}\r
-\r
-static void\r
-associate P((void))\r
-{\r
-   register struct zone *  zp;\r
-   register struct rule *  rp;\r
-   register int        base, out;\r
-   register int        i, j;\r
-\r
-   if (nrules != 0) {\r
-       (void) qsort((void *) rules, (size_t) nrules,\r
-           (size_t) sizeof *rules, rcomp);\r
-       for (i = 0; i < nrules - 1; ++i) {\r
-           if (strcmp(rules[i].r_name,\r
-               rules[i + 1].r_name) != 0)\r
-                   continue;\r
-           if (strcmp(rules[i].r_filename,\r
-               rules[i + 1].r_filename) == 0)\r
-                   continue;\r
-           eat(rules[i].r_filename, rules[i].r_linenum);\r
-           warning(_("same rule name in multiple files"));\r
-           eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);\r
-           warning(_("same rule name in multiple files"));\r
-           for (j = i + 2; j < nrules; ++j) {\r
-               if (strcmp(rules[i].r_name,\r
-                   rules[j].r_name) != 0)\r
-                       break;\r
-               if (strcmp(rules[i].r_filename,\r
-                   rules[j].r_filename) == 0)\r
-                       continue;\r
-               if (strcmp(rules[i + 1].r_filename,\r
-                   rules[j].r_filename) == 0)\r
-                       continue;\r
-               break;\r
-           }\r
-           i = j - 1;\r
-       }\r
-   }\r
-   for (i = 0; i < nzones; ++i) {\r
-       zp = &zones[i];\r
-       zp->z_rules = NULL;\r
-       zp->z_nrules = 0;\r
-   }\r
-   for (base = 0; base < nrules; base = out) {\r
-       rp = &rules[base];\r
-       for (out = base + 1; out < nrules; ++out)\r
-           if (strcmp(rp->r_name, rules[out].r_name) != 0)\r
-               break;\r
-       for (i = 0; i < nzones; ++i) {\r
-           zp = &zones[i];\r
-           if (strcmp(zp->z_rule, rp->r_name) != 0)\r
-               continue;\r
-           zp->z_rules = rp;\r
-           zp->z_nrules = out - base;\r
-       }\r
-   }\r
-   for (i = 0; i < nzones; ++i) {\r
-       zp = &zones[i];\r
-       if (zp->z_nrules == 0) {\r
-           /*\r
-           ** Maybe we have a local standard time offset.\r
-           */\r
-           eat(zp->z_filename, zp->z_linenum);\r
-           zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),\r
-                         TRUE);\r
-           /*\r
-           ** Note, though, that if there's no rule,\r
-           ** a '%s' in the format is a bad thing.\r
-           */\r
-           if (strchr(zp->z_format, '%') != 0)\r
-               error(_("%s in ruleless zone"));\r
-       }\r
-   }\r
-   if (errors)\r
-       (void) exit(EXIT_FAILURE);\r
-}\r
-\r
-static void\r
-infile(name)\r
-const char *   name;\r
-{\r
-   register FILE *         fp;\r
-   register char **        fields;\r
-   register char *         cp;\r
-   register const struct lookup *  lp;\r
-   register int            nfields;\r
-   register int            wantcont;\r
-   register int            num;\r
-   char                buf[BUFSIZ];\r
-\r
-   if (strcmp(name, "-") == 0) {\r
-       name = _("standard input");\r
-       fp = stdin;\r
-   } else if ((fp = fopen(name, "r")) == NULL) {\r
-       const char *e = strerror(errno);\r
-\r
-       (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),\r
-           progname, name, e);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   wantcont = FALSE;\r
-   for (num = 1; ; ++num) {\r
-       eat(name, num);\r
-       if (fgets(buf, (int) sizeof buf, fp) != buf)\r
-           break;\r
-       cp = strchr(buf, '\n');\r
-       if (cp == NULL) {\r
-           error(_("line too long"));\r
-           (void) exit(EXIT_FAILURE);\r
-       }\r
-       *cp = '\0';\r
-       fields = getfields(buf);\r
-       nfields = 0;\r
-       while (fields[nfields] != NULL) {\r
-           static char nada;\r
-\r
-           if (strcmp(fields[nfields], "-") == 0)\r
-               fields[nfields] = &nada;\r
-           ++nfields;\r
-       }\r
-       if (nfields == 0) {\r
-           /* nothing to do */\r
-       } else if (wantcont) {\r
-           wantcont = inzcont(fields, nfields);\r
-       } else {\r
-           lp = byword(fields[0], line_codes);\r
-           if (lp == NULL)\r
-               error(_("input line of unknown type"));\r
-           else switch ((int) (lp->l_value)) {\r
-               case LC_RULE:\r
-                   inrule(fields, nfields);\r
-                   wantcont = FALSE;\r
-                   break;\r
-               case LC_ZONE:\r
-                   wantcont = inzone(fields, nfields);\r
-                   break;\r
-               case LC_LINK:\r
-                   inlink(fields, nfields);\r
-                   wantcont = FALSE;\r
-                   break;\r
-               case LC_LEAP:\r
-                   if (name != leapsec)\r
-                       (void) fprintf(stderr,\r
-_("%s: Leap line in non leap seconds file %s\n"),\r
-                           progname, name);\r
-                   else    inleap(fields, nfields);\r
-                   wantcont = FALSE;\r
-                   break;\r
-               default:    /* "cannot happen" */\r
-                   (void) fprintf(stderr,\r
-_("%s: panic: Invalid l_value %d\n"),\r
-                       progname, lp->l_value);\r
-                   (void) exit(EXIT_FAILURE);\r
-           }\r
-       }\r
-       ifree((char *) fields);\r
-   }\r
-   if (ferror(fp)) {\r
-       (void) fprintf(stderr, _("%s: Error reading %s\n"),\r
-           progname, filename);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   if (fp != stdin && fclose(fp)) {\r
-       const char *e = strerror(errno);\r
-\r
-       (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),\r
-           progname, filename, e);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   if (wantcont)\r
-       error(_("expected continuation line not found"));\r
-}\r
-\r
-/*\r
-** Convert a string of one of the forms\r
-** h   -h  hh:mm   -hh:mm  hh:mm:ss    -hh:mm:ss\r
-** into a number of seconds.\r
-** A null string maps to zero.\r
-** Call error with errstring and return zero on errors.\r
-*/\r
-\r
-static long\r
-gethms(string, errstring, signable)\r
-const char *       string;\r
-const char * const errstring;\r
-const int      signable;\r
-{\r
-   int hh, mm, ss, sign;\r
-\r
-   if (string == NULL || *string == '\0')\r
-       return 0;\r
-   if (!signable)\r
-       sign = 1;\r
-   else if (*string == '-') {\r
-       sign = -1;\r
-       ++string;\r
-   } else  sign = 1;\r
-   if (sscanf(string, scheck(string, "%d"), &hh) == 1)\r
-       mm = ss = 0;\r
-   else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)\r
-       ss = 0;\r
-   else if (sscanf(string, scheck(string, "%d:%d:%d"),\r
-       &hh, &mm, &ss) != 3) {\r
-           error(errstring);\r
-           return 0;\r
-   }\r
-   if ((hh < 0 || hh >= HOURSPERDAY ||\r
-       mm < 0 || mm >= MINSPERHOUR ||\r
-       ss < 0 || ss > SECSPERMIN) &&\r
-       !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {\r
-           error(errstring);\r
-           return 0;\r
-   }\r
-   if (noise && hh == HOURSPERDAY)\r
-       warning(_("24:00 not handled by pre-1998 versions of zic"));\r
-   return eitol(sign) *\r
-       (eitol(hh * MINSPERHOUR + mm) *\r
-       eitol(SECSPERMIN) + eitol(ss));\r
-}\r
-\r
-static void\r
-inrule(fields, nfields)\r
-register char ** const fields;\r
-const int      nfields;\r
-{\r
-   static struct rule  r;\r
-\r
-   if (nfields != RULE_FIELDS) {\r
-       error(_("wrong number of fields on Rule line"));\r
-       return;\r
-   }\r
-   if (*fields[RF_NAME] == '\0') {\r
-       error(_("nameless rule"));\r
-       return;\r
-   }\r
-   r.r_filename = filename;\r
-   r.r_linenum = linenum;\r
-   r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);\r
-   rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],\r
-       fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);\r
-   r.r_name = ecpyalloc(fields[RF_NAME]);\r
-   r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);\r
-   rules = (struct rule *) (void *) erealloc((char *) rules,\r
-       (int) ((nrules + 1) * sizeof *rules));\r
-   rules[nrules++] = r;\r
-}\r
-\r
-static int\r
-inzone(fields, nfields)\r
-register char ** const fields;\r
-const int      nfields;\r
-{\r
-   register int    i;\r
-   static char *   buf;\r
-\r
-   if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {\r
-       error(_("wrong number of fields on Zone line"));\r
-       return FALSE;\r
-   }\r
-   if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {\r
-       buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));\r
-       (void) sprintf(buf,\r
-_("\"Zone %s\" line and -l option are mutually exclusive"),\r
-           TZDEFAULT);\r
-       error(buf);\r
-       return FALSE;\r
-   }\r
-   if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {\r
-       buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));\r
-       (void) sprintf(buf,\r
-_("\"Zone %s\" line and -p option are mutually exclusive"),\r
-           TZDEFRULES);\r
-       error(buf);\r
-       return FALSE;\r
-   }\r
-   for (i = 0; i < nzones; ++i)\r
-       if (zones[i].z_name != NULL &&\r
-           strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {\r
-               buf = erealloc(buf, (int) (132 +\r
-                   strlen(fields[ZF_NAME]) +\r
-                   strlen(zones[i].z_filename)));\r
-               (void) sprintf(buf,\r
-_("duplicate zone name %s (file \"%s\", line %d)"),\r
-                   fields[ZF_NAME],\r
-                   zones[i].z_filename,\r
-                   zones[i].z_linenum);\r
-               error(buf);\r
-               return FALSE;\r
-       }\r
-   return inzsub(fields, nfields, FALSE);\r
-}\r
-\r
-static int\r
-inzcont(fields, nfields)\r
-register char ** const fields;\r
-const int      nfields;\r
-{\r
-   if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {\r
-       error(_("wrong number of fields on Zone continuation line"));\r
-       return FALSE;\r
-   }\r
-   return inzsub(fields, nfields, TRUE);\r
-}\r
-\r
-static int\r
-inzsub(fields, nfields, iscont)\r
-register char ** const fields;\r
-const int      nfields;\r
-const int      iscont;\r
-{\r
-   register char *     cp;\r
-   static struct zone  z;\r
-   register int        i_gmtoff, i_rule, i_format;\r
-   register int        i_untilyear, i_untilmonth;\r
-   register int        i_untilday, i_untiltime;\r
-   register int        hasuntil;\r
-\r
-   if (iscont) {\r
-       i_gmtoff = ZFC_GMTOFF;\r
-       i_rule = ZFC_RULE;\r
-       i_format = ZFC_FORMAT;\r
-       i_untilyear = ZFC_TILYEAR;\r
-       i_untilmonth = ZFC_TILMONTH;\r
-       i_untilday = ZFC_TILDAY;\r
-       i_untiltime = ZFC_TILTIME;\r
-       z.z_name = NULL;\r
-   } else {\r
-       i_gmtoff = ZF_GMTOFF;\r
-       i_rule = ZF_RULE;\r
-       i_format = ZF_FORMAT;\r
-       i_untilyear = ZF_TILYEAR;\r
-       i_untilmonth = ZF_TILMONTH;\r
-       i_untilday = ZF_TILDAY;\r
-       i_untiltime = ZF_TILTIME;\r
-       z.z_name = ecpyalloc(fields[ZF_NAME]);\r
-   }\r
-   z.z_filename = filename;\r
-   z.z_linenum = linenum;\r
-   z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);\r
-   if ((cp = strchr(fields[i_format], '%')) != 0) {\r
-       if (*++cp != 's' || strchr(cp, '%') != 0) {\r
-           error(_("invalid abbreviation format"));\r
-           return FALSE;\r
-       }\r
-   }\r
-   z.z_rule = ecpyalloc(fields[i_rule]);\r
-   z.z_format = ecpyalloc(fields[i_format]);\r
-   hasuntil = nfields > i_untilyear;\r
-   if (hasuntil) {\r
-       z.z_untilrule.r_filename = filename;\r
-       z.z_untilrule.r_linenum = linenum;\r
-       rulesub(&z.z_untilrule,\r
-           fields[i_untilyear],\r
-           "only",\r
-           "",\r
-           (nfields > i_untilmonth) ?\r
-           fields[i_untilmonth] : "Jan",\r
-           (nfields > i_untilday) ? fields[i_untilday] : "1",\r
-           (nfields > i_untiltime) ? fields[i_untiltime] : "0");\r
-       z.z_untiltime = rpytime(&z.z_untilrule,\r
-           z.z_untilrule.r_loyear);\r
-       if (iscont && nzones > 0 &&\r
-           z.z_untiltime > min_time &&\r
-           z.z_untiltime < max_time &&\r
-           zones[nzones - 1].z_untiltime > min_time &&\r
-           zones[nzones - 1].z_untiltime < max_time &&\r
-           zones[nzones - 1].z_untiltime >= z.z_untiltime) {\r
-               error(_("Zone continuation line end time is not after end time of previous line"));\r
-               return FALSE;\r
-       }\r
-   }\r
-   zones = (struct zone *) (void *) erealloc((char *) zones,\r
-       (int) ((nzones + 1) * sizeof *zones));\r
-   zones[nzones++] = z;\r
-   /*\r
-   ** If there was an UNTIL field on this line,\r
-   ** there's more information about the zone on the next line.\r
-   */\r
-   return hasuntil;\r
-}\r
-\r
-static void\r
-inleap(fields, nfields)\r
-register char ** const fields;\r
-const int      nfields;\r
-{\r
-   register const char *       cp;\r
-   register const struct lookup *  lp;\r
-   register int            i, j;\r
-   int             year, month, day;\r
-   long                dayoff, tod;\r
-   time_t              t;\r
-\r
-   if (nfields != LEAP_FIELDS) {\r
-       error(_("wrong number of fields on Leap line"));\r
-       return;\r
-   }\r
-   dayoff = 0;\r
-   cp = fields[LP_YEAR];\r
-   if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {\r
-           /*\r
-            * Leapin' Lizards!\r
-            */\r
-           error(_("invalid leaping year"));\r
-           return;\r
-   }\r
-   j = EPOCH_YEAR;\r
-   while (j != year) {\r
-       if (year > j) {\r
-           i = len_years[isleap(j)];\r
-           ++j;\r
-       } else {\r
-           --j;\r
-           i = -len_years[isleap(j)];\r
-       }\r
-       dayoff = oadd(dayoff, eitol(i));\r
-   }\r
-   if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {\r
-       error(_("invalid month name"));\r
-       return;\r
-   }\r
-   month = lp->l_value;\r
-   j = TM_JANUARY;\r
-   while (j != month) {\r
-       i = len_months[isleap(year)][j];\r
-       dayoff = oadd(dayoff, eitol(i));\r
-       ++j;\r
-   }\r
-   cp = fields[LP_DAY];\r
-   if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||\r
-       day <= 0 || day > len_months[isleap(year)][month]) {\r
-           error(_("invalid day of month"));\r
-           return;\r
-   }\r
-   dayoff = oadd(dayoff, eitol(day - 1));\r
-   if (dayoff < 0 && !TYPE_SIGNED(time_t)) {\r
-       error(_("time before zero"));\r
-       return;\r
-   }\r
-   if (dayoff < min_time / SECSPERDAY) {\r
-       error(_("time too small"));\r
-       return;\r
-   }\r
-   if (dayoff > max_time / SECSPERDAY) {\r
-       error(_("time too large"));\r
-       return;\r
-   }\r
-   t = (time_t) dayoff * SECSPERDAY;\r
-   tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);\r
-   cp = fields[LP_CORR];\r
-   {\r
-       register int    positive;\r
-       int     count;\r
-\r
-       if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */\r
-           positive = FALSE;\r
-           count = 1;\r
-       } else if (strcmp(cp, "--") == 0) {\r
-           positive = FALSE;\r
-           count = 2;\r
-       } else if (strcmp(cp, "+") == 0) {\r
-           positive = TRUE;\r
-           count = 1;\r
-       } else if (strcmp(cp, "++") == 0) {\r
-           positive = TRUE;\r
-           count = 2;\r
-       } else {\r
-           error(_("illegal CORRECTION field on Leap line"));\r
-           return;\r
-       }\r
-       if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {\r
-           error(_("illegal Rolling/Stationary field on Leap line"));\r
-           return;\r
-       }\r
-       leapadd(tadd(t, tod), positive, lp->l_value, count);\r
-   }\r
-}\r
-\r
-static void\r
-inlink(fields, nfields)\r
-register char ** const fields;\r
-const int      nfields;\r
-{\r
-   struct link l;\r
-\r
-   if (nfields != LINK_FIELDS) {\r
-       error(_("wrong number of fields on Link line"));\r
-       return;\r
-   }\r
-   if (*fields[LF_FROM] == '\0') {\r
-       error(_("blank FROM field on Link line"));\r
-       return;\r
-   }\r
-   if (*fields[LF_TO] == '\0') {\r
-       error(_("blank TO field on Link line"));\r
-       return;\r
-   }\r
-   l.l_filename = filename;\r
-   l.l_linenum = linenum;\r
-   l.l_from = ecpyalloc(fields[LF_FROM]);\r
-   l.l_to = ecpyalloc(fields[LF_TO]);\r
-   links = (struct link *) (void *) erealloc((char *) links,\r
-       (int) ((nlinks + 1) * sizeof *links));\r
-   links[nlinks++] = l;\r
-}\r
-\r
-static void\r
-rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)\r
-register struct rule * const   rp;\r
-const char * const     loyearp;\r
-const char * const     hiyearp;\r
-const char * const     typep;\r
-const char * const     monthp;\r
-const char * const     dayp;\r
-const char * const     timep;\r
-{\r
-   register const struct lookup *  lp;\r
-   register const char *       cp;\r
-   register char *         dp;\r
-   register char *         ep;\r
-\r
-   if ((lp = byword(monthp, mon_names)) == NULL) {\r
-       error(_("invalid month name"));\r
-       return;\r
-   }\r
-   rp->r_month = lp->l_value;\r
-   rp->r_todisstd = FALSE;\r
-   rp->r_todisgmt = FALSE;\r
-   dp = ecpyalloc(timep);\r
-   if (*dp != '\0') {\r
-       ep = dp + strlen(dp) - 1;\r
-       switch (lowerit(*ep)) {\r
-           case 's':   /* Standard */\r
-               rp->r_todisstd = TRUE;\r
-               rp->r_todisgmt = FALSE;\r
-               *ep = '\0';\r
-               break;\r
-           case 'w':   /* Wall */\r
-               rp->r_todisstd = FALSE;\r
-               rp->r_todisgmt = FALSE;\r
-               *ep = '\0';\r
-               break;\r
-           case 'g':   /* Greenwich */\r
-           case 'u':   /* Universal */\r
-           case 'z':   /* Zulu */\r
-               rp->r_todisstd = TRUE;\r
-               rp->r_todisgmt = TRUE;\r
-               *ep = '\0';\r
-               break;\r
-       }\r
-   }\r
-   rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);\r
-   ifree(dp);\r
-   /*\r
-   ** Year work.\r
-   */\r
-   cp = loyearp;\r
-   lp = byword(cp, begin_years);\r
-   if (lp != NULL) switch ((int) lp->l_value) {\r
-       case YR_MINIMUM:\r
-           rp->r_loyear = INT_MIN;\r
-           break;\r
-       case YR_MAXIMUM:\r
-           rp->r_loyear = INT_MAX;\r
-           break;\r
-       default:    /* "cannot happen" */\r
-           (void) fprintf(stderr,\r
-               _("%s: panic: Invalid l_value %d\n"),\r
-               progname, lp->l_value);\r
-           (void) exit(EXIT_FAILURE);\r
-   } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {\r
-       error(_("invalid starting year"));\r
-       return;\r
-   } else if (noise) {\r
-       if (rp->r_loyear < min_year_representable)\r
-           warning(_("starting year too low to be represented"));\r
-       else if (rp->r_loyear > max_year_representable)\r
-           warning(_("starting year too high to be represented"));\r
-   }\r
-   cp = hiyearp;\r
-   if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {\r
-       case YR_MINIMUM:\r
-           rp->r_hiyear = INT_MIN;\r
-           break;\r
-       case YR_MAXIMUM:\r
-           rp->r_hiyear = INT_MAX;\r
-           break;\r
-       case YR_ONLY:\r
-           rp->r_hiyear = rp->r_loyear;\r
-           break;\r
-       default:    /* "cannot happen" */\r
-           (void) fprintf(stderr,\r
-               _("%s: panic: Invalid l_value %d\n"),\r
-               progname, lp->l_value);\r
-           (void) exit(EXIT_FAILURE);\r
-   } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {\r
-       error(_("invalid ending year"));\r
-       return;\r
-   } else if (noise) {\r
-       if (rp->r_loyear < min_year_representable)\r
-           warning(_("ending year too low to be represented"));\r
-       else if (rp->r_loyear > max_year_representable)\r
-           warning(_("ending year too high to be represented"));\r
-   }\r
-   if (rp->r_loyear > rp->r_hiyear) {\r
-       error(_("starting year greater than ending year"));\r
-       return;\r
-   }\r
-   if (*typep == '\0')\r
-       rp->r_yrtype = NULL;\r
-   else {\r
-       if (rp->r_loyear == rp->r_hiyear) {\r
-           error(_("typed single year"));\r
-           return;\r
-       }\r
-       rp->r_yrtype = ecpyalloc(typep);\r
-   }\r
-   if (rp->r_loyear < min_year && rp->r_loyear > 0)\r
-       min_year = rp->r_loyear;\r
-   /*\r
-   ** Day work.\r
-   ** Accept things such as:\r
-   **  1\r
-   **  last-Sunday\r
-   **  Sun<=20\r
-   **  Sun>=7\r
-   */\r
-   dp = ecpyalloc(dayp);\r
-   if ((lp = byword(dp, lasts)) != NULL) {\r
-       rp->r_dycode = DC_DOWLEQ;\r
-       rp->r_wday = lp->l_value;\r
-       rp->r_dayofmonth = len_months[1][rp->r_month];\r
-   } else {\r
-       if ((ep = strchr(dp, '<')) != 0)\r
-           rp->r_dycode = DC_DOWLEQ;\r
-       else if ((ep = strchr(dp, '>')) != 0)\r
-           rp->r_dycode = DC_DOWGEQ;\r
-       else {\r
-           ep = dp;\r
-           rp->r_dycode = DC_DOM;\r
-       }\r
-       if (rp->r_dycode != DC_DOM) {\r
-           *ep++ = 0;\r
-           if (*ep++ != '=') {\r
-               error(_("invalid day of month"));\r
-               ifree(dp);\r
-               return;\r
-           }\r
-           if ((lp = byword(dp, wday_names)) == NULL) {\r
-               error(_("invalid weekday name"));\r
-               ifree(dp);\r
-               return;\r
-           }\r
-           rp->r_wday = lp->l_value;\r
-       }\r
-       if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||\r
-           rp->r_dayofmonth <= 0 ||\r
-           (rp->r_dayofmonth > len_months[1][rp->r_month])) {\r
-               error(_("invalid day of month"));\r
-               ifree(dp);\r
-               return;\r
-       }\r
-   }\r
-   ifree(dp);\r
-}\r
-\r
-static void\r
-convert(val, buf)\r
-const long val;\r
-char * const   buf;\r
-{\r
-   register int    i;\r
-   register long   shift;\r
-\r
-   for (i = 0, shift = 24; i < 4; ++i, shift -= 8)\r
-       buf[i] = val >> shift;\r
-}\r
-\r
-static void\r
-puttzcode(val, fp)\r
-const long val;\r
-FILE * const   fp;\r
-{\r
-   char    buf[4];\r
-\r
-   convert(val, buf);\r
-   (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);\r
-}\r
-\r
-static int\r
-atcomp(avp, bvp)\r
-void * avp;\r
-void * bvp;\r
-{\r
-   if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)\r
-       return -1;\r
-   else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)\r
-       return 1;\r
-   else    return 0;\r
-}\r
-\r
-static void\r
-writezone(name)\r
-const char * const name;\r
-{\r
-   register FILE *     fp;\r
-   register int        i, j;\r
-   static char *       fullname;\r
-   static struct tzhead    tzh;\r
-   time_t          ats[TZ_MAX_TIMES];\r
-   unsigned char       types[TZ_MAX_TIMES];\r
-\r
-   /*\r
-   ** Sort.\r
-   */\r
-   if (timecnt > 1)\r
-       (void) qsort((void *) attypes, (size_t) timecnt,\r
-           (size_t) sizeof *attypes, atcomp);\r
-   /*\r
-   ** Optimize.\r
-   */\r
-   {\r
-       int fromi;\r
-       int toi;\r
-\r
-       toi = 0;\r
-       fromi = 0;\r
-       while (fromi < timecnt && attypes[fromi].at < min_time)\r
-           ++fromi;\r
-       if (isdsts[0] == 0)\r
-           while (fromi < timecnt && attypes[fromi].type == 0)\r
-               ++fromi;    /* handled by default rule */\r
-       for ( ; fromi < timecnt; ++fromi) {\r
-           if (toi != 0\r
-               && ((attypes[fromi].at\r
-                + gmtoffs[attypes[toi - 1].type])\r
-               <= (attypes[toi - 1].at\r
-                   + gmtoffs[toi == 1 ? 0\r
-                         : attypes[toi - 2].type]))) {\r
-               attypes[toi - 1].type = attypes[fromi].type;\r
-               continue;\r
-           }\r
-           if (toi == 0 ||\r
-               attypes[toi - 1].type != attypes[fromi].type)\r
-                   attypes[toi++] = attypes[fromi];\r
-       }\r
-       timecnt = toi;\r
-   }\r
-   /*\r
-   ** Transfer.\r
-   */\r
-   for (i = 0; i < timecnt; ++i) {\r
-       ats[i] = attypes[i].at;\r
-       types[i] = attypes[i].type;\r
-   }\r
-   fullname = erealloc(fullname,\r
-       (int) (strlen(directory) + 1 + strlen(name) + 1));\r
-   (void) sprintf(fullname, "%s/%s", directory, name);\r
-   /*\r
-   ** Remove old file, if any, to snap links.\r
-   */\r
-   if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {\r
-       const char *e = strerror(errno);\r
-\r
-       (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),\r
-           progname, fullname, e);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   if ((fp = fopen(fullname, "wb")) == NULL) {\r
-       if (mkdirs(fullname) != 0)\r
-           (void) exit(EXIT_FAILURE);\r
-       if ((fp = fopen(fullname, "wb")) == NULL) {\r
-           const char *e = strerror(errno);\r
-\r
-           (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),\r
-               progname, fullname, e);\r
-           (void) exit(EXIT_FAILURE);\r
-       }\r
-   }\r
-   convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);\r
-   convert(eitol(typecnt), tzh.tzh_ttisstdcnt);\r
-   convert(eitol(leapcnt), tzh.tzh_leapcnt);\r
-   convert(eitol(timecnt), tzh.tzh_timecnt);\r
-   convert(eitol(typecnt), tzh.tzh_typecnt);\r
-   convert(eitol(charcnt), tzh.tzh_charcnt);\r
-   (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);\r
-#define DO(field)  (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)\r
-   DO(tzh_magic);\r
-   DO(tzh_reserved);\r
-   DO(tzh_ttisgmtcnt);\r
-   DO(tzh_ttisstdcnt);\r
-   DO(tzh_leapcnt);\r
-   DO(tzh_timecnt);\r
-   DO(tzh_typecnt);\r
-   DO(tzh_charcnt);\r
-#undef DO\r
-   for (i = 0; i < timecnt; ++i) {\r
-       j = leapcnt;\r
-       while (--j >= 0)\r
-           if (ats[i] >= trans[j]) {\r
-               ats[i] = tadd(ats[i], corr[j]);\r
-               break;\r
-           }\r
-       puttzcode((long) ats[i], fp);\r
-   }\r
-   if (timecnt > 0)\r
-       (void) fwrite((void *) types, (size_t) sizeof types[0],\r
-           (size_t) timecnt, fp);\r
-   for (i = 0; i < typecnt; ++i) {\r
-       puttzcode((long) gmtoffs[i], fp);\r
-       (void) putc(isdsts[i], fp);\r
-       (void) putc(abbrinds[i], fp);\r
-   }\r
-   if (charcnt != 0)\r
-       (void) fwrite((void *) chars, (size_t) sizeof chars[0],\r
-           (size_t) charcnt, fp);\r
-   for (i = 0; i < leapcnt; ++i) {\r
-       if (roll[i]) {\r
-           if (timecnt == 0 || trans[i] < ats[0]) {\r
-               j = 0;\r
-               while (isdsts[j])\r
-                   if (++j >= typecnt) {\r
-                       j = 0;\r
-                       break;\r
-                   }\r
-           } else {\r
-               j = 1;\r
-               while (j < timecnt && trans[i] >= ats[j])\r
-                   ++j;\r
-               j = types[j - 1];\r
-           }\r
-           puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);\r
-       } else  puttzcode((long) trans[i], fp);\r
-       puttzcode((long) corr[i], fp);\r
-   }\r
-   for (i = 0; i < typecnt; ++i)\r
-       (void) putc(ttisstds[i], fp);\r
-   for (i = 0; i < typecnt; ++i)\r
-       (void) putc(ttisgmts[i], fp);\r
-   if (ferror(fp) || fclose(fp)) {\r
-       (void) fprintf(stderr, _("%s: Error writing %s\n"),\r
-           progname, fullname);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-}\r
-\r
-static void\r
-doabbr(abbr, format, letters, isdst)\r
-char * const       abbr;\r
-const char * const format;\r
-const char * const letters;\r
-const int      isdst;\r
-{\r
-   if (strchr(format, '/') == NULL) {\r
-       if (letters == NULL)\r
-           (void) strcpy(abbr, format);\r
-       else    (void) sprintf(abbr, format, letters);\r
-   } else if (isdst)\r
-       (void) strcpy(abbr, strchr(format, '/') + 1);\r
-   else {\r
-       (void) strcpy(abbr, format);\r
-       *strchr(abbr, '/') = '\0';\r
-   }\r
-}\r
-\r
-static void\r
-outzone(zpfirst, zonecount)\r
-const struct zone * const  zpfirst;\r
-const int          zonecount;\r
-{\r
-   register const struct zone *    zp;\r
-   register struct rule *      rp;\r
-   register int            i, j;\r
-   register int            usestart, useuntil;\r
-   register time_t         starttime, untiltime;\r
-   register long           gmtoff;\r
-   register long           stdoff;\r
-   register int            year;\r
-   register long           startoff;\r
-   register int            startttisstd;\r
-   register int            startttisgmt;\r
-   register int            type;\r
-   char                startbuf[BUFSIZ];\r
-\r
-   INITIALIZE(untiltime);\r
-   INITIALIZE(starttime);\r
-   /*\r
-   ** Now. . .finally. . .generate some useful data!\r
-   */\r
-   timecnt = 0;\r
-   typecnt = 0;\r
-   charcnt = 0;\r
-   /*\r
-   ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)\r
-   ** for noting the need to unconditionally initialize startttisstd.\r
-   */\r
-   startttisstd = FALSE;\r
-   startttisgmt = FALSE;\r
-   for (i = 0; i < zonecount; ++i) {\r
-       /*\r
-       ** A guess that may well be corrected later.\r
-       */\r
-       stdoff = 0;\r
-       zp = &zpfirst[i];\r
-       usestart = i > 0 && (zp - 1)->z_untiltime > min_time;\r
-       useuntil = i < (zonecount - 1);\r
-       if (useuntil && zp->z_untiltime <= min_time)\r
-           continue;\r
-       gmtoff = zp->z_gmtoff;\r
-       eat(zp->z_filename, zp->z_linenum);\r
-       *startbuf = '\0';\r
-       startoff = zp->z_gmtoff;\r
-       if (zp->z_nrules == 0) {\r
-           stdoff = zp->z_stdoff;\r
-           doabbr(startbuf, zp->z_format,\r
-               (char *) NULL, stdoff != 0);\r
-           type = addtype(oadd(zp->z_gmtoff, stdoff),\r
-               startbuf, stdoff != 0, startttisstd,\r
-               startttisgmt);\r
-           if (usestart) {\r
-               addtt(starttime, type);\r
-               usestart = FALSE;\r
-           } else if (stdoff != 0)\r
-               addtt(min_time, type);\r
-       } else for (year = min_year; year <= max_year; ++year) {\r
-           if (useuntil && year > zp->z_untilrule.r_hiyear)\r
-               break;\r
-           /*\r
-           ** Mark which rules to do in the current year.\r
-           ** For those to do, calculate rpytime(rp, year);\r
-           */\r
-           for (j = 0; j < zp->z_nrules; ++j) {\r
-               rp = &zp->z_rules[j];\r
-               eats(zp->z_filename, zp->z_linenum,\r
-                   rp->r_filename, rp->r_linenum);\r
-               rp->r_todo = year >= rp->r_loyear &&\r
-                       year <= rp->r_hiyear &&\r
-                       yearistype(year, rp->r_yrtype);\r
-               if (rp->r_todo)\r
-                   rp->r_temp = rpytime(rp, year);\r
-           }\r
-           for ( ; ; ) {\r
-               register int    k;\r
-               register time_t jtime, ktime;\r
-               register long   offset;\r
-               char        buf[BUFSIZ];\r
-\r
-               INITIALIZE(ktime);\r
-               if (useuntil) {\r
-                   /*\r
-                   ** Turn untiltime into UTC\r
-                   ** assuming the current gmtoff and\r
-                   ** stdoff values.\r
-                   */\r
-                   untiltime = zp->z_untiltime;\r
-                   if (!zp->z_untilrule.r_todisgmt)\r
-                       untiltime = tadd(untiltime,\r
-                           -gmtoff);\r
-                   if (!zp->z_untilrule.r_todisstd)\r
-                       untiltime = tadd(untiltime,\r
-                           -stdoff);\r
-               }\r
-               /*\r
-               ** Find the rule (of those to do, if any)\r
-               ** that takes effect earliest in the year.\r
-               */\r
-               k = -1;\r
-               for (j = 0; j < zp->z_nrules; ++j) {\r
-                   rp = &zp->z_rules[j];\r
-                   if (!rp->r_todo)\r
-                       continue;\r
-                   eats(zp->z_filename, zp->z_linenum,\r
-                       rp->r_filename, rp->r_linenum);\r
-                   offset = rp->r_todisgmt ? 0 : gmtoff;\r
-                   if (!rp->r_todisstd)\r
-                       offset = oadd(offset, stdoff);\r
-                   jtime = rp->r_temp;\r
-                   if (jtime == min_time ||\r
-                       jtime == max_time)\r
-                           continue;\r
-                   jtime = tadd(jtime, -offset);\r
-                   if (k < 0 || jtime < ktime) {\r
-                       k = j;\r
-                       ktime = jtime;\r
-                   }\r
-               }\r
-               if (k < 0)\r
-                   break;  /* go on to next year */\r
-               rp = &zp->z_rules[k];\r
-               rp->r_todo = FALSE;\r
-               if (useuntil && ktime >= untiltime)\r
-                   break;\r
-               stdoff = rp->r_stdoff;\r
-               if (usestart && ktime == starttime)\r
-                   usestart = FALSE;\r
-               if (usestart) {\r
-                   if (ktime < starttime) {\r
-                       startoff = oadd(zp->z_gmtoff,\r
-                           stdoff);\r
-                       doabbr(startbuf, zp->z_format,\r
-                           rp->r_abbrvar,\r
-                           rp->r_stdoff != 0);\r
-                       continue;\r
-                   }\r
-                   if (*startbuf == '\0' &&\r
-                       startoff == oadd(zp->z_gmtoff,\r
-                       stdoff)) {\r
-                       doabbr(startbuf, zp->z_format,\r
-                           rp->r_abbrvar,\r
-                           rp->r_stdoff != 0);\r
-                   }\r
-               }\r
-               eats(zp->z_filename, zp->z_linenum,\r
-                   rp->r_filename, rp->r_linenum);\r
-               doabbr(buf, zp->z_format, rp->r_abbrvar,\r
-                   rp->r_stdoff != 0);\r
-               offset = oadd(zp->z_gmtoff, rp->r_stdoff);\r
-               type = addtype(offset, buf, rp->r_stdoff != 0,\r
-                   rp->r_todisstd, rp->r_todisgmt);\r
-               addtt(ktime, type);\r
-           }\r
-       }\r
-       if (usestart) {\r
-           if (*startbuf == '\0' &&\r
-               zp->z_format != NULL &&\r
-               strchr(zp->z_format, '%') == NULL &&\r
-               strchr(zp->z_format, '/') == NULL)\r
-                   (void) strcpy(startbuf, zp->z_format);\r
-           eat(zp->z_filename, zp->z_linenum);\r
-           if (*startbuf == '\0')\r
-error(_("can't determine time zone abbreviation to use just after until time"));\r
-           else    addtt(starttime,\r
-                   addtype(startoff, startbuf,\r
-                       startoff != zp->z_gmtoff,\r
-                       startttisstd,\r
-                       startttisgmt));\r
-       }\r
-       /*\r
-       ** Now we may get to set starttime for the next zone line.\r
-       */\r
-       if (useuntil) {\r
-           startttisstd = zp->z_untilrule.r_todisstd;\r
-           startttisgmt = zp->z_untilrule.r_todisgmt;\r
-           starttime = zp->z_untiltime;\r
-           if (!startttisstd)\r
-               starttime = tadd(starttime, -stdoff);\r
-           if (!startttisgmt)\r
-               starttime = tadd(starttime, -gmtoff);\r
-       }\r
-   }\r
-   writezone(zpfirst->z_name);\r
-}\r
-\r
-static void\r
-addtt(starttime, type)\r
-const time_t   starttime;\r
-int        type;\r
-{\r
-   if (starttime <= min_time ||\r
-       (timecnt == 1 && attypes[0].at < min_time)) {\r
-       gmtoffs[0] = gmtoffs[type];\r
-       isdsts[0] = isdsts[type];\r
-       ttisstds[0] = ttisstds[type];\r
-       ttisgmts[0] = ttisgmts[type];\r
-       if (abbrinds[type] != 0)\r
-           (void) strcpy(chars, &chars[abbrinds[type]]);\r
-       abbrinds[0] = 0;\r
-       charcnt = strlen(chars) + 1;\r
-       typecnt = 1;\r
-       timecnt = 0;\r
-       type = 0;\r
-   }\r
-   if (timecnt >= TZ_MAX_TIMES) {\r
-       error(_("too many transitions?!"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   attypes[timecnt].at = starttime;\r
-   attypes[timecnt].type = type;\r
-   ++timecnt;\r
-}\r
-\r
-static int\r
-addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)\r
-const long     gmtoff;\r
-const char * const abbr;\r
-const int      isdst;\r
-const int      ttisstd;\r
-const int      ttisgmt;\r
-{\r
-   register int    i, j;\r
-\r
-   if (isdst != TRUE && isdst != FALSE) {\r
-       error(_("internal error - addtype called with bad isdst"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   if (ttisstd != TRUE && ttisstd != FALSE) {\r
-       error(_("internal error - addtype called with bad ttisstd"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   if (ttisgmt != TRUE && ttisgmt != FALSE) {\r
-       error(_("internal error - addtype called with bad ttisgmt"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   /*\r
-   ** See if there's already an entry for this zone type.\r
-   ** If so, just return its index.\r
-   */\r
-   for (i = 0; i < typecnt; ++i) {\r
-       if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&\r
-           strcmp(abbr, &chars[abbrinds[i]]) == 0 &&\r
-           ttisstd == ttisstds[i] &&\r
-           ttisgmt == ttisgmts[i])\r
-               return i;\r
-   }\r
-   /*\r
-   ** There isn't one; add a new one, unless there are already too\r
-   ** many.\r
-   */\r
-   if (typecnt >= TZ_MAX_TYPES) {\r
-       error(_("too many local time types"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   gmtoffs[i] = gmtoff;\r
-   isdsts[i] = isdst;\r
-   ttisstds[i] = ttisstd;\r
-   ttisgmts[i] = ttisgmt;\r
-\r
-   for (j = 0; j < charcnt; ++j)\r
-       if (strcmp(&chars[j], abbr) == 0)\r
-           break;\r
-   if (j == charcnt)\r
-       newabbr(abbr);\r
-   abbrinds[i] = j;\r
-   ++typecnt;\r
-   return i;\r
-}\r
-\r
-static void\r
-leapadd(t, positive, rolling, count)\r
-const time_t   t;\r
-const int  positive;\r
-const int  rolling;\r
-int        count;\r
-{\r
-   register int    i, j;\r
-\r
-   if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {\r
-       error(_("too many leap seconds"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   for (i = 0; i < leapcnt; ++i)\r
-       if (t <= trans[i]) {\r
-           if (t == trans[i]) {\r
-               error(_("repeated leap second moment"));\r
-               (void) exit(EXIT_FAILURE);\r
-           }\r
-           break;\r
-       }\r
-   do {\r
-       for (j = leapcnt; j > i; --j) {\r
-           trans[j] = trans[j - 1];\r
-           corr[j] = corr[j - 1];\r
-           roll[j] = roll[j - 1];\r
-       }\r
-       trans[i] = t;\r
-       corr[i] = positive ? 1L : eitol(-count);\r
-       roll[i] = rolling;\r
-       ++leapcnt;\r
-   } while (positive && --count != 0);\r
-}\r
-\r
-static void\r
-adjleap P((void))\r
-{\r
-   register int    i;\r
-   register long   last = 0;\r
-\r
-   /*\r
-   ** propagate leap seconds forward\r
-   */\r
-   for (i = 0; i < leapcnt; ++i) {\r
-       trans[i] = tadd(trans[i], last);\r
-       last = corr[i] += last;\r
-   }\r
-}\r
-\r
-static int\r
-yearistype(year, type)\r
-const int      year;\r
-const char * const type;\r
-{\r
-   static char *   buf;\r
-   int     result;\r
-\r
-   if (type == NULL || *type == '\0')\r
-       return TRUE;\r
-   buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));\r
-   (void) sprintf(buf, "%s %d %s", yitcommand, year, type);\r
-   result = system(buf);\r
-   if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {\r
-       case 0:\r
-           return TRUE;\r
-       case 1:\r
-           return FALSE;\r
-   }\r
-   error(_("Wild result from command execution"));\r
-   (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),\r
-       progname, buf, result);\r
-   for ( ; ; )\r
-       (void) exit(EXIT_FAILURE);\r
-}\r
-\r
-static int\r
-lowerit(a)\r
-int    a;\r
-{\r
-   a = (unsigned char) a;\r
-   return (isascii(a) && isupper(a)) ? tolower(a) : a;\r
-}\r
-\r
-static int\r
-ciequal(ap, bp)        /* case-insensitive equality */\r
-register const char *  ap;\r
-register const char *  bp;\r
-{\r
-   while (lowerit(*ap) == lowerit(*bp++))\r
-       if (*ap++ == '\0')\r
-           return TRUE;\r
-   return FALSE;\r
-}\r
-\r
-static int\r
-itsabbr(abbr, word)\r
-register const char *  abbr;\r
-register const char *  word;\r
-{\r
-   if (lowerit(*abbr) != lowerit(*word))\r
-       return FALSE;\r
-   ++word;\r
-   while (*++abbr != '\0')\r
-       do {\r
-           if (*word == '\0')\r
-               return FALSE;\r
-       } while (lowerit(*word++) != lowerit(*abbr));\r
-   return TRUE;\r
-}\r
-\r
-static const struct lookup *\r
-byword(word, table)\r
-register const char * const        word;\r
-register const struct lookup * const   table;\r
-{\r
-   register const struct lookup *  foundlp;\r
-   register const struct lookup *  lp;\r
-\r
-   if (word == NULL || table == NULL)\r
-       return NULL;\r
-   /*\r
-   ** Look for exact match.\r
-   */\r
-   for (lp = table; lp->l_word != NULL; ++lp)\r
-       if (ciequal(word, lp->l_word))\r
-           return lp;\r
-   /*\r
-   ** Look for inexact match.\r
-   */\r
-   foundlp = NULL;\r
-   for (lp = table; lp->l_word != NULL; ++lp)\r
-       if (itsabbr(word, lp->l_word)) {\r
-           if (foundlp == NULL)\r
-               foundlp = lp;\r
-           else    return NULL;    /* multiple inexact matches */\r
-       }\r
-   return foundlp;\r
-}\r
-\r
-static char **\r
-getfields(cp)\r
-register char *    cp;\r
-{\r
-   register char *     dp;\r
-   register char **    array;\r
-   register int        nsubs;\r
-\r
-   if (cp == NULL)\r
-       return NULL;\r
-   array = (char **) (void *)\r
-       emalloc((int) ((strlen(cp) + 1) * sizeof *array));\r
-   nsubs = 0;\r
-   for ( ; ; ) {\r
-       while (isascii(*cp) && isspace((unsigned char) *cp))\r
-           ++cp;\r
-       if (*cp == '\0' || *cp == '#')\r
-           break;\r
-       array[nsubs++] = dp = cp;\r
-       do {\r
-           if ((*dp = *cp++) != '"')\r
-               ++dp;\r
-           else while ((*dp = *cp++) != '"')\r
-               if (*dp != '\0')\r
-                   ++dp;\r
-               else    error(_("Odd number of quotation marks"));\r
-       } while (*cp != '\0' && *cp != '#' &&\r
-           (!isascii(*cp) || !isspace((unsigned char) *cp)));\r
-       if (isascii(*cp) && isspace((unsigned char) *cp))\r
-           ++cp;\r
-       *dp = '\0';\r
-   }\r
-   array[nsubs] = NULL;\r
-   return array;\r
-}\r
-\r
-static long\r
-oadd(t1, t2)\r
-const long t1;\r
-const long t2;\r
-{\r
-   register long   t;\r
-\r
-   t = t1 + t2;\r
-   if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {\r
-       error(_("time overflow"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   return t;\r
-}\r
-\r
-static time_t\r
-tadd(t1, t2)\r
-const time_t   t1;\r
-const long t2;\r
-{\r
-   register time_t t;\r
-\r
-   if (t1 == max_time && t2 > 0)\r
-       return max_time;\r
-   if (t1 == min_time && t2 < 0)\r
-       return min_time;\r
-   t = t1 + t2;\r
-   if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {\r
-       error(_("time overflow"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   return t;\r
-}\r
-\r
-/*\r
-** Given a rule, and a year, compute the date - in seconds since January 1,\r
-** 1970, 00:00 LOCAL time - in that year that the rule refers to.\r
-*/\r
-\r
-static time_t\r
-rpytime(rp, wantedy)\r
-register const struct rule * const rp;\r
-register const int         wantedy;\r
-{\r
-   register int    y, m, i;\r
-   register long   dayoff;         /* with a nod to Margaret O. */\r
-   register time_t t;\r
-\r
-   if (wantedy == INT_MIN)\r
-       return min_time;\r
-   if (wantedy == INT_MAX)\r
-       return max_time;\r
-   dayoff = 0;\r
-   m = TM_JANUARY;\r
-   y = EPOCH_YEAR;\r
-   while (wantedy != y) {\r
-       if (wantedy > y) {\r
-           i = len_years[isleap(y)];\r
-           ++y;\r
-       } else {\r
-           --y;\r
-           i = -len_years[isleap(y)];\r
-       }\r
-       dayoff = oadd(dayoff, eitol(i));\r
-   }\r
-   while (m != rp->r_month) {\r
-       i = len_months[isleap(y)][m];\r
-       dayoff = oadd(dayoff, eitol(i));\r
-       ++m;\r
-   }\r
-   i = rp->r_dayofmonth;\r
-   if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {\r
-       if (rp->r_dycode == DC_DOWLEQ)\r
-           --i;\r
-       else {\r
-           error(_("use of 2/29 in non leap-year"));\r
-           (void) exit(EXIT_FAILURE);\r
-       }\r
-   }\r
-   --i;\r
-   dayoff = oadd(dayoff, eitol(i));\r
-   if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {\r
-       register long   wday;\r
-\r
-#define LDAYSPERWEEK   ((long) DAYSPERWEEK)\r
-       wday = eitol(EPOCH_WDAY);\r
-       /*\r
-       ** Don't trust mod of negative numbers.\r
-       */\r
-       if (dayoff >= 0)\r
-           wday = (wday + dayoff) % LDAYSPERWEEK;\r
-       else {\r
-           wday -= ((-dayoff) % LDAYSPERWEEK);\r
-           if (wday < 0)\r
-               wday += LDAYSPERWEEK;\r
-       }\r
-       while (wday != eitol(rp->r_wday))\r
-           if (rp->r_dycode == DC_DOWGEQ) {\r
-               dayoff = oadd(dayoff, (long) 1);\r
-               if (++wday >= LDAYSPERWEEK)\r
-                   wday = 0;\r
-               ++i;\r
-           } else {\r
-               dayoff = oadd(dayoff, (long) -1);\r
-               if (--wday < 0)\r
-                   wday = LDAYSPERWEEK - 1;\r
-               --i;\r
-           }\r
-       if (i < 0 || i >= len_months[isleap(y)][m]) {\r
-           error(_("no day in month matches rule"));\r
-           (void) exit(EXIT_FAILURE);\r
-       }\r
-   }\r
-   if (dayoff < 0 && !TYPE_SIGNED(time_t))\r
-       return min_time;\r
-   if (dayoff < min_time / SECSPERDAY)\r
-       return min_time;\r
-   if (dayoff > max_time / SECSPERDAY)\r
-       return max_time;\r
-   t = (time_t) dayoff * SECSPERDAY;\r
-   return tadd(t, rp->r_tod);\r
-}\r
-\r
-static void\r
-newabbr(string)\r
-const char * const string;\r
-{\r
-   register int    i;\r
-\r
-   i = strlen(string) + 1;\r
-   if (charcnt + i > TZ_MAX_CHARS) {\r
-       error(_("too many, or too long, time zone abbreviations"));\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   (void) strcpy(&chars[charcnt], string);\r
-   charcnt += eitol(i);\r
-}\r
-\r
-static int\r
-mkdirs(argname)\r
-char * const   argname;\r
-{\r
-   register char * name;\r
-   register char * cp;\r
-\r
-   if (argname == NULL || *argname == '\0')\r
-       return 0;\r
-   cp = name = ecpyalloc(argname);\r
-   while ((cp = strchr(cp + 1, '/')) != 0) {\r
-       *cp = '\0';\r
-#ifndef unix\r
-       /*\r
-       ** DOS drive specifier?\r
-       */\r
-       if (isalpha((unsigned char) name[0]) &&\r
-           name[1] == ':' && name[2] == '\0') {\r
-               *cp = '/';\r
-               continue;\r
-       }\r
-#endif /* !defined unix */\r
-       if (!itsdir(name)) {\r
-           /*\r
-           ** It doesn't seem to exist, so we try to create it.\r
-           ** Creation may fail because of the directory being\r
-           ** created by some other multiprocessor, so we get\r
-           ** to do extra checking.\r
-           */\r
-           if (mkdir(name, MKDIR_UMASK) != 0) {\r
-               const char *e = strerror(errno);\r
-\r
-               if (errno != EEXIST || !itsdir(name)) {\r
-                   (void) fprintf(stderr,\r
-_("%s: Can't create directory %s: %s\n"),\r
-                       progname, name, e);\r
-                   ifree(name);\r
-                   return -1;\r
-               }\r
-           }\r
-       }\r
-       *cp = '/';\r
-   }\r
-   ifree(name);\r
-   return 0;\r
-}\r
-\r
-static long\r
-eitol(i)\r
-const int  i;\r
-{\r
-   long    l;\r
-\r
-   l = i;\r
-   if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {\r
-       (void) fprintf(stderr,\r
-           _("%s: %d did not sign extend correctly\n"),\r
-           progname, i);\r
-       (void) exit(EXIT_FAILURE);\r
-   }\r
-   return l;\r
-}\r
-\r
-/*\r
-** UNIX was a registered trademark of The Open Group in 2003.\r
-*/\r
-\r
-\r
-#ifdef WIN32\r
-/*\r
- * To run on win32 \r
- */\r
-int link(const char *oldpath, const char *newpath) {\r
-   if (!CopyFileEx(oldpath, newpath, NULL, NULL, FALSE, 0)) {\r
-       return -1;\r
-   }\r
-   return 0;\r
-}\r
-#endif\r
+static char    elsieid[] = "@(#)zic.c  7.115";
+#include "pgtz.h"
+#undef unlink
+#undef TZDIR
+#define TZDIR "data"
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "private.h"
+#include "locale.h"
+#include "tzfile.h"
+
+#if HAVE_SYS_STAT_H
+#include "sys/stat.h"
+#endif
+#ifndef WIN32
+#ifdef S_IRUSR
+#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+#else
+#define MKDIR_UMASK 0755
+#endif
+#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.
+** If isascii is not defined, the isascii check succeeds trivially.
+*/
+#include "ctype.h"
+#ifndef isascii
+#define isascii(x) 1
+#endif
+
+struct rule {
+   const char *    r_filename;
+   int     r_linenum;
+   const char *    r_name;
+
+   int     r_loyear;   /* for example, 1986 */
+   int     r_hiyear;   /* for example, 1986 */
+   const char *    r_yrtype;
+
+   int     r_month;    /* 0..11 */
+
+   int     r_dycode;   /* see below */
+   int     r_dayofmonth;
+   int     r_wday;
+
+   long        r_tod;      /* time from midnight */
+   int     r_todisstd; /* above is standard time if TRUE */
+                   /* or wall clock time if FALSE */
+   int     r_todisgmt; /* above is GMT if TRUE */
+                   /* or local time if FALSE */
+   long        r_stdoff;   /* offset from standard time */
+   const char *    r_abbrvar;  /* variable part of abbreviation */
+
+   int     r_todo;     /* a rule to do (used in outzone) */
+   time_t      r_temp;     /* used in outzone */
+};
+
+/*
+** r_dycode        r_dayofmonth    r_wday
+*/
+
+#define DC_DOM     0   /* 1..31 */ /* unused */
+#define DC_DOWGEQ  1   /* 1..31 */ /* 0..6 (Sun..Sat) */
+#define DC_DOWLEQ  2   /* 1..31 */ /* 0..6 (Sun..Sat) */
+
+struct zone {
+   const char *    z_filename;
+   int     z_linenum;
+
+   const char *    z_name;
+   long        z_gmtoff;
+   const char *    z_rule;
+   const char *    z_format;
+
+   long        z_stdoff;
+
+   struct rule *   z_rules;
+   int     z_nrules;
+
+   struct rule z_untilrule;
+   time_t      z_untiltime;
+};
+
+extern int getopt P((int argc, char * const argv[],
+           const char * options));
+extern int link P((const char * fromname, const char * toname));
+extern char *  optarg;
+extern int optind;
+
+static void    addtt P((time_t starttime, int type));
+static int addtype P((long gmtoff, const char * abbr, int isdst,
+               int ttisstd, int ttisgmt));
+static void    leapadd P((time_t t, int positive, int rolling, int count));
+static void    adjleap P((void));
+static void    associate P((void));
+static int ciequal P((const char * ap, const char * bp));
+static void    convert P((long val, char * buf));
+static void    dolink P((const char * fromfile, const char * tofile));
+static void    doabbr P((char * abbr, const char * format,
+           const char * letters, int isdst));
+static void    eat P((const char * name, int num));
+static void    eats P((const char * name, int num,
+           const char * rname, int rnum));
+static long    eitol P((int i));
+static void    error P((const char * message));
+static char ** getfields P((char * buf));
+static long    gethms P((const char * string, const char * errstrng,
+           int signable));
+static void    infile P((const char * filename));
+static void    inleap P((char ** fields, int nfields));
+static void    inlink P((char ** fields, int nfields));
+static void    inrule P((char ** fields, int nfields));
+static int inzcont P((char ** fields, int nfields));
+static int inzone P((char ** fields, int nfields));
+static int inzsub P((char ** fields, int nfields, int iscont));
+static int itsabbr P((const char * abbr, const char * word));
+static int itsdir P((const char * name));
+static int lowerit P((int c));
+static char *  memcheck P((char * tocheck));
+static int mkdirs P((char * filename));
+static void    newabbr P((const char * abbr));
+static long    oadd P((long t1, long t2));
+static void    outzone P((const struct zone * zp, int ntzones));
+static void    puttzcode P((long code, FILE * fp));
+static int rcomp P((const void * leftp, const void * rightp));
+static time_t  rpytime P((const struct rule * rp, int wantedy));
+static void    rulesub P((struct rule * rp,
+           const char * loyearp, const char * hiyearp,
+           const char * typep, const char * monthp,
+           const char * dayp, const char * timep));
+static void    setboundaries P((void));
+static time_t  tadd P((time_t t1, long t2));
+static void    usage P((void));
+static void    writezone P((const char * name));
+static int yearistype P((int year, const char * type));
+
+#if !(HAVE_STRERROR - 0)
+static char *  strerror P((int));
+#endif /* !(HAVE_STRERROR - 0) */
+
+static int     charcnt;
+static int     errors;
+static const char *    filename;
+static int     leapcnt;
+static int     linenum;
+static time_t      max_time;
+static int     max_year;
+static int     max_year_representable;
+static time_t      min_time;
+static int     min_year;
+static int     min_year_representable;
+static int     noise;
+static const char *    rfilename;
+static int     rlinenum;
+static const char *    progname;
+static int     timecnt;
+static int     typecnt;
+
+/*
+** Line codes.
+*/
+
+#define LC_RULE        0
+#define LC_ZONE        1
+#define LC_LINK        2
+#define LC_LEAP        3
+
+/*
+** Which fields are which on a Zone line.
+*/
+
+#define ZF_NAME        1
+#define ZF_GMTOFF  2
+#define ZF_RULE        3
+#define ZF_FORMAT  4
+#define ZF_TILYEAR 5
+#define ZF_TILMONTH    6
+#define ZF_TILDAY  7
+#define ZF_TILTIME 8
+#define ZONE_MINFIELDS 5
+#define ZONE_MAXFIELDS 9
+
+/*
+** Which fields are which on a Zone continuation line.
+*/
+
+#define ZFC_GMTOFF 0
+#define ZFC_RULE   1
+#define ZFC_FORMAT 2
+#define ZFC_TILYEAR    3
+#define ZFC_TILMONTH   4
+#define ZFC_TILDAY 5
+#define ZFC_TILTIME    6
+#define ZONEC_MINFIELDS    3
+#define ZONEC_MAXFIELDS    7
+
+/*
+** Which files are which on a Rule line.
+*/
+
+#define RF_NAME        1
+#define RF_LOYEAR  2
+#define RF_HIYEAR  3
+#define RF_COMMAND 4
+#define RF_MONTH   5
+#define RF_DAY     6
+#define RF_TOD     7
+#define RF_STDOFF  8
+#define RF_ABBRVAR 9
+#define RULE_FIELDS    10
+
+/*
+** Which fields are which on a Link line.
+*/
+
+#define LF_FROM        1
+#define LF_TO      2
+#define LINK_FIELDS    3
+
+/*
+** Which fields are which on a Leap line.
+*/
+
+#define LP_YEAR        1
+#define LP_MONTH   2
+#define LP_DAY     3
+#define LP_TIME        4
+#define LP_CORR        5
+#define LP_ROLL        6
+#define LEAP_FIELDS    7
+
+/*
+** Year synonyms.
+*/
+
+#define YR_MINIMUM 0
+#define YR_MAXIMUM 1
+#define YR_ONLY        2
+
+static struct rule *   rules;
+static int     nrules; /* number of rules */
+
+static struct zone *   zones;
+static int     nzones; /* number of zones */
+
+struct link {
+   const char *    l_filename;
+   int     l_linenum;
+   const char *    l_from;
+   const char *    l_to;
+};
+
+static struct link *   links;
+static int     nlinks;
+
+struct lookup {
+   const char *    l_word;
+   const int   l_value;
+};
+
+static struct lookup const *   byword P((const char * string,
+                   const struct lookup * lp));
+
+static struct lookup const line_codes[] = {
+   { "Rule",   LC_RULE },
+   { "Zone",   LC_ZONE },
+   { "Link",   LC_LINK },
+   { "Leap",   LC_LEAP },
+   { NULL,     0}
+};
+
+static struct lookup const mon_names[] = {
+   { "January",    TM_JANUARY },
+   { "February",   TM_FEBRUARY },
+   { "March",  TM_MARCH },
+   { "April",  TM_APRIL },
+   { "May",    TM_MAY },
+   { "June",   TM_JUNE },
+   { "July",   TM_JULY },
+   { "August", TM_AUGUST },
+   { "September",  TM_SEPTEMBER },
+   { "October",    TM_OCTOBER },
+   { "November",   TM_NOVEMBER },
+   { "December",   TM_DECEMBER },
+   { NULL,     0 }
+};
+
+static struct lookup const wday_names[] = {
+   { "Sunday", TM_SUNDAY },
+   { "Monday", TM_MONDAY },
+   { "Tuesday",    TM_TUESDAY },
+   { "Wednesday",  TM_WEDNESDAY },
+   { "Thursday",   TM_THURSDAY },
+   { "Friday", TM_FRIDAY },
+   { "Saturday",   TM_SATURDAY },
+   { NULL,     0 }
+};
+
+static struct lookup const lasts[] = {
+   { "last-Sunday",    TM_SUNDAY },
+   { "last-Monday",    TM_MONDAY },
+   { "last-Tuesday",   TM_TUESDAY },
+   { "last-Wednesday", TM_WEDNESDAY },
+   { "last-Thursday",  TM_THURSDAY },
+   { "last-Friday",    TM_FRIDAY },
+   { "last-Saturday",  TM_SATURDAY },
+   { NULL,         0 }
+};
+
+static struct lookup const begin_years[] = {
+   { "minimum",    YR_MINIMUM },
+   { "maximum",    YR_MAXIMUM },
+   { NULL,     0 }
+};
+
+static struct lookup const end_years[] = {
+   { "minimum",    YR_MINIMUM },
+   { "maximum",    YR_MAXIMUM },
+   { "only",   YR_ONLY },
+   { NULL,     0 }
+};
+
+static struct lookup const leap_types[] = {
+   { "Rolling",    TRUE },
+   { "Stationary", FALSE },
+   { NULL,     0 }
+};
+
+static const int   len_months[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 }
+};
+
+static const int   len_years[2] = {
+   DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+static struct attype {
+   time_t      at;
+   unsigned char   type;
+}          attypes[TZ_MAX_TIMES];
+static long        gmtoffs[TZ_MAX_TYPES];
+static char        isdsts[TZ_MAX_TYPES];
+static unsigned char   abbrinds[TZ_MAX_TYPES];
+static char        ttisstds[TZ_MAX_TYPES];
+static char        ttisgmts[TZ_MAX_TYPES];
+static char        chars[TZ_MAX_CHARS];
+static time_t      trans[TZ_MAX_LEAPS];
+static long        corr[TZ_MAX_LEAPS];
+static char        roll[TZ_MAX_LEAPS];
+
+/*
+** Memory allocation.
+*/
+
+static char *
+memcheck(ptr)
+char * const   ptr;
+{
+   if (ptr == NULL) {
+       const char *e = strerror(errno);
+
+       (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
+           progname, e);
+       (void) exit(EXIT_FAILURE);
+   }
+   return ptr;
+}
+
+#define emalloc(size)      memcheck(imalloc(size))
+#define erealloc(ptr, size)    memcheck(irealloc((ptr), (size)))
+#define ecpyalloc(ptr)     memcheck(icpyalloc(ptr))
+#define ecatalloc(oldp, newp)  memcheck(icatalloc((oldp), (newp)))
+
+/*
+** Error handling.
+*/
+
+#if !(HAVE_STRERROR - 0)
+static char *
+strerror(errnum)
+int    errnum;
+{
+   extern char *   sys_errlist[];
+   extern int  sys_nerr;
+
+   return (errnum > 0 && errnum <= sys_nerr) ?
+       sys_errlist[errnum] : _("Unknown system error");
+}
+#endif /* !(HAVE_STRERROR - 0) */
+
+static void
+eats(name, num, rname, rnum)
+const char * const name;
+const int      num;
+const char * const rname;
+const int      rnum;
+{
+   filename = name;
+   linenum = num;
+   rfilename = rname;
+   rlinenum = rnum;
+}
+
+static void
+eat(name, num)
+const char * const name;
+const int      num;
+{
+   eats(name, num, (char *) NULL, -1);
+}
+
+static void
+error(string)
+const char * const string;
+{
+   /*
+   ** Match the format of "cc" to allow sh users to
+   **  zic ... 2>&1 | error -t "*" -v
+   ** on BSD systems.
+   */
+   (void) fprintf(stderr, _("\"%s\", line %d: %s"),
+       filename, linenum, string);
+   if (rfilename != NULL)
+       (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
+           rfilename, rlinenum);
+   (void) fprintf(stderr, "\n");
+   ++errors;
+}
+
+static void
+warning(string)
+const char * const string;
+{
+   char *  cp;
+
+   cp = ecpyalloc(_("warning: "));
+   cp = ecatalloc(cp, string);
+   error(cp);
+   ifree(cp);
+   --errors;
+}
+
+static void
+usage P((void))
+{
+   (void) fprintf(stderr, _("%s: usage is %s [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
+       progname, progname);
+   (void) exit(EXIT_FAILURE);
+}
+
+static const char *    psxrules;
+static const char *    lcltime;
+static const char *    directory;
+static const char *    leapsec;
+static const char *    yitcommand;
+static int     sflag = FALSE;
+
+int
+main(argc, argv)
+int    argc;
+char * argv[];
+{
+   register int    i;
+   register int    j;
+   register int    c;
+
+#ifdef unix
+   (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
+#endif /* defined unix */
+#if HAVE_GETTEXT - 0
+   (void) setlocale(LC_MESSAGES, "");
+#ifdef TZ_DOMAINDIR
+   (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined TEXTDOMAINDIR */
+   (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT - 0 */
+   progname = argv[0];
+   for (i = 1; i < argc; ++i)
+       if (strcmp(argv[i], "--version") == 0) {
+           (void) printf("%s\n", elsieid);
+           (void) exit(EXIT_SUCCESS);
+       }
+   while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
+       switch (c) {
+           default:
+               usage();
+           case 'd':
+               if (directory == NULL)
+                   directory = optarg;
+               else {
+                   (void) fprintf(stderr,
+_("%s: More than one -d option specified\n"),
+                       progname);
+                   (void) exit(EXIT_FAILURE);
+               }
+               break;
+           case 'l':
+               if (lcltime == NULL)
+                   lcltime = optarg;
+               else {
+                   (void) fprintf(stderr,
+_("%s: More than one -l option specified\n"),
+                       progname);
+                   (void) exit(EXIT_FAILURE);
+               }
+               break;
+           case 'p':
+               if (psxrules == NULL)
+                   psxrules = optarg;
+               else {
+                   (void) fprintf(stderr,
+_("%s: More than one -p option specified\n"),
+                       progname);
+                   (void) exit(EXIT_FAILURE);
+               }
+               break;
+           case 'y':
+               if (yitcommand == NULL)
+                   yitcommand = optarg;
+               else {
+                   (void) fprintf(stderr,
+_("%s: More than one -y option specified\n"),
+                       progname);
+                   (void) exit(EXIT_FAILURE);
+               }
+               break;
+           case 'L':
+               if (leapsec == NULL)
+                   leapsec = optarg;
+               else {
+                   (void) fprintf(stderr,
+_("%s: More than one -L option specified\n"),
+                       progname);
+                   (void) exit(EXIT_FAILURE);
+               }
+               break;
+           case 'v':
+               noise = TRUE;
+               break;
+           case 's':
+               sflag = TRUE;
+               break;
+       }
+   if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
+       usage();    /* usage message by request */
+   if (directory == NULL)
+       directory = TZDIR;
+   if (yitcommand == NULL)
+       yitcommand = "yearistype";
+
+   setboundaries();
+
+   if (optind < argc && leapsec != NULL) {
+       infile(leapsec);
+       adjleap();
+   }
+
+   for (i = optind; i < argc; ++i)
+       infile(argv[i]);
+   if (errors)
+       (void) exit(EXIT_FAILURE);
+   associate();
+   for (i = 0; i < nzones; i = j) {
+       /*
+       ** Find the next non-continuation zone entry.
+       */
+       for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
+           continue;
+       outzone(&zones[i], j - i);
+   }
+   /*
+   ** Make links.
+   */
+   for (i = 0; i < nlinks; ++i) {
+       eat(links[i].l_filename, links[i].l_linenum);
+       dolink(links[i].l_from, links[i].l_to);
+   }
+   if (lcltime != NULL) {
+       eat("command line", 1);
+       dolink(lcltime, TZDEFAULT);
+   }
+   if (psxrules != NULL) {
+       eat("command line", 1);
+       dolink(psxrules, TZDEFRULES);
+   }
+   return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+dolink(fromfile, tofile)
+const char * const fromfile;
+const char * const tofile;
+{
+   register char * fromname;
+   register char * toname;
+
+   if (fromfile[0] == '/')
+       fromname = ecpyalloc(fromfile);
+   else {
+       fromname = ecpyalloc(directory);
+       fromname = ecatalloc(fromname, "/");
+       fromname = ecatalloc(fromname, fromfile);
+   }
+   if (tofile[0] == '/')
+       toname = ecpyalloc(tofile);
+   else {
+       toname = ecpyalloc(directory);
+       toname = ecatalloc(toname, "/");
+       toname = ecatalloc(toname, tofile);
+   }
+   /*
+   ** We get to be careful here since
+   ** there's a fair chance of root running us.
+   */
+   if (!itsdir(toname))
+       (void) remove(toname);
+   if (link(fromname, toname) != 0) {
+       int result;
+
+       if (mkdirs(toname) != 0)
+           (void) exit(EXIT_FAILURE);
+
+       result = link(fromname, toname);
+#if (HAVE_SYMLINK - 0)
+       if (result != 0 &&
+           access(fromname, F_OK) == 0 &&
+           !itsdir(fromname)) {
+               const char *s = tofile;
+               register char * symlinkcontents = NULL;
+               while ((s = strchr(s+1, '/')) != NULL)
+                   symlinkcontents = ecatalloc(symlinkcontents, "../");
+           symlinkcontents = ecatalloc(symlinkcontents, fromfile);
+
+           result = symlink(symlinkcontents, toname);
+           if (result == 0)
+warning(_("hard link failed, symbolic link used"));
+           ifree(symlinkcontents);
+       }
+#endif
+       if (result != 0) {
+           const char *e = strerror(errno);
+
+           (void) fprintf(stderr,
+               _("%s: Can't link from %s to %s: %s\n"),
+               progname, fromname, toname, e);
+           (void) exit(EXIT_FAILURE);
+       }
+   }
+   ifree(fromname);
+   ifree(toname);
+}
+
+#ifndef INT_MAX
+#define INT_MAX    ((int) (((unsigned)~0)>>1))
+#endif /* !defined INT_MAX */
+
+#ifndef INT_MIN
+#define INT_MIN    ((int) ~(((unsigned)~0)>>1))
+#endif /* !defined INT_MIN */
+
+/*
+** The tz file format currently allows at most 32-bit quantities.
+** This restriction should be removed before signed 32-bit values
+** wrap around in 2038, but unfortunately this will require a
+** change to the tz file format.
+*/
+
+#define MAX_BITS_IN_FILE   32
+#define TIME_T_BITS_IN_FILE    ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)
+
+static void
+setboundaries P((void))
+{
+   if (TYPE_SIGNED(time_t)) {
+       min_time = ~ (time_t) 0;
+       min_time <<= TIME_T_BITS_IN_FILE - 1;
+       max_time = ~ (time_t) 0 - min_time;
+       if (sflag)
+           min_time = 0;
+   } else {
+       min_time = 0;
+       max_time = 2 - sflag;
+       max_time <<= TIME_T_BITS_IN_FILE - 1;
+       --max_time;
+   }
+   min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
+   max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+   min_year_representable = min_year;
+   max_year_representable = max_year;
+}
+
+static int
+itsdir(name)
+const char * const name;
+{
+   register char * myname;
+   register int    accres;
+
+   myname = ecpyalloc(name);
+   myname = ecatalloc(myname, "/.");
+   accres = access(myname, F_OK);
+   ifree(myname);
+   return accres == 0;
+}
+
+/*
+** Associate sets of rules with zones.
+*/
+
+/*
+** Sort by rule name.
+*/
+
+static int
+rcomp(cp1, cp2)
+const void *   cp1;
+const void *   cp2;
+{
+   return strcmp(((const struct rule *) cp1)->r_name,
+       ((const struct rule *) cp2)->r_name);
+}
+
+static void
+associate P((void))
+{
+   register struct zone *  zp;
+   register struct rule *  rp;
+   register int        base, out;
+   register int        i, j;
+
+   if (nrules != 0) {
+       (void) qsort((void *) rules, (size_t) nrules,
+           (size_t) sizeof *rules, rcomp);
+       for (i = 0; i < nrules - 1; ++i) {
+           if (strcmp(rules[i].r_name,
+               rules[i + 1].r_name) != 0)
+                   continue;
+           if (strcmp(rules[i].r_filename,
+               rules[i + 1].r_filename) == 0)
+                   continue;
+           eat(rules[i].r_filename, rules[i].r_linenum);
+           warning(_("same rule name in multiple files"));
+           eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
+           warning(_("same rule name in multiple files"));
+           for (j = i + 2; j < nrules; ++j) {
+               if (strcmp(rules[i].r_name,
+                   rules[j].r_name) != 0)
+                       break;
+               if (strcmp(rules[i].r_filename,
+                   rules[j].r_filename) == 0)
+                       continue;
+               if (strcmp(rules[i + 1].r_filename,
+                   rules[j].r_filename) == 0)
+                       continue;
+               break;
+           }
+           i = j - 1;
+       }
+   }
+   for (i = 0; i < nzones; ++i) {
+       zp = &zones[i];
+       zp->z_rules = NULL;
+       zp->z_nrules = 0;
+   }
+   for (base = 0; base < nrules; base = out) {
+       rp = &rules[base];
+       for (out = base + 1; out < nrules; ++out)
+           if (strcmp(rp->r_name, rules[out].r_name) != 0)
+               break;
+       for (i = 0; i < nzones; ++i) {
+           zp = &zones[i];
+           if (strcmp(zp->z_rule, rp->r_name) != 0)
+               continue;
+           zp->z_rules = rp;
+           zp->z_nrules = out - base;
+       }
+   }
+   for (i = 0; i < nzones; ++i) {
+       zp = &zones[i];
+       if (zp->z_nrules == 0) {
+           /*
+           ** Maybe we have a local standard time offset.
+           */
+           eat(zp->z_filename, zp->z_linenum);
+           zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
+                         TRUE);
+           /*
+           ** Note, though, that if there's no rule,
+           ** a '%s' in the format is a bad thing.
+           */
+           if (strchr(zp->z_format, '%') != 0)
+               error(_("%s in ruleless zone"));
+       }
+   }
+   if (errors)
+       (void) exit(EXIT_FAILURE);
+}
+
+static void
+infile(name)
+const char *   name;
+{
+   register FILE *         fp;
+   register char **        fields;
+   register char *         cp;
+   register const struct lookup *  lp;
+   register int            nfields;
+   register int            wantcont;
+   register int            num;
+   char                buf[BUFSIZ];
+
+   if (strcmp(name, "-") == 0) {
+       name = _("standard input");
+       fp = stdin;
+   } else if ((fp = fopen(name, "r")) == NULL) {
+       const char *e = strerror(errno);
+
+       (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
+           progname, name, e);
+       (void) exit(EXIT_FAILURE);
+   }
+   wantcont = FALSE;
+   for (num = 1; ; ++num) {
+       eat(name, num);
+       if (fgets(buf, (int) sizeof buf, fp) != buf)
+           break;
+       cp = strchr(buf, '\n');
+       if (cp == NULL) {
+           error(_("line too long"));
+           (void) exit(EXIT_FAILURE);
+       }
+       *cp = '\0';
+       fields = getfields(buf);
+       nfields = 0;
+       while (fields[nfields] != NULL) {
+           static char nada;
+
+           if (strcmp(fields[nfields], "-") == 0)
+               fields[nfields] = &nada;
+           ++nfields;
+       }
+       if (nfields == 0) {
+           /* nothing to do */
+       } else if (wantcont) {
+           wantcont = inzcont(fields, nfields);
+       } else {
+           lp = byword(fields[0], line_codes);
+           if (lp == NULL)
+               error(_("input line of unknown type"));
+           else switch ((int) (lp->l_value)) {
+               case LC_RULE:
+                   inrule(fields, nfields);
+                   wantcont = FALSE;
+                   break;
+               case LC_ZONE:
+                   wantcont = inzone(fields, nfields);
+                   break;
+               case LC_LINK:
+                   inlink(fields, nfields);
+                   wantcont = FALSE;
+                   break;
+               case LC_LEAP:
+                   if (name != leapsec)
+                       (void) fprintf(stderr,
+_("%s: Leap line in non leap seconds file %s\n"),
+                           progname, name);
+                   else    inleap(fields, nfields);
+                   wantcont = FALSE;
+                   break;
+               default:    /* "cannot happen" */
+                   (void) fprintf(stderr,
+_("%s: panic: Invalid l_value %d\n"),
+                       progname, lp->l_value);
+                   (void) exit(EXIT_FAILURE);
+           }
+       }
+       ifree((char *) fields);
+   }
+   if (ferror(fp)) {
+       (void) fprintf(stderr, _("%s: Error reading %s\n"),
+           progname, filename);
+       (void) exit(EXIT_FAILURE);
+   }
+   if (fp != stdin && fclose(fp)) {
+       const char *e = strerror(errno);
+
+       (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
+           progname, filename, e);
+       (void) exit(EXIT_FAILURE);
+   }
+   if (wantcont)
+       error(_("expected continuation line not found"));
+}
+
+/*
+** Convert a string of one of the forms
+** h   -h  hh:mm   -hh:mm  hh:mm:ss    -hh:mm:ss
+** into a number of seconds.
+** A null string maps to zero.
+** Call error with errstring and return zero on errors.
+*/
+
+static long
+gethms(string, errstring, signable)
+const char *       string;
+const char * const errstring;
+const int      signable;
+{
+   int hh, mm, ss, sign;
+
+   if (string == NULL || *string == '\0')
+       return 0;
+   if (!signable)
+       sign = 1;
+   else if (*string == '-') {
+       sign = -1;
+       ++string;
+   } else  sign = 1;
+   if (sscanf(string, scheck(string, "%d"), &hh) == 1)
+       mm = ss = 0;
+   else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
+       ss = 0;
+   else if (sscanf(string, scheck(string, "%d:%d:%d"),
+       &hh, &mm, &ss) != 3) {
+           error(errstring);
+           return 0;
+   }
+   if ((hh < 0 || hh >= HOURSPERDAY ||
+       mm < 0 || mm >= MINSPERHOUR ||
+       ss < 0 || ss > SECSPERMIN) &&
+       !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {
+           error(errstring);
+           return 0;
+   }
+   if (noise && hh == HOURSPERDAY)
+       warning(_("24:00 not handled by pre-1998 versions of zic"));
+   return eitol(sign) *
+       (eitol(hh * MINSPERHOUR + mm) *
+       eitol(SECSPERMIN) + eitol(ss));
+}
+
+static void
+inrule(fields, nfields)
+register char ** const fields;
+const int      nfields;
+{
+   static struct rule  r;
+
+   if (nfields != RULE_FIELDS) {
+       error(_("wrong number of fields on Rule line"));
+       return;
+   }
+   if (*fields[RF_NAME] == '\0') {
+       error(_("nameless rule"));
+       return;
+   }
+   r.r_filename = filename;
+   r.r_linenum = linenum;
+   r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
+   rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
+       fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
+   r.r_name = ecpyalloc(fields[RF_NAME]);
+   r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+   rules = (struct rule *) (void *) erealloc((char *) rules,
+       (int) ((nrules + 1) * sizeof *rules));
+   rules[nrules++] = r;
+}
+
+static int
+inzone(fields, nfields)
+register char ** const fields;
+const int      nfields;
+{
+   register int    i;
+   static char *   buf;
+
+   if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
+       error(_("wrong number of fields on Zone line"));
+       return FALSE;
+   }
+   if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
+       buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
+       (void) sprintf(buf,
+_("\"Zone %s\" line and -l option are mutually exclusive"),
+           TZDEFAULT);
+       error(buf);
+       return FALSE;
+   }
+   if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
+       buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
+       (void) sprintf(buf,
+_("\"Zone %s\" line and -p option are mutually exclusive"),
+           TZDEFRULES);
+       error(buf);
+       return FALSE;
+   }
+   for (i = 0; i < nzones; ++i)
+       if (zones[i].z_name != NULL &&
+           strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
+               buf = erealloc(buf, (int) (132 +
+                   strlen(fields[ZF_NAME]) +
+                   strlen(zones[i].z_filename)));
+               (void) sprintf(buf,
+_("duplicate zone name %s (file \"%s\", line %d)"),
+                   fields[ZF_NAME],
+                   zones[i].z_filename,
+                   zones[i].z_linenum);
+               error(buf);
+               return FALSE;
+       }
+   return inzsub(fields, nfields, FALSE);
+}
+
+static int
+inzcont(fields, nfields)
+register char ** const fields;
+const int      nfields;
+{
+   if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
+       error(_("wrong number of fields on Zone continuation line"));
+       return FALSE;
+   }
+   return inzsub(fields, nfields, TRUE);
+}
+
+static int
+inzsub(fields, nfields, iscont)
+register char ** const fields;
+const int      nfields;
+const int      iscont;
+{
+   register char *     cp;
+   static struct zone  z;
+   register int        i_gmtoff, i_rule, i_format;
+   register int        i_untilyear, i_untilmonth;
+   register int        i_untilday, i_untiltime;
+   register int        hasuntil;
+
+   if (iscont) {
+       i_gmtoff = ZFC_GMTOFF;
+       i_rule = ZFC_RULE;
+       i_format = ZFC_FORMAT;
+       i_untilyear = ZFC_TILYEAR;
+       i_untilmonth = ZFC_TILMONTH;
+       i_untilday = ZFC_TILDAY;
+       i_untiltime = ZFC_TILTIME;
+       z.z_name = NULL;
+   } else {
+       i_gmtoff = ZF_GMTOFF;
+       i_rule = ZF_RULE;
+       i_format = ZF_FORMAT;
+       i_untilyear = ZF_TILYEAR;
+       i_untilmonth = ZF_TILMONTH;
+       i_untilday = ZF_TILDAY;
+       i_untiltime = ZF_TILTIME;
+       z.z_name = ecpyalloc(fields[ZF_NAME]);
+   }
+   z.z_filename = filename;
+   z.z_linenum = linenum;
+   z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
+   if ((cp = strchr(fields[i_format], '%')) != 0) {
+       if (*++cp != 's' || strchr(cp, '%') != 0) {
+           error(_("invalid abbreviation format"));
+           return FALSE;
+       }
+   }
+   z.z_rule = ecpyalloc(fields[i_rule]);
+   z.z_format = ecpyalloc(fields[i_format]);
+   hasuntil = nfields > i_untilyear;
+   if (hasuntil) {
+       z.z_untilrule.r_filename = filename;
+       z.z_untilrule.r_linenum = linenum;
+       rulesub(&z.z_untilrule,
+           fields[i_untilyear],
+           "only",
+           "",
+           (nfields > i_untilmonth) ?
+           fields[i_untilmonth] : "Jan",
+           (nfields > i_untilday) ? fields[i_untilday] : "1",
+           (nfields > i_untiltime) ? fields[i_untiltime] : "0");
+       z.z_untiltime = rpytime(&z.z_untilrule,
+           z.z_untilrule.r_loyear);
+       if (iscont && nzones > 0 &&
+           z.z_untiltime > min_time &&
+           z.z_untiltime < max_time &&
+           zones[nzones - 1].z_untiltime > min_time &&
+           zones[nzones - 1].z_untiltime < max_time &&
+           zones[nzones - 1].z_untiltime >= z.z_untiltime) {
+               error(_("Zone continuation line end time is not after end time of previous line"));
+               return FALSE;
+       }
+   }
+   zones = (struct zone *) (void *) erealloc((char *) zones,
+       (int) ((nzones + 1) * sizeof *zones));
+   zones[nzones++] = z;
+   /*
+   ** If there was an UNTIL field on this line,
+   ** there's more information about the zone on the next line.
+   */
+   return hasuntil;
+}
+
+static void
+inleap(fields, nfields)
+register char ** const fields;
+const int      nfields;
+{
+   register const char *       cp;
+   register const struct lookup *  lp;
+   register int            i, j;
+   int             year, month, day;
+   long                dayoff, tod;
+   time_t              t;
+
+   if (nfields != LEAP_FIELDS) {
+       error(_("wrong number of fields on Leap line"));
+       return;
+   }
+   dayoff = 0;
+   cp = fields[LP_YEAR];
+   if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
+           /*
+            * Leapin' Lizards!
+            */
+           error(_("invalid leaping year"));
+           return;
+   }
+   j = EPOCH_YEAR;
+   while (j != year) {
+       if (year > j) {
+           i = len_years[isleap(j)];
+           ++j;
+       } else {
+           --j;
+           i = -len_years[isleap(j)];
+       }
+       dayoff = oadd(dayoff, eitol(i));
+   }
+   if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
+       error(_("invalid month name"));
+       return;
+   }
+   month = lp->l_value;
+   j = TM_JANUARY;
+   while (j != month) {
+       i = len_months[isleap(year)][j];
+       dayoff = oadd(dayoff, eitol(i));
+       ++j;
+   }
+   cp = fields[LP_DAY];
+   if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
+       day <= 0 || day > len_months[isleap(year)][month]) {
+           error(_("invalid day of month"));
+           return;
+   }
+   dayoff = oadd(dayoff, eitol(day - 1));
+   if (dayoff < 0 && !TYPE_SIGNED(time_t)) {
+       error(_("time before zero"));
+       return;
+   }
+   if (dayoff < min_time / SECSPERDAY) {
+       error(_("time too small"));
+       return;
+   }
+   if (dayoff > max_time / SECSPERDAY) {
+       error(_("time too large"));
+       return;
+   }
+   t = (time_t) dayoff * SECSPERDAY;
+   tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
+   cp = fields[LP_CORR];
+   {
+       register int    positive;
+       int     count;
+
+       if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
+           positive = FALSE;
+           count = 1;
+       } else if (strcmp(cp, "--") == 0) {
+           positive = FALSE;
+           count = 2;
+       } else if (strcmp(cp, "+") == 0) {
+           positive = TRUE;
+           count = 1;
+       } else if (strcmp(cp, "++") == 0) {
+           positive = TRUE;
+           count = 2;
+       } else {
+           error(_("illegal CORRECTION field on Leap line"));
+           return;
+       }
+       if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
+           error(_("illegal Rolling/Stationary field on Leap line"));
+           return;
+       }
+       leapadd(tadd(t, tod), positive, lp->l_value, count);
+   }
+}
+
+static void
+inlink(fields, nfields)
+register char ** const fields;
+const int      nfields;
+{
+   struct link l;
+
+   if (nfields != LINK_FIELDS) {
+       error(_("wrong number of fields on Link line"));
+       return;
+   }
+   if (*fields[LF_FROM] == '\0') {
+       error(_("blank FROM field on Link line"));
+       return;
+   }
+   if (*fields[LF_TO] == '\0') {
+       error(_("blank TO field on Link line"));
+       return;
+   }
+   l.l_filename = filename;
+   l.l_linenum = linenum;
+   l.l_from = ecpyalloc(fields[LF_FROM]);
+   l.l_to = ecpyalloc(fields[LF_TO]);
+   links = (struct link *) (void *) erealloc((char *) links,
+       (int) ((nlinks + 1) * sizeof *links));
+   links[nlinks++] = l;
+}
+
+static void
+rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
+register struct rule * const   rp;
+const char * const     loyearp;
+const char * const     hiyearp;
+const char * const     typep;
+const char * const     monthp;
+const char * const     dayp;
+const char * const     timep;
+{
+   register const struct lookup *  lp;
+   register const char *       cp;
+   register char *         dp;
+   register char *         ep;
+
+   if ((lp = byword(monthp, mon_names)) == NULL) {
+       error(_("invalid month name"));
+       return;
+   }
+   rp->r_month = lp->l_value;
+   rp->r_todisstd = FALSE;
+   rp->r_todisgmt = FALSE;
+   dp = ecpyalloc(timep);
+   if (*dp != '\0') {
+       ep = dp + strlen(dp) - 1;
+       switch (lowerit(*ep)) {
+           case 's':   /* Standard */
+               rp->r_todisstd = TRUE;
+               rp->r_todisgmt = FALSE;
+               *ep = '\0';
+               break;
+           case 'w':   /* Wall */
+               rp->r_todisstd = FALSE;
+               rp->r_todisgmt = FALSE;
+               *ep = '\0';
+               break;
+           case 'g':   /* Greenwich */
+           case 'u':   /* Universal */
+           case 'z':   /* Zulu */
+               rp->r_todisstd = TRUE;
+               rp->r_todisgmt = TRUE;
+               *ep = '\0';
+               break;
+       }
+   }
+   rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
+   ifree(dp);
+   /*
+   ** Year work.
+   */
+   cp = loyearp;
+   lp = byword(cp, begin_years);
+   if (lp != NULL) switch ((int) lp->l_value) {
+       case YR_MINIMUM:
+           rp->r_loyear = INT_MIN;
+           break;
+       case YR_MAXIMUM:
+           rp->r_loyear = INT_MAX;
+           break;
+       default:    /* "cannot happen" */
+           (void) fprintf(stderr,
+               _("%s: panic: Invalid l_value %d\n"),
+               progname, lp->l_value);
+           (void) exit(EXIT_FAILURE);
+   } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
+       error(_("invalid starting year"));
+       return;
+   } else if (noise) {
+       if (rp->r_loyear < min_year_representable)
+           warning(_("starting year too low to be represented"));
+       else if (rp->r_loyear > max_year_representable)
+           warning(_("starting year too high to be represented"));
+   }
+   cp = hiyearp;
+   if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
+       case YR_MINIMUM:
+           rp->r_hiyear = INT_MIN;
+           break;
+       case YR_MAXIMUM:
+           rp->r_hiyear = INT_MAX;
+           break;
+       case YR_ONLY:
+           rp->r_hiyear = rp->r_loyear;
+           break;
+       default:    /* "cannot happen" */
+           (void) fprintf(stderr,
+               _("%s: panic: Invalid l_value %d\n"),
+               progname, lp->l_value);
+           (void) exit(EXIT_FAILURE);
+   } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
+       error(_("invalid ending year"));
+       return;
+   } else if (noise) {
+       if (rp->r_loyear < min_year_representable)
+           warning(_("ending year too low to be represented"));
+       else if (rp->r_loyear > max_year_representable)
+           warning(_("ending year too high to be represented"));
+   }
+   if (rp->r_loyear > rp->r_hiyear) {
+       error(_("starting year greater than ending year"));
+       return;
+   }
+   if (*typep == '\0')
+       rp->r_yrtype = NULL;
+   else {
+       if (rp->r_loyear == rp->r_hiyear) {
+           error(_("typed single year"));
+           return;
+       }
+       rp->r_yrtype = ecpyalloc(typep);
+   }
+   if (rp->r_loyear < min_year && rp->r_loyear > 0)
+       min_year = rp->r_loyear;
+   /*
+   ** Day work.
+   ** Accept things such as:
+   **  1
+   **  last-Sunday
+   **  Sun<=20
+   **  Sun>=7
+   */
+   dp = ecpyalloc(dayp);
+   if ((lp = byword(dp, lasts)) != NULL) {
+       rp->r_dycode = DC_DOWLEQ;
+       rp->r_wday = lp->l_value;
+       rp->r_dayofmonth = len_months[1][rp->r_month];
+   } else {
+       if ((ep = strchr(dp, '<')) != 0)
+           rp->r_dycode = DC_DOWLEQ;
+       else if ((ep = strchr(dp, '>')) != 0)
+           rp->r_dycode = DC_DOWGEQ;
+       else {
+           ep = dp;
+           rp->r_dycode = DC_DOM;
+       }
+       if (rp->r_dycode != DC_DOM) {
+           *ep++ = 0;
+           if (*ep++ != '=') {
+               error(_("invalid day of month"));
+               ifree(dp);
+               return;
+           }
+           if ((lp = byword(dp, wday_names)) == NULL) {
+               error(_("invalid weekday name"));
+               ifree(dp);
+               return;
+           }
+           rp->r_wday = lp->l_value;
+       }
+       if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
+           rp->r_dayofmonth <= 0 ||
+           (rp->r_dayofmonth > len_months[1][rp->r_month])) {
+               error(_("invalid day of month"));
+               ifree(dp);
+               return;
+       }
+   }
+   ifree(dp);
+}
+
+static void
+convert(val, buf)
+const long val;
+char * const   buf;
+{
+   register int    i;
+   register long   shift;
+
+   for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
+       buf[i] = val >> shift;
+}
+
+static void
+puttzcode(val, fp)
+const long val;
+FILE * const   fp;
+{
+   char    buf[4];
+
+   convert(val, buf);
+   (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+}
+
+static int
+atcomp(avp, bvp)
+void * avp;
+void * bvp;
+{
+   if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
+       return -1;
+   else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
+       return 1;
+   else    return 0;
+}
+
+static void
+writezone(name)
+const char * const name;
+{
+   register FILE *     fp;
+   register int        i, j;
+   static char *       fullname;
+   static struct tzhead    tzh;
+   time_t          ats[TZ_MAX_TIMES];
+   unsigned char       types[TZ_MAX_TIMES];
+
+   /*
+   ** Sort.
+   */
+   if (timecnt > 1)
+       (void) qsort((void *) attypes, (size_t) timecnt,
+           (size_t) sizeof *attypes, atcomp);
+   /*
+   ** Optimize.
+   */
+   {
+       int fromi;
+       int toi;
+
+       toi = 0;
+       fromi = 0;
+       while (fromi < timecnt && attypes[fromi].at < min_time)
+           ++fromi;
+       if (isdsts[0] == 0)
+           while (fromi < timecnt && attypes[fromi].type == 0)
+               ++fromi;    /* handled by default rule */
+       for ( ; fromi < timecnt; ++fromi) {
+           if (toi != 0
+               && ((attypes[fromi].at
+                + gmtoffs[attypes[toi - 1].type])
+               <= (attypes[toi - 1].at
+                   + gmtoffs[toi == 1 ? 0
+                         : attypes[toi - 2].type]))) {
+               attypes[toi - 1].type = attypes[fromi].type;
+               continue;
+           }
+           if (toi == 0 ||
+               attypes[toi - 1].type != attypes[fromi].type)
+                   attypes[toi++] = attypes[fromi];
+       }
+       timecnt = toi;
+   }
+   /*
+   ** Transfer.
+   */
+   for (i = 0; i < timecnt; ++i) {
+       ats[i] = attypes[i].at;
+       types[i] = attypes[i].type;
+   }
+   fullname = erealloc(fullname,
+       (int) (strlen(directory) + 1 + strlen(name) + 1));
+   (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);
+
+       (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
+           progname, fullname, e);
+       (void) exit(EXIT_FAILURE);
+   }
+   if ((fp = fopen(fullname, "wb")) == NULL) {
+       if (mkdirs(fullname) != 0)
+           (void) exit(EXIT_FAILURE);
+       if ((fp = fopen(fullname, "wb")) == NULL) {
+           const char *e = strerror(errno);
+
+           (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
+               progname, fullname, e);
+           (void) exit(EXIT_FAILURE);
+       }
+   }
+   convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
+   convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
+   convert(eitol(leapcnt), tzh.tzh_leapcnt);
+   convert(eitol(timecnt), tzh.tzh_timecnt);
+   convert(eitol(typecnt), tzh.tzh_typecnt);
+   convert(eitol(charcnt), tzh.tzh_charcnt);
+   (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
+#define DO(field)  (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
+   DO(tzh_magic);
+   DO(tzh_reserved);
+   DO(tzh_ttisgmtcnt);
+   DO(tzh_ttisstdcnt);
+   DO(tzh_leapcnt);
+   DO(tzh_timecnt);
+   DO(tzh_typecnt);
+   DO(tzh_charcnt);
+#undef DO
+   for (i = 0; i < timecnt; ++i) {
+       j = leapcnt;
+       while (--j >= 0)
+           if (ats[i] >= trans[j]) {
+               ats[i] = tadd(ats[i], corr[j]);
+               break;
+           }
+       puttzcode((long) ats[i], fp);
+   }
+   if (timecnt > 0)
+       (void) fwrite((void *) types, (size_t) sizeof types[0],
+           (size_t) timecnt, fp);
+   for (i = 0; i < typecnt; ++i) {
+       puttzcode((long) gmtoffs[i], fp);
+       (void) putc(isdsts[i], fp);
+       (void) putc(abbrinds[i], fp);
+   }
+   if (charcnt != 0)
+       (void) fwrite((void *) chars, (size_t) sizeof chars[0],
+           (size_t) charcnt, fp);
+   for (i = 0; i < leapcnt; ++i) {
+       if (roll[i]) {
+           if (timecnt == 0 || trans[i] < ats[0]) {
+               j = 0;
+               while (isdsts[j])
+                   if (++j >= typecnt) {
+                       j = 0;
+                       break;
+                   }
+           } else {
+               j = 1;
+               while (j < timecnt && trans[i] >= ats[j])
+                   ++j;
+               j = types[j - 1];
+           }
+           puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
+       } else  puttzcode((long) trans[i], fp);
+       puttzcode((long) corr[i], fp);
+   }
+   for (i = 0; i < typecnt; ++i)
+       (void) putc(ttisstds[i], fp);
+   for (i = 0; i < typecnt; ++i)
+       (void) putc(ttisgmts[i], fp);
+   if (ferror(fp) || fclose(fp)) {
+       (void) fprintf(stderr, _("%s: Error writing %s\n"),
+           progname, fullname);
+       (void) exit(EXIT_FAILURE);
+   }
+}
+
+static void
+doabbr(abbr, format, letters, isdst)
+char * const       abbr;
+const char * const format;
+const char * const letters;
+const int      isdst;
+{
+   if (strchr(format, '/') == NULL) {
+       if (letters == NULL)
+           (void) strcpy(abbr, format);
+       else    (void) sprintf(abbr, format, letters);
+   } else if (isdst)
+       (void) strcpy(abbr, strchr(format, '/') + 1);
+   else {
+       (void) strcpy(abbr, format);
+       *strchr(abbr, '/') = '\0';
+   }
+}
+
+static void
+outzone(zpfirst, zonecount)
+const struct zone * const  zpfirst;
+const int          zonecount;
+{
+   register const struct zone *    zp;
+   register struct rule *      rp;
+   register int            i, j;
+   register int            usestart, useuntil;
+   register time_t         starttime, untiltime;
+   register long           gmtoff;
+   register long           stdoff;
+   register int            year;
+   register long           startoff;
+   register int            startttisstd;
+   register int            startttisgmt;
+   register int            type;
+   char                startbuf[BUFSIZ];
+
+   INITIALIZE(untiltime);
+   INITIALIZE(starttime);
+   /*
+   ** Now. . .finally. . .generate some useful data!
+   */
+   timecnt = 0;
+   typecnt = 0;
+   charcnt = 0;
+   /*
+   ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
+   ** for noting the need to unconditionally initialize startttisstd.
+   */
+   startttisstd = FALSE;
+   startttisgmt = FALSE;
+   for (i = 0; i < zonecount; ++i) {
+       /*
+       ** A guess that may well be corrected later.
+       */
+       stdoff = 0;
+       zp = &zpfirst[i];
+       usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
+       useuntil = i < (zonecount - 1);
+       if (useuntil && zp->z_untiltime <= min_time)
+           continue;
+       gmtoff = zp->z_gmtoff;
+       eat(zp->z_filename, zp->z_linenum);
+       *startbuf = '\0';
+       startoff = zp->z_gmtoff;
+       if (zp->z_nrules == 0) {
+           stdoff = zp->z_stdoff;
+           doabbr(startbuf, zp->z_format,
+               (char *) NULL, stdoff != 0);
+           type = addtype(oadd(zp->z_gmtoff, stdoff),
+               startbuf, stdoff != 0, startttisstd,
+               startttisgmt);
+           if (usestart) {
+               addtt(starttime, type);
+               usestart = FALSE;
+           } else if (stdoff != 0)
+               addtt(min_time, type);
+       } else for (year = min_year; year <= max_year; ++year) {
+           if (useuntil && year > zp->z_untilrule.r_hiyear)
+               break;
+           /*
+           ** Mark which rules to do in the current year.
+           ** For those to do, calculate rpytime(rp, year);
+           */
+           for (j = 0; j < zp->z_nrules; ++j) {
+               rp = &zp->z_rules[j];
+               eats(zp->z_filename, zp->z_linenum,
+                   rp->r_filename, rp->r_linenum);
+               rp->r_todo = year >= rp->r_loyear &&
+                       year <= rp->r_hiyear &&
+                       yearistype(year, rp->r_yrtype);
+               if (rp->r_todo)
+                   rp->r_temp = rpytime(rp, year);
+           }
+           for ( ; ; ) {
+               register int    k;
+               register time_t jtime, ktime;
+               register long   offset;
+               char        buf[BUFSIZ];
+
+               INITIALIZE(ktime);
+               if (useuntil) {
+                   /*
+                   ** Turn untiltime into UTC
+                   ** assuming the current gmtoff and
+                   ** stdoff values.
+                   */
+                   untiltime = zp->z_untiltime;
+                   if (!zp->z_untilrule.r_todisgmt)
+                       untiltime = tadd(untiltime,
+                           -gmtoff);
+                   if (!zp->z_untilrule.r_todisstd)
+                       untiltime = tadd(untiltime,
+                           -stdoff);
+               }
+               /*
+               ** Find the rule (of those to do, if any)
+               ** that takes effect earliest in the year.
+               */
+               k = -1;
+               for (j = 0; j < zp->z_nrules; ++j) {
+                   rp = &zp->z_rules[j];
+                   if (!rp->r_todo)
+                       continue;
+                   eats(zp->z_filename, zp->z_linenum,
+                       rp->r_filename, rp->r_linenum);
+                   offset = rp->r_todisgmt ? 0 : gmtoff;
+                   if (!rp->r_todisstd)
+                       offset = oadd(offset, stdoff);
+                   jtime = rp->r_temp;
+                   if (jtime == min_time ||
+                       jtime == max_time)
+                           continue;
+                   jtime = tadd(jtime, -offset);
+                   if (k < 0 || jtime < ktime) {
+                       k = j;
+                       ktime = jtime;
+                   }
+               }
+               if (k < 0)
+                   break;  /* go on to next year */
+               rp = &zp->z_rules[k];
+               rp->r_todo = FALSE;
+               if (useuntil && ktime >= untiltime)
+                   break;
+               stdoff = rp->r_stdoff;
+               if (usestart && ktime == starttime)
+                   usestart = FALSE;
+               if (usestart) {
+                   if (ktime < starttime) {
+                       startoff = oadd(zp->z_gmtoff,
+                           stdoff);
+                       doabbr(startbuf, zp->z_format,
+                           rp->r_abbrvar,
+                           rp->r_stdoff != 0);
+                       continue;
+                   }
+                   if (*startbuf == '\0' &&
+                       startoff == oadd(zp->z_gmtoff,
+                       stdoff)) {
+                       doabbr(startbuf, zp->z_format,
+                           rp->r_abbrvar,
+                           rp->r_stdoff != 0);
+                   }
+               }
+               eats(zp->z_filename, zp->z_linenum,
+                   rp->r_filename, rp->r_linenum);
+               doabbr(buf, zp->z_format, rp->r_abbrvar,
+                   rp->r_stdoff != 0);
+               offset = oadd(zp->z_gmtoff, rp->r_stdoff);
+               type = addtype(offset, buf, rp->r_stdoff != 0,
+                   rp->r_todisstd, rp->r_todisgmt);
+               addtt(ktime, type);
+           }
+       }
+       if (usestart) {
+           if (*startbuf == '\0' &&
+               zp->z_format != NULL &&
+               strchr(zp->z_format, '%') == NULL &&
+               strchr(zp->z_format, '/') == NULL)
+                   (void) strcpy(startbuf, zp->z_format);
+           eat(zp->z_filename, zp->z_linenum);
+           if (*startbuf == '\0')
+error(_("can't determine time zone abbreviation to use just after until time"));
+           else    addtt(starttime,
+                   addtype(startoff, startbuf,
+                       startoff != zp->z_gmtoff,
+                       startttisstd,
+                       startttisgmt));
+       }
+       /*
+       ** Now we may get to set starttime for the next zone line.
+       */
+       if (useuntil) {
+           startttisstd = zp->z_untilrule.r_todisstd;
+           startttisgmt = zp->z_untilrule.r_todisgmt;
+           starttime = zp->z_untiltime;
+           if (!startttisstd)
+               starttime = tadd(starttime, -stdoff);
+           if (!startttisgmt)
+               starttime = tadd(starttime, -gmtoff);
+       }
+   }
+   writezone(zpfirst->z_name);
+}
+
+static void
+addtt(starttime, type)
+const time_t   starttime;
+int        type;
+{
+   if (starttime <= min_time ||
+       (timecnt == 1 && attypes[0].at < min_time)) {
+       gmtoffs[0] = gmtoffs[type];
+       isdsts[0] = isdsts[type];
+       ttisstds[0] = ttisstds[type];
+       ttisgmts[0] = ttisgmts[type];
+       if (abbrinds[type] != 0)
+           (void) strcpy(chars, &chars[abbrinds[type]]);
+       abbrinds[0] = 0;
+       charcnt = strlen(chars) + 1;
+       typecnt = 1;
+       timecnt = 0;
+       type = 0;
+   }
+   if (timecnt >= TZ_MAX_TIMES) {
+       error(_("too many transitions?!"));
+       (void) exit(EXIT_FAILURE);
+   }
+   attypes[timecnt].at = starttime;
+   attypes[timecnt].type = type;
+   ++timecnt;
+}
+
+static int
+addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
+const long     gmtoff;
+const char * const abbr;
+const int      isdst;
+const int      ttisstd;
+const int      ttisgmt;
+{
+   register int    i, j;
+
+   if (isdst != TRUE && isdst != FALSE) {
+       error(_("internal error - addtype called with bad isdst"));
+       (void) exit(EXIT_FAILURE);
+   }
+   if (ttisstd != TRUE && ttisstd != FALSE) {
+       error(_("internal error - addtype called with bad ttisstd"));
+       (void) exit(EXIT_FAILURE);
+   }
+   if (ttisgmt != TRUE && ttisgmt != FALSE) {
+       error(_("internal error - addtype called with bad ttisgmt"));
+       (void) exit(EXIT_FAILURE);
+   }
+   /*
+   ** See if there's already an entry for this zone type.
+   ** If so, just return its index.
+   */
+   for (i = 0; i < typecnt; ++i) {
+       if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
+           strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
+           ttisstd == ttisstds[i] &&
+           ttisgmt == ttisgmts[i])
+               return i;
+   }
+   /*
+   ** There isn't one; add a new one, unless there are already too
+   ** many.
+   */
+   if (typecnt >= TZ_MAX_TYPES) {
+       error(_("too many local time types"));
+       (void) exit(EXIT_FAILURE);
+   }
+   gmtoffs[i] = gmtoff;
+   isdsts[i] = isdst;
+   ttisstds[i] = ttisstd;
+   ttisgmts[i] = ttisgmt;
+
+   for (j = 0; j < charcnt; ++j)
+       if (strcmp(&chars[j], abbr) == 0)
+           break;
+   if (j == charcnt)
+       newabbr(abbr);
+   abbrinds[i] = j;
+   ++typecnt;
+   return i;
+}
+
+static void
+leapadd(t, positive, rolling, count)
+const time_t   t;
+const int  positive;
+const int  rolling;
+int        count;
+{
+   register int    i, j;
+
+   if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
+       error(_("too many leap seconds"));
+       (void) exit(EXIT_FAILURE);
+   }
+   for (i = 0; i < leapcnt; ++i)
+       if (t <= trans[i]) {
+           if (t == trans[i]) {
+               error(_("repeated leap second moment"));
+               (void) exit(EXIT_FAILURE);
+           }
+           break;
+       }
+   do {
+       for (j = leapcnt; j > i; --j) {
+           trans[j] = trans[j - 1];
+           corr[j] = corr[j - 1];
+           roll[j] = roll[j - 1];
+       }
+       trans[i] = t;
+       corr[i] = positive ? 1L : eitol(-count);
+       roll[i] = rolling;
+       ++leapcnt;
+   } while (positive && --count != 0);
+}
+
+static void
+adjleap P((void))
+{
+   register int    i;
+   register long   last = 0;
+
+   /*
+   ** propagate leap seconds forward
+   */
+   for (i = 0; i < leapcnt; ++i) {
+       trans[i] = tadd(trans[i], last);
+       last = corr[i] += last;
+   }
+}
+
+static int
+yearistype(year, type)
+const int      year;
+const char * const type;
+{
+   static char *   buf;
+   int     result;
+
+   if (type == NULL || *type == '\0')
+       return TRUE;
+   buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
+   (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
+   result = system(buf);
+   if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
+       case 0:
+           return TRUE;
+       case 1:
+           return FALSE;
+   }
+   error(_("Wild result from command execution"));
+   (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
+       progname, buf, result);
+   for ( ; ; )
+       (void) exit(EXIT_FAILURE);
+}
+
+static int
+lowerit(a)
+int    a;
+{
+   a = (unsigned char) a;
+   return (isascii(a) && isupper(a)) ? tolower(a) : a;
+}
+
+static int
+ciequal(ap, bp)        /* case-insensitive equality */
+register const char *  ap;
+register const char *  bp;
+{
+   while (lowerit(*ap) == lowerit(*bp++))
+       if (*ap++ == '\0')
+           return TRUE;
+   return FALSE;
+}
+
+static int
+itsabbr(abbr, word)
+register const char *  abbr;
+register const char *  word;
+{
+   if (lowerit(*abbr) != lowerit(*word))
+       return FALSE;
+   ++word;
+   while (*++abbr != '\0')
+       do {
+           if (*word == '\0')
+               return FALSE;
+       } while (lowerit(*word++) != lowerit(*abbr));
+   return TRUE;
+}
+
+static const struct lookup *
+byword(word, table)
+register const char * const        word;
+register const struct lookup * const   table;
+{
+   register const struct lookup *  foundlp;
+   register const struct lookup *  lp;
+
+   if (word == NULL || table == NULL)
+       return NULL;
+   /*
+   ** Look for exact match.
+   */
+   for (lp = table; lp->l_word != NULL; ++lp)
+       if (ciequal(word, lp->l_word))
+           return lp;
+   /*
+   ** Look for inexact match.
+   */
+   foundlp = NULL;
+   for (lp = table; lp->l_word != NULL; ++lp)
+       if (itsabbr(word, lp->l_word)) {
+           if (foundlp == NULL)
+               foundlp = lp;
+           else    return NULL;    /* multiple inexact matches */
+       }
+   return foundlp;
+}
+
+static char **
+getfields(cp)
+register char *    cp;
+{
+   register char *     dp;
+   register char **    array;
+   register int        nsubs;
+
+   if (cp == NULL)
+       return NULL;
+   array = (char **) (void *)
+       emalloc((int) ((strlen(cp) + 1) * sizeof *array));
+   nsubs = 0;
+   for ( ; ; ) {
+       while (isascii(*cp) && isspace((unsigned char) *cp))
+           ++cp;
+       if (*cp == '\0' || *cp == '#')
+           break;
+       array[nsubs++] = dp = cp;
+       do {
+           if ((*dp = *cp++) != '"')
+               ++dp;
+           else while ((*dp = *cp++) != '"')
+               if (*dp != '\0')
+                   ++dp;
+               else    error(_("Odd number of quotation marks"));
+       } while (*cp != '\0' && *cp != '#' &&
+           (!isascii(*cp) || !isspace((unsigned char) *cp)));
+       if (isascii(*cp) && isspace((unsigned char) *cp))
+           ++cp;
+       *dp = '\0';
+   }
+   array[nsubs] = NULL;
+   return array;
+}
+
+static long
+oadd(t1, t2)
+const long t1;
+const long t2;
+{
+   register long   t;
+
+   t = t1 + t2;
+   if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+       error(_("time overflow"));
+       (void) exit(EXIT_FAILURE);
+   }
+   return t;
+}
+
+static time_t
+tadd(t1, t2)
+const time_t   t1;
+const long t2;
+{
+   register time_t t;
+
+   if (t1 == max_time && t2 > 0)
+       return max_time;
+   if (t1 == min_time && t2 < 0)
+       return min_time;
+   t = t1 + t2;
+   if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+       error(_("time overflow"));
+       (void) exit(EXIT_FAILURE);
+   }
+   return t;
+}
+
+/*
+** Given a rule, and a year, compute the date - in seconds since January 1,
+** 1970, 00:00 LOCAL time - in that year that the rule refers to.
+*/
+
+static time_t
+rpytime(rp, wantedy)
+register const struct rule * const rp;
+register const int         wantedy;
+{
+   register int    y, m, i;
+   register long   dayoff;         /* with a nod to Margaret O. */
+   register time_t t;
+
+   if (wantedy == INT_MIN)
+       return min_time;
+   if (wantedy == INT_MAX)
+       return max_time;
+   dayoff = 0;
+   m = TM_JANUARY;
+   y = EPOCH_YEAR;
+   while (wantedy != y) {
+       if (wantedy > y) {
+           i = len_years[isleap(y)];
+           ++y;
+       } else {
+           --y;
+           i = -len_years[isleap(y)];
+       }
+       dayoff = oadd(dayoff, eitol(i));
+   }
+   while (m != rp->r_month) {
+       i = len_months[isleap(y)][m];
+       dayoff = oadd(dayoff, eitol(i));
+       ++m;
+   }
+   i = rp->r_dayofmonth;
+   if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
+       if (rp->r_dycode == DC_DOWLEQ)
+           --i;
+       else {
+           error(_("use of 2/29 in non leap-year"));
+           (void) exit(EXIT_FAILURE);
+       }
+   }
+   --i;
+   dayoff = oadd(dayoff, eitol(i));
+   if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
+       register long   wday;
+
+#define LDAYSPERWEEK   ((long) DAYSPERWEEK)
+       wday = eitol(EPOCH_WDAY);
+       /*
+       ** Don't trust mod of negative numbers.
+       */
+       if (dayoff >= 0)
+           wday = (wday + dayoff) % LDAYSPERWEEK;
+       else {
+           wday -= ((-dayoff) % LDAYSPERWEEK);
+           if (wday < 0)
+               wday += LDAYSPERWEEK;
+       }
+       while (wday != eitol(rp->r_wday))
+           if (rp->r_dycode == DC_DOWGEQ) {
+               dayoff = oadd(dayoff, (long) 1);
+               if (++wday >= LDAYSPERWEEK)
+                   wday = 0;
+               ++i;
+           } else {
+               dayoff = oadd(dayoff, (long) -1);
+               if (--wday < 0)
+                   wday = LDAYSPERWEEK - 1;
+               --i;
+           }
+       if (i < 0 || i >= len_months[isleap(y)][m]) {
+           error(_("no day in month matches rule"));
+           (void) exit(EXIT_FAILURE);
+       }
+   }
+   if (dayoff < 0 && !TYPE_SIGNED(time_t))
+       return min_time;
+   if (dayoff < min_time / SECSPERDAY)
+       return min_time;
+   if (dayoff > max_time / SECSPERDAY)
+       return max_time;
+   t = (time_t) dayoff * SECSPERDAY;
+   return tadd(t, rp->r_tod);
+}
+
+static void
+newabbr(string)
+const char * const string;
+{
+   register int    i;
+
+   i = strlen(string) + 1;
+   if (charcnt + i > TZ_MAX_CHARS) {
+       error(_("too many, or too long, time zone abbreviations"));
+       (void) exit(EXIT_FAILURE);
+   }
+   (void) strcpy(&chars[charcnt], string);
+   charcnt += eitol(i);
+}
+
+static int
+mkdirs(argname)
+char * const   argname;
+{
+   register char * name;
+   register char * cp;
+
+   if (argname == NULL || *argname == '\0')
+       return 0;
+   cp = name = ecpyalloc(argname);
+   while ((cp = strchr(cp + 1, '/')) != 0) {
+       *cp = '\0';
+#ifndef unix
+       /*
+       ** DOS drive specifier?
+       */
+       if (isalpha((unsigned char) name[0]) &&
+           name[1] == ':' && name[2] == '\0') {
+               *cp = '/';
+               continue;
+       }
+#endif /* !defined unix */
+       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);
+                   ifree(name);
+                   return -1;
+               }
+           }
+       }
+       *cp = '/';
+   }
+   ifree(name);
+   return 0;
+}
+
+static long
+eitol(i)
+const int  i;
+{
+   long    l;
+
+   l = i;
+   if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
+       (void) fprintf(stderr,
+           _("%s: %d did not sign extend correctly\n"),
+           progname, i);
+       (void) exit(EXIT_FAILURE);
+   }
+   return l;
+}
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+
+#ifdef WIN32
+/*
+ * To run on win32 
+ */
+int link(const char *oldpath, const char *newpath) {
+   if (!CopyFileEx(oldpath, newpath, NULL, NULL, FALSE, 0)) {
+       return -1;
+   }
+   return 0;
+}
+#endif