[BACK]Return to zic.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libc/time/zic.c between version 1.24 and 1.25

version 1.24, 2009/04/23 01:39:47 version 1.25, 2009/12/31 22:49:16
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   /*
   ** This file is in the public domain, so clarified as of
   ** 2006-07-17 by Arthur David Olson.
   */
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 #ifndef lint  #ifndef lint
Line 7  __RCSID("$NetBSD$");
Line 11  __RCSID("$NetBSD$");
 #endif /* !defined NOID */  #endif /* !defined NOID */
 #endif /* !defined lint */  #endif /* !defined lint */
   
 static char     elsieid[] = "@(#)zic.c  7.116";  static char     elsieid[] = "@(#)zic.c  8.20";
   
 #include "private.h"  #include "private.h"
 #include "locale.h"  #include "locale.h"
 #include "tzfile.h"  #include "tzfile.h"
   
   #define ZIC_VERSION     '2'
   
   typedef int_fast64_t    zic_t;
   
   #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
   #define ZIC_MAX_ABBR_LEN_WO_WARN        6
   #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
   
 #if HAVE_SYS_STAT_H  #if HAVE_SYS_STAT_H
 #include "sys/stat.h"  #include "sys/stat.h"
 #endif  #endif
Line 26  static char elsieid[] = "@(#)zic.c 7.116
Line 38  static char elsieid[] = "@(#)zic.c 7.116
   
 /*  /*
 ** On some ancient hosts, predicates like `isspace(C)' are defined  ** On some ancient hosts, predicates like `isspace(C)' are defined
 ** only if isascii(C) || C == EOF.  Modern hosts obey the C Standard,  ** 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.  ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
 ** Neither the C Standard nor Posix require that `isascii' exist.  ** Neither the C Standard nor Posix require that `isascii' exist.
 ** For portability, we check both ancient and modern requirements.  ** For portability, we check both ancient and modern requirements.
Line 37  static char elsieid[] = "@(#)zic.c 7.116
Line 49  static char elsieid[] = "@(#)zic.c 7.116
 #define isascii(x) 1  #define isascii(x) 1
 #endif  #endif
   
   #define OFFSET_STRLEN_MAXIMUM   (7 + INT_STRLEN_MAXIMUM(long))
   #define RULE_STRLEN_MAXIMUM     8       /* "Mdd.dd.d" */
   
   #define end(cp) (strchr((cp), '\0'))
   
 struct rule {  struct rule {
         const char *    r_filename;          const char *    r_filename;
         int             r_linenum;          int             r_linenum;
Line 45  struct rule {
Line 62  struct rule {
         int             r_loyear;       /* for example, 1986 */          int             r_loyear;       /* for example, 1986 */
         int             r_hiyear;       /* for example, 1986 */          int             r_hiyear;       /* for example, 1986 */
         const char *    r_yrtype;          const char *    r_yrtype;
           int             r_lowasnum;
           int             r_hiwasnum;
   
         int             r_month;        /* 0..11 */          int             r_month;        /* 0..11 */
   
Line 61  struct rule {
Line 80  struct rule {
         const char *    r_abbrvar;      /* variable part of abbreviation */          const char *    r_abbrvar;      /* variable part of abbreviation */
   
         int             r_todo;         /* a rule to do (used in outzone) */          int             r_todo;         /* a rule to do (used in outzone) */
         time_t          r_temp;         /* used in outzone */          zic_t           r_temp;         /* used in outzone */
 };  };
   
 /*  /*
Line 87  struct zone {
Line 106  struct zone {
         int             z_nrules;          int             z_nrules;
   
         struct rule     z_untilrule;          struct rule     z_untilrule;
         time_t          z_untiltime;          zic_t           z_untiltime;
 };  };
   
 extern int      getopt P((int argc, char * const argv[],  extern int      getopt(int argc, char * const argv[],
                         const char * options));                          const char * options);
 extern int      link P((const char * fromname, const char * toname));  extern int      link(const char * fromname, const char * toname);
 extern char *   optarg;  extern char *   optarg;
 extern int      optind;  extern int      optind;
   
 static int      atcomp P((const void *, const void *));  static void     addtt(zic_t starttime, int type);
 static void     addtt P((time_t starttime, int type));  static int      addtype(long gmtoff, const char * abbr, int isdst,
 static int      addtype P((long gmtoff, const char * abbr, int isdst,                                  int ttisstd, int ttisgmt);
                                 int ttisstd, int ttisgmt));  static void     leapadd(zic_t t, int positive, int rolling, int count);
 static void     leapadd P((time_t t, int positive, int rolling, int count));  static void     adjleap(void);
 static void     adjleap P((void));  static void     associate(void);
 static void     associate P((void));  static int      ciequal(const char * ap, const char * bp);
 static int      ciequal P((const char * ap, const char * bp));  static void     convert(long val, char * buf);
 static void     convert P((long val, char * buf));  static void     convert64(zic_t val, char * buf);
 static void     dolink P((const char * fromfile, const char * tofile));  static void     dolink(const char * fromfield, const char * tofield);
 static void     doabbr P((char * abbr, int abbrlen, const char * format,  static void     doabbr(char * abbr, const int, const char * format,
                         const char * letters, int isdst));                          const char * letters, int isdst, int doquotes);
 static void     eat P((const char * name, int num));  static void     eat(const char * name, int num);
 static void     eats P((const char * name, int num,  static void     eats(const char * name, int num,
                         const char * rname, int rnum));                          const char * rname, int rnum);
 static long     eitol P((int i));  static long     eitol(int i);
 static void     error P((const char * message));  static void     error(const char * message);
 static char **  getfields P((char * buf));  static char **  getfields(char * buf);
 static long     gethms P((const char * string, const char * errstrng,  static long     gethms(const char * string, const char * errstrng,
                         int signable));                          int signable);
 static void     infile P((const char * filename));  static void     infile(const char * filename);
 static void     inleap P((char ** fields, int nfields));  static void     inleap(char ** fields, int nfields);
 static void     inlink P((char ** fields, int nfields));  static void     inlink(char ** fields, int nfields);
 static void     inrule P((char ** fields, int nfields));  static void     inrule(char ** fields, int nfields);
 static int      inzcont P((char ** fields, int nfields));  static int      inzcont(char ** fields, int nfields);
 static int      inzone P((char ** fields, int nfields));  static int      inzone(char ** fields, int nfields);
 static int      inzsub P((char ** fields, int nfields, int iscont));  static int      inzsub(char ** fields, int nfields, int iscont);
 static int      itsabbr P((const char * abbr, const char * word));  static int      is32(zic_t x);
 static int      itsdir P((const char * name));  static int      itsabbr(const char * abbr, const char * word);
 static int      lowerit P((int c));  static int      itsdir(const char * name);
 int             main P((int, char **));  static int      lowerit(int c);
 static char *   memcheck P((char * tocheck));  int             main(int, char **);
 static int      mkdirs P((char * filename));  static char *   memcheck(char * tocheck);
 static void     newabbr P((const char * abbr));  static int      mkdirs(char * filename);
 static long     oadd P((long t1, long t2));  static void     newabbr(const char * abbr);
 static void     outzone P((const struct zone * zp, int ntzones));  static long     oadd(long t1, long t2);
 static void     puttzcode P((long code, FILE * fp));  static void     outzone(const struct zone * zp, int ntzones);
 static int      rcomp P((const void * leftp, const void * rightp));  static void     puttzcode(long code, FILE * fp);
 static time_t   rpytime P((const struct rule * rp, int wantedy));  static void     puttzcode64(zic_t code, FILE * fp);
 static void     rulesub P((struct rule * rp,  static int      rcomp(const void * leftp, const void * rightp);
   static zic_t    rpytime(const struct rule * rp, int wantedy);
   static void     rulesub(struct rule * rp,
                         const char * loyearp, const char * hiyearp,                          const char * loyearp, const char * hiyearp,
                         const char * typep, const char * monthp,                          const char * typep, const char * monthp,
                         const char * dayp, const char * timep));                          const char * dayp, const char * timep);
 static void     setboundaries P((void));  static int      stringoffset(char * result, long offset);
 static time_t   tadd P((time_t t1, long t2));  static int      stringrule(char * result, const struct rule * rp,
 static void     usage P((void));                          long dstoff, long gmtoff);
 static void     warning P((const char * const));  static void     stringzone(char * result, const int,
 static void     writezone P((const char * name));                          const struct zone * zp, int ntzones);
 static int      yearistype P((int year, const char * type));  static void     setboundaries(void);
   static zic_t    tadd(zic_t t1, long t2);
 #if !(HAVE_STRERROR - 0)  static void     usage(FILE *stream, int status);
 static char *   strerror P((int));  static void     warning(const char * const);
 #endif /* !(HAVE_STRERROR - 0) */  static void     writezone(const char * name, const char * string);
   static int      yearistype(int year, const char * type);
   static int      atcomp(const void *avp, const void *bvp);
   static void     updateminmax(int x);
   
 static int              charcnt;  static int              charcnt;
 static int              errors;  static int              errors;
 static const char *     filename;  static const char *     filename;
 static int              leapcnt;  static int              leapcnt;
   static int              leapseen;
   static int              leapminyear;
   static int              leapmaxyear;
 static int              linenum;  static int              linenum;
 static time_t           max_time;  static int              max_abbrvar_len;
   static int              max_format_len;
   static zic_t            max_time;
 static int              max_year;  static int              max_year;
 static int              max_year_representable;  static zic_t            min_time;
 static time_t           min_time;  
 static int              min_year;  static int              min_year;
 static int              min_year_representable;  
 static int              noise;  static int              noise;
 static const char *     rfilename;  static const char *     rfilename;
 static int              rlinenum;  static int              rlinenum;
Line 270  struct lookup {
Line 297  struct lookup {
         const int       l_value;          const int       l_value;
 };  };
   
 static struct lookup const *    byword P((const char * string,  static struct lookup const *    byword(const char * string,
                                         const struct lookup * lp));                                          const struct lookup * lp);
   
 static struct lookup const      line_codes[] = {  static struct lookup const      line_codes[] = {
         { "Rule",       LC_RULE },          { "Rule",       LC_RULE },
Line 348  static const int len_years[2] = {
Line 375  static const int len_years[2] = {
 };  };
   
 static struct attype {  static struct attype {
         time_t          at;          zic_t           at;
         unsigned char   type;          unsigned char   type;
 }                       attypes[TZ_MAX_TIMES];  }                       attypes[TZ_MAX_TIMES];
 static long             gmtoffs[TZ_MAX_TYPES];  static long             gmtoffs[TZ_MAX_TYPES];
Line 357  static unsigned char abbrinds[TZ_MAX_TYP
Line 384  static unsigned char abbrinds[TZ_MAX_TYP
 static char             ttisstds[TZ_MAX_TYPES];  static char             ttisstds[TZ_MAX_TYPES];
 static char             ttisgmts[TZ_MAX_TYPES];  static char             ttisgmts[TZ_MAX_TYPES];
 static char             chars[TZ_MAX_CHARS];  static char             chars[TZ_MAX_CHARS];
 static time_t           trans[TZ_MAX_LEAPS];  static zic_t            trans[TZ_MAX_LEAPS];
 static long             corr[TZ_MAX_LEAPS];  static long             corr[TZ_MAX_LEAPS];
 static char             roll[TZ_MAX_LEAPS];  static char             roll[TZ_MAX_LEAPS];
   
Line 374  char * const ptr;
Line 401  char * const ptr;
   
                 (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),                  (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
                         progname, e);                          progname, e);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         return ptr;          return ptr;
 }  }
Line 388  char * const ptr;
Line 415  char * const ptr;
 ** Error handling.  ** 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  static void
 eats(name, num, rname, rnum)  eats(name, num, rname, rnum)
 const char * const      name;  const char * const      name;
Line 454  const char * const string;
Line 468  const char * const string;
 }  }
   
 static void  static void
 usage P((void))  usage(FILE *stream, int status)
 {  {
         (void) fprintf(stderr, _("%s: usage is %s [ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),          (void) fprintf(stream, _("%s: usage is %s \
                 progname, progname);  [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
         (void) exit(EXIT_FAILURE);  \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
   \n\
   Report bugs to tz@elsie.nci.nih.gov.\n"),
                          progname, progname);
           exit(status);
 }  }
   
 static const char *     psxrules;  static const char *     psxrules;
Line 466  static const char * lcltime;
Line 484  static const char * lcltime;
 static const char *     directory;  static const char *     directory;
 static const char *     leapsec;  static const char *     leapsec;
 static const char *     yitcommand;  static const char *     yitcommand;
 static int              sflag = FALSE;  
   
 int  int
 main(argc, argv)  main(argc, argv)
Line 486  char * argv[];
Line 503  char * argv[];
         (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);          (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
 #endif /* defined TEXTDOMAINDIR */  #endif /* defined TEXTDOMAINDIR */
         (void) textdomain(TZ_DOMAIN);          (void) textdomain(TZ_DOMAIN);
 #endif /* HAVE_GETTEXT - 0 */  #endif /* HAVE_GETTEXT */
         progname = argv[0];          progname = argv[0];
           if (TYPE_BIT(zic_t) < 64) {
                   (void) fprintf(stderr, "%s: %s\n", progname,
                           _("wild compilation-time specification of zic_t"));
                   exit(EXIT_FAILURE);
           }
         for (i = 1; i < argc; ++i)          for (i = 1; i < argc; ++i)
                 if (strcmp(argv[i], "--version") == 0) {                  if (strcmp(argv[i], "--version") == 0) {
                         (void) printf("%s\n", elsieid);                          (void) printf("%s\n", elsieid);
                         (void) exit(EXIT_SUCCESS);                          exit(EXIT_SUCCESS);
                   } else if (strcmp(argv[i], "--help") == 0) {
                           usage(stdout, EXIT_SUCCESS);
                 }                  }
         while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)          while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
                 switch (c) {                  switch (c) {
                         default:                          default:
                                 usage();                                  usage(stderr, EXIT_FAILURE);
                         case 'd':                          case 'd':
                                 if (directory == NULL)                                  if (directory == NULL)
                                         directory = optarg;                                          directory = optarg;
Line 504  char * argv[];
Line 528  char * argv[];
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: More than one -d option specified\n"),  _("%s: More than one -d option specified\n"),
                                                 progname);                                                  progname);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                                 }                                  }
                                 break;                                  break;
                         case 'l':                          case 'l':
Line 514  _("%s: More than one -d option specified
Line 538  _("%s: More than one -d option specified
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: More than one -l option specified\n"),  _("%s: More than one -l option specified\n"),
                                                 progname);                                                  progname);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                                 }                                  }
                                 break;                                  break;
                         case 'p':                          case 'p':
Line 524  _("%s: More than one -l option specified
Line 548  _("%s: More than one -l option specified
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: More than one -p option specified\n"),  _("%s: More than one -p option specified\n"),
                                                 progname);                                                  progname);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                                 }                                  }
                                 break;                                  break;
                         case 'y':                          case 'y':
Line 534  _("%s: More than one -p option specified
Line 558  _("%s: More than one -p option specified
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: More than one -y option specified\n"),  _("%s: More than one -y option specified\n"),
                                                 progname);                                                  progname);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                                 }                                  }
                                 break;                                  break;
                         case 'L':                          case 'L':
Line 544  _("%s: More than one -y option specified
Line 568  _("%s: More than one -y option specified
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: More than one -L option specified\n"),  _("%s: More than one -L option specified\n"),
                                                 progname);                                                  progname);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                                 }                                  }
                                 break;                                  break;
                         case 'v':                          case 'v':
                                 noise = TRUE;                                  noise = TRUE;
                                 break;                                  break;
                         case 's':                          case 's':
                                 sflag = TRUE;                                  (void) printf("%s: -s ignored\n", progname);
                                 break;                                  break;
                 }                  }
         if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)          if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
                 usage();        /* usage message by request */                  usage(stderr, EXIT_FAILURE);    /* usage message by request */
         if (directory == NULL)          if (directory == NULL)
                 directory = TZDIR;                  directory = TZDIR;
         if (yitcommand == NULL)          if (yitcommand == NULL)
Line 571  _("%s: More than one -L option specified
Line 595  _("%s: More than one -L option specified
         for (i = optind; i < argc; ++i)          for (i = optind; i < argc; ++i)
                 infile(argv[i]);                  infile(argv[i]);
         if (errors)          if (errors)
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         associate();          associate();
         for (i = 0; i < nzones; i = j) {          for (i = 0; i < nzones; i = j) {
                 /*                  /*
Line 587  _("%s: More than one -L option specified
Line 611  _("%s: More than one -L option specified
         for (i = 0; i < nlinks; ++i) {          for (i = 0; i < nlinks; ++i) {
                 eat(links[i].l_filename, links[i].l_linenum);                  eat(links[i].l_filename, links[i].l_linenum);
                 dolink(links[i].l_from, links[i].l_to);                  dolink(links[i].l_from, links[i].l_to);
                   if (noise)
                           for (j = 0; j < nlinks; ++j)
                                   if (strcmp(links[i].l_to,
                                           links[j].l_from) == 0)
                                                   warning(_("link to link"));
         }          }
         if (lcltime != NULL) {          if (lcltime != NULL) {
                 eat("command line", 1);                  eat("command line", 1);
Line 600  _("%s: More than one -L option specified
Line 629  _("%s: More than one -L option specified
 }  }
   
 static void  static void
 dolink(fromfile, tofile)  dolink(fromfield, tofield)
 const char * const      fromfile;  const char * const      fromfield;
 const char * const      tofile;  const char * const      tofield;
 {  {
         register char * fromname;          register char * fromname;
         register char * toname;          register char * toname;
   
         if (fromfile[0] == '/')          if (fromfield[0] == '/')
                 fromname = ecpyalloc(fromfile);                  fromname = ecpyalloc(fromfield);
         else {          else {
                 fromname = ecpyalloc(directory);                  fromname = ecpyalloc(directory);
                 fromname = ecatalloc(fromname, "/");                  fromname = ecatalloc(fromname, "/");
                 fromname = ecatalloc(fromname, fromfile);                  fromname = ecatalloc(fromname, fromfield);
         }          }
         if (tofile[0] == '/')          if (tofield[0] == '/')
                 toname = ecpyalloc(tofile);                  toname = ecpyalloc(tofield);
         else {          else {
                 toname = ecpyalloc(directory);                  toname = ecpyalloc(directory);
                 toname = ecatalloc(toname, "/");                  toname = ecatalloc(toname, "/");
                 toname = ecatalloc(toname, tofile);                  toname = ecatalloc(toname, tofield);
         }          }
         /*          /*
         ** We get to be careful here since          ** We get to be careful here since
Line 631  const char * const tofile;
Line 660  const char * const tofile;
                 int     result;                  int     result;
   
                 if (mkdirs(toname) != 0)                  if (mkdirs(toname) != 0)
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
   
                 result = link(fromname, toname);                  result = link(fromname, toname);
 #if (HAVE_SYMLINK - 0)  #if HAVE_SYMLINK
                 if (result != 0 &&                  if (result != 0 &&
                     access(fromname, F_OK) == 0 &&                          access(fromname, F_OK) == 0 &&
                     !itsdir(fromname)) {                          !itsdir(fromname)) {
                         const char *s = tofile;                                  const char *s = tofield;
                         register char * symlinkcontents = NULL;                                  register char * symlinkcontents = NULL;
                         while ((s = strchr(s+1, '/')) != NULL)  
                                 symlinkcontents = ecatalloc(symlinkcontents, "../");                                  while ((s = strchr(s+1, '/')) != NULL)
                         symlinkcontents = ecatalloc(symlinkcontents, fromfile);                                          symlinkcontents =
                                                   ecatalloc(symlinkcontents,
                         result = symlink(symlinkcontents, toname);                                                  "../");
                         if (result == 0)                                  symlinkcontents =
                                           ecatalloc(symlinkcontents,
                                           fromname);
                                   result = symlink(symlinkcontents,
                                           toname);
                                   if (result == 0)
 warning(_("hard link failed, symbolic link used"));  warning(_("hard link failed, symbolic link used"));
                         ifree(symlinkcontents);                                  ifree(symlinkcontents);
                 }                  }
 #endif  #endif /* HAVE_SYMLINK */
                 if (result != 0) {                  if (result != 0) {
                         const char *e = strerror(errno);                          const char *e = strerror(errno);
   
                         (void) fprintf(stderr,                          (void) fprintf(stderr,
                                 _("%s: Can't link from %s to %s: %s\n"),                                  _("%s: Can't link from %s to %s: %s\n"),
                                 progname, fromname, toname, e);                                  progname, fromname, toname, e);
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
                 }                  }
         }          }
         ifree(fromname);          ifree(fromname);
         ifree(toname);          ifree(toname);
 }  }
   
 #ifndef INT_MAX  #define TIME_T_BITS_IN_FILE     64
 #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  static void
 setboundaries P((void))  setboundaries(void)
 {  {
         if (TYPE_SIGNED(time_t)) {          register int    i;
                 min_time = ~ (time_t) 0;  
                 min_time <<= TIME_T_BITS_IN_FILE - 1;          min_time = -1;
                 max_time = ~ (time_t) 0 - min_time;          for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
                 if (sflag)                  min_time *= 2;
                         min_time = 0;          max_time = -(min_time + 1);
         } 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  static int
Line 734  const void * cp2;
Line 742  const void * cp2;
 }  }
   
 static void  static void
 associate P((void))  associate(void)
 {  {
         register struct zone *  zp;          register struct zone *  zp;
         register struct rule *  rp;          register struct rule *  rp;
Line 796  associate P((void))
Line 804  associate P((void))
                         */                          */
                         eat(zp->z_filename, zp->z_linenum);                          eat(zp->z_filename, zp->z_linenum);
                         zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),                          zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
                                               TRUE);                                  TRUE);
                         /*                          /*
                         ** Note, though, that if there's no rule,                          ** Note, though, that if there's no rule,
                         ** a '%s' in the format is a bad thing.                          ** a '%s' in the format is a bad thing.
Line 806  associate P((void))
Line 814  associate P((void))
                 }                  }
         }          }
         if (errors)          if (errors)
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
 }  }
   
 static void  static void
Line 830  const char * name;
Line 838  const char * name;
   
                 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),                  (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
                         progname, name, e);                          progname, name, e);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         wantcont = FALSE;          wantcont = FALSE;
         for (num = 1; ; ++num) {          for (num = 1; ; ++num) {
Line 840  const char * name;
Line 848  const char * name;
                 cp = strchr(buf, '\n');                  cp = strchr(buf, '\n');
                 if (cp == NULL) {                  if (cp == NULL) {
                         error(_("line too long"));                          error(_("line too long"));
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
                 }                  }
                 *cp = '\0';                  *cp = '\0';
                 fields = getfields(buf);                  fields = getfields(buf);
Line 884  _("%s: Leap line in non leap seconds fil
Line 892  _("%s: Leap line in non leap seconds fil
                                         (void) fprintf(stderr,                                          (void) fprintf(stderr,
 _("%s: panic: Invalid l_value %d\n"),  _("%s: panic: Invalid l_value %d\n"),
                                                 progname, lp->l_value);                                                  progname, lp->l_value);
                                         (void) exit(EXIT_FAILURE);                                          exit(EXIT_FAILURE);
                         }                          }
                 }                  }
                 ifree((char *) fields);                  ifree((char *) fields);
Line 892  _("%s: panic: Invalid l_value %d\n"),
Line 900  _("%s: panic: Invalid l_value %d\n"),
         if (ferror(fp)) {          if (ferror(fp)) {
                 (void) fprintf(stderr, _("%s: Error reading %s\n"),                  (void) fprintf(stderr, _("%s: Error reading %s\n"),
                         progname, filename);                          progname, filename);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         if (fp != stdin && fclose(fp)) {          if (fp != stdin && fclose(fp)) {
                 const char *e = strerror(errno);                  const char *e = strerror(errno);
   
                 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),                  (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
                         progname, filename, e);                          progname, filename, e);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         if (wantcont)          if (wantcont)
                 error(_("expected continuation line not found"));                  error(_("expected continuation line not found"));
Line 919  const char *  string;
Line 927  const char *  string;
 const char * const      errstring;  const char * const      errstring;
 const int               signable;  const int               signable;
 {  {
         int     hh, mm, ss, sign;          long    hh;
           int     mm, ss, sign;
   
         if (string == NULL || *string == '\0')          if (string == NULL || *string == '\0')
                 return 0;                  return 0;
Line 929  const int  signable;
Line 938  const int  signable;
                 sign = -1;                  sign = -1;
                 ++string;                  ++string;
         } else  sign = 1;          } else  sign = 1;
         if (sscanf(string, scheck(string, "%d"), &hh) == 1)          if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
                 mm = ss = 0;                  mm = ss = 0;
         else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)          else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
                 ss = 0;                  ss = 0;
         else if (sscanf(string, scheck(string, "%d:%d:%d"),          else if (sscanf(string, scheck(string, "%ld:%d:%d"),
                 &hh, &mm, &ss) != 3) {                  &hh, &mm, &ss) != 3) {
                         error(errstring);                          error(errstring);
                         return 0;                          return 0;
         }          }
         if ((hh < 0 || hh >= HOURSPERDAY ||          if (hh < 0 ||
                 mm < 0 || mm >= MINSPERHOUR ||                  mm < 0 || mm >= MINSPERHOUR ||
                 ss < 0 || ss > SECSPERMIN) &&                  ss < 0 || ss > SECSPERMIN) {
                 !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {  
                         error(errstring);                          error(errstring);
                         return 0;                          return 0;
         }          }
         if (noise && hh == HOURSPERDAY)          if (LONG_MAX / SECSPERHOUR < hh) {
                   error(_("time overflow"));
                   return 0;
           }
           if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
                 warning(_("24:00 not handled by pre-1998 versions of zic"));                  warning(_("24:00 not handled by pre-1998 versions of zic"));
         return eitol(sign) *          if (noise && (hh > HOURSPERDAY ||
                 (eitol(hh * MINSPERHOUR + mm) *                  (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
                 eitol(SECSPERMIN) + eitol(ss));  warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
           return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
                       eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
 }  }
   
 static void  static void
Line 974  const int  nfields;
Line 988  const int  nfields;
                 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);                  fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
         r.r_name = ecpyalloc(fields[RF_NAME]);          r.r_name = ecpyalloc(fields[RF_NAME]);
         r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);          r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
           if (max_abbrvar_len < strlen(r.r_abbrvar))
                   max_abbrvar_len = strlen(r.r_abbrvar);
         rules = (struct rule *) (void *) erealloc((char *) rules,          rules = (struct rule *) (void *) erealloc((char *) rules,
                 (int) ((nrules + 1) * sizeof *rules));                  (int) ((nrules + 1) * sizeof *rules));
         rules[nrules++] = r;          rules[nrules++] = r;
Line 1079  const int  iscont;
Line 1095  const int  iscont;
         }          }
         z.z_rule = ecpyalloc(fields[i_rule]);          z.z_rule = ecpyalloc(fields[i_rule]);
         z.z_format = ecpyalloc(fields[i_format]);          z.z_format = ecpyalloc(fields[i_format]);
           if (max_format_len < strlen(z.z_format))
                   max_format_len = strlen(z.z_format);
         hasuntil = nfields > i_untilyear;          hasuntil = nfields > i_untilyear;
         if (hasuntil) {          if (hasuntil) {
                 z.z_untilrule.r_filename = filename;                  z.z_untilrule.r_filename = filename;
Line 1099  const int  iscont;
Line 1117  const int  iscont;
                         zones[nzones - 1].z_untiltime > min_time &&                          zones[nzones - 1].z_untiltime > min_time &&
                         zones[nzones - 1].z_untiltime < max_time &&                          zones[nzones - 1].z_untiltime < max_time &&
                         zones[nzones - 1].z_untiltime >= z.z_untiltime) {                          zones[nzones - 1].z_untiltime >= z.z_untiltime) {
                                 error(_("Zone continuation line end time is not after end time of previous line"));                                  error(_(
   "Zone continuation line end time is not after end time of previous line"
                                           ));
                                 return FALSE;                                  return FALSE;
                 }                  }
         }          }
Line 1123  const int  nfields;
Line 1143  const int  nfields;
         register int                    i, j;          register int                    i, j;
         int                             year, month, day;          int                             year, month, day;
         long                            dayoff, tod;          long                            dayoff, tod;
         time_t                          t;          zic_t                           t;
   
         if (nfields != LEAP_FIELDS) {          if (nfields != LEAP_FIELDS) {
                 error(_("wrong number of fields on Leap line"));                  error(_("wrong number of fields on Leap line"));
Line 1132  const int  nfields;
Line 1152  const int  nfields;
         dayoff = 0;          dayoff = 0;
         cp = fields[LP_YEAR];          cp = fields[LP_YEAR];
         if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {          if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
                         /*                  /*
                          * Leapin' Lizards!                  ** Leapin' Lizards!
                          */                  */
                         error(_("invalid leaping year"));                  error(_("invalid leaping year"));
                         return;                  return;
         }          }
           if (!leapseen || leapmaxyear < year)
                   leapmaxyear = year;
           if (!leapseen || leapminyear > year)
                   leapminyear = year;
           leapseen = TRUE;
         j = EPOCH_YEAR;          j = EPOCH_YEAR;
         while (j != year) {          while (j != year) {
                 if (year > j) {                  if (year > j) {
Line 1167  const int  nfields;
Line 1192  const int  nfields;
                         return;                          return;
         }          }
         dayoff = oadd(dayoff, eitol(day - 1));          dayoff = oadd(dayoff, eitol(day - 1));
         if (dayoff < 0 && !TYPE_SIGNED(time_t)) {          if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
                 error(_("time before zero"));                  error(_("time before zero"));
                 return;                  return;
         }          }
Line 1179  const int  nfields;
Line 1204  const int  nfields;
                 error(_("time too large"));                  error(_("time too large"));
                 return;                  return;
         }          }
         t = (time_t) dayoff * SECSPERDAY;          t = (zic_t) dayoff * SECSPERDAY;
         tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);          tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
         cp = fields[LP_CORR];          cp = fields[LP_CORR];
         {          {
Line 1203  const int  nfields;
Line 1228  const int  nfields;
                         return;                          return;
                 }                  }
                 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {                  if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
                         error(_("illegal Rolling/Stationary field on Leap line"));                          error(_(
                                   "illegal Rolling/Stationary field on Leap line"
                                   ));
                         return;                          return;
                 }                  }
                 leapadd(tadd(t, tod), positive, lp->l_value, count);                  leapadd(tadd(t, tod), positive, lp->l_value, count);
Line 1290  const char * const  timep;
Line 1317  const char * const  timep;
         */          */
         cp = loyearp;          cp = loyearp;
         lp = byword(cp, begin_years);          lp = byword(cp, begin_years);
         if (lp != NULL) switch ((int) lp->l_value) {          rp->r_lowasnum = lp == NULL;
           if (!rp->r_lowasnum) switch ((int) lp->l_value) {
                 case YR_MINIMUM:                  case YR_MINIMUM:
                         rp->r_loyear = INT_MIN;                          rp->r_loyear = INT_MIN;
                         break;                          break;
Line 1301  const char * const  timep;
Line 1329  const char * const  timep;
                         (void) fprintf(stderr,                          (void) fprintf(stderr,
                                 _("%s: panic: Invalid l_value %d\n"),                                  _("%s: panic: Invalid l_value %d\n"),
                                 progname, lp->l_value);                                  progname, lp->l_value);
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {          } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
                 error(_("invalid starting year"));                  error(_("invalid starting year"));
                 return;                  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;          cp = hiyearp;
         if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {          lp = byword(cp, end_years);
           rp->r_hiwasnum = lp == NULL;
           if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
                 case YR_MINIMUM:                  case YR_MINIMUM:
                         rp->r_hiyear = INT_MIN;                          rp->r_hiyear = INT_MIN;
                         break;                          break;
Line 1326  const char * const  timep;
Line 1351  const char * const  timep;
                         (void) fprintf(stderr,                          (void) fprintf(stderr,
                                 _("%s: panic: Invalid l_value %d\n"),                                  _("%s: panic: Invalid l_value %d\n"),
                                 progname, lp->l_value);                                  progname, lp->l_value);
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {          } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
                 error(_("invalid ending year"));                  error(_("invalid ending year"));
                 return;                  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) {          if (rp->r_loyear > rp->r_hiyear) {
                 error(_("starting year greater than ending year"));                  error(_("starting year greater than ending year"));
Line 1349  const char * const  timep;
Line 1369  const char * const  timep;
                 }                  }
                 rp->r_yrtype = ecpyalloc(typep);                  rp->r_yrtype = ecpyalloc(typep);
         }          }
         if (rp->r_loyear < min_year && rp->r_loyear > 0)  
                 min_year = rp->r_loyear;  
         /*          /*
         ** Day work.          ** Day work.
         ** Accept things such as:          ** Accept things such as:
Line 1404  const long val;
Line 1422  const long val;
 char * const    buf;  char * const    buf;
 {  {
         register int    i;          register int    i;
         register long   shift;          register int    shift;
   
         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)          for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
                 buf[i] = val >> shift;                  buf[i] = val >> shift;
 }  }
   
 static void  static void
   convert64(val, buf)
   const zic_t     val;
   char * const    buf;
   {
           register int    i;
           register int    shift;
   
           for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
                   buf[i] = val >> shift;
   }
   
   static void
 puttzcode(val, fp)  puttzcode(val, fp)
 const long      val;  const long      val;
 FILE * const    fp;  FILE * const    fp;
Line 1421  FILE * const fp;
Line 1451  FILE * const fp;
         (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);          (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
 }  }
   
   static void
   puttzcode64(val, fp)
   const zic_t     val;
   FILE * const    fp;
   {
           char    buf[8];
   
           convert64(val, buf);
           (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
   }
   
 static int  static int
 atcomp(avp, bvp)  atcomp(avp, bvp)
 const void *    avp;  const void *    avp;
 const void *    bvp;  const void *    bvp;
 {  {
         if (((const struct attype *) avp)->at < ((const struct attype *) bvp)->at)          const zic_t     a = ((const struct attype *) avp)->at;
                 return -1;          const zic_t     b = ((const struct attype *) bvp)->at;
         else if (((const struct attype *) avp)->at > ((const struct attype *) bvp)->at)  
                 return 1;          return (a < b) ? -1 : (a > b);
         else    return 0;  }
   
   static int
   is32(x)
   const zic_t     x;
   {
           return INT32_MIN <= x && x <= INT32_MAX;
 }  }
   
 static void  static void
 writezone(name)  writezone(name, string)
 const char * const      name;  const char * const      name;
   const char * const      string;
 {  {
         register FILE *         fp;          register FILE *                 fp;
         register int            i, j;          register int                    i, j;
         static char *           fullname;          register int                    leapcnt32, leapi32;
         static struct tzhead    tzh;          register int                    timecnt32, timei32;
         time_t                  ats[TZ_MAX_TIMES];          register int                    pass;
         unsigned char           types[TZ_MAX_TIMES];          static char *                   fullname;
           static const struct tzhead      tzh0;
           static struct tzhead            tzh;
           zic_t                           ats[TZ_MAX_TIMES];
           unsigned char                   types[TZ_MAX_TIMES];
   
         /*          /*
         ** Sort.          ** Sort.
Line 1465  const char * const name;
Line 1517  const char * const name;
                         while (fromi < timecnt && attypes[fromi].type == 0)                          while (fromi < timecnt && attypes[fromi].type == 0)
                                 ++fromi;        /* handled by default rule */                                  ++fromi;        /* handled by default rule */
                 for ( ; fromi < timecnt; ++fromi) {                  for ( ; fromi < timecnt; ++fromi) {
                         if (toi != 0                          if (toi != 0 && ((attypes[fromi].at +
                             && ((attypes[fromi].at                                  gmtoffs[attypes[toi - 1].type]) <=
                                  + gmtoffs[attypes[toi - 1].type])                                  (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
                                 <= (attypes[toi - 1].at                                  : attypes[toi - 2].type]))) {
                                     + gmtoffs[toi == 1 ? 0                                          attypes[toi - 1].type =
                                               : attypes[toi - 2].type]))) {                                                  attypes[fromi].type;
                                 attypes[toi - 1].type = attypes[fromi].type;                                          continue;
                                 continue;  
                         }                          }
                         if (toi == 0 ||                          if (toi == 0 ||
                                 attypes[toi - 1].type != attypes[fromi].type)                                  attypes[toi - 1].type != attypes[fromi].type)
Line 1487  const char * const name;
Line 1538  const char * const name;
                 ats[i] = attypes[i].at;                  ats[i] = attypes[i].at;
                 types[i] = attypes[i].type;                  types[i] = attypes[i].type;
         }          }
           /*
           ** Correct for leap seconds.
           */
           for (i = 0; i < timecnt; ++i) {
                   j = leapcnt;
                   while (--j >= 0)
                           if (ats[i] > trans[j] - corr[j]) {
                                   ats[i] = tadd(ats[i], corr[j]);
                                   break;
                           }
           }
           /*
           ** Figure out 32-bit-limited starts and counts.
           */
           timecnt32 = timecnt;
           timei32 = 0;
           leapcnt32 = leapcnt;
           leapi32 = 0;
           while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
                   --timecnt32;
           while (timecnt32 > 0 && !is32(ats[timei32])) {
                   --timecnt32;
                   ++timei32;
           }
           while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
                   --leapcnt32;
           while (leapcnt32 > 0 && !is32(trans[leapi32])) {
                   --leapcnt32;
                   ++leapi32;
           }
         fullname = erealloc(fullname,          fullname = erealloc(fullname,
                 (int) (strlen(directory) + 1 + strlen(name) + 1));                  (int) (strlen(directory) + 1 + strlen(name) + 1));
         (void) sprintf(fullname, "%s/%s", directory, name);     /* XXX: sprintf is safe */          (void) sprintf(fullname, "%s/%s", directory, name);     /* XXX: sprintf is safe */
Line 1498  const char * const name;
Line 1579  const char * const name;
   
                 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),                  (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
                         progname, fullname, e);                          progname, fullname, e);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         if ((fp = fopen(fullname, "wb")) == NULL) {          if ((fp = fopen(fullname, "wb")) == NULL) {
                 if (mkdirs(fullname) != 0)                  if (mkdirs(fullname) != 0)
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
                 if ((fp = fopen(fullname, "wb")) == NULL) {                  if ((fp = fopen(fullname, "wb")) == NULL) {
                         const char *e = strerror(errno);                          const char *e = strerror(errno);
   
                         (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),                          (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
                                 progname, fullname, e);                                  progname, fullname, e);
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
                 }                  }
         }          }
         convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);          for (pass = 1; pass <= 2; ++pass) {
         convert(eitol(typecnt), tzh.tzh_ttisstdcnt);                  register int    thistimei, thistimecnt;
         convert(eitol(leapcnt), tzh.tzh_leapcnt);                  register int    thisleapi, thisleapcnt;
         convert(eitol(timecnt), tzh.tzh_timecnt);                  register int    thistimelim, thisleaplim;
         convert(eitol(typecnt), tzh.tzh_typecnt);                  int             writetype[TZ_MAX_TIMES];
         convert(eitol(charcnt), tzh.tzh_charcnt);                  int             typemap[TZ_MAX_TYPES];
         (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);                  register int    thistypecnt;
 #define DO(field)       (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)                  char            thischars[TZ_MAX_CHARS];
         DO(tzh_magic);                  char            thischarcnt;
         DO(tzh_reserved);                  int             indmap[TZ_MAX_CHARS];
         DO(tzh_ttisgmtcnt);  
         DO(tzh_ttisstdcnt);                  if (pass == 1) {
         DO(tzh_leapcnt);                          thistimei = timei32;
         DO(tzh_timecnt);                          thistimecnt = timecnt32;
         DO(tzh_typecnt);                          thisleapi = leapi32;
         DO(tzh_charcnt);                          thisleapcnt = leapcnt32;
                   } else {
                           thistimei = 0;
                           thistimecnt = timecnt;
                           thisleapi = 0;
                           thisleapcnt = leapcnt;
                   }
                   thistimelim = thistimei + thistimecnt;
                   thisleaplim = thisleapi + thisleapcnt;
                   for (i = 0; i < typecnt; ++i)
                           writetype[i] = thistimecnt == timecnt;
                   if (thistimecnt == 0) {
                           /*
                           ** No transition times fall in the current
                           ** (32- or 64-bit) window.
                           */
                           if (typecnt != 0)
                                   writetype[typecnt - 1] = TRUE;
                   } else {
                           for (i = thistimei - 1; i < thistimelim; ++i)
                                   if (i >= 0)
                                           writetype[types[i]] = TRUE;
                           /*
                           ** For America/Godthab and Antarctica/Palmer
                           */
                           if (thistimei == 0)
                                   writetype[0] = TRUE;
                   }
                   thistypecnt = 0;
                   for (i = 0; i < typecnt; ++i)
                           typemap[i] = writetype[i] ?  thistypecnt++ : -1;
                   for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
                           indmap[i] = -1;
                   thischarcnt = 0;
                   for (i = 0; i < typecnt; ++i) {
                           register char * thisabbr;
   
                           if (!writetype[i])
                                   continue;
                           if (indmap[abbrinds[i]] >= 0)
                                   continue;
                           thisabbr = &chars[abbrinds[i]];
                           for (j = 0; j < thischarcnt; ++j)
                                   if (strcmp(&thischars[j], thisabbr) == 0)
                                           break;
                           if (j == thischarcnt) {
                                   (void) strcpy(&thischars[(int) thischarcnt],
                                           thisabbr);
                                   thischarcnt += strlen(thisabbr) + 1;
                           }
                           indmap[abbrinds[i]] = j;
                   }
   #define DO(field)       (void) fwrite((void *) tzh.field, \
                                   (size_t) sizeof tzh.field, (size_t) 1, fp)
                   tzh = tzh0;
                   (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
                   tzh.tzh_version[0] = ZIC_VERSION;
                   convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
                   convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
                   convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
                   convert(eitol(thistimecnt), tzh.tzh_timecnt);
                   convert(eitol(thistypecnt), tzh.tzh_typecnt);
                   convert(eitol(thischarcnt), tzh.tzh_charcnt);
                   DO(tzh_magic);
                   DO(tzh_version);
                   DO(tzh_reserved);
                   DO(tzh_ttisgmtcnt);
                   DO(tzh_ttisstdcnt);
                   DO(tzh_leapcnt);
                   DO(tzh_timecnt);
                   DO(tzh_typecnt);
                   DO(tzh_charcnt);
 #undef DO  #undef DO
         for (i = 0; i < timecnt; ++i) {                  for (i = thistimei; i < thistimelim; ++i)
                 j = leapcnt;                          if (pass == 1)
                 while (--j >= 0)                                  puttzcode((long) ats[i], fp);
                         if (ats[i] >= trans[j]) {                          else    puttzcode64(ats[i], fp);
                                 ats[i] = tadd(ats[i], corr[j]);                  for (i = thistimei; i < thistimelim; ++i) {
                                 break;                          unsigned char   uc;
   
                           uc = typemap[types[i]];
                           (void) fwrite((void *) &uc,
                                   (size_t) sizeof uc,
                                   (size_t) 1,
                                   fp);
                   }
                   for (i = 0; i < typecnt; ++i)
                           if (writetype[i]) {
                                   puttzcode(gmtoffs[i], fp);
                                   (void) putc(isdsts[i], fp);
                                   (void) putc((unsigned char) indmap[abbrinds[i]], fp);
                         }                          }
                 puttzcode((long) ats[i], fp);                  if (thischarcnt != 0)
                           (void) fwrite((void *) thischars,
                                   (size_t) sizeof thischars[0],
                                   (size_t) thischarcnt, fp);
                   for (i = thisleapi; i < thisleaplim; ++i) {
                           register zic_t  todo;
   
                           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];
                                   }
                                   todo = tadd(trans[i], -gmtoffs[j]);
                           } else  todo = trans[i];
                           if (pass == 1)
                                   puttzcode((long) todo, fp);
                           else    puttzcode64(todo, fp);
                           puttzcode(corr[i], fp);
                   }
                   for (i = 0; i < typecnt; ++i)
                           if (writetype[i])
                                   (void) putc(ttisstds[i], fp);
                   for (i = 0; i < typecnt; ++i)
                           if (writetype[i])
                                   (void) putc(ttisgmts[i], fp);
         }          }
         if (timecnt > 0)          (void) fprintf(fp, "\n%s\n", string);
                 (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)) {          if (ferror(fp) || fclose(fp)) {
                 (void) fprintf(stderr, _("%s: Error writing %s\n"),                  (void) fprintf(stderr, _("%s: Error writing %s\n"),
                         progname, fullname);                          progname, fullname);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
 }  }
   
 static void  static void
 doabbr(abbr, abbrlen, format, letters, isdst)  doabbr(abbr, abbrlen, format, letters, isdst, doquotes)
 char * const            abbr;  char * const            abbr;
 const int               abbrlen;  const int               abbrlen;
 const char * const      format;  const char * const      format;
 const char * const      letters;  const char * const      letters;
 const int               isdst;  const int               isdst;
   const int               doquotes;
 {  {
         if (strchr(format, '/') == NULL) {          register char * cp;
           register char * slashp;
           register int    len;
   
           slashp = strchr(format, '/');
           if (slashp == NULL) {
                 if (letters == NULL)                  if (letters == NULL)
                         (void)strncpy(abbr, format, abbrlen - 1);                          (void) strlcpy(abbr, format, abbrlen);
                 else                  else    (void) snprintf(abbr, abbrlen, format, letters);
                         (void)snprintf(abbr, abbrlen, format, letters);          } else if (isdst) {
         } else if (isdst)                  (void) strlcpy(abbr, slashp + 1, abbrlen);
                 (void)strncpy(abbr, strchr(format, '/') + 1, abbrlen - 1);          } else {
         else {                  if (slashp > format)
                 (void)strncpy(abbr, format, abbrlen - 1);                          (void) strncpy(abbr, format,
                 *strchr(abbr, '/') = '\0';                                  (unsigned) (slashp - format));
                   abbr[slashp - format] = '\0';
           }
           if (!doquotes)
                   return;
           for (cp = abbr; *cp != '\0'; ++cp)
                   if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
                           strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
                                   break;
           len = strlen(abbr);
           if (len > 0 && *cp == '\0')
                   return;
           abbr[len + 2] = '\0';
           abbr[len + 1] = '>';
           for ( ; len > 0; --len)
                   abbr[len] = abbr[len - 1];
           abbr[0] = '<';
   }
   
   static void
   updateminmax(x)
   const int       x;
   {
           if (min_year > x)
                   min_year = x;
           if (max_year < x)
                   max_year = x;
   }
   
   static int
   stringoffset(result, offset)
   char *  result;
   long    offset;
   {
           register int    hours;
           register int    minutes;
           register int    seconds;
   
           result[0] = '\0';
           if (offset < 0) {
                   (void) strcpy(result, "-");
                   offset = -offset;
           }
           seconds = offset % SECSPERMIN;
           offset /= SECSPERMIN;
           minutes = offset % MINSPERHOUR;
           offset /= MINSPERHOUR;
           hours = offset;
           if (hours >= HOURSPERDAY) {
                   result[0] = '\0';
                   return -1;
           }
           (void) sprintf(end(result), "%d", hours);
           if (minutes != 0 || seconds != 0) {
                   (void) sprintf(end(result), ":%02d", minutes);
                   if (seconds != 0)
                           (void) sprintf(end(result), ":%02d", seconds);
           }
           return 0;
   }
   
   static int
   stringrule(result, rp, dstoff, gmtoff)
   char *                          result;
   const struct rule * const       rp;
   const long                      dstoff;
   const long                      gmtoff;
   {
           register long   tod;
   
           result = end(result);
           if (rp->r_dycode == DC_DOM) {
                   register int    month, total;
   
                   if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
                           return -1;
                   total = 0;
                   for (month = 0; month < rp->r_month; ++month)
                           total += len_months[0][month];
                   (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
           } else {
                   register int    week;
   
                   if (rp->r_dycode == DC_DOWGEQ) {
                           week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
                           if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
                                   return -1;
                   } else if (rp->r_dycode == DC_DOWLEQ) {
                           if (rp->r_dayofmonth == len_months[1][rp->r_month])
                                   week = 5;
                           else {
                                   week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
                                   if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
                                           return -1;
                           }
                   } else  return -1;      /* "cannot happen" */
                   (void) sprintf(result, "M%d.%d.%d",
                           rp->r_month + 1, week, rp->r_wday);
           }
           tod = rp->r_tod;
           if (rp->r_todisgmt)
                   tod += gmtoff;
           if (rp->r_todisstd && rp->r_stdoff == 0)
                   tod += dstoff;
           if (tod < 0) {
                   result[0] = '\0';
                   return -1;
           }
           if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
                   (void) strcat(result, "/");
                   if (stringoffset(end(result), tod) != 0)
                           return -1;
           }
           return 0;
   }
   
   static void
   stringzone(result, resultlen, zpfirst, zonecount)
   char *                          result;
   const int                       resultlen;
   const struct zone * const       zpfirst;
   const int                       zonecount;
   {
           register const struct zone *    zp;
           register struct rule *          rp;
           register struct rule *          stdrp;
           register struct rule *          dstrp;
           register int                    i;
           register const char *           abbrvar;
   
           result[0] = '\0';
           zp = zpfirst + zonecount - 1;
           stdrp = dstrp = NULL;
           for (i = 0; i < zp->z_nrules; ++i) {
                   rp = &zp->z_rules[i];
                   if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
                           continue;
                   if (rp->r_yrtype != NULL)
                           continue;
                   if (rp->r_stdoff == 0) {
                           if (stdrp == NULL)
                                   stdrp = rp;
                           else    return;
                   } else {
                           if (dstrp == NULL)
                                   dstrp = rp;
                           else    return;
                   }
           }
           if (stdrp == NULL && dstrp == NULL) {
                   /*
                   ** There are no rules running through "max".
                   ** Let's find the latest rule.
                   */
                   for (i = 0; i < zp->z_nrules; ++i) {
                           rp = &zp->z_rules[i];
                           if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
                                   (rp->r_hiyear == stdrp->r_hiyear &&
                                   rp->r_month > stdrp->r_month))
                                           stdrp = rp;
                   }
                   if (stdrp != NULL && stdrp->r_stdoff != 0)
                           return; /* We end up in DST (a POSIX no-no). */
                   /*
                   ** Horrid special case: if year is 2037,
                   ** presume this is a zone handled on a year-by-year basis;
                   ** do not try to apply a rule to the zone.
                   */
                   if (stdrp != NULL && stdrp->r_hiyear == 2037)
                           return;
           }
           if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
                   return;
           abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
           doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE);
           if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
                   result[0] = '\0';
                   return;
           }
           if (dstrp == NULL)
                   return;
           doabbr(end(result), resultlen - strlen(result),
                   zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
           if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
                   if (stringoffset(end(result),
                           -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
                                   result[0] = '\0';
                                   return;
                   }
           (void) strcat(result, ",");
           if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
                   result[0] = '\0';
                   return;
           }
           (void) strcat(result, ",");
           if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
                   result[0] = '\0';
                   return;
         }          }
 }  }
   
Line 1608  const int   zonecount;
Line 1976  const int   zonecount;
         register struct rule *          rp;          register struct rule *          rp;
         register int                    i, j;          register int                    i, j;
         register int                    usestart, useuntil;          register int                    usestart, useuntil;
         register time_t                 starttime, untiltime;          register zic_t                  starttime, untiltime;
         register long                   gmtoff;          register long                   gmtoff;
         register long                   stdoff;          register long                   stdoff;
         register int                    year;          register int                    year;
Line 1616  const int   zonecount;
Line 1984  const int   zonecount;
         register int                    startttisstd;          register int                    startttisstd;
         register int                    startttisgmt;          register int                    startttisgmt;
         register int                    type;          register int                    type;
         char                            startbuf[BUFSIZ];          register char *                 startbuf;
           register char *                 ab;
           register char *                 envvar;
           register int                    max_abbr_len;
           register int                    max_envvar_len;
   
           max_abbr_len = 2 + max_format_len + max_abbrvar_len;
           max_envvar_len = 2 * max_abbr_len + 5 * 9;
           startbuf = emalloc(max_abbr_len + 1);
           ab = emalloc(max_abbr_len + 1);
           envvar = emalloc(max_envvar_len + 1);
         INITIALIZE(untiltime);          INITIALIZE(untiltime);
         INITIALIZE(starttime);          INITIALIZE(starttime);
         /*          /*
Line 1627  const int   zonecount;
Line 2004  const int   zonecount;
         typecnt = 0;          typecnt = 0;
         charcnt = 0;          charcnt = 0;
         /*          /*
         ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)          ** Thanks to Earl Chew
         ** for noting the need to unconditionally initialize startttisstd.          ** for noting the need to unconditionally initialize startttisstd.
         */          */
         startttisstd = FALSE;          startttisstd = FALSE;
         startttisgmt = FALSE;          startttisgmt = FALSE;
           min_year = max_year = EPOCH_YEAR;
           if (leapseen) {
                   updateminmax(leapminyear);
                   updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
           }
           for (i = 0; i < zonecount; ++i) {
                   zp = &zpfirst[i];
                   if (i < zonecount - 1)
                           updateminmax(zp->z_untilrule.r_loyear);
                   for (j = 0; j < zp->z_nrules; ++j) {
                           rp = &zp->z_rules[j];
                           if (rp->r_lowasnum)
                                   updateminmax(rp->r_loyear);
                           if (rp->r_hiwasnum)
                                   updateminmax(rp->r_hiyear);
                   }
           }
           /*
           ** Generate lots of data if a rule can't cover all future times.
           */
           stringzone(envvar, max_envvar_len+1, zpfirst, zonecount);
           if (noise && envvar[0] == '\0') {
                   register char * wp;
   
   wp = ecpyalloc(_("no POSIX environment variable for zone"));
                   wp = ecatalloc(wp, " ");
                   wp = ecatalloc(wp, zpfirst->z_name);
                   warning(wp);
                   ifree(wp);
           }
           if (envvar[0] == '\0') {
                   if (min_year >= INT_MIN + YEARSPERREPEAT)
                           min_year -= YEARSPERREPEAT;
                   else    min_year = INT_MIN;
                   if (max_year <= INT_MAX - YEARSPERREPEAT)
                           max_year += YEARSPERREPEAT;
                   else    max_year = INT_MAX;
           }
           /*
           ** For the benefit of older systems,
           ** generate data from 1900 through 2037.
           */
           if (min_year > 1900)
                   min_year = 1900;
           if (max_year < 2037)
                   max_year = 2037;
         for (i = 0; i < zonecount; ++i) {          for (i = 0; i < zonecount; ++i) {
                 /*                  /*
                 ** A guess that may well be corrected later.                  ** A guess that may well be corrected later.
Line 1648  const int   zonecount;
Line 2071  const int   zonecount;
                 startoff = zp->z_gmtoff;                  startoff = zp->z_gmtoff;
                 if (zp->z_nrules == 0) {                  if (zp->z_nrules == 0) {
                         stdoff = zp->z_stdoff;                          stdoff = zp->z_stdoff;
                         doabbr(startbuf, sizeof startbuf, zp->z_format,                          doabbr(startbuf, max_abbr_len + 1, zp->z_format,
                                 (char *) NULL, stdoff != 0);                                  (char *) NULL, stdoff != 0, FALSE);
                         type = addtype(oadd(zp->z_gmtoff, stdoff),                          type = addtype(oadd(zp->z_gmtoff, stdoff),
                                 startbuf, stdoff != 0, startttisstd,                                  startbuf, stdoff != 0, startttisstd,
                                 startttisgmt);                                  startttisgmt);
Line 1677  const int   zonecount;
Line 2100  const int   zonecount;
                         }                          }
                         for ( ; ; ) {                          for ( ; ; ) {
                                 register int    k;                                  register int    k;
                                 register time_t jtime, ktime;                                  register zic_t  jtime, ktime;
                                 register long   offset;                                  register long   offset;
                                 char            buf[BUFSIZ];  
   
                                 INITIALIZE(ktime);                                  INITIALIZE(ktime);
                                 if (useuntil) {                                  if (useuntil) {
Line 1733  const int   zonecount;
Line 2155  const int   zonecount;
                                         if (ktime < starttime) {                                          if (ktime < starttime) {
                                                 startoff = oadd(zp->z_gmtoff,                                                  startoff = oadd(zp->z_gmtoff,
                                                         stdoff);                                                          stdoff);
                                                 doabbr(startbuf,sizeof startbuf,                                                  doabbr(startbuf,
                                                           max_abbr_len + 1,
                                                         zp->z_format,                                                          zp->z_format,
                                                         rp->r_abbrvar,                                                          rp->r_abbrvar,
                                                         rp->r_stdoff != 0);                                                          rp->r_stdoff != 0,
                                                           FALSE);
                                                 continue;                                                  continue;
                                         }                                          }
                                         if (*startbuf == '\0' &&                                          if (*startbuf == '\0' &&
                                             startoff == oadd(zp->z_gmtoff,                                                  startoff == oadd(zp->z_gmtoff,
                                             stdoff)) {                                                  stdoff)) {
                                                 doabbr(startbuf,sizeof startbuf,                                                          doabbr(startbuf,
                                                         zp->z_format,                                                                  max_abbr_len + 1,
                                                         rp->r_abbrvar,                                                                  zp->z_format,
                                                         rp->r_stdoff != 0);                                                                  rp->r_abbrvar,
                                                                   rp->r_stdoff !=
                                                                   0,
                                                                   FALSE);
                                         }                                          }
                                 }                                  }
                                 eats(zp->z_filename, zp->z_linenum,                                  eats(zp->z_filename, zp->z_linenum,
                                         rp->r_filename, rp->r_linenum);                                          rp->r_filename, rp->r_linenum);
                                 doabbr(buf, sizeof buf, zp->z_format,                                  doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar,
                                         rp->r_abbrvar, rp->r_stdoff != 0);                                          rp->r_stdoff != 0, FALSE);
                                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);                                  offset = oadd(zp->z_gmtoff, rp->r_stdoff);
                                 type = addtype(offset, buf, rp->r_stdoff != 0,                                  type = addtype(offset, ab, rp->r_stdoff != 0,
                                         rp->r_todisstd, rp->r_todisgmt);                                          rp->r_todisstd, rp->r_todisgmt);
                                 addtt(ktime, type);                                  addtt(ktime, type);
                         }                          }
Line 1764  const int   zonecount;
Line 2191  const int   zonecount;
                                 strchr(zp->z_format, '%') == NULL &&                                  strchr(zp->z_format, '%') == NULL &&
                                 strchr(zp->z_format, '/') == NULL)                                  strchr(zp->z_format, '/') == NULL)
                                         (void)strncpy(startbuf, zp->z_format,                                          (void)strncpy(startbuf, zp->z_format,
                                             sizeof(startbuf) - 1);                                              max_abbr_len + 1 - 1);
                         eat(zp->z_filename, zp->z_linenum);                          eat(zp->z_filename, zp->z_linenum);
                         if (*startbuf == '\0')                          if (*startbuf == '\0')
 error(_("can't determine time zone abbreviation to use just after until time"));  error(_("can't determine time zone abbreviation to use just after until time"));
Line 1787  error(_("can't determine time zone abbre
Line 2214  error(_("can't determine time zone abbre
                                 starttime = tadd(starttime, -gmtoff);                                  starttime = tadd(starttime, -gmtoff);
                 }                  }
         }          }
         writezone(zpfirst->z_name);          writezone(zpfirst->z_name, envvar);
           ifree(startbuf);
           ifree(ab);
           ifree(envvar);
 }  }
   
 static void  static void
 addtt(starttime, type)  addtt(starttime, type)
 const time_t    starttime;  const zic_t     starttime;
 int             type;  int             type;
 {  {
         if (starttime <= min_time ||          if (starttime <= min_time ||
Line 1811  int  type;
Line 2241  int  type;
         }          }
         if (timecnt >= TZ_MAX_TIMES) {          if (timecnt >= TZ_MAX_TIMES) {
                 error(_("too many transitions?!"));                  error(_("too many transitions?!"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         attypes[timecnt].at = starttime;          attypes[timecnt].at = starttime;
         attypes[timecnt].type = type;          attypes[timecnt].type = type;
Line 1830  const int  ttisgmt;
Line 2260  const int  ttisgmt;
   
         if (isdst != TRUE && isdst != FALSE) {          if (isdst != TRUE && isdst != FALSE) {
                 error(_("internal error - addtype called with bad isdst"));                  error(_("internal error - addtype called with bad isdst"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         if (ttisstd != TRUE && ttisstd != FALSE) {          if (ttisstd != TRUE && ttisstd != FALSE) {
                 error(_("internal error - addtype called with bad ttisstd"));                  error(_("internal error - addtype called with bad ttisstd"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         if (ttisgmt != TRUE && ttisgmt != FALSE) {          if (ttisgmt != TRUE && ttisgmt != FALSE) {
                 error(_("internal error - addtype called with bad ttisgmt"));                  error(_("internal error - addtype called with bad ttisgmt"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         /*          /*
         ** See if there's already an entry for this zone type.          ** See if there's already an entry for this zone type.
Line 1857  const int  ttisgmt;
Line 2287  const int  ttisgmt;
         */          */
         if (typecnt >= TZ_MAX_TYPES) {          if (typecnt >= TZ_MAX_TYPES) {
                 error(_("too many local time types"));                  error(_("too many local time types"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
           }
           if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
                   error(_("UTC offset out of range"));
                   exit(EXIT_FAILURE);
         }          }
         gmtoffs[i] = gmtoff;          gmtoffs[i] = gmtoff;
         isdsts[i] = isdst;          isdsts[i] = isdst;
Line 1876  const int  ttisgmt;
Line 2310  const int  ttisgmt;
   
 static void  static void
 leapadd(t, positive, rolling, count)  leapadd(t, positive, rolling, count)
 const time_t    t;  const zic_t     t;
 const int       positive;  const int       positive;
 const int       rolling;  const int       rolling;
 int             count;  int             count;
Line 1885  int  count;
Line 2319  int  count;
   
         if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {          if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
                 error(_("too many leap seconds"));                  error(_("too many leap seconds"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         for (i = 0; i < leapcnt; ++i)          for (i = 0; i < leapcnt; ++i)
                 if (t <= trans[i]) {                  if (t <= trans[i]) {
                         if (t == trans[i]) {                          if (t == trans[i]) {
                                 error(_("repeated leap second moment"));                                  error(_("repeated leap second moment"));
                                 (void) exit(EXIT_FAILURE);                                  exit(EXIT_FAILURE);
                         }                          }
                         break;                          break;
                 }                  }
Line 1909  int  count;
Line 2343  int  count;
 }  }
   
 static void  static void
 adjleap P((void))  adjleap(void)
 {  {
         register int    i;          register int    i;
         register long   last = 0;          register long   last = 0;
Line 1946  const char * const type;
Line 2380  const char * const type;
         (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),          (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
                 progname, buf, result);                  progname, buf, result);
         for ( ; ; )          for ( ; ; )
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
 }  }
   
 static int  static int
Line 2027  register char * cp;
Line 2461  register char * cp;
                 emalloc((int) ((strlen(cp) + 1) * sizeof *array));                  emalloc((int) ((strlen(cp) + 1) * sizeof *array));
         nsubs = 0;          nsubs = 0;
         for ( ; ; ) {          for ( ; ; ) {
                 while (isascii(*cp) && isspace((unsigned char) *cp))                  while (isascii((unsigned char) *cp) &&
                         ++cp;                          isspace((unsigned char) *cp))
                                   ++cp;
                 if (*cp == '\0' || *cp == '#')                  if (*cp == '\0' || *cp == '#')
                         break;                          break;
                 array[nsubs++] = dp = cp;                  array[nsubs++] = dp = cp;
Line 2038  register char * cp;
Line 2473  register char * cp;
                         else while ((*dp = *cp++) != '"')                          else while ((*dp = *cp++) != '"')
                                 if (*dp != '\0')                                  if (*dp != '\0')
                                         ++dp;                                          ++dp;
                                 else    error(_("Odd number of quotation marks"));                                  else {
                                           error(_(
                                                   "Odd number of quotation marks"
                                                   ));
                                           exit(1);
                                   }
                 } while (*cp != '\0' && *cp != '#' &&                  } while (*cp != '\0' && *cp != '#' &&
                         (!isascii(*cp) || !isspace((unsigned char) *cp)));                          (!isascii(*cp) || !isspace((unsigned char) *cp)));
                 if (isascii(*cp) && isspace((unsigned char) *cp))                  if (isascii(*cp) && isspace((unsigned char) *cp))
Line 2059  const long t2;
Line 2499  const long t2;
         t = t1 + t2;          t = t1 + t2;
         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {          if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
                 error(_("time overflow"));                  error(_("time overflow"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         return t;          return t;
 }  }
   
 static time_t  static zic_t
 tadd(t1, t2)  tadd(t1, t2)
 const time_t    t1;  const zic_t     t1;
 const long      t2;  const long      t2;
 {  {
         register time_t t;          register zic_t  t;
   
         if (t1 == max_time && t2 > 0)          if (t1 == max_time && t2 > 0)
                 return max_time;                  return max_time;
Line 2078  const long t2;
Line 2518  const long t2;
         t = t1 + t2;          t = t1 + t2;
         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {          if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
                 error(_("time overflow"));                  error(_("time overflow"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         return t;          return t;
 }  }
Line 2088  const long t2;
Line 2528  const long t2;
 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.  ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
 */  */
   
 static time_t  static zic_t
 rpytime(rp, wantedy)  rpytime(rp, wantedy)
 register const struct rule * const      rp;  register const struct rule * const      rp;
 register const int                      wantedy;  register const int                      wantedy;
 {  {
         register int    y, m, i;          register int    y, m, i;
         register long   dayoff;                 /* with a nod to Margaret O. */          register long   dayoff;                 /* with a nod to Margaret O. */
         register time_t t;          register zic_t  t;
   
         if (wantedy == INT_MIN)          if (wantedy == INT_MIN)
                 return min_time;                  return min_time;
Line 2125  register const int   wantedy;
Line 2565  register const int   wantedy;
                         --i;                          --i;
                 else {                  else {
                         error(_("use of 2/29 in non leap-year"));                          error(_("use of 2/29 in non leap-year"));
                         (void) exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
                 }                  }
         }          }
         --i;          --i;
Line 2159  register const int   wantedy;
Line 2599  register const int   wantedy;
                         }                          }
                 if (i < 0 || i >= len_months[isleap(y)][m]) {                  if (i < 0 || i >= len_months[isleap(y)][m]) {
                         if (noise)                          if (noise)
                                 warning(_("rule goes past start/end of month--will not work with pre-2004 versions of zic"));                                  warning(_("rule goes past start/end of month--\
   will not work with pre-2004 versions of zic"));
                 }                  }
         }          }
         if (dayoff < 0 && !TYPE_SIGNED(time_t))  
                 return min_time;  
         if (dayoff < min_time / SECSPERDAY)          if (dayoff < min_time / SECSPERDAY)
                 return min_time;                  return min_time;
         if (dayoff > max_time / SECSPERDAY)          if (dayoff > max_time / SECSPERDAY)
                 return max_time;                  return max_time;
         t = (time_t) dayoff * SECSPERDAY;          t = (zic_t) dayoff * SECSPERDAY;
         return tadd(t, rp->r_tod);          return tadd(t, rp->r_tod);
 }  }
   
Line 2178  const char * const string;
Line 2617  const char * const string;
 {  {
         register int    i;          register int    i;
   
           if (strcmp(string, GRANDPARENTED) != 0) {
                   register const char *   cp;
                   register char *         wp;
   
                   /*
                   ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
                   ** optionally followed by a + or - and a number from 1 to 14.
                   */
                   cp = string;
                   wp = NULL;
                   while (isascii((unsigned char) *cp) &&
                           isalpha((unsigned char) *cp))
                                   ++cp;
                   if (cp - string == 0)
   wp = _("time zone abbreviation lacks alphabetic at start");
                   if (noise && cp - string > 3)
   wp = _("time zone abbreviation has more than 3 alphabetics");
                   if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
   wp = _("time zone abbreviation has too many alphabetics");
                   if (wp == NULL && (*cp == '+' || *cp == '-')) {
                           ++cp;
                           if (isascii((unsigned char) *cp) &&
                                   isdigit((unsigned char) *cp))
                                           if (*cp++ == '1' &&
                                                   *cp >= '0' && *cp <= '4')
                                                           ++cp;
                   }
                   if (*cp != '\0')
   wp = _("time zone abbreviation differs from POSIX standard");
                   if (wp != NULL) {
                           wp = ecpyalloc(wp);
                           wp = ecatalloc(wp, " (");
                           wp = ecatalloc(wp, string);
                           wp = ecatalloc(wp, ")");
                           warning(wp);
                           ifree(wp);
                   }
           }
         i = strlen(string) + 1;          i = strlen(string) + 1;
         if (charcnt + i > TZ_MAX_CHARS) {          if (charcnt + i > TZ_MAX_CHARS) {
                 error(_("too many, or too long, time zone abbreviations"));                  error(_("too many, or too long, time zone abbreviations"));
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);          (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
         charcnt += eitol(i);          charcnt += eitol(i);
Line 2189  const char * const string;
Line 2666  const char * const string;
   
 static int  static int
 mkdirs(argname)  mkdirs(argname)
 char * const    argname;  char *          argname;
 {  {
         register char * name;          register char * name;
         register char * cp;          register char * cp;
Line 2245  const int i;
Line 2722  const int i;
                 (void) fprintf(stderr,                  (void) fprintf(stderr,
                         _("%s: %d did not sign extend correctly\n"),                          _("%s: %d did not sign extend correctly\n"),
                         progname, i);                          progname, i);
                 (void) exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
         }          }
         return l;          return l;
 }  }

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.25

CVSweb <webmaster@jp.NetBSD.org>