Header And Logo

PostgreSQL
| The world's most advanced open source database.

zic.c

Go to the documentation of this file.
00001 /*
00002  * This file is in the public domain, so clarified as of
00003  * 2006-07-17 by Arthur David Olson.
00004  *
00005  * IDENTIFICATION
00006  *    src/timezone/zic.c
00007  */
00008 
00009 #include "postgres_fe.h"
00010 
00011 #ifdef HAVE_GETOPT_H
00012 #include <getopt.h>
00013 #endif
00014 #include <limits.h>
00015 #include <locale.h>
00016 #include <time.h>
00017 
00018 extern int  optind;
00019 extern char *optarg;
00020 
00021 #include "private.h"
00022 #include "pgtz.h"
00023 #include "tzfile.h"
00024 
00025 #define       ZIC_VERSION     '2'
00026 
00027 typedef int64 zic_t;
00028 
00029 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
00030 #define ZIC_MAX_ABBR_LEN_WO_WARN      6
00031 #endif   /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
00032 
00033 #ifdef HAVE_SYS_STAT_H
00034 #include <sys/stat.h>
00035 #endif
00036 
00037 #ifndef WIN32
00038 #ifdef S_IRUSR
00039 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
00040 #else
00041 #define MKDIR_UMASK 0755
00042 #endif
00043 #endif
00044 
00045 static char elsieid[] = "@(#)zic.c  8.20";
00046 
00047 /*
00048  * On some ancient hosts, predicates like `isspace(C)' are defined
00049  * only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
00050  * which says they are defined only if C == ((unsigned char) C) || C == EOF.
00051  * Neither the C Standard nor Posix require that `isascii' exist.
00052  * For portability, we check both ancient and modern requirements.
00053  * If isascii is not defined, the isascii check succeeds trivially.
00054  */
00055 #include <ctype.h>
00056 #ifndef isascii
00057 #define isascii(x) 1
00058 #endif
00059 
00060 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
00061 #define RULE_STRLEN_MAXIMUM   8 /* "Mdd.dd.d" */
00062 
00063 #define end(cp)       (strchr((cp), '\0'))
00064 
00065 struct rule
00066 {
00067     const char *r_filename;
00068     int         r_linenum;
00069     const char *r_name;
00070 
00071     int         r_loyear;       /* for example, 1986 */
00072     int         r_hiyear;       /* for example, 1986 */
00073     const char *r_yrtype;
00074     int         r_lowasnum;
00075     int         r_hiwasnum;
00076 
00077     int         r_month;        /* 0..11 */
00078 
00079     int         r_dycode;       /* see below */
00080     int         r_dayofmonth;
00081     int         r_wday;
00082 
00083     long        r_tod;          /* time from midnight */
00084     int         r_todisstd;     /* above is standard time if TRUE */
00085     /* or wall clock time if FALSE */
00086     int         r_todisgmt;     /* above is GMT if TRUE */
00087     /* or local time if FALSE */
00088     long        r_stdoff;       /* offset from standard time */
00089     const char *r_abbrvar;      /* variable part of abbreviation */
00090 
00091     int         r_todo;         /* a rule to do (used in outzone) */
00092     zic_t       r_temp;         /* used in outzone */
00093 };
00094 
00095 /*
00096  *  r_dycode        r_dayofmonth    r_wday
00097  */
00098 
00099 #define DC_DOM      0   /* 1..31 */     /* unused */
00100 #define DC_DOWGEQ   1   /* 1..31 */     /* 0..6 (Sun..Sat) */
00101 #define DC_DOWLEQ   2   /* 1..31 */     /* 0..6 (Sun..Sat) */
00102 
00103 struct zone
00104 {
00105     const char *z_filename;
00106     int         z_linenum;
00107 
00108     const char *z_name;
00109     long        z_gmtoff;
00110     const char *z_rule;
00111     const char *z_format;
00112 
00113     long        z_stdoff;
00114 
00115     struct rule *z_rules;
00116     int         z_nrules;
00117 
00118     struct rule z_untilrule;
00119     zic_t       z_untiltime;
00120 };
00121 
00122 extern int  link(const char *fromname, const char *toname);
00123 static void addtt(const pg_time_t starttime, int type);
00124 static int addtype(long gmtoff, const char *abbr, int isdst,
00125         int ttisstd, int ttisgmt);
00126 static void leapadd(const pg_time_t t, int positive, int rolling, int count);
00127 static void adjleap(void);
00128 static void associate(void);
00129 static int  ciequal(const char *ap, const char *bp);
00130 static void convert(long val, char *buf);
00131 static void dolink(const char *fromfile, const char *tofile);
00132 static void doabbr(char *abbr, const char *format,
00133        const char *letters, int isdst, int doquotes);
00134 static void eat(const char *name, int num);
00135 static void eats(const char *name, int num,
00136      const char *rname, int rnum);
00137 static long eitol(int i);
00138 static void error(const char *message);
00139 static char **getfields(char *buf);
00140 static long gethms(const char *string, const char *errstrng,
00141        int signable);
00142 static void infile(const char *filename);
00143 static void inleap(char **fields, int nfields);
00144 static void inlink(char **fields, int nfields);
00145 static void inrule(char **fields, int nfields);
00146 static int  inzcont(char **fields, int nfields);
00147 static int  inzone(char **fields, int nfields);
00148 static int  inzsub(char **fields, int nfields, int iscont);
00149 static int  itsabbr(const char *abbr, const char *word);
00150 static int  itsdir(const char *name);
00151 static int  lowerit(int c);
00152 static char *memcheck(char *tocheck);
00153 static int  mkdirs(char *filename);
00154 static void newabbr(const char *abbr);
00155 static long oadd(long t1, long t2);
00156 static void outzone(const struct zone * zp, int ntzones);
00157 static void puttzcode(long code, FILE *fp);
00158 static int  rcomp(const void *leftp, const void *rightp);
00159 static pg_time_t rpytime(const struct rule * rp, int wantedy);
00160 static void rulesub(struct rule * rp,
00161         const char *loyearp, const char *hiyearp,
00162         const char *typep, const char *monthp,
00163         const char *dayp, const char *timep);
00164 static void setboundaries(void);
00165 static pg_time_t tadd(const pg_time_t t1, long t2);
00166 static void usage(FILE *stream, int status);
00167 static void writezone(const char *name, const char *string);
00168 static int  yearistype(int year, const char *type);
00169 
00170 static int  charcnt;
00171 static int  errors;
00172 static const char *filename;
00173 static int  leapcnt;
00174 static int  leapseen;
00175 static int  leapminyear;
00176 static int  leapmaxyear;
00177 static int  linenum;
00178 static int  max_abbrvar_len;
00179 static int  max_format_len;
00180 static zic_t max_time;
00181 static int  max_year;
00182 static zic_t min_time;
00183 static int  min_year;
00184 static int  noise;
00185 static int  print_abbrevs;
00186 static zic_t print_cutoff;
00187 static const char *rfilename;
00188 static int  rlinenum;
00189 static const char *progname;
00190 static int  timecnt;
00191 static int  typecnt;
00192 
00193 /*
00194  * Line codes.
00195  */
00196 
00197 #define LC_RULE     0
00198 #define LC_ZONE     1
00199 #define LC_LINK     2
00200 #define LC_LEAP     3
00201 
00202 /*
00203  * Which fields are which on a Zone line.
00204  */
00205 
00206 #define ZF_NAME     1
00207 #define ZF_GMTOFF   2
00208 #define ZF_RULE     3
00209 #define ZF_FORMAT   4
00210 #define ZF_TILYEAR  5
00211 #define ZF_TILMONTH 6
00212 #define ZF_TILDAY   7
00213 #define ZF_TILTIME  8
00214 #define ZONE_MINFIELDS  5
00215 #define ZONE_MAXFIELDS  9
00216 
00217 /*
00218  * Which fields are which on a Zone continuation line.
00219  */
00220 
00221 #define ZFC_GMTOFF  0
00222 #define ZFC_RULE    1
00223 #define ZFC_FORMAT  2
00224 #define ZFC_TILYEAR 3
00225 #define ZFC_TILMONTH    4
00226 #define ZFC_TILDAY  5
00227 #define ZFC_TILTIME 6
00228 #define ZONEC_MINFIELDS 3
00229 #define ZONEC_MAXFIELDS 7
00230 
00231 /*
00232  * Which files are which on a Rule line.
00233  */
00234 
00235 #define RF_NAME     1
00236 #define RF_LOYEAR   2
00237 #define RF_HIYEAR   3
00238 #define RF_COMMAND  4
00239 #define RF_MONTH    5
00240 #define RF_DAY      6
00241 #define RF_TOD      7
00242 #define RF_STDOFF   8
00243 #define RF_ABBRVAR  9
00244 #define RULE_FIELDS 10
00245 
00246 /*
00247  * Which fields are which on a Link line.
00248  */
00249 
00250 #define LF_FROM     1
00251 #define LF_TO       2
00252 #define LINK_FIELDS 3
00253 
00254 /*
00255  * Which fields are which on a Leap line.
00256  */
00257 
00258 #define LP_YEAR     1
00259 #define LP_MONTH    2
00260 #define LP_DAY      3
00261 #define LP_TIME     4
00262 #define LP_CORR     5
00263 #define LP_ROLL     6
00264 #define LEAP_FIELDS 7
00265 
00266 /*
00267  * Year synonyms.
00268  */
00269 
00270 #define YR_MINIMUM  0
00271 #define YR_MAXIMUM  1
00272 #define YR_ONLY     2
00273 
00274 static struct rule *rules;
00275 static int  nrules;             /* number of rules */
00276 
00277 static struct zone *zones;
00278 static int  nzones;             /* number of zones */
00279 
00280 struct link
00281 {
00282     const char *l_filename;
00283     int         l_linenum;
00284     const char *l_from;
00285     const char *l_to;
00286 };
00287 
00288 static struct link *links;
00289 static int  nlinks;
00290 
00291 struct lookup
00292 {
00293     const char *l_word;
00294     const int   l_value;
00295 };
00296 
00297 static struct lookup const *byword(const char *string,
00298        const struct lookup * lp);
00299 
00300 static struct lookup const line_codes[] = {
00301     {"Rule", LC_RULE},
00302     {"Zone", LC_ZONE},
00303     {"Link", LC_LINK},
00304     {"Leap", LC_LEAP},
00305     {NULL, 0}
00306 };
00307 
00308 static struct lookup const mon_names[] = {
00309     {"January", TM_JANUARY},
00310     {"February", TM_FEBRUARY},
00311     {"March", TM_MARCH},
00312     {"April", TM_APRIL},
00313     {"May", TM_MAY},
00314     {"June", TM_JUNE},
00315     {"July", TM_JULY},
00316     {"August", TM_AUGUST},
00317     {"September", TM_SEPTEMBER},
00318     {"October", TM_OCTOBER},
00319     {"November", TM_NOVEMBER},
00320     {"December", TM_DECEMBER},
00321     {NULL, 0}
00322 };
00323 
00324 static struct lookup const wday_names[] = {
00325     {"Sunday", TM_SUNDAY},
00326     {"Monday", TM_MONDAY},
00327     {"Tuesday", TM_TUESDAY},
00328     {"Wednesday", TM_WEDNESDAY},
00329     {"Thursday", TM_THURSDAY},
00330     {"Friday", TM_FRIDAY},
00331     {"Saturday", TM_SATURDAY},
00332     {NULL, 0}
00333 };
00334 
00335 static struct lookup const lasts[] = {
00336     {"last-Sunday", TM_SUNDAY},
00337     {"last-Monday", TM_MONDAY},
00338     {"last-Tuesday", TM_TUESDAY},
00339     {"last-Wednesday", TM_WEDNESDAY},
00340     {"last-Thursday", TM_THURSDAY},
00341     {"last-Friday", TM_FRIDAY},
00342     {"last-Saturday", TM_SATURDAY},
00343     {NULL, 0}
00344 };
00345 
00346 static struct lookup const begin_years[] = {
00347     {"minimum", YR_MINIMUM},
00348     {"maximum", YR_MAXIMUM},
00349     {NULL, 0}
00350 };
00351 
00352 static struct lookup const end_years[] = {
00353     {"minimum", YR_MINIMUM},
00354     {"maximum", YR_MAXIMUM},
00355     {"only", YR_ONLY},
00356     {NULL, 0}
00357 };
00358 
00359 static struct lookup const leap_types[] = {
00360     {"Rolling", TRUE},
00361     {"Stationary", FALSE},
00362     {NULL, 0}
00363 };
00364 
00365 static const int len_months[2][MONSPERYEAR] = {
00366     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00367     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
00368 };
00369 
00370 static const int len_years[2] = {
00371     DAYSPERNYEAR, DAYSPERLYEAR
00372 };
00373 
00374 static struct attype
00375 {
00376     zic_t       at;
00377     unsigned char type;
00378 }   attypes[TZ_MAX_TIMES];
00379 static long gmtoffs[TZ_MAX_TYPES];
00380 static char isdsts[TZ_MAX_TYPES];
00381 static unsigned char abbrinds[TZ_MAX_TYPES];
00382 static char ttisstds[TZ_MAX_TYPES];
00383 static char ttisgmts[TZ_MAX_TYPES];
00384 static char chars[TZ_MAX_CHARS];
00385 static zic_t trans[TZ_MAX_LEAPS];
00386 static long corr[TZ_MAX_LEAPS];
00387 static char roll[TZ_MAX_LEAPS];
00388 
00389 /*
00390  * Memory allocation.
00391  */
00392 
00393 static char *
00394 memcheck(char *ptr)
00395 {
00396     if (ptr == NULL)
00397     {
00398         const char *e = strerror(errno);
00399 
00400         (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
00401                        progname, e);
00402         exit(EXIT_FAILURE);
00403     }
00404     return ptr;
00405 }
00406 
00407 #define emalloc(size)       memcheck(imalloc(size))
00408 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
00409 #define ecpyalloc(ptr)      memcheck(icpyalloc(ptr))
00410 #define ecatalloc(oldp, newp)   memcheck(icatalloc((oldp), (newp)))
00411 
00412 /*
00413  * Error handling.
00414  */
00415 
00416 static void
00417 eats(const char *name, int num, const char *rname, int rnum)
00418 {
00419     filename = name;
00420     linenum = num;
00421     rfilename = rname;
00422     rlinenum = rnum;
00423 }
00424 
00425 static void
00426 eat(const char *name, int num)
00427 {
00428     eats(name, num, (char *) NULL, -1);
00429 }
00430 
00431 static void
00432 error(const char *string)
00433 {
00434     /*
00435      * Match the format of "cc" to allow sh users to  zic ... 2>&1 | error -t
00436      * "*" -v on BSD systems.
00437      */
00438     (void) fprintf(stderr, _("\"%s\", line %d: %s"),
00439                    filename, linenum, string);
00440     if (rfilename != NULL)
00441         (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
00442                        rfilename, rlinenum);
00443     (void) fprintf(stderr, "\n");
00444     ++errors;
00445 }
00446 
00447 static void
00448 warning(const char *string)
00449 {
00450     char       *cp;
00451 
00452     cp = ecpyalloc(_("warning: "));
00453     cp = ecatalloc(cp, string);
00454     error(cp);
00455     ifree(cp);
00456     --errors;
00457 }
00458 
00459 static void
00460 usage(FILE *stream, int status)
00461 {
00462     (void) fprintf(stream, _("%s: usage is %s \
00463 [ --version ] [ --help ] [ -v ] [ -P ] [ -l localtime ] [ -p posixrules ] \\\n\
00464 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
00465 \n\
00466 Report bugs to [email protected].\n"),
00467                    progname, progname);
00468     exit(status);
00469 }
00470 
00471 static const char *psxrules;
00472 static const char *lcltime;
00473 static const char *directory;
00474 static const char *leapsec;
00475 static const char *yitcommand;
00476 
00477 int
00478 main(int argc, char *argv[])
00479 {
00480     int         i;
00481     int         j;
00482     int         c;
00483 
00484 #ifndef WIN32
00485     (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
00486 #endif   /* !WIN32 */
00487     progname = argv[0];
00488     if (TYPE_BIT(zic_t) < 64)
00489     {
00490         (void) fprintf(stderr, "%s: %s\n", progname,
00491                        _("wild compilation-time specification of zic_t"));
00492         exit(EXIT_FAILURE);
00493     }
00494     for (i = 1; i < argc; ++i)
00495         if (strcmp(argv[i], "--version") == 0)
00496         {
00497             (void) printf("%s\n", elsieid);
00498             exit(EXIT_SUCCESS);
00499         }
00500         else if (strcmp(argv[i], "--help") == 0)
00501         {
00502             usage(stdout, EXIT_SUCCESS);
00503         }
00504     while ((c = getopt(argc, argv, "d:l:p:L:vPsy:")) != EOF && c != -1)
00505         switch (c)
00506         {
00507             default:
00508                 usage(stderr, EXIT_FAILURE);
00509             case 'd':
00510                 if (directory == NULL)
00511                     directory = strdup(optarg);
00512                 else
00513                 {
00514                     (void) fprintf(stderr,
00515                                 _("%s: More than one -d option specified\n"),
00516                                    progname);
00517                     exit(EXIT_FAILURE);
00518                 }
00519                 break;
00520             case 'l':
00521                 if (lcltime == NULL)
00522                     lcltime = strdup(optarg);
00523                 else
00524                 {
00525                     (void) fprintf(stderr,
00526                                 _("%s: More than one -l option specified\n"),
00527                                    progname);
00528                     exit(EXIT_FAILURE);
00529                 }
00530                 break;
00531             case 'p':
00532                 if (psxrules == NULL)
00533                     psxrules = strdup(optarg);
00534                 else
00535                 {
00536                     (void) fprintf(stderr,
00537                                 _("%s: More than one -p option specified\n"),
00538                                    progname);
00539                     exit(EXIT_FAILURE);
00540                 }
00541                 break;
00542             case 'y':
00543                 if (yitcommand == NULL)
00544                     yitcommand = strdup(optarg);
00545                 else
00546                 {
00547                     (void) fprintf(stderr,
00548                                 _("%s: More than one -y option specified\n"),
00549                                    progname);
00550                     exit(EXIT_FAILURE);
00551                 }
00552                 break;
00553             case 'L':
00554                 if (leapsec == NULL)
00555                     leapsec = strdup(optarg);
00556                 else
00557                 {
00558                     (void) fprintf(stderr,
00559                                 _("%s: More than one -L option specified\n"),
00560                                    progname);
00561                     exit(EXIT_FAILURE);
00562                 }
00563                 break;
00564             case 'v':
00565                 noise = TRUE;
00566                 break;
00567             case 'P':
00568                 print_abbrevs = TRUE;
00569                 print_cutoff = time(NULL);
00570                 break;
00571             case 's':
00572                 (void) printf("%s: -s ignored\n", progname);
00573                 break;
00574         }
00575     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
00576         usage(stderr, EXIT_FAILURE);    /* usage message by request */
00577     if (directory == NULL)
00578         directory = "data";
00579     if (yitcommand == NULL)
00580         yitcommand = "yearistype";
00581 
00582     setboundaries();
00583 
00584     if (optind < argc && leapsec != NULL)
00585     {
00586         infile(leapsec);
00587         adjleap();
00588     }
00589 
00590     for (i = optind; i < argc; ++i)
00591         infile(argv[i]);
00592     if (errors)
00593         exit(EXIT_FAILURE);
00594     associate();
00595     for (i = 0; i < nzones; i = j)
00596     {
00597         /*
00598          * Find the next non-continuation zone entry.
00599          */
00600         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
00601             continue;
00602         outzone(&zones[i], j - i);
00603     }
00604 
00605     /*
00606      * Make links.
00607      */
00608     for (i = 0; i < nlinks; ++i)
00609     {
00610         eat(links[i].l_filename, links[i].l_linenum);
00611         dolink(links[i].l_from, links[i].l_to);
00612         if (noise)
00613             for (j = 0; j < nlinks; ++j)
00614                 if (strcmp(links[i].l_to,
00615                            links[j].l_from) == 0)
00616                     warning(_("link to link"));
00617     }
00618     if (lcltime != NULL)
00619     {
00620         eat("command line", 1);
00621         dolink(lcltime, TZDEFAULT);
00622     }
00623     if (psxrules != NULL)
00624     {
00625         eat("command line", 1);
00626         dolink(psxrules, TZDEFRULES);
00627     }
00628     return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
00629 }
00630 
00631 static void
00632 dolink(const char *fromfield, const char *tofield)
00633 {
00634     char       *fromname;
00635     char       *toname;
00636 
00637     if (fromfield[0] == '/')
00638         fromname = ecpyalloc(fromfield);
00639     else
00640     {
00641         fromname = ecpyalloc(directory);
00642         fromname = ecatalloc(fromname, "/");
00643         fromname = ecatalloc(fromname, fromfield);
00644     }
00645     if (tofield[0] == '/')
00646         toname = ecpyalloc(tofield);
00647     else
00648     {
00649         toname = ecpyalloc(directory);
00650         toname = ecatalloc(toname, "/");
00651         toname = ecatalloc(toname, tofield);
00652     }
00653 
00654     /*
00655      * We get to be careful here since there's a fair chance of root running
00656      * us.
00657      */
00658     if (!itsdir(toname))
00659         (void) remove(toname);
00660     if (link(fromname, toname) != 0)
00661     {
00662         int         result;
00663 
00664         if (mkdirs(toname) != 0)
00665             exit(EXIT_FAILURE);
00666 
00667         result = link(fromname, toname);
00668 #ifdef HAVE_SYMLINK
00669         if (result != 0 &&
00670             access(fromname, F_OK) == 0 &&
00671             !itsdir(fromname))
00672         {
00673             const char *s = tofield;
00674             char       *symlinkcontents = NULL;
00675 
00676             while ((s = strchr(s + 1, '/')) != NULL)
00677                 symlinkcontents = ecatalloc(symlinkcontents, "../");
00678             symlinkcontents = ecatalloc(symlinkcontents, fromfield);
00679 
00680             result = symlink(symlinkcontents, toname);
00681             if (result == 0)
00682                 warning(_("hard link failed, symbolic link used"));
00683             ifree(symlinkcontents);
00684         }
00685 #endif
00686         if (result != 0)
00687         {
00688             const char *e = strerror(errno);
00689 
00690             (void) fprintf(stderr,
00691                            _("%s: Cannot link from %s to %s: %s\n"),
00692                            progname, fromname, toname, e);
00693             exit(EXIT_FAILURE);
00694         }
00695     }
00696     ifree(fromname);
00697     ifree(toname);
00698 }
00699 
00700 #define TIME_T_BITS_IN_FILE   64
00701 
00702 static void
00703 setboundaries(void)
00704 {
00705     int         i;
00706 
00707     min_time = -1;
00708     for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
00709         min_time *= 2;
00710     max_time = -(min_time + 1);
00711 }
00712 
00713 static int
00714 itsdir(const char *name)
00715 {
00716     char       *myname;
00717     int         accres;
00718 
00719     myname = ecpyalloc(name);
00720     myname = ecatalloc(myname, "/.");
00721     accres = access(myname, F_OK);
00722     ifree(myname);
00723     return accres == 0;
00724 }
00725 
00726 /*
00727  * Associate sets of rules with zones.
00728  */
00729 
00730 /*
00731  * Sort by rule name.
00732  */
00733 
00734 static int
00735 rcomp(const void *cp1, const void *cp2)
00736 {
00737     return strcmp(((const struct rule *) cp1)->r_name,
00738                   ((const struct rule *) cp2)->r_name);
00739 }
00740 
00741 static void
00742 associate(void)
00743 {
00744     struct zone *zp;
00745     struct rule *rp;
00746     int         base,
00747                 out;
00748     int         i,
00749                 j;
00750 
00751     if (nrules != 0)
00752     {
00753         (void) qsort((void *) rules, (size_t) nrules,
00754                      (size_t) sizeof *rules, rcomp);
00755         for (i = 0; i < nrules - 1; ++i)
00756         {
00757             if (strcmp(rules[i].r_name,
00758                        rules[i + 1].r_name) != 0)
00759                 continue;
00760             if (strcmp(rules[i].r_filename,
00761                        rules[i + 1].r_filename) == 0)
00762                 continue;
00763             eat(rules[i].r_filename, rules[i].r_linenum);
00764             warning(_("same rule name in multiple files"));
00765             eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
00766             warning(_("same rule name in multiple files"));
00767             for (j = i + 2; j < nrules; ++j)
00768             {
00769                 if (strcmp(rules[i].r_name,
00770                            rules[j].r_name) != 0)
00771                     break;
00772                 if (strcmp(rules[i].r_filename,
00773                            rules[j].r_filename) == 0)
00774                     continue;
00775                 if (strcmp(rules[i + 1].r_filename,
00776                            rules[j].r_filename) == 0)
00777                     continue;
00778                 break;
00779             }
00780             i = j - 1;
00781         }
00782     }
00783     for (i = 0; i < nzones; ++i)
00784     {
00785         zp = &zones[i];
00786         zp->z_rules = NULL;
00787         zp->z_nrules = 0;
00788     }
00789     for (base = 0; base < nrules; base = out)
00790     {
00791         rp = &rules[base];
00792         for (out = base + 1; out < nrules; ++out)
00793             if (strcmp(rp->r_name, rules[out].r_name) != 0)
00794                 break;
00795         for (i = 0; i < nzones; ++i)
00796         {
00797             zp = &zones[i];
00798             if (strcmp(zp->z_rule, rp->r_name) != 0)
00799                 continue;
00800             zp->z_rules = rp;
00801             zp->z_nrules = out - base;
00802         }
00803     }
00804     for (i = 0; i < nzones; ++i)
00805     {
00806         zp = &zones[i];
00807         if (zp->z_nrules == 0)
00808         {
00809             /*
00810              * Maybe we have a local standard time offset.
00811              */
00812             eat(zp->z_filename, zp->z_linenum);
00813             zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
00814                                   TRUE);
00815 
00816             /*
00817              * Note, though, that if there's no rule, a '%s' in the format is
00818              * a bad thing.
00819              */
00820             if (strchr(zp->z_format, '%') != NULL)
00821                 error(_("%s in ruleless zone"));
00822         }
00823     }
00824     if (errors)
00825         exit(EXIT_FAILURE);
00826 }
00827 
00828 static void
00829 infile(const char *name)
00830 {
00831     FILE       *fp;
00832     char      **fields;
00833     char       *cp;
00834     const struct lookup *lp;
00835     int         nfields;
00836     int         wantcont;
00837     int         num;
00838     char        buf[BUFSIZ];
00839 
00840     if (strcmp(name, "-") == 0)
00841     {
00842         name = _("standard input");
00843         fp = stdin;
00844     }
00845     else if ((fp = fopen(name, "r")) == NULL)
00846     {
00847         const char *e = strerror(errno);
00848 
00849         (void) fprintf(stderr, _("%s: Cannot open %s: %s\n"),
00850                        progname, name, e);
00851         exit(EXIT_FAILURE);
00852     }
00853     wantcont = FALSE;
00854     for (num = 1;; ++num)
00855     {
00856         eat(name, num);
00857         if (fgets(buf, (int) sizeof buf, fp) != buf)
00858             break;
00859         cp = strchr(buf, '\n');
00860         if (cp == NULL)
00861         {
00862             error(_("line too long"));
00863             exit(EXIT_FAILURE);
00864         }
00865         *cp = '\0';
00866         fields = getfields(buf);
00867         nfields = 0;
00868         while (fields[nfields] != NULL)
00869         {
00870             static char nada;
00871 
00872             if (strcmp(fields[nfields], "-") == 0)
00873                 fields[nfields] = &nada;
00874             ++nfields;
00875         }
00876         if (nfields == 0)
00877         {
00878             /* nothing to do */
00879         }
00880         else if (wantcont)
00881             wantcont = inzcont(fields, nfields);
00882         else
00883         {
00884             lp = byword(fields[0], line_codes);
00885             if (lp == NULL)
00886                 error(_("input line of unknown type"));
00887             else
00888                 switch ((int) (lp->l_value))
00889                 {
00890                     case LC_RULE:
00891                         inrule(fields, nfields);
00892                         wantcont = FALSE;
00893                         break;
00894                     case LC_ZONE:
00895                         wantcont = inzone(fields, nfields);
00896                         break;
00897                     case LC_LINK:
00898                         inlink(fields, nfields);
00899                         wantcont = FALSE;
00900                         break;
00901                     case LC_LEAP:
00902                         if (name != leapsec)
00903                             (void) fprintf(stderr,
00904                             _("%s: Leap line in non leap seconds file %s\n"),
00905                                            progname, name);
00906                         else
00907                             inleap(fields, nfields);
00908                         wantcont = FALSE;
00909                         break;
00910                     default:    /* "cannot happen" */
00911                         (void) fprintf(stderr,
00912                                        _("%s: panic: Invalid l_value %d\n"),
00913                                        progname, lp->l_value);
00914                         exit(EXIT_FAILURE);
00915                 }
00916         }
00917         ifree((char *) fields);
00918     }
00919     if (ferror(fp))
00920     {
00921         (void) fprintf(stderr, _("%s: Error reading %s\n"),
00922                        progname, filename);
00923         exit(EXIT_FAILURE);
00924     }
00925     if (fp != stdin && fclose(fp))
00926     {
00927         const char *e = strerror(errno);
00928 
00929         (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
00930                        progname, filename, e);
00931         exit(EXIT_FAILURE);
00932     }
00933     if (wantcont)
00934         error(_("expected continuation line not found"));
00935 }
00936 
00937 /*----------
00938  * Convert a string of one of the forms
00939  *  h   -h  hh:mm   -hh:mm  hh:mm:ss    -hh:mm:ss
00940  * into a number of seconds.
00941  * A null string maps to zero.
00942  * Call error with errstring and return zero on errors.
00943  *----------
00944  */
00945 static long
00946 gethms(const char *string, const char *errstring, int signable)
00947 {
00948     long        hh;
00949     int         mm,
00950                 ss,
00951                 sign;
00952 
00953     if (string == NULL || *string == '\0')
00954         return 0;
00955     if (!signable)
00956         sign = 1;
00957     else if (*string == '-')
00958     {
00959         sign = -1;
00960         ++string;
00961     }
00962     else
00963         sign = 1;
00964     if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
00965         mm = ss = 0;
00966     else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
00967         ss = 0;
00968     else if (sscanf(string, scheck(string, "%ld:%d:%d"),
00969                     &hh, &mm, &ss) != 3)
00970     {
00971         error(errstring);
00972         return 0;
00973     }
00974     if (hh < 0 ||
00975         mm < 0 || mm >= MINSPERHOUR ||
00976         ss < 0 || ss > SECSPERMIN)
00977     {
00978         error(errstring);
00979         return 0;
00980     }
00981     if (LONG_MAX / SECSPERHOUR < hh)
00982     {
00983         error(_("time overflow"));
00984         return 0;
00985     }
00986     if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
00987         warning(_("24:00 not handled by pre-1998 versions of zic"));
00988     if (noise && (hh > HOURSPERDAY ||
00989                   (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
00990         warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
00991     return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
00992                 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
00993 }
00994 
00995 static void
00996 inrule(char **fields, int nfields)
00997 {
00998     static struct rule r;
00999 
01000     if (nfields != RULE_FIELDS)
01001     {
01002         error(_("wrong number of fields on Rule line"));
01003         return;
01004     }
01005     if (*fields[RF_NAME] == '\0')
01006     {
01007         error(_("nameless rule"));
01008         return;
01009     }
01010     r.r_filename = filename;
01011     r.r_linenum = linenum;
01012     r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
01013     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
01014             fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
01015     r.r_name = ecpyalloc(fields[RF_NAME]);
01016     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
01017     if (max_abbrvar_len < strlen(r.r_abbrvar))
01018         max_abbrvar_len = strlen(r.r_abbrvar);
01019     rules = (struct rule *) (void *) erealloc((char *) rules,
01020                                        (int) ((nrules + 1) * sizeof *rules));
01021     rules[nrules++] = r;
01022 }
01023 
01024 static int
01025 inzone(char **fields, int nfields)
01026 {
01027     int         i;
01028     static char *buf;
01029 
01030     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
01031     {
01032         error(_("wrong number of fields on Zone line"));
01033         return FALSE;
01034     }
01035     if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL)
01036     {
01037         buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
01038         (void) sprintf(buf,
01039                   _("\"Zone %s\" line and -l option are mutually exclusive"),
01040                        TZDEFAULT);
01041         error(buf);
01042         return FALSE;
01043     }
01044     if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
01045     {
01046         buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
01047         (void) sprintf(buf,
01048                   _("\"Zone %s\" line and -p option are mutually exclusive"),
01049                        TZDEFRULES);
01050         error(buf);
01051         return FALSE;
01052     }
01053     for (i = 0; i < nzones; ++i)
01054         if (zones[i].z_name != NULL &&
01055             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
01056         {
01057             buf = erealloc(buf, (int) (132 +
01058                                        strlen(fields[ZF_NAME]) +
01059                                        strlen(zones[i].z_filename)));
01060             (void) sprintf(buf,
01061                            _("duplicate zone name %s (file \"%s\", line %d)"),
01062                            fields[ZF_NAME],
01063                            zones[i].z_filename,
01064                            zones[i].z_linenum);
01065             error(buf);
01066             return FALSE;
01067         }
01068     return inzsub(fields, nfields, FALSE);
01069 }
01070 
01071 static int
01072 inzcont(char **fields, int nfields)
01073 {
01074     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS)
01075     {
01076         error(_("wrong number of fields on Zone continuation line"));
01077         return FALSE;
01078     }
01079     return inzsub(fields, nfields, TRUE);
01080 }
01081 
01082 static int
01083 inzsub(char **fields, int nfields, int iscont)
01084 {
01085     char       *cp;
01086     static struct zone z;
01087     int         i_gmtoff,
01088                 i_rule,
01089                 i_format;
01090     int         i_untilyear,
01091                 i_untilmonth;
01092     int         i_untilday,
01093                 i_untiltime;
01094     int         hasuntil;
01095 
01096     if (iscont)
01097     {
01098         i_gmtoff = ZFC_GMTOFF;
01099         i_rule = ZFC_RULE;
01100         i_format = ZFC_FORMAT;
01101         i_untilyear = ZFC_TILYEAR;
01102         i_untilmonth = ZFC_TILMONTH;
01103         i_untilday = ZFC_TILDAY;
01104         i_untiltime = ZFC_TILTIME;
01105         z.z_name = NULL;
01106     }
01107     else
01108     {
01109         i_gmtoff = ZF_GMTOFF;
01110         i_rule = ZF_RULE;
01111         i_format = ZF_FORMAT;
01112         i_untilyear = ZF_TILYEAR;
01113         i_untilmonth = ZF_TILMONTH;
01114         i_untilday = ZF_TILDAY;
01115         i_untiltime = ZF_TILTIME;
01116         z.z_name = ecpyalloc(fields[ZF_NAME]);
01117     }
01118     z.z_filename = filename;
01119     z.z_linenum = linenum;
01120     z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
01121     if ((cp = strchr(fields[i_format], '%')) != NULL)
01122     {
01123         if (*++cp != 's' || strchr(cp, '%') != NULL)
01124         {
01125             error(_("invalid abbreviation format"));
01126             return FALSE;
01127         }
01128     }
01129     z.z_rule = ecpyalloc(fields[i_rule]);
01130     z.z_format = ecpyalloc(fields[i_format]);
01131     if (max_format_len < strlen(z.z_format))
01132         max_format_len = strlen(z.z_format);
01133     hasuntil = nfields > i_untilyear;
01134     if (hasuntil)
01135     {
01136         z.z_untilrule.r_filename = filename;
01137         z.z_untilrule.r_linenum = linenum;
01138         rulesub(&z.z_untilrule,
01139                 fields[i_untilyear],
01140                 "only",
01141                 "",
01142                 (nfields > i_untilmonth) ?
01143                 fields[i_untilmonth] : "Jan",
01144                 (nfields > i_untilday) ? fields[i_untilday] : "1",
01145                 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
01146         z.z_untiltime = rpytime(&z.z_untilrule,
01147                                 z.z_untilrule.r_loyear);
01148         if (iscont && nzones > 0 &&
01149             z.z_untiltime > min_time &&
01150             z.z_untiltime < max_time &&
01151             zones[nzones - 1].z_untiltime > min_time &&
01152             zones[nzones - 1].z_untiltime < max_time &&
01153             zones[nzones - 1].z_untiltime >= z.z_untiltime)
01154         {
01155             error(_("Zone continuation line end time is not after end time of previous line"));
01156             return FALSE;
01157         }
01158     }
01159     zones = (struct zone *) (void *) erealloc((char *) zones,
01160                                        (int) ((nzones + 1) * sizeof *zones));
01161     zones[nzones++] = z;
01162 
01163     /*
01164      * If there was an UNTIL field on this line, there's more information
01165      * about the zone on the next line.
01166      */
01167     return hasuntil;
01168 }
01169 
01170 static void
01171 inleap(char **fields, int nfields)
01172 {
01173     const char *cp;
01174     const struct lookup *lp;
01175     int         i,
01176                 j;
01177     int         year,
01178                 month,
01179                 day;
01180     long        dayoff,
01181                 tod;
01182     zic_t       t;
01183 
01184     if (nfields != LEAP_FIELDS)
01185     {
01186         error(_("wrong number of fields on Leap line"));
01187         return;
01188     }
01189     dayoff = 0;
01190     cp = fields[LP_YEAR];
01191     if (sscanf(cp, scheck(cp, "%d"), &year) != 1)
01192     {
01193         /*
01194          * Leapin' Lizards!
01195          */
01196         error(_("invalid leaping year"));
01197         return;
01198     }
01199     if (!leapseen || leapmaxyear < year)
01200         leapmaxyear = year;
01201     if (!leapseen || leapminyear > year)
01202         leapminyear = year;
01203     leapseen = TRUE;
01204     j = EPOCH_YEAR;
01205     while (j != year)
01206     {
01207         if (year > j)
01208         {
01209             i = len_years[isleap(j)];
01210             ++j;
01211         }
01212         else
01213         {
01214             --j;
01215             i = -len_years[isleap(j)];
01216         }
01217         dayoff = oadd(dayoff, eitol(i));
01218     }
01219     if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
01220     {
01221         error(_("invalid month name"));
01222         return;
01223     }
01224     month = lp->l_value;
01225     j = TM_JANUARY;
01226     while (j != month)
01227     {
01228         i = len_months[isleap(year)][j];
01229         dayoff = oadd(dayoff, eitol(i));
01230         ++j;
01231     }
01232     cp = fields[LP_DAY];
01233     if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
01234         day <= 0 || day > len_months[isleap(year)][month])
01235     {
01236         error(_("invalid day of month"));
01237         return;
01238     }
01239     dayoff = oadd(dayoff, eitol(day - 1));
01240     if (dayoff < min_time / SECSPERDAY)
01241     {
01242         error(_("time too small"));
01243         return;
01244     }
01245     if (dayoff > max_time / SECSPERDAY)
01246     {
01247         error(_("time too large"));
01248         return;
01249     }
01250     t = (zic_t) dayoff *SECSPERDAY;
01251 
01252     tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
01253     cp = fields[LP_CORR];
01254     {
01255         int         positive;
01256         int         count;
01257 
01258         if (strcmp(cp, "") == 0)
01259         {                       /* infile() turns "-" into "" */
01260             positive = FALSE;
01261             count = 1;
01262         }
01263         else if (strcmp(cp, "--") == 0)
01264         {
01265             positive = FALSE;
01266             count = 2;
01267         }
01268         else if (strcmp(cp, "+") == 0)
01269         {
01270             positive = TRUE;
01271             count = 1;
01272         }
01273         else if (strcmp(cp, "++") == 0)
01274         {
01275             positive = TRUE;
01276             count = 2;
01277         }
01278         else
01279         {
01280             error(_("illegal CORRECTION field on Leap line"));
01281             return;
01282         }
01283         if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL)
01284         {
01285             error(_("illegal Rolling/Stationary field on Leap line"));
01286             return;
01287         }
01288         leapadd(tadd(t, tod), positive, lp->l_value, count);
01289     }
01290 }
01291 
01292 static void
01293 inlink(char **fields, int nfields)
01294 {
01295     struct link l;
01296 
01297     if (nfields != LINK_FIELDS)
01298     {
01299         error(_("wrong number of fields on Link line"));
01300         return;
01301     }
01302     if (*fields[LF_FROM] == '\0')
01303     {
01304         error(_("blank FROM field on Link line"));
01305         return;
01306     }
01307     if (*fields[LF_TO] == '\0')
01308     {
01309         error(_("blank TO field on Link line"));
01310         return;
01311     }
01312     l.l_filename = filename;
01313     l.l_linenum = linenum;
01314     l.l_from = ecpyalloc(fields[LF_FROM]);
01315     l.l_to = ecpyalloc(fields[LF_TO]);
01316     links = (struct link *) (void *) erealloc((char *) links,
01317                                        (int) ((nlinks + 1) * sizeof *links));
01318     links[nlinks++] = l;
01319 }
01320 
01321 static void
01322 rulesub(struct rule * rp, const char *loyearp, const char *hiyearp,
01323         const char *typep, const char *monthp, const char *dayp,
01324         const char *timep)
01325 {
01326     const struct lookup *lp;
01327     const char *cp;
01328     char       *dp;
01329     char       *ep;
01330 
01331     if ((lp = byword(monthp, mon_names)) == NULL)
01332     {
01333         error(_("invalid month name"));
01334         return;
01335     }
01336     rp->r_month = lp->l_value;
01337     rp->r_todisstd = FALSE;
01338     rp->r_todisgmt = FALSE;
01339     dp = ecpyalloc(timep);
01340     if (*dp != '\0')
01341     {
01342         ep = dp + strlen(dp) - 1;
01343         switch (lowerit(*ep))
01344         {
01345             case 's':           /* Standard */
01346                 rp->r_todisstd = TRUE;
01347                 rp->r_todisgmt = FALSE;
01348                 *ep = '\0';
01349                 break;
01350             case 'w':           /* Wall */
01351                 rp->r_todisstd = FALSE;
01352                 rp->r_todisgmt = FALSE;
01353                 *ep = '\0';
01354                 break;
01355             case 'g':           /* Greenwich */
01356             case 'u':           /* Universal */
01357             case 'z':           /* Zulu */
01358                 rp->r_todisstd = TRUE;
01359                 rp->r_todisgmt = TRUE;
01360                 *ep = '\0';
01361                 break;
01362         }
01363     }
01364     rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
01365     ifree(dp);
01366 
01367     /*
01368      * Year work.
01369      */
01370     cp = loyearp;
01371     lp = byword(cp, begin_years);
01372     rp->r_lowasnum = lp == NULL;
01373     if (!rp->r_lowasnum)
01374         switch ((int) lp->l_value)
01375         {
01376             case YR_MINIMUM:
01377                 rp->r_loyear = INT_MIN;
01378                 break;
01379             case YR_MAXIMUM:
01380                 rp->r_loyear = INT_MAX;
01381                 break;
01382             default:            /* "cannot happen" */
01383                 (void) fprintf(stderr,
01384                                _("%s: panic: Invalid l_value %d\n"),
01385                                progname, lp->l_value);
01386                 exit(EXIT_FAILURE);
01387         }
01388     else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1)
01389     {
01390         error(_("invalid starting year"));
01391         return;
01392     }
01393     cp = hiyearp;
01394     lp = byword(cp, end_years);
01395     rp->r_hiwasnum = lp == NULL;
01396     if (!rp->r_hiwasnum)
01397         switch ((int) lp->l_value)
01398         {
01399             case YR_MINIMUM:
01400                 rp->r_hiyear = INT_MIN;
01401                 break;
01402             case YR_MAXIMUM:
01403                 rp->r_hiyear = INT_MAX;
01404                 break;
01405             case YR_ONLY:
01406                 rp->r_hiyear = rp->r_loyear;
01407                 break;
01408             default:            /* "cannot happen" */
01409                 (void) fprintf(stderr,
01410                                _("%s: panic: Invalid l_value %d\n"),
01411                                progname, lp->l_value);
01412                 exit(EXIT_FAILURE);
01413         }
01414     else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1)
01415     {
01416         error(_("invalid ending year"));
01417         return;
01418     }
01419     if (rp->r_loyear > rp->r_hiyear)
01420     {
01421         error(_("starting year greater than ending year"));
01422         return;
01423     }
01424     if (*typep == '\0')
01425         rp->r_yrtype = NULL;
01426     else
01427     {
01428         if (rp->r_loyear == rp->r_hiyear)
01429         {
01430             error(_("typed single year"));
01431             return;
01432         }
01433         rp->r_yrtype = ecpyalloc(typep);
01434     }
01435 
01436     /*
01437      * Day work. Accept things such as:  1  last-Sunday  Sun<=20  Sun>=7
01438      */
01439     dp = ecpyalloc(dayp);
01440     if ((lp = byword(dp, lasts)) != NULL)
01441     {
01442         rp->r_dycode = DC_DOWLEQ;
01443         rp->r_wday = lp->l_value;
01444         rp->r_dayofmonth = len_months[1][rp->r_month];
01445     }
01446     else
01447     {
01448         if ((ep = strchr(dp, '<')) != NULL)
01449             rp->r_dycode = DC_DOWLEQ;
01450         else if ((ep = strchr(dp, '>')) != NULL)
01451             rp->r_dycode = DC_DOWGEQ;
01452         else
01453         {
01454             ep = dp;
01455             rp->r_dycode = DC_DOM;
01456         }
01457         if (rp->r_dycode != DC_DOM)
01458         {
01459             *ep++ = 0;
01460             if (*ep++ != '=')
01461             {
01462                 error(_("invalid day of month"));
01463                 ifree(dp);
01464                 return;
01465             }
01466             if ((lp = byword(dp, wday_names)) == NULL)
01467             {
01468                 error(_("invalid weekday name"));
01469                 ifree(dp);
01470                 return;
01471             }
01472             rp->r_wday = lp->l_value;
01473         }
01474         if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
01475             rp->r_dayofmonth <= 0 ||
01476             (rp->r_dayofmonth > len_months[1][rp->r_month]))
01477         {
01478             error(_("invalid day of month"));
01479             ifree(dp);
01480             return;
01481         }
01482     }
01483     ifree(dp);
01484 }
01485 
01486 static void
01487 convert(long val, char *buf)
01488 {
01489     int         i;
01490     int         shift;
01491 
01492     for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
01493         buf[i] = val >> shift;
01494 }
01495 
01496 static void
01497 convert64(zic_t val, char *buf)
01498 {
01499     int         i;
01500     int         shift;
01501 
01502     for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
01503         buf[i] = val >> shift;
01504 }
01505 
01506 static void
01507 puttzcode(long val, FILE *fp)
01508 {
01509     char        buf[4];
01510 
01511     convert(val, buf);
01512     (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
01513 }
01514 
01515 static void
01516 puttzcode64(zic_t val, FILE *fp)
01517 {
01518     char        buf[8];
01519 
01520     convert64(val, buf);
01521     (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
01522 }
01523 
01524 static int
01525 atcomp(const void *avp, const void *bvp)
01526 {
01527     const zic_t a = ((const struct attype *) avp)->at;
01528     const zic_t b = ((const struct attype *) bvp)->at;
01529 
01530     return (a < b) ? -1 : (a > b);
01531 }
01532 
01533 static int
01534 is32(zic_t x)
01535 {
01536     return x == ((zic_t) ((int32) x));
01537 }
01538 
01539 static void
01540 writezone(const char *name, const char *string)
01541 {
01542     FILE       *fp;
01543     int         i,
01544                 j;
01545     int         leapcnt32,
01546                 leapi32;
01547     int         timecnt32,
01548                 timei32;
01549     int         pass;
01550     static char *fullname;
01551     static const struct tzhead tzh0;
01552     static struct tzhead tzh;
01553     zic_t       ats[TZ_MAX_TIMES];
01554     unsigned char types[TZ_MAX_TIMES];
01555 
01556     /*
01557      * Sort.
01558      */
01559     if (timecnt > 1)
01560         (void) qsort((void *) attypes, (size_t) timecnt,
01561                      (size_t) sizeof *attypes, atcomp);
01562 
01563     /*
01564      * Optimize.
01565      */
01566     {
01567         int         fromi;
01568         int         toi;
01569 
01570         toi = 0;
01571         fromi = 0;
01572         while (fromi < timecnt && attypes[fromi].at < min_time)
01573             ++fromi;
01574         if (isdsts[0] == 0)
01575             while (fromi < timecnt && attypes[fromi].type == 0)
01576                 ++fromi;        /* handled by default rule */
01577         for (; fromi < timecnt; ++fromi)
01578         {
01579             if (toi != 0
01580                 && ((attypes[fromi].at
01581                      + gmtoffs[attypes[toi - 1].type])
01582                     <= (attypes[toi - 1].at
01583                         + gmtoffs[toi == 1 ? 0
01584                                   : attypes[toi - 2].type])))
01585             {
01586                 attypes[toi - 1].type = attypes[fromi].type;
01587                 continue;
01588             }
01589             if (toi == 0 ||
01590                 attypes[toi - 1].type != attypes[fromi].type)
01591                 attypes[toi++] = attypes[fromi];
01592         }
01593         timecnt = toi;
01594     }
01595 
01596     /*
01597      * Transfer.
01598      */
01599     for (i = 0; i < timecnt; ++i)
01600     {
01601         ats[i] = attypes[i].at;
01602         types[i] = attypes[i].type;
01603     }
01604 
01605     /*
01606      * Correct for leap seconds.
01607      */
01608     for (i = 0; i < timecnt; ++i)
01609     {
01610         j = leapcnt;
01611         while (--j >= 0)
01612             if (ats[i] > trans[j] - corr[j])
01613             {
01614                 ats[i] = tadd(ats[i], corr[j]);
01615                 break;
01616             }
01617     }
01618 
01619     /*
01620      * Figure out 32-bit-limited starts and counts.
01621      */
01622     timecnt32 = timecnt;
01623     timei32 = 0;
01624     leapcnt32 = leapcnt;
01625     leapi32 = 0;
01626     while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
01627         --timecnt32;
01628     while (timecnt32 > 0 && !is32(ats[timei32]))
01629     {
01630         --timecnt32;
01631         ++timei32;
01632     }
01633     while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
01634         --leapcnt32;
01635     while (leapcnt32 > 0 && !is32(trans[leapi32]))
01636     {
01637         --leapcnt32;
01638         ++leapi32;
01639     }
01640     fullname = erealloc(fullname,
01641                         (int) (strlen(directory) + 1 + strlen(name) + 1));
01642     (void) sprintf(fullname, "%s/%s", directory, name);
01643 
01644     /*
01645      * Remove old file, if any, to snap links.
01646      */
01647     if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
01648     {
01649         const char *e = strerror(errno);
01650 
01651         (void) fprintf(stderr, _("%s: Cannot remove %s: %s\n"),
01652                        progname, fullname, e);
01653         exit(EXIT_FAILURE);
01654     }
01655     if ((fp = fopen(fullname, "wb")) == NULL)
01656     {
01657         if (mkdirs(fullname) != 0)
01658             (void) exit(EXIT_FAILURE);
01659         if ((fp = fopen(fullname, "wb")) == NULL)
01660         {
01661             const char *e = strerror(errno);
01662 
01663             (void) fprintf(stderr, _("%s: Cannot create %s: %s\n"),
01664                            progname, fullname, e);
01665             exit(EXIT_FAILURE);
01666         }
01667     }
01668     for (pass = 1; pass <= 2; ++pass)
01669     {
01670         register int thistimei,
01671                     thistimecnt;
01672         register int thisleapi,
01673                     thisleapcnt;
01674         register int thistimelim,
01675                     thisleaplim;
01676         int         writetype[TZ_MAX_TIMES];
01677         int         typemap[TZ_MAX_TYPES];
01678         register int thistypecnt;
01679         char        thischars[TZ_MAX_CHARS];
01680         char        thischarcnt;
01681         int         indmap[TZ_MAX_CHARS];
01682 
01683         if (pass == 1)
01684         {
01685             thistimei = timei32;
01686             thistimecnt = timecnt32;
01687             thisleapi = leapi32;
01688             thisleapcnt = leapcnt32;
01689         }
01690         else
01691         {
01692             thistimei = 0;
01693             thistimecnt = timecnt;
01694             thisleapi = 0;
01695             thisleapcnt = leapcnt;
01696         }
01697         thistimelim = thistimei + thistimecnt;
01698         thisleaplim = thisleapi + thisleapcnt;
01699         for (i = 0; i < typecnt; ++i)
01700             writetype[i] = thistimecnt == timecnt;
01701         if (thistimecnt == 0)
01702         {
01703             /*
01704              * * No transition times fall in the current * (32- or 64-bit)
01705              * window.
01706              */
01707             if (typecnt != 0)
01708                 writetype[typecnt - 1] = TRUE;
01709         }
01710         else
01711         {
01712             for (i = thistimei - 1; i < thistimelim; ++i)
01713                 if (i >= 0)
01714                     writetype[types[i]] = TRUE;
01715 
01716             /*
01717              * * For America/Godthab and Antarctica/Palmer
01718              */
01719             if (thistimei == 0)
01720                 writetype[0] = TRUE;
01721         }
01722         thistypecnt = 0;
01723         for (i = 0; i < typecnt; ++i)
01724             typemap[i] = writetype[i] ? thistypecnt++ : -1;
01725         for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
01726             indmap[i] = -1;
01727         thischarcnt = 0;
01728         for (i = 0; i < typecnt; ++i)
01729         {
01730             register char *thisabbr;
01731 
01732             if (!writetype[i])
01733                 continue;
01734             if (indmap[abbrinds[i]] >= 0)
01735                 continue;
01736             thisabbr = &chars[abbrinds[i]];
01737             for (j = 0; j < thischarcnt; ++j)
01738                 if (strcmp(&thischars[j], thisabbr) == 0)
01739                     break;
01740             if (j == thischarcnt)
01741             {
01742                 (void) strcpy(&thischars[(int) thischarcnt],
01743                               thisabbr);
01744                 thischarcnt += strlen(thisabbr) + 1;
01745             }
01746             indmap[abbrinds[i]] = j;
01747         }
01748 #define DO(field)   (void) fwrite((void *) tzh.field, \
01749                 (size_t) sizeof tzh.field, (size_t) 1, fp)
01750         tzh = tzh0;
01751         (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
01752         tzh.tzh_version[0] = ZIC_VERSION;
01753         convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
01754         convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
01755         convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
01756         convert(eitol(thistimecnt), tzh.tzh_timecnt);
01757         convert(eitol(thistypecnt), tzh.tzh_typecnt);
01758         convert(eitol(thischarcnt), tzh.tzh_charcnt);
01759         DO(tzh_magic);
01760         DO(tzh_version);
01761         DO(tzh_reserved);
01762         DO(tzh_ttisgmtcnt);
01763         DO(tzh_ttisstdcnt);
01764         DO(tzh_leapcnt);
01765         DO(tzh_timecnt);
01766         DO(tzh_typecnt);
01767         DO(tzh_charcnt);
01768 #undef DO
01769         for (i = thistimei; i < thistimelim; ++i)
01770             if (pass == 1)
01771                 puttzcode((long) ats[i], fp);
01772             else
01773                 puttzcode64(ats[i], fp);
01774         for (i = thistimei; i < thistimelim; ++i)
01775         {
01776             unsigned char uc;
01777 
01778             uc = typemap[types[i]];
01779             (void) fwrite((void *) &uc,
01780                           (size_t) sizeof uc,
01781                           (size_t) 1,
01782                           fp);
01783         }
01784         for (i = 0; i < typecnt; ++i)
01785             if (writetype[i])
01786             {
01787                 puttzcode(gmtoffs[i], fp);
01788                 (void) putc(isdsts[i], fp);
01789                 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
01790 
01791                 /* Print current timezone abbreviations if requested */
01792                 if (print_abbrevs && pass == 2 &&
01793                     (ats[i] >= print_cutoff || i == typecnt - 1))
01794                 {
01795                     char *thisabbrev = &thischars[indmap[abbrinds[i]]];
01796 
01797                     /* filter out assorted junk entries */
01798                     if (strcmp(thisabbrev, GRANDPARENTED) != 0 &&
01799                         strcmp(thisabbrev, "zzz") != 0)
01800                         fprintf(stdout, "%s\t%ld%s\n",
01801                                 thisabbrev,
01802                                 gmtoffs[i],
01803                                 isdsts[i] ? "\tD" : "");
01804                 }
01805             }
01806         if (thischarcnt != 0)
01807             (void) fwrite((void *) thischars,
01808                           (size_t) sizeof thischars[0],
01809                           (size_t) thischarcnt, fp);
01810         for (i = thisleapi; i < thisleaplim; ++i)
01811         {
01812             register zic_t todo;
01813 
01814             if (roll[i])
01815             {
01816                 if (timecnt == 0 || trans[i] < ats[0])
01817                 {
01818                     j = 0;
01819                     while (isdsts[j])
01820                         if (++j >= typecnt)
01821                         {
01822                             j = 0;
01823                             break;
01824                         }
01825                 }
01826                 else
01827                 {
01828                     j = 1;
01829                     while (j < timecnt &&
01830                            trans[i] >= ats[j])
01831                         ++j;
01832                     j = types[j - 1];
01833                 }
01834                 todo = tadd(trans[i], -gmtoffs[j]);
01835             }
01836             else
01837                 todo = trans[i];
01838             if (pass == 1)
01839                 puttzcode((long) todo, fp);
01840             else
01841                 puttzcode64(todo, fp);
01842             puttzcode(corr[i], fp);
01843         }
01844         for (i = 0; i < typecnt; ++i)
01845             if (writetype[i])
01846                 (void) putc(ttisstds[i], fp);
01847         for (i = 0; i < typecnt; ++i)
01848             if (writetype[i])
01849                 (void) putc(ttisgmts[i], fp);
01850     }
01851     (void) fprintf(fp, "\n%s\n", string);
01852     if (ferror(fp) || fclose(fp))
01853     {
01854         (void) fprintf(stderr, _("%s: Error writing %s\n"),
01855                        progname, fullname);
01856         exit(EXIT_FAILURE);
01857     }
01858 }
01859 
01860 static void
01861 doabbr(char *abbr, const char *format, const char *letters, int isdst,
01862        int doquotes)
01863 {
01864     char       *cp;
01865     char       *slashp;
01866     int         len;
01867 
01868     slashp = strchr(format, '/');
01869     if (slashp == NULL)
01870     {
01871         if (letters == NULL)
01872             (void) strcpy(abbr, format);
01873         else
01874             (void) sprintf(abbr, format, letters);
01875     }
01876     else if (isdst)
01877         (void) strcpy(abbr, slashp + 1);
01878     else
01879     {
01880         if (slashp > format)
01881             (void) strncpy(abbr, format,
01882                            (unsigned) (slashp - format));
01883         abbr[slashp - format] = '\0';
01884     }
01885     if (!doquotes)
01886         return;
01887     for (cp = abbr; *cp != '\0'; ++cp)
01888         if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
01889             strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
01890             break;
01891     len = strlen(abbr);
01892     if (len > 0 && *cp == '\0')
01893         return;
01894     abbr[len + 2] = '\0';
01895     abbr[len + 1] = '>';
01896     for (; len > 0; --len)
01897         abbr[len] = abbr[len - 1];
01898     abbr[0] = '<';
01899 }
01900 
01901 static void
01902 updateminmax(int x)
01903 {
01904     if (min_year > x)
01905         min_year = x;
01906     if (max_year < x)
01907         max_year = x;
01908 }
01909 
01910 static int
01911 stringoffset(char *result, long offset)
01912 {
01913     int         hours;
01914     int         minutes;
01915     int         seconds;
01916 
01917     result[0] = '\0';
01918     if (offset < 0)
01919     {
01920         (void) strcpy(result, "-");
01921         offset = -offset;
01922     }
01923     seconds = offset % SECSPERMIN;
01924     offset /= SECSPERMIN;
01925     minutes = offset % MINSPERHOUR;
01926     offset /= MINSPERHOUR;
01927     hours = offset;
01928     if (hours >= HOURSPERDAY)
01929     {
01930         result[0] = '\0';
01931         return -1;
01932     }
01933     (void) sprintf(end(result), "%d", hours);
01934     if (minutes != 0 || seconds != 0)
01935     {
01936         (void) sprintf(end(result), ":%02d", minutes);
01937         if (seconds != 0)
01938             (void) sprintf(end(result), ":%02d", seconds);
01939     }
01940     return 0;
01941 }
01942 
01943 static int
01944 stringrule(char *result, const struct rule * rp, long dstoff, long gmtoff)
01945 {
01946     long        tod;
01947 
01948     result = end(result);
01949     if (rp->r_dycode == DC_DOM)
01950     {
01951         int         month,
01952                     total;
01953 
01954         if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
01955             return -1;
01956         total = 0;
01957         for (month = 0; month < rp->r_month; ++month)
01958             total += len_months[0][month];
01959         (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
01960     }
01961     else
01962     {
01963         int         week;
01964 
01965         if (rp->r_dycode == DC_DOWGEQ)
01966         {
01967             week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
01968             if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
01969                 return -1;
01970         }
01971         else if (rp->r_dycode == DC_DOWLEQ)
01972         {
01973             if (rp->r_dayofmonth == len_months[1][rp->r_month])
01974                 week = 5;
01975             else
01976             {
01977                 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
01978                 if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
01979                     return -1;
01980             }
01981         }
01982         else
01983             return -1;          /* "cannot happen" */
01984         (void) sprintf(result, "M%d.%d.%d",
01985                        rp->r_month + 1, week, rp->r_wday);
01986     }
01987     tod = rp->r_tod;
01988     if (rp->r_todisgmt)
01989         tod += gmtoff;
01990     if (rp->r_todisstd && rp->r_stdoff == 0)
01991         tod += dstoff;
01992     if (tod < 0)
01993     {
01994         result[0] = '\0';
01995         return -1;
01996     }
01997     if (tod != 2 * SECSPERMIN * MINSPERHOUR)
01998     {
01999         (void) strcat(result, "/");
02000         if (stringoffset(end(result), tod) != 0)
02001             return -1;
02002     }
02003     return 0;
02004 }
02005 
02006 static void
02007 stringzone(char *result, const struct zone * zpfirst, int zonecount)
02008 {
02009     const struct zone *zp;
02010     struct rule *rp;
02011     struct rule *stdrp;
02012     struct rule *dstrp;
02013     int         i;
02014     const char *abbrvar;
02015 
02016     result[0] = '\0';
02017     zp = zpfirst + zonecount - 1;
02018     stdrp = dstrp = NULL;
02019     for (i = 0; i < zp->z_nrules; ++i)
02020     {
02021         rp = &zp->z_rules[i];
02022         if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
02023             continue;
02024         if (rp->r_yrtype != NULL)
02025             continue;
02026         if (rp->r_stdoff == 0)
02027         {
02028             if (stdrp == NULL)
02029                 stdrp = rp;
02030             else
02031                 return;
02032         }
02033         else
02034         {
02035             if (dstrp == NULL)
02036                 dstrp = rp;
02037             else
02038                 return;
02039         }
02040     }
02041     if (stdrp == NULL && dstrp == NULL)
02042     {
02043         /*
02044          * There are no rules running through "max". Let's find the latest
02045          * rule.
02046          */
02047         for (i = 0; i < zp->z_nrules; ++i)
02048         {
02049             rp = &zp->z_rules[i];
02050             if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
02051                 (rp->r_hiyear == stdrp->r_hiyear &&
02052                  rp->r_month > stdrp->r_month))
02053                 stdrp = rp;
02054         }
02055         if (stdrp != NULL && stdrp->r_stdoff != 0)
02056             return;             /* We end up in DST (a POSIX no-no). */
02057 
02058         /*
02059          * Horrid special case: if year is 2037, presume this is a zone
02060          * handled on a year-by-year basis; do not try to apply a rule to the
02061          * zone.
02062          */
02063         if (stdrp != NULL && stdrp->r_hiyear == 2037)
02064             return;
02065     }
02066     if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
02067         return;
02068     abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
02069     doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
02070     if (stringoffset(end(result), -zp->z_gmtoff) != 0)
02071     {
02072         result[0] = '\0';
02073         return;
02074     }
02075     if (dstrp == NULL)
02076         return;
02077     doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
02078     if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
02079         if (stringoffset(end(result),
02080                          -(zp->z_gmtoff + dstrp->r_stdoff)) != 0)
02081         {
02082             result[0] = '\0';
02083             return;
02084         }
02085     (void) strcat(result, ",");
02086     if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0)
02087     {
02088         result[0] = '\0';
02089         return;
02090     }
02091     (void) strcat(result, ",");
02092     if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0)
02093     {
02094         result[0] = '\0';
02095         return;
02096     }
02097 }
02098 
02099 static void
02100 outzone(const struct zone * zpfirst, int zonecount)
02101 {
02102     const struct zone *zp;
02103     struct rule *rp;
02104     int         i,
02105                 j;
02106     int         usestart,
02107                 useuntil;
02108     zic_t       starttime = 0;
02109     zic_t       untiltime = 0;
02110     long        gmtoff;
02111     long        stdoff;
02112     int         year;
02113     long        startoff;
02114     int         startttisstd;
02115     int         startttisgmt;
02116     int         type;
02117     char       *startbuf;
02118     char       *ab;
02119     char       *envvar;
02120     int         max_abbr_len;
02121     int         max_envvar_len;
02122 
02123     max_abbr_len = 2 + max_format_len + max_abbrvar_len;
02124     max_envvar_len = 2 * max_abbr_len + 5 * 9;
02125     startbuf = emalloc(max_abbr_len + 1);
02126     ab = emalloc(max_abbr_len + 1);
02127     envvar = emalloc(max_envvar_len + 1);
02128 
02129     /*
02130      * Now. . .finally. . .generate some useful data!
02131      */
02132     timecnt = 0;
02133     typecnt = 0;
02134     charcnt = 0;
02135 
02136     /*
02137      * Thanks to Earl Chew for noting the need to unconditionally initialize
02138      * startttisstd.
02139      */
02140     startttisstd = FALSE;
02141     startttisgmt = FALSE;
02142     min_year = max_year = EPOCH_YEAR;
02143     if (leapseen)
02144     {
02145         updateminmax(leapminyear);
02146         updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
02147     }
02148     for (i = 0; i < zonecount; ++i)
02149     {
02150         zp = &zpfirst[i];
02151         if (i < zonecount - 1)
02152             updateminmax(zp->z_untilrule.r_loyear);
02153         for (j = 0; j < zp->z_nrules; ++j)
02154         {
02155             rp = &zp->z_rules[j];
02156             if (rp->r_lowasnum)
02157                 updateminmax(rp->r_loyear);
02158             if (rp->r_hiwasnum)
02159                 updateminmax(rp->r_hiyear);
02160         }
02161     }
02162 
02163     /*
02164      * Generate lots of data if a rule can't cover all future times.
02165      */
02166     stringzone(envvar, zpfirst, zonecount);
02167     if (noise && envvar[0] == '\0')
02168     {
02169         char       *wp;
02170 
02171         wp = ecpyalloc(_("no POSIX environment variable for zone"));
02172         wp = ecatalloc(wp, " ");
02173         wp = ecatalloc(wp, zpfirst->z_name);
02174         warning(wp);
02175         ifree(wp);
02176     }
02177     if (envvar[0] == '\0')
02178     {
02179         if (min_year >= INT_MIN + YEARSPERREPEAT)
02180             min_year -= YEARSPERREPEAT;
02181         else
02182             min_year = INT_MIN;
02183         if (max_year <= INT_MAX - YEARSPERREPEAT)
02184             max_year += YEARSPERREPEAT;
02185         else
02186             max_year = INT_MAX;
02187     }
02188 
02189     /*
02190      * For the benefit of older systems, generate data from 1900 through 2037.
02191      */
02192     if (min_year > 1900)
02193         min_year = 1900;
02194     if (max_year < 2037)
02195         max_year = 2037;
02196     for (i = 0; i < zonecount; ++i)
02197     {
02198         /*
02199          * A guess that may well be corrected later.
02200          */
02201         stdoff = 0;
02202         zp = &zpfirst[i];
02203         usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
02204         useuntil = i < (zonecount - 1);
02205         if (useuntil && zp->z_untiltime <= min_time)
02206             continue;
02207         gmtoff = zp->z_gmtoff;
02208         eat(zp->z_filename, zp->z_linenum);
02209         *startbuf = '\0';
02210         startoff = zp->z_gmtoff;
02211         if (zp->z_nrules == 0)
02212         {
02213             stdoff = zp->z_stdoff;
02214             doabbr(startbuf, zp->z_format,
02215                    (char *) NULL, stdoff != 0, FALSE);
02216             type = addtype(oadd(zp->z_gmtoff, stdoff),
02217                            startbuf, stdoff != 0, startttisstd,
02218                            startttisgmt);
02219             if (usestart)
02220             {
02221                 addtt(starttime, type);
02222                 usestart = FALSE;
02223             }
02224             else if (stdoff != 0)
02225                 addtt(min_time, type);
02226         }
02227         else
02228             for (year = min_year; year <= max_year; ++year)
02229             {
02230                 if (useuntil && year > zp->z_untilrule.r_hiyear)
02231                     break;
02232 
02233                 /*
02234                  * Mark which rules to do in the current year. For those to
02235                  * do, calculate rpytime(rp, year);
02236                  */
02237                 for (j = 0; j < zp->z_nrules; ++j)
02238                 {
02239                     rp = &zp->z_rules[j];
02240                     eats(zp->z_filename, zp->z_linenum,
02241                          rp->r_filename, rp->r_linenum);
02242                     rp->r_todo = year >= rp->r_loyear &&
02243                         year <= rp->r_hiyear &&
02244                         yearistype(year, rp->r_yrtype);
02245                     if (rp->r_todo)
02246                         rp->r_temp = rpytime(rp, year);
02247                 }
02248                 for (;;)
02249                 {
02250                     int         k;
02251                     zic_t       jtime,
02252                                 ktime = 0;
02253                     long        offset;
02254 
02255                     if (useuntil)
02256                     {
02257                         /*
02258                          * Turn untiltime into UTC assuming the current gmtoff
02259                          * and stdoff values.
02260                          */
02261                         untiltime = zp->z_untiltime;
02262                         if (!zp->z_untilrule.r_todisgmt)
02263                             untiltime = tadd(untiltime,
02264                                              -gmtoff);
02265                         if (!zp->z_untilrule.r_todisstd)
02266                             untiltime = tadd(untiltime,
02267                                              -stdoff);
02268                     }
02269 
02270                     /*
02271                      * Find the rule (of those to do, if any) that takes
02272                      * effect earliest in the year.
02273                      */
02274                     k = -1;
02275                     for (j = 0; j < zp->z_nrules; ++j)
02276                     {
02277                         rp = &zp->z_rules[j];
02278                         if (!rp->r_todo)
02279                             continue;
02280                         eats(zp->z_filename, zp->z_linenum,
02281                              rp->r_filename, rp->r_linenum);
02282                         offset = rp->r_todisgmt ? 0 : gmtoff;
02283                         if (!rp->r_todisstd)
02284                             offset = oadd(offset, stdoff);
02285                         jtime = rp->r_temp;
02286                         if (jtime == min_time ||
02287                             jtime == max_time)
02288                             continue;
02289                         jtime = tadd(jtime, -offset);
02290                         if (k < 0 || jtime < ktime)
02291                         {
02292                             k = j;
02293                             ktime = jtime;
02294                         }
02295                     }
02296                     if (k < 0)
02297                         break;  /* go on to next year */
02298                     rp = &zp->z_rules[k];
02299                     rp->r_todo = FALSE;
02300                     if (useuntil && ktime >= untiltime)
02301                         break;
02302                     stdoff = rp->r_stdoff;
02303                     if (usestart && ktime == starttime)
02304                         usestart = FALSE;
02305                     if (usestart)
02306                     {
02307                         if (ktime < starttime)
02308                         {
02309                             startoff = oadd(zp->z_gmtoff,
02310                                             stdoff);
02311                             doabbr(startbuf, zp->z_format,
02312                                    rp->r_abbrvar,
02313                                    rp->r_stdoff != 0,
02314                                    FALSE);
02315                             continue;
02316                         }
02317                         if (*startbuf == '\0' &&
02318                             startoff == oadd(zp->z_gmtoff, stdoff))
02319                         {
02320                             doabbr(startbuf,
02321                                    zp->z_format,
02322                                    rp->r_abbrvar,
02323                                    rp->r_stdoff !=
02324                                    0,
02325                                    FALSE);
02326                         }
02327                     }
02328                     eats(zp->z_filename, zp->z_linenum,
02329                          rp->r_filename, rp->r_linenum);
02330                     doabbr(ab, zp->z_format, rp->r_abbrvar,
02331                            rp->r_stdoff != 0, FALSE);
02332                     offset = oadd(zp->z_gmtoff, rp->r_stdoff);
02333                     type = addtype(offset, ab, rp->r_stdoff != 0,
02334                                    rp->r_todisstd, rp->r_todisgmt);
02335                     addtt(ktime, type);
02336                 }
02337             }
02338         if (usestart)
02339         {
02340             if (*startbuf == '\0' &&
02341                 zp->z_format != NULL &&
02342                 strchr(zp->z_format, '%') == NULL &&
02343                 strchr(zp->z_format, '/') == NULL)
02344                 (void) strcpy(startbuf, zp->z_format);
02345             eat(zp->z_filename, zp->z_linenum);
02346             if (*startbuf == '\0')
02347                 error(_("cannot determine time zone abbreviation to use just after until time"));
02348             else
02349                 addtt(starttime,
02350                       addtype(startoff, startbuf,
02351                               startoff != zp->z_gmtoff,
02352                               startttisstd,
02353                               startttisgmt));
02354         }
02355 
02356         /*
02357          * Now we may get to set starttime for the next zone line.
02358          */
02359         if (useuntil)
02360         {
02361             startttisstd = zp->z_untilrule.r_todisstd;
02362             startttisgmt = zp->z_untilrule.r_todisgmt;
02363             starttime = zp->z_untiltime;
02364             if (!startttisstd)
02365                 starttime = tadd(starttime, -stdoff);
02366             if (!startttisgmt)
02367                 starttime = tadd(starttime, -gmtoff);
02368         }
02369     }
02370     writezone(zpfirst->z_name, envvar);
02371     ifree(startbuf);
02372     ifree(ab);
02373     ifree(envvar);
02374 }
02375 
02376 static void
02377 addtt(const zic_t starttime, int type)
02378 {
02379     if (starttime <= min_time ||
02380         (timecnt == 1 && attypes[0].at < min_time))
02381     {
02382         gmtoffs[0] = gmtoffs[type];
02383         isdsts[0] = isdsts[type];
02384         ttisstds[0] = ttisstds[type];
02385         ttisgmts[0] = ttisgmts[type];
02386         if (abbrinds[type] != 0)
02387             (void) strcpy(chars, &chars[abbrinds[type]]);
02388         abbrinds[0] = 0;
02389         charcnt = strlen(chars) + 1;
02390         typecnt = 1;
02391         timecnt = 0;
02392         type = 0;
02393     }
02394     if (timecnt >= TZ_MAX_TIMES)
02395     {
02396         error(_("too many transitions?!"));
02397         exit(EXIT_FAILURE);
02398     }
02399     attypes[timecnt].at = starttime;
02400     attypes[timecnt].type = type;
02401     ++timecnt;
02402 }
02403 
02404 static int
02405 addtype(long gmtoff, const char *abbr, int isdst,
02406         int ttisstd, int ttisgmt)
02407 {
02408     int         i;
02409     int         j;
02410 
02411     if (isdst != TRUE && isdst != FALSE)
02412     {
02413         error(_("internal error - addtype called with bad isdst"));
02414         exit(EXIT_FAILURE);
02415     }
02416     if (ttisstd != TRUE && ttisstd != FALSE)
02417     {
02418         error(_("internal error - addtype called with bad ttisstd"));
02419         exit(EXIT_FAILURE);
02420     }
02421     if (ttisgmt != TRUE && ttisgmt != FALSE)
02422     {
02423         error(_("internal error - addtype called with bad ttisgmt"));
02424         exit(EXIT_FAILURE);
02425     }
02426 
02427     /*
02428      * See if there's already an entry for this zone type. If so, just return
02429      * its index.
02430      */
02431     for (i = 0; i < typecnt; ++i)
02432     {
02433         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
02434             strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
02435             ttisstd == ttisstds[i] &&
02436             ttisgmt == ttisgmts[i])
02437             return i;
02438     }
02439 
02440     /*
02441      * There isn't one; add a new one, unless there are already too many.
02442      */
02443     if (typecnt >= TZ_MAX_TYPES)
02444     {
02445         error(_("too many local time types"));
02446         exit(EXIT_FAILURE);
02447     }
02448     if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L))
02449     {
02450         error(_("UTC offset out of range"));
02451         exit(EXIT_FAILURE);
02452     }
02453     gmtoffs[i] = gmtoff;
02454     isdsts[i] = isdst;
02455     ttisstds[i] = ttisstd;
02456     ttisgmts[i] = ttisgmt;
02457 
02458     for (j = 0; j < charcnt; ++j)
02459         if (strcmp(&chars[j], abbr) == 0)
02460             break;
02461     if (j == charcnt)
02462         newabbr(abbr);
02463     abbrinds[i] = j;
02464     ++typecnt;
02465     return i;
02466 }
02467 
02468 static void
02469 leapadd(const zic_t t, int positive, int rolling, int count)
02470 {
02471     int         i;
02472     int         j;
02473 
02474     if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS)
02475     {
02476         error(_("too many leap seconds"));
02477         exit(EXIT_FAILURE);
02478     }
02479     for (i = 0; i < leapcnt; ++i)
02480         if (t <= trans[i])
02481         {
02482             if (t == trans[i])
02483             {
02484                 error(_("repeated leap second moment"));
02485                 exit(EXIT_FAILURE);
02486             }
02487             break;
02488         }
02489     do
02490     {
02491         for (j = leapcnt; j > i; --j)
02492         {
02493             trans[j] = trans[j - 1];
02494             corr[j] = corr[j - 1];
02495             roll[j] = roll[j - 1];
02496         }
02497         trans[i] = t;
02498         corr[i] = positive ? 1L : eitol(-count);
02499         roll[i] = rolling;
02500         ++leapcnt;
02501     } while (positive && --count != 0);
02502 }
02503 
02504 static void
02505 adjleap(void)
02506 {
02507     int         i;
02508     long        last = 0;
02509 
02510     /*
02511      * propagate leap seconds forward
02512      */
02513     for (i = 0; i < leapcnt; ++i)
02514     {
02515         trans[i] = tadd(trans[i], last);
02516         last = corr[i] += last;
02517     }
02518 }
02519 
02520 static int
02521 yearistype(int year, const char *type)
02522 {
02523     static char *buf;
02524     int         result;
02525 
02526     if (type == NULL || *type == '\0')
02527         return TRUE;
02528     buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
02529     (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
02530     result = system(buf);
02531     if (WIFEXITED(result))
02532         switch (WEXITSTATUS(result))
02533         {
02534             case 0:
02535                 return TRUE;
02536             case 1:
02537                 return FALSE;
02538         }
02539     error(_("Wild result from command execution"));
02540     (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
02541                    progname, buf, result);
02542     for (;;)
02543         exit(EXIT_FAILURE);
02544 }
02545 
02546 static int
02547 lowerit(int a)
02548 {
02549     a = (unsigned char) a;
02550     return (isascii(a) && isupper(a)) ? tolower(a) : a;
02551 }
02552 
02553 static int
02554 ciequal(const char *ap, const char *bp)
02555 {
02556     while (lowerit(*ap) == lowerit(*bp++))
02557         if (*ap++ == '\0')
02558             return TRUE;
02559     return FALSE;
02560 }
02561 
02562 static int
02563 itsabbr(const char *abbr, const char *word)
02564 {
02565     if (lowerit(*abbr) != lowerit(*word))
02566         return FALSE;
02567     ++word;
02568     while (*++abbr != '\0')
02569         do
02570         {
02571             if (*word == '\0')
02572                 return FALSE;
02573         } while (lowerit(*word++) != lowerit(*abbr));
02574     return TRUE;
02575 }
02576 
02577 static const struct lookup *
02578 byword(const char *word, const struct lookup * table)
02579 {
02580     const struct lookup *foundlp;
02581     const struct lookup *lp;
02582 
02583     if (word == NULL || table == NULL)
02584         return NULL;
02585 
02586     /*
02587      * Look for exact match.
02588      */
02589     for (lp = table; lp->l_word != NULL; ++lp)
02590         if (ciequal(word, lp->l_word))
02591             return lp;
02592 
02593     /*
02594      * Look for inexact match.
02595      */
02596     foundlp = NULL;
02597     for (lp = table; lp->l_word != NULL; ++lp)
02598         if (itsabbr(word, lp->l_word))
02599         {
02600             if (foundlp == NULL)
02601                 foundlp = lp;
02602             else
02603                 return NULL;    /* multiple inexact matches */
02604         }
02605     return foundlp;
02606 }
02607 
02608 static char **
02609 getfields(char *cp)
02610 {
02611     char       *dp;
02612     char      **array;
02613     int         nsubs;
02614 
02615     if (cp == NULL)
02616         return NULL;
02617     array = (char **) (void *)
02618         emalloc((int) ((strlen(cp) + 1) * sizeof *array));
02619     nsubs = 0;
02620     for (;;)
02621     {
02622         while (isascii((unsigned char) *cp) &&
02623                isspace((unsigned char) *cp))
02624             ++cp;
02625         if (*cp == '\0' || *cp == '#')
02626             break;
02627         array[nsubs++] = dp = cp;
02628         do
02629         {
02630             if ((*dp = *cp++) != '"')
02631                 ++dp;
02632             else
02633                 while ((*dp = *cp++) != '"')
02634                     if (*dp != '\0')
02635                         ++dp;
02636                     else
02637                     {
02638                         error(_("Odd number of quotation marks"));
02639                         exit(1);
02640                     }
02641         } while (*cp != '\0' && *cp != '#' &&
02642                  (!isascii(*cp) || !isspace((unsigned char) *cp)));
02643         if (isascii(*cp) && isspace((unsigned char) *cp))
02644             ++cp;
02645         *dp = '\0';
02646     }
02647     array[nsubs] = NULL;
02648     return array;
02649 }
02650 
02651 static long
02652 oadd(long t1, long t2)
02653 {
02654     long        t;
02655 
02656     t = t1 + t2;
02657     if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1))
02658     {
02659         error(_("time overflow"));
02660         exit(EXIT_FAILURE);
02661     }
02662     return t;
02663 }
02664 
02665 static zic_t
02666 tadd(const zic_t t1, long t2)
02667 {
02668     zic_t       t;
02669 
02670     if (t1 == max_time && t2 > 0)
02671         return max_time;
02672     if (t1 == min_time && t2 < 0)
02673         return min_time;
02674     t = t1 + t2;
02675     if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1))
02676     {
02677         error(_("time overflow"));
02678         exit(EXIT_FAILURE);
02679     }
02680     return t;
02681 }
02682 
02683 /*
02684  * Given a rule, and a year, compute the date - in seconds since January 1,
02685  * 1970, 00:00 LOCAL time - in that year that the rule refers to.
02686  */
02687 
02688 static zic_t
02689 rpytime(const struct rule * rp, int wantedy)
02690 {
02691     int         y,
02692                 m,
02693                 i;
02694     long        dayoff;         /* with a nod to Margaret O. */
02695     zic_t       t;
02696 
02697     if (wantedy == INT_MIN)
02698         return min_time;
02699     if (wantedy == INT_MAX)
02700         return max_time;
02701     dayoff = 0;
02702     m = TM_JANUARY;
02703     y = EPOCH_YEAR;
02704     while (wantedy != y)
02705     {
02706         if (wantedy > y)
02707         {
02708             i = len_years[isleap(y)];
02709             ++y;
02710         }
02711         else
02712         {
02713             --y;
02714             i = -len_years[isleap(y)];
02715         }
02716         dayoff = oadd(dayoff, eitol(i));
02717     }
02718     while (m != rp->r_month)
02719     {
02720         i = len_months[isleap(y)][m];
02721         dayoff = oadd(dayoff, eitol(i));
02722         ++m;
02723     }
02724     i = rp->r_dayofmonth;
02725     if (m == TM_FEBRUARY && i == 29 && !isleap(y))
02726     {
02727         if (rp->r_dycode == DC_DOWLEQ)
02728             --i;
02729         else
02730         {
02731             error(_("use of 2/29 in non leap-year"));
02732             exit(EXIT_FAILURE);
02733         }
02734     }
02735     --i;
02736     dayoff = oadd(dayoff, eitol(i));
02737     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
02738     {
02739         long        wday;
02740 
02741 #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
02742         wday = eitol(EPOCH_WDAY);
02743 
02744         /*
02745          * Don't trust mod of negative numbers.
02746          */
02747         if (dayoff >= 0)
02748             wday = (wday + dayoff) % LDAYSPERWEEK;
02749         else
02750         {
02751             wday -= ((-dayoff) % LDAYSPERWEEK);
02752             if (wday < 0)
02753                 wday += LDAYSPERWEEK;
02754         }
02755         while (wday != eitol(rp->r_wday))
02756             if (rp->r_dycode == DC_DOWGEQ)
02757             {
02758                 dayoff = oadd(dayoff, (long) 1);
02759                 if (++wday >= LDAYSPERWEEK)
02760                     wday = 0;
02761                 ++i;
02762             }
02763             else
02764             {
02765                 dayoff = oadd(dayoff, (long) -1);
02766                 if (--wday < 0)
02767                     wday = LDAYSPERWEEK - 1;
02768                 --i;
02769             }
02770         if (i < 0 || i >= len_months[isleap(y)][m])
02771         {
02772             if (noise)
02773                 warning(_("rule goes past start/end of month--\
02774 will not work with pre-2004 versions of zic"));
02775         }
02776     }
02777     if (dayoff < min_time / SECSPERDAY)
02778         return min_time;
02779     if (dayoff > max_time / SECSPERDAY)
02780         return max_time;
02781     t = (zic_t) dayoff *SECSPERDAY;
02782 
02783     return tadd(t, rp->r_tod);
02784 }
02785 
02786 static void
02787 newabbr(const char *string)
02788 {
02789     int         i;
02790 
02791     if (strcmp(string, GRANDPARENTED) != 0)
02792     {
02793         const char *cp;
02794         char       *wp;
02795 
02796         /*
02797          * Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics optionally
02798          * followed by a + or - and a number from 1 to 14.
02799          */
02800         cp = string;
02801         wp = NULL;
02802         while (isascii((unsigned char) *cp) &&
02803                isalpha((unsigned char) *cp))
02804             ++cp;
02805         if (cp - string == 0)
02806             wp = _("time zone abbreviation lacks alphabetic at start");
02807         if (noise && cp - string > 3)
02808             wp = _("time zone abbreviation has more than 3 alphabetics");
02809         if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
02810             wp = _("time zone abbreviation has too many alphabetics");
02811         if (wp == NULL && (*cp == '+' || *cp == '-'))
02812         {
02813             ++cp;
02814             if (isascii((unsigned char) *cp) &&
02815                 isdigit((unsigned char) *cp))
02816                 if (*cp++ == '1' &&
02817                     *cp >= '0' && *cp <= '4')
02818                     ++cp;
02819         }
02820         if (*cp != '\0')
02821             wp = _("time zone abbreviation differs from POSIX standard");
02822         if (wp != NULL)
02823         {
02824             wp = ecpyalloc(wp);
02825             wp = ecatalloc(wp, " (");
02826             wp = ecatalloc(wp, string);
02827             wp = ecatalloc(wp, ")");
02828             warning(wp);
02829             ifree(wp);
02830         }
02831     }
02832     i = strlen(string) + 1;
02833     if (charcnt + i > TZ_MAX_CHARS)
02834     {
02835         error(_("too many, or too long, time zone abbreviations"));
02836         exit(EXIT_FAILURE);
02837     }
02838     (void) strcpy(&chars[charcnt], string);
02839     charcnt += eitol(i);
02840 }
02841 
02842 static int
02843 mkdirs(char *argname)
02844 {
02845     char       *name;
02846     char       *cp;
02847 
02848     if (argname == NULL || *argname == '\0')
02849         return 0;
02850     cp = name = ecpyalloc(argname);
02851     while ((cp = strchr(cp + 1, '/')) != NULL)
02852     {
02853         *cp = '\0';
02854 #ifdef WIN32
02855 
02856         /*
02857          * DOS drive specifier?
02858          */
02859         if (isalpha((unsigned char) name[0]) &&
02860             name[1] == ':' && name[2] == '\0')
02861         {
02862             *cp = '/';
02863             continue;
02864         }
02865 #endif   /* WIN32 */
02866         if (!itsdir(name))
02867         {
02868             /*
02869              * It doesn't seem to exist, so we try to create it. Creation may
02870              * fail because of the directory being created by some other
02871              * multiprocessor, so we get to do extra checking.
02872              */
02873             if (mkdir(name, MKDIR_UMASK) != 0)
02874             {
02875                 const char *e = strerror(errno);
02876 
02877                 if (errno != EEXIST || !itsdir(name))
02878                 {
02879                     (void) fprintf(stderr,
02880                                    _("%s: Cannot create directory %s: %s\n"),
02881                                    progname, name, e);
02882                     ifree(name);
02883                     return -1;
02884                 }
02885             }
02886         }
02887         *cp = '/';
02888     }
02889     ifree(name);
02890     return 0;
02891 }
02892 
02893 static long
02894 eitol(int i)
02895 {
02896     long        l;
02897 
02898     l = i;
02899     if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
02900     {
02901         (void) fprintf(stderr,
02902                        _("%s: %d did not sign extend correctly\n"),
02903                        progname, i);
02904         exit(EXIT_FAILURE);
02905     }
02906     return l;
02907 }
02908 
02909 /*
02910  * UNIX was a registered trademark of The Open Group in 2003.
02911  */
02912 
02913 
02914 #ifdef WIN32
02915 /*
02916  * To run on win32
02917  */
02918 int
02919 link(const char *oldpath, const char *newpath)
02920 {
02921     if (!CopyFile(oldpath, newpath, FALSE))
02922         return -1;
02923     return 0;
02924 }
02925 #endif
02926 
02927 /*
02928  *  This allows zic to compile by just returning a dummy value.
02929  *  localtime.c references it, but no one uses it from zic.
02930  */
02931 int
02932 pg_open_tzfile(const char *name, char *canonname)
02933 {
02934     return -1;
02935 }