Back to index

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