1 /*
   2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 #pragma ident   "%Z%%M% %I%     %E% SMI"
   6 
   7 static char     elsieid[] = "@(#)zic.c  7.128.1";
   8 
   9 /*
  10  * #define      LEAPSECOND_SUPPORT
  11  */
  12 
  13 /*
  14  * Regardless of the type of time_t, we do our work using this type.
  15  */
  16 
  17 typedef int     zic_t;
  18 
  19 #include "private.h"
  20 #include <tzfile.h>                       /* this is in system headers at Sun */
  21 
  22 #include <sys/stat.h>                     /* for umask manifest constants */
  23 #include <ctype.h>
  24 #include <locale.h>
  25 #include <stdlib.h>                       /* for getopt */
  26 
  27 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
  28 #define ZIC_MAX_ABBR_LEN_WO_WARN        6
  29 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
  30 
  31 #ifdef S_IRUSR
  32 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
  33 #else
  34 #define MKDIR_UMASK 0755
  35 #endif
  36 
  37 struct rule {
  38         const char      *r_filename;
  39         int             r_linenum;
  40         const char      *r_name;
  41 
  42         int             r_loyear;       /* for example, 1986 */
  43         int             r_hiyear;       /* for example, 1986 */
  44         const char      *r_yrtype;
  45 
  46         int             r_month;        /* 0..11 */
  47 
  48         int             r_dycode;       /* see below */
  49         int             r_dayofmonth;
  50         int             r_wday;
  51 
  52         long            r_tod;          /* time from midnight */
  53         int             r_todisstd;     /* above is standard time if TRUE */
  54                                         /* or wall clock time if FALSE */
  55         int             r_todisgmt;     /* above is GMT if TRUE */
  56                                         /* or local time if FALSE */
  57         long            r_stdoff;       /* offset from standard time */
  58         const char      *r_abbrvar;     /* variable part of abbreviation */
  59 
  60         int             r_todo;         /* a rule to do (used in outzone) */
  61         zic_t           r_temp;         /* used in outzone */
  62 };
  63 
  64 /*
  65  *      r_dycode                r_dayofmonth    r_wday
  66  */
  67 
  68 #define DC_DOM          0       /* 1..31 */     /* unused */
  69 #define DC_DOWGEQ       1       /* 1..31 */     /* 0..6 (Sun..Sat) */
  70 #define DC_DOWLEQ       2       /* 1..31 */     /* 0..6 (Sun..Sat) */
  71 
  72 struct zone {
  73         const char      *z_filename;
  74         int             z_linenum;
  75 
  76         const char      *z_name;
  77         long            z_gmtoff;
  78         const char      *z_rule;
  79         const char      *z_format;
  80 
  81         long            z_stdoff;
  82 
  83         struct rule     *z_rules;
  84         int             z_nrules;
  85 
  86         struct rule     z_untilrule;
  87         zic_t           z_untiltime;
  88 };
  89 
  90 static void     addtt(zic_t starttime, int type);
  91 static int      addtype(long gmtoff, const char *abbr, int isdst,
  92                                 int ttisstd, int ttisgmt);
  93 #ifdef LEAPSECOND_SUPPORT
  94 static void     leapadd(zic_t t, int positive, int rolling, int count);
  95 static void     adjleap(void);
  96 #endif
  97 static void     associate(void);
  98 static int      ciequal(const char *ap, const char *bp);
  99 static void     convert(long val, char *buf);
 100 static void     dolink(const char *fromfield, const char *tofield);
 101 static void     doabbr(char *abbr, const char *format,
 102                         const char *letters, int isdst);
 103 static void     eat(const char *name, int num);
 104 static void     eats(const char *name, int num,
 105                         const char *rname, int rnum);
 106 static long     eitol(int i);
 107 static void     error(const char *message);
 108 static char     **getfields(char *buf);
 109 static long     gethms(const char *string, const char *errstrng, int signable);
 110 static void     infile(const char *filename);
 111 #ifdef LEAPSECOND_SUPPORT
 112 static void     inleap(char **fields, int nfields);
 113 #endif
 114 static void     inlink(char **fields, int nfields);
 115 static void     inrule(char **fields, int nfields);
 116 static int      inzcont(char **fields, int nfields);
 117 static int      inzone(char **fields, int nfields);
 118 static int      inzsub(char **fields, int nfields, int iscont);
 119 static int      itsabbr(const char *abbr, const char *word);
 120 static int      itsdir(const char *name);
 121 static int      lowerit(int c);
 122 static char     *memcheck(char *tocheck);
 123 static int      mkdirs(char *filename);
 124 static void     newabbr(const char *abbr);
 125 static long     oadd(long t1, long t2);
 126 static void     outzone(const struct zone *zp, int ntzones);
 127 static void     puttzcode(long code, FILE *fp);
 128 static int      rcomp(const void *leftp, const void *rightp);
 129 static zic_t    rpytime(const struct rule *rp, int wantedy);
 130 static void     rulesub(struct rule *rp,
 131                         const char *loyearp, const char *hiyearp,
 132                         const char *typep, const char *monthp,
 133                         const char *dayp, const char *timep);
 134 static void     setboundaries(void);
 135 static zic_t    tadd(zic_t t1, long t2);
 136 static void     usage(void);
 137 static void     writezone(const char *name);
 138 static int      yearistype(int year, const char *type);
 139 
 140 static int              charcnt;
 141 static int              errors;
 142 static const char       *filename;
 143 static int              leapcnt;
 144 static int              linenum;
 145 static zic_t            max_time;
 146 static int              max_year;
 147 static int              max_year_representable;
 148 static zic_t            min_time;
 149 static int              min_year;
 150 static int              min_year_representable;
 151 static int              noise;
 152 static const char       *rfilename;
 153 static int              rlinenum;
 154 static const char       *progname;
 155 static int              timecnt;
 156 static int              typecnt;
 157 
 158 /*
 159  * Line codes.
 160  */
 161 
 162 #define LC_RULE         0
 163 #define LC_ZONE         1
 164 #define LC_LINK         2
 165 #define LC_LEAP         3
 166 
 167 /*
 168  * Which fields are which on a Zone line.
 169  */
 170 
 171 #define ZF_NAME         1
 172 #define ZF_GMTOFF       2
 173 #define ZF_RULE         3
 174 #define ZF_FORMAT       4
 175 #define ZF_TILYEAR      5
 176 #define ZF_TILMONTH     6
 177 #define ZF_TILDAY       7
 178 #define ZF_TILTIME      8
 179 #define ZONE_MINFIELDS  5
 180 #define ZONE_MAXFIELDS  9
 181 
 182 /*
 183  * Which fields are which on a Zone continuation line.
 184  */
 185 
 186 #define ZFC_GMTOFF      0
 187 #define ZFC_RULE        1
 188 #define ZFC_FORMAT      2
 189 #define ZFC_TILYEAR     3
 190 #define ZFC_TILMONTH    4
 191 #define ZFC_TILDAY      5
 192 #define ZFC_TILTIME     6
 193 #define ZONEC_MINFIELDS 3
 194 #define ZONEC_MAXFIELDS 7
 195 
 196 /*
 197  * Which files are which on a Rule line.
 198  */
 199 
 200 #define RF_NAME         1
 201 #define RF_LOYEAR       2
 202 #define RF_HIYEAR       3
 203 #define RF_COMMAND      4
 204 #define RF_MONTH        5
 205 #define RF_DAY          6
 206 #define RF_TOD          7
 207 #define RF_STDOFF       8
 208 #define RF_ABBRVAR      9
 209 #define RULE_FIELDS     10
 210 
 211 /*
 212  * Which fields are which on a Link line.
 213  */
 214 
 215 #define LF_FROM         1
 216 #define LF_TO           2
 217 #define LINK_FIELDS     3
 218 
 219 /*
 220  * Which fields are which on a Leap line.
 221  */
 222 
 223 #define LP_YEAR         1
 224 #define LP_MONTH        2
 225 #define LP_DAY          3
 226 #define LP_TIME         4
 227 #define LP_CORR         5
 228 #define LP_ROLL         6
 229 #define LEAP_FIELDS     7
 230 
 231 /*
 232  * Year synonyms.
 233  */
 234 
 235 #define YR_MINIMUM      0
 236 #define YR_MAXIMUM      1
 237 #define YR_ONLY         2
 238 
 239 static struct rule      *rules;
 240 static int              nrules; /* number of rules */
 241 
 242 static struct zone      *zones;
 243 static int              nzones; /* number of zones */
 244 
 245 struct link {
 246         const char      *l_filename;
 247         int             l_linenum;
 248         const char      *l_from;
 249         const char      *l_to;
 250 };
 251 
 252 static struct link      *links;
 253 static int              nlinks;
 254 
 255 struct lookup {
 256         const char      *l_word;
 257         const int       l_value;
 258 };
 259 
 260 static struct lookup const *byword(const char *string,
 261     const struct lookup *lp);
 262 
 263 static struct lookup const      line_codes[] = {
 264         { "Rule",       LC_RULE },
 265         { "Zone",       LC_ZONE },
 266         { "Link",       LC_LINK },
 267         { "Leap",       LC_LEAP },
 268         { NULL,         0}
 269 };
 270 
 271 static struct lookup const      mon_names[] = {
 272         { "January",    TM_JANUARY },
 273         { "February",   TM_FEBRUARY },
 274         { "March",      TM_MARCH },
 275         { "April",      TM_APRIL },
 276         { "May",        TM_MAY },
 277         { "June",       TM_JUNE },
 278         { "July",       TM_JULY },
 279         { "August",     TM_AUGUST },
 280         { "September",  TM_SEPTEMBER },
 281         { "October",    TM_OCTOBER },
 282         { "November",   TM_NOVEMBER },
 283         { "December",   TM_DECEMBER },
 284         { NULL,         0 }
 285 };
 286 
 287 static struct lookup const      wday_names[] = {
 288         { "Sunday",     TM_SUNDAY },
 289         { "Monday",     TM_MONDAY },
 290         { "Tuesday",    TM_TUESDAY },
 291         { "Wednesday",  TM_WEDNESDAY },
 292         { "Thursday",   TM_THURSDAY },
 293         { "Friday",     TM_FRIDAY },
 294         { "Saturday",   TM_SATURDAY },
 295         { NULL,         0 }
 296 };
 297 
 298 static struct lookup const      lasts[] = {
 299         { "last-Sunday",        TM_SUNDAY },
 300         { "last-Monday",        TM_MONDAY },
 301         { "last-Tuesday",       TM_TUESDAY },
 302         { "last-Wednesday",     TM_WEDNESDAY },
 303         { "last-Thursday",      TM_THURSDAY },
 304         { "last-Friday",        TM_FRIDAY },
 305         { "last-Saturday",      TM_SATURDAY },
 306         { NULL,                 0 }
 307 };
 308 
 309 static struct lookup const      begin_years[] = {
 310         { "minimum",    YR_MINIMUM },
 311         { "maximum",    YR_MAXIMUM },
 312         { NULL,         0 }
 313 };
 314 
 315 static struct lookup const      end_years[] = {
 316         { "minimum",    YR_MINIMUM },
 317         { "maximum",    YR_MAXIMUM },
 318         { "only",       YR_ONLY },
 319         { NULL,         0 }
 320 };
 321 
 322 static struct lookup const      leap_types[] = {
 323         { "Rolling",    TRUE },
 324         { "Stationary", FALSE },
 325         { NULL,         0 }
 326 };
 327 
 328 static const int        len_months[2][MONSPERYEAR] = {
 329         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 330         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 331 };
 332 
 333 static const int        len_years[2] = {
 334         DAYSPERNYEAR, DAYSPERLYEAR
 335 };
 336 
 337 static struct attype {
 338         zic_t           at;
 339         unsigned char   type;
 340 }                       attypes[TZ_MAX_TIMES];
 341 static long             gmtoffs[TZ_MAX_TYPES];
 342 static char             isdsts[TZ_MAX_TYPES];
 343 static unsigned char    abbrinds[TZ_MAX_TYPES];
 344 static char             ttisstds[TZ_MAX_TYPES];
 345 static char             ttisgmts[TZ_MAX_TYPES];
 346 static char             chars[TZ_MAX_CHARS];
 347 static zic_t            trans[TZ_MAX_LEAPS];
 348 static long             corr[TZ_MAX_LEAPS];
 349 static char             roll[TZ_MAX_LEAPS];
 350 
 351 /*
 352  * Memory allocation.
 353  */
 354 
 355 static char *
 356 memcheck(ptr)
 357 char * const    ptr;
 358 {
 359         if (ptr == NULL) {
 360                 const char *e = strerror(errno);
 361                 (void) fprintf(stderr, gettext("%s: Memory exhausted: %s\n"),
 362                         progname, e);
 363                 exit(EXIT_FAILURE);
 364         }
 365         return (ptr);
 366 }
 367 
 368 #define emalloc(size)           memcheck(imalloc(size))
 369 #define erealloc(ptr, size)     memcheck(irealloc((ptr), (size)))
 370 #define ecpyalloc(ptr)          memcheck(icpyalloc(ptr))
 371 #define ecatalloc(oldp, newp)   memcheck(icatalloc((oldp), (newp)))
 372 
 373 /*
 374  * Error handling.
 375  */
 376 
 377 static void
 378 eats(name, num, rname, rnum)
 379 const char * const      name;
 380 const int               num;
 381 const char * const      rname;
 382 const int               rnum;
 383 {
 384         filename = name;
 385         linenum = num;
 386         rfilename = rname;
 387         rlinenum = rnum;
 388 }
 389 
 390 static void
 391 eat(name, num)
 392 const char * const      name;
 393 const int               num;
 394 {
 395         eats(name, num, (char *)NULL, -1);
 396 }
 397 
 398 static void
 399 error(string)
 400 const char * const      string;
 401 {
 402         /*
 403          * Match the format of "cc" to allow sh users to
 404          *      zic ... 2>&1 | error -t "*" -v
 405          * on BSD systems.
 406          */
 407         (void) fprintf(stderr, gettext("\"%s\", line %d: %s"),
 408                 filename, linenum, string);
 409         if (rfilename != NULL)
 410                 (void) fprintf(stderr, gettext(" (rule from \"%s\", line %d)"),
 411                         rfilename, rlinenum);
 412         (void) fprintf(stderr, "\n");
 413         ++errors;
 414 }
 415 
 416 static void
 417 warning(string)
 418 const char * const      string;
 419 {
 420         char *cp;
 421 
 422         cp = ecpyalloc(gettext("warning: "));
 423         cp = ecatalloc(cp, string);
 424         error(cp);
 425         ifree(cp);
 426         --errors;
 427 }
 428 
 429 static void
 430 usage(void)
 431 {
 432 #ifdef LEAPSECOND_SUPPORT
 433         (void) fprintf(stderr, gettext("%s: usage is %s "
 434             "[ --version ] [ -s ] [ -v ] [ -l localtime ] "
 435             "\n\t[ -p posixrules ] [ -d directory ] [ -L leapseconds ] "
 436             "[ -y yearistype ] [ filename ... ]\n"), progname, progname);
 437 #else /* ! LEAPSECOND_SUPPORT */
 438         (void) fprintf(stderr, gettext("%s: usage is %s "
 439             "[ --version ] [ -s ] [ -v ] [ -l localtime ]"
 440             "\n\t[ -p posixrules ] [ -d directory ] [ -y yearistype ] "
 441             "[ filename ... ]\n"), progname, progname);
 442 #endif /* LEAPSECOND_SUPPORT */
 443 }
 444 
 445 static const char       *psxrules;
 446 static const char       *lcltime;
 447 static const char       *directory;
 448 static const char       *leapsec;
 449 static const char       *yitcommand;
 450 static int              sflag = FALSE;
 451 
 452 int
 453 main(argc, argv)
 454 int     argc;
 455 char    *argv[];
 456 {
 457         register int    i;
 458         register int    j;
 459         register int    c;
 460 
 461         (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
 462 
 463         (void) setlocale(LC_ALL, "");
 464 #if !defined(TEXT_DOMAIN)
 465 #define TEXT_DOMAIN     "SYS_TEST"
 466 #endif
 467         (void) textdomain(TEXT_DOMAIN);
 468 
 469         progname = argv[0];
 470         for (i = 1; i < argc; ++i)
 471                 if (strcmp(argv[i], "--version") == 0) {
 472                         (void) printf("%s\n", elsieid);
 473                         exit(EXIT_SUCCESS);
 474                 }
 475 
 476 #ifdef LEAPSECOND_SUPPORT
 477         while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF)
 478 #else
 479         while ((c = getopt(argc, argv, "d:l:p:vsy:")) != EOF)
 480 #endif
 481                 switch (c) {
 482                         default:
 483                                 usage();
 484                         case 'd':
 485                                 if (directory == NULL)
 486                                         directory = optarg;
 487                                 else {
 488                                         (void) fprintf(stderr, gettext(
 489 "%s: More than one -d option specified\n"),
 490                                                 progname);
 491                                         exit(EXIT_FAILURE);
 492                                 }
 493                                 break;
 494                         case 'l':
 495                                 if (lcltime == NULL)
 496                                         lcltime = optarg;
 497                                 else {
 498                                         (void) fprintf(stderr, gettext(
 499 "%s: More than one -l option specified\n"),
 500                                                 progname);
 501                                         exit(EXIT_FAILURE);
 502                                 }
 503                                 break;
 504                         case 'p':
 505                                 if (psxrules == NULL)
 506                                         psxrules = optarg;
 507                                 else {
 508                                         (void) fprintf(stderr, gettext(
 509 "%s: More than one -p option specified\n"),
 510                                                 progname);
 511                                         exit(EXIT_FAILURE);
 512                                 }
 513                                 break;
 514                         case 'y':
 515                                 if (yitcommand == NULL)
 516                                         yitcommand = optarg;
 517                                 else {
 518                                         (void) fprintf(stderr, gettext(
 519 "%s: More than one -y option specified\n"),
 520                                                 progname);
 521                                         exit(EXIT_FAILURE);
 522                                 }
 523                                 break;
 524 #ifdef LEAPSECOND_SUPPORT
 525                         case 'L':
 526                                 if (leapsec == NULL)
 527                                         leapsec = optarg;
 528                                 else {
 529                                         (void) fprintf(stderr, gettext(
 530 "%s: More than one -L option specified\n"),
 531                                                 progname);
 532                                         exit(EXIT_FAILURE);
 533                                 }
 534                                 break;
 535 #endif /* LEAPSECOND_SUPPORT */
 536                         case 'v':
 537                                 noise = TRUE;
 538                                 break;
 539                         case 's':
 540                                 sflag = TRUE;
 541                                 break;
 542                 }
 543         if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
 544                 usage();        /* usage message by request */
 545         if (directory == NULL)
 546                 directory = TZDIR;
 547         if (yitcommand == NULL)
 548                 yitcommand = "yearistype";
 549 
 550         setboundaries();
 551 
 552 #ifdef LEAPSECOND_SUPPORT
 553         if (optind < argc && leapsec != NULL) {
 554                 infile(leapsec);
 555                 adjleap();
 556         }
 557 #endif /* LEAPSECOND_SUPPORT */
 558 
 559         for (i = optind; i < argc; ++i)
 560                 infile(argv[i]);
 561         if (errors)
 562                 exit(EXIT_FAILURE);
 563         associate();
 564         for (i = 0; i < nzones; i = j) {
 565                 /*
 566                  * Find the next non-continuation zone entry.
 567                  */
 568                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
 569                         continue;
 570                 outzone(&zones[i], j - i);
 571         }
 572         /*
 573          * Make links.
 574          */
 575         for (i = 0; i < nlinks; ++i) {
 576                 eat(links[i].l_filename, links[i].l_linenum);
 577                 dolink(links[i].l_from, links[i].l_to);
 578                 if (noise)
 579                         for (j = 0; j < nlinks; ++j)
 580                                 if (strcmp(links[i].l_to, links[j].l_from) == 0)
 581                                         warning(gettext("link to link"));
 582         }
 583         if (lcltime != NULL) {
 584                 eat("command line", 1);
 585                 dolink(lcltime, TZDEFAULT);
 586         }
 587         if (psxrules != NULL) {
 588                 eat("command line", 1);
 589                 dolink(psxrules, TZDEFRULES);
 590         }
 591         return ((errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
 592 }
 593 
 594 static void
 595 dolink(fromfield, tofield)
 596 const char * const      fromfield;
 597 const char * const      tofield;
 598 {
 599         register char *fromname;
 600         register char *toname;
 601 
 602         if (fromfield[0] == '/')
 603                 fromname = ecpyalloc(fromfield);
 604         else {
 605                 fromname = ecpyalloc(directory);
 606                 fromname = ecatalloc(fromname, "/");
 607                 fromname = ecatalloc(fromname, fromfield);
 608         }
 609         if (tofield[0] == '/')
 610                 toname = ecpyalloc(tofield);
 611         else {
 612                 toname = ecpyalloc(directory);
 613                 toname = ecatalloc(toname, "/");
 614                 toname = ecatalloc(toname, tofield);
 615         }
 616         /*
 617          * We get to be careful here since
 618          * there's a fair chance of root running us.
 619          */
 620         if (!itsdir(toname))
 621                 (void) remove(toname);
 622         if (link(fromname, toname) != 0) {
 623                 int     result;
 624 
 625                 if (mkdirs(toname) != 0)
 626                         exit(EXIT_FAILURE);
 627 
 628                 result = link(fromname, toname);
 629 
 630                 if (result != 0 && access(fromname, F_OK) == 0 &&
 631                     !itsdir(fromname)) {
 632                         const char *s = tofield;
 633                         register char *symlinkcontents = NULL;
 634 
 635                         while ((s = strchr(s+1, '/')) != NULL)
 636                                 symlinkcontents = ecatalloc(symlinkcontents,
 637                                         "../");
 638                         symlinkcontents = ecatalloc(symlinkcontents, fromname);
 639                         result = symlink(symlinkcontents, toname);
 640                         if (result == 0)
 641                                 warning(gettext(
 642                                     "hard link failed, symbolic link used"));
 643                         ifree(symlinkcontents);
 644                 }
 645 
 646                 if (result != 0) {
 647                         const char *e = strerror(errno);
 648 
 649                         (void) fprintf(stderr, gettext(
 650                                 "%s: Can't link from %s to %s: %s\n"),
 651                                 progname, fromname, toname, e);
 652                         exit(EXIT_FAILURE);
 653                 }
 654         }
 655         ifree(fromname);
 656         ifree(toname);
 657 }
 658 
 659 #ifndef INT_MAX
 660 #define INT_MAX         ((int)(((unsigned)~0)>>1))
 661 #endif /* !defined INT_MAX */
 662 
 663 #ifndef INT_MIN
 664 #define INT_MIN         ((int)~(((unsigned)~0)>>1))
 665 #endif /* !defined INT_MIN */
 666 
 667 /*
 668  * The tz file format currently allows at most 32-bit quantities.
 669  * This restriction should be removed before signed 32-bit values
 670  * wrap around in 2038, but unfortunately this will require a
 671  * change to the tz file format.
 672  */
 673 
 674 #define MAX_BITS_IN_FILE        32
 675 /* CSTYLED */
 676 #define TIME_T_BITS_IN_FILE     ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
 677                                     TYPE_BIT(zic_t): MAX_BITS_IN_FILE)
 678 
 679 static void
 680 setboundaries(void)
 681 {
 682         register int    i;
 683 
 684         if (TYPE_SIGNED(zic_t)) {
 685                 min_time = -1;
 686                 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
 687                         min_time *= 2;
 688                 max_time = -(min_time + 1);
 689                 if (sflag)
 690                         min_time = 0;
 691         } else {
 692                 min_time = 0;
 693                 max_time = 2 - sflag;
 694                 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
 695                         max_time *= 2;
 696                 --max_time;
 697         }
 698         {
 699                 time_t  t;
 700 
 701                 t = (time_t)min_time;
 702                 min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
 703                 t = (time_t)max_time;
 704                 max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
 705         }
 706         min_year_representable = min_year;
 707         max_year_representable = max_year;
 708 }
 709 
 710 static int
 711 itsdir(name)
 712 const char * const      name;
 713 {
 714         register char   *myname;
 715         register int    accres;
 716 
 717         myname = ecpyalloc(name);
 718         myname = ecatalloc(myname, "/.");
 719         accres = access(myname, F_OK);
 720         ifree(myname);
 721         return (accres == 0);
 722 }
 723 
 724 /*
 725  * Associate sets of rules with zones.
 726  */
 727 
 728 /*
 729  * Sort by rule name.
 730  */
 731 
 732 static int
 733 rcomp(cp1, cp2)
 734 const void *    cp1;
 735 const void *    cp2;
 736 {
 737         return (strcmp(((const struct rule *) cp1)->r_name,
 738                 ((const struct rule *) cp2)->r_name));
 739 }
 740 
 741 static void
 742 associate(void)
 743 {
 744         register struct zone    *zp;
 745         register struct rule    *rp;
 746         register int            base, out;
 747         register int            i, j;
 748 
 749         if (nrules != 0) {
 750                 (void) qsort((void *)rules, (size_t)nrules,
 751                         (size_t)sizeof (*rules), rcomp);
 752                 for (i = 0; i < nrules - 1; ++i) {
 753                         if (strcmp(rules[i].r_name,
 754                                 rules[i + 1].r_name) != 0)
 755                                         continue;
 756                         if (strcmp(rules[i].r_filename,
 757                                 rules[i + 1].r_filename) == 0)
 758                                         continue;
 759                         eat(rules[i].r_filename, rules[i].r_linenum);
 760                         warning(gettext("same rule name in multiple files"));
 761                         eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
 762                         warning(gettext("same rule name in multiple files"));
 763                         for (j = i + 2; j < nrules; ++j) {
 764                                 if (strcmp(rules[i].r_name,
 765                                         rules[j].r_name) != 0)
 766                                                 break;
 767                                 if (strcmp(rules[i].r_filename,
 768                                         rules[j].r_filename) == 0)
 769                                                 continue;
 770                                 if (strcmp(rules[i + 1].r_filename,
 771                                         rules[j].r_filename) == 0)
 772                                                 continue;
 773                                 break;
 774                         }
 775                         i = j - 1;
 776                 }
 777         }
 778         for (i = 0; i < nzones; ++i) {
 779                 zp = &zones[i];
 780                 zp->z_rules = NULL;
 781                 zp->z_nrules = 0;
 782         }
 783         for (base = 0; base < nrules; base = out) {
 784                 rp = &rules[base];
 785                 for (out = base + 1; out < nrules; ++out)
 786                         if (strcmp(rp->r_name, rules[out].r_name) != 0)
 787                                 break;
 788                 for (i = 0; i < nzones; ++i) {
 789                         zp = &zones[i];
 790                         if (strcmp(zp->z_rule, rp->r_name) != 0)
 791                                 continue;
 792                         zp->z_rules = rp;
 793                         zp->z_nrules = out - base;
 794                 }
 795         }
 796         for (i = 0; i < nzones; ++i) {
 797                 zp = &zones[i];
 798                 if (zp->z_nrules == 0) {
 799                         /*
 800                          * Maybe we have a local standard time offset.
 801                          */
 802                         eat(zp->z_filename, zp->z_linenum);
 803                         zp->z_stdoff = gethms(zp->z_rule,
 804                                 gettext("unruly zone"), TRUE);
 805                         /*
 806                          * Note, though, that if there's no rule,
 807                          * a '%s' in the format is a bad thing.
 808                          */
 809                         if (strchr(zp->z_format, '%') != 0)
 810                                 error(gettext("%s in ruleless zone"));
 811                 }
 812         }
 813         if (errors)
 814                 exit(EXIT_FAILURE);
 815 }
 816 
 817 static void
 818 infile(name)
 819 const char *name;
 820 {
 821         register FILE                   *fp;
 822         register char                   **fields;
 823         register char                   *cp;
 824         register const struct lookup    *lp;
 825         register int                    nfields;
 826         register int                    wantcont;
 827         register int                    num;
 828         char                            buf[BUFSIZ];
 829 
 830         if (strcmp(name, "-") == 0) {
 831                 name = gettext("standard input");
 832                 fp = stdin;
 833         } else if ((fp = fopen(name, "r")) == NULL) {
 834                 const char *e = strerror(errno);
 835 
 836                 (void) fprintf(stderr, gettext("%s: Can't open %s: %s\n"),
 837                         progname, name, e);
 838                 exit(EXIT_FAILURE);
 839         }
 840         wantcont = FALSE;
 841         for (num = 1; ; ++num) {
 842                 eat(name, num);
 843                 if (fgets(buf, (int)sizeof (buf), fp) != buf)
 844                         break;
 845                 cp = strchr(buf, '\n');
 846                 if (cp == NULL) {
 847                         error(gettext("line too long"));
 848                         exit(EXIT_FAILURE);
 849                 }
 850                 *cp = '\0';
 851                 fields = getfields(buf);
 852                 nfields = 0;
 853                 while (fields[nfields] != NULL) {
 854                         static char     nada;
 855 
 856                         if (strcmp(fields[nfields], "-") == 0)
 857                                 fields[nfields] = &nada;
 858                         ++nfields;
 859                 }
 860                 if (nfields == 0) {
 861                         /* nothing to do */
 862                 } else if (wantcont) {
 863                         wantcont = inzcont(fields, nfields);
 864                 } else {
 865                         lp = byword(fields[0], line_codes);
 866                         if (lp == NULL)
 867                                 error(gettext("input line of unknown type"));
 868                         else switch ((int)(lp->l_value)) {
 869                                 case LC_RULE:
 870                                         inrule(fields, nfields);
 871                                         wantcont = FALSE;
 872                                         break;
 873                                 case LC_ZONE:
 874                                         wantcont = inzone(fields, nfields);
 875                                         break;
 876                                 case LC_LINK:
 877                                         inlink(fields, nfields);
 878                                         wantcont = FALSE;
 879                                         break;
 880 #ifdef LEAPSECOND_SUPPORT
 881                                 case LC_LEAP:
 882                                         if (name != leapsec)
 883                                                 (void) fprintf(stderr, gettext(
 884 "%s: Leap line in non leap seconds file %s\n"),
 885                                                         progname, name);
 886                                         else    inleap(fields, nfields);
 887                                         wantcont = FALSE;
 888                                         break;
 889 #endif /* LEAPSECOND_SUPPORT */
 890                                 default:        /* "cannot happen" */
 891                                         (void) fprintf(stderr, gettext(
 892 "%s: panic: Invalid l_value %d\n"),
 893                                                 progname, lp->l_value);
 894                                         exit(EXIT_FAILURE);
 895                         }
 896                 }
 897                 ifree((char *)fields);
 898         }
 899         if (ferror(fp)) {
 900                 (void) fprintf(stderr, gettext("%s: Error reading %s\n"),
 901                         progname, filename);
 902                 exit(EXIT_FAILURE);
 903         }
 904         if (fp != stdin && fclose(fp)) {
 905                 const char *e = strerror(errno);
 906                 (void) fprintf(stderr, gettext("%s: Error closing %s: %s\n"),
 907                         progname, filename, e);
 908                 exit(EXIT_FAILURE);
 909         }
 910         if (wantcont)
 911                 error(gettext("expected continuation line not found"));
 912 }
 913 
 914 /*
 915  * Convert a string of one of the forms
 916  *      h       -h      hh:mm   -hh:mm  hh:mm:ss        -hh:mm:ss
 917  * into a number of seconds.
 918  * A null string maps to zero.
 919  * Call error with errstring and return zero on errors.
 920  */
 921 
 922 static long
 923 gethms(string, errstring, signable)
 924 const char              *string;
 925 const char * const      errstring;
 926 const int               signable;
 927 {
 928         long    hh;
 929         int     mm, ss, sign;
 930 
 931         if (string == NULL || *string == '\0')
 932                 return (0);
 933         if (!signable)
 934                 sign = 1;
 935         else if (*string == '-') {
 936                 sign = -1;
 937                 ++string;
 938         } else  sign = 1;
 939         if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
 940                 mm = ss = 0;
 941         else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
 942                 ss = 0;
 943         else if (sscanf(string, scheck(string, "%ld:%d:%d"),
 944                 &hh, &mm, &ss) != 3) {
 945                         error(errstring);
 946                         return (0);
 947         }
 948         if (hh < 0 ||
 949                 mm < 0 || mm >= MINSPERHOUR ||
 950                 ss < 0 || ss > SECSPERMIN) {
 951                         error(errstring);
 952                         return (0);
 953         }
 954         if (LONG_MAX / SECSPERHOUR < hh) {
 955                 error(gettext("time overflow"));
 956                 return (0);
 957         }
 958         if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
 959                 warning(
 960                     gettext("24:00 not handled by pre-1998 versions of zic"));
 961         if (noise && (hh > HOURSPERDAY ||
 962                 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
 963                 warning(gettext("values over 24 hours not handled by "
 964                             "pre-2007 versions of zic"));
 965 
 966         return (oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
 967                 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))));
 968 }
 969 
 970 static void
 971 inrule(fields, nfields)
 972 register char ** const  fields;
 973 const int               nfields;
 974 {
 975         static struct rule      r;
 976 
 977         if (nfields != RULE_FIELDS) {
 978                 error(gettext("wrong number of fields on Rule line"));
 979                 return;
 980         }
 981         if (*fields[RF_NAME] == '\0') {
 982                 error(gettext("nameless rule"));
 983                 return;
 984         }
 985         r.r_filename = filename;
 986         r.r_linenum = linenum;
 987         r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"),
 988                 TRUE);
 989         rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
 990                 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
 991         r.r_name = ecpyalloc(fields[RF_NAME]);
 992         r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
 993         rules = (struct rule *)(void *)erealloc((char *)rules,
 994                 (int)((nrules + 1) * sizeof (*rules)));
 995         rules[nrules++] = r;
 996 }
 997 
 998 static int
 999 inzone(fields, nfields)
1000 register char ** const  fields;
1001 const int               nfields;
1002 {
1003         register int    i;
1004         static char     *buf;
1005 
1006         if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1007                 error(gettext("wrong number of fields on Zone line"));
1008                 return (FALSE);
1009         }
1010         if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1011                 buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT)));
1012                 (void) sprintf(buf,
1013 gettext("\"Zone %s\" line and -l option are mutually exclusive"),
1014                         TZDEFAULT);
1015                 error(buf);
1016                 return (FALSE);
1017         }
1018         if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1019                 buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES)));
1020                 (void) sprintf(buf,
1021 gettext("\"Zone %s\" line and -p option are mutually exclusive"),
1022                         TZDEFRULES);
1023                 error(buf);
1024                 return (FALSE);
1025         }
1026         for (i = 0; i < nzones; ++i)
1027                 if (zones[i].z_name != NULL &&
1028                         strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1029                                 buf = erealloc(buf, (int)(132 +
1030                                         strlen(fields[ZF_NAME]) +
1031                                         strlen(zones[i].z_filename)));
1032                                 (void) sprintf(buf,
1033 gettext("duplicate zone name %s (file \"%s\", line %d)"),
1034                                         fields[ZF_NAME],
1035                                         zones[i].z_filename,
1036                                         zones[i].z_linenum);
1037                                 error(buf);
1038                                 return (FALSE);
1039                 }
1040         return (inzsub(fields, nfields, FALSE));
1041 }
1042 
1043 static int
1044 inzcont(fields, nfields)
1045 register char ** const  fields;
1046 const int               nfields;
1047 {
1048         if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1049                 error(gettext(
1050                     "wrong number of fields on Zone continuation line"));
1051                 return (FALSE);
1052         }
1053         return (inzsub(fields, nfields, TRUE));
1054 }
1055 
1056 static int
1057 inzsub(fields, nfields, iscont)
1058 register char ** const  fields;
1059 const int               nfields;
1060 const int               iscont;
1061 {
1062         register char           *cp;
1063         static struct zone      z;
1064         register int            i_gmtoff, i_rule, i_format;
1065         register int            i_untilyear, i_untilmonth;
1066         register int            i_untilday, i_untiltime;
1067         register int            hasuntil;
1068 
1069         if (iscont) {
1070                 i_gmtoff = ZFC_GMTOFF;
1071                 i_rule = ZFC_RULE;
1072                 i_format = ZFC_FORMAT;
1073                 i_untilyear = ZFC_TILYEAR;
1074                 i_untilmonth = ZFC_TILMONTH;
1075                 i_untilday = ZFC_TILDAY;
1076                 i_untiltime = ZFC_TILTIME;
1077                 z.z_name = NULL;
1078         } else {
1079                 i_gmtoff = ZF_GMTOFF;
1080                 i_rule = ZF_RULE;
1081                 i_format = ZF_FORMAT;
1082                 i_untilyear = ZF_TILYEAR;
1083                 i_untilmonth = ZF_TILMONTH;
1084                 i_untilday = ZF_TILDAY;
1085                 i_untiltime = ZF_TILTIME;
1086                 z.z_name = ecpyalloc(fields[ZF_NAME]);
1087         }
1088         z.z_filename = filename;
1089         z.z_linenum = linenum;
1090         z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"),
1091                 TRUE);
1092         if ((cp = strchr(fields[i_format], '%')) != 0) {
1093                 if (*++cp != 's' || strchr(cp, '%') != 0) {
1094                         error(gettext("invalid abbreviation format"));
1095                         return (FALSE);
1096                 }
1097         }
1098         z.z_rule = ecpyalloc(fields[i_rule]);
1099         z.z_format = ecpyalloc(fields[i_format]);
1100         hasuntil = nfields > i_untilyear;
1101         if (hasuntil) {
1102                 z.z_untilrule.r_filename = filename;
1103                 z.z_untilrule.r_linenum = linenum;
1104                 rulesub(&z.z_untilrule,
1105                         fields[i_untilyear],
1106                         "only",
1107                         "",
1108                         (nfields > i_untilmonth) ?
1109                         fields[i_untilmonth] : "Jan",
1110                         (nfields > i_untilday) ? fields[i_untilday] : "1",
1111                         (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1112                 z.z_untiltime = rpytime(&z.z_untilrule,
1113                         z.z_untilrule.r_loyear);
1114                 if (iscont && nzones > 0 &&
1115                         z.z_untiltime > min_time &&
1116                         z.z_untiltime < max_time &&
1117                         zones[nzones - 1].z_untiltime > min_time &&
1118                         zones[nzones - 1].z_untiltime < max_time &&
1119                         zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1120                                 error(gettext(
1121 "Zone continuation line end time is not after end time of previous line"));
1122                                 return (FALSE);
1123                 }
1124         }
1125         zones = (struct zone *)(void *)erealloc((char *)zones,
1126                 (int)((nzones + 1) * sizeof (*zones)));
1127         zones[nzones++] = z;
1128         /*
1129          * If there was an UNTIL field on this line,
1130          * there's more information about the zone on the next line.
1131          */
1132         return (hasuntil);
1133 }
1134 
1135 #ifdef LEAPSECOND_SUPPORT
1136 static void
1137 inleap(fields, nfields)
1138 register char ** const  fields;
1139 const int               nfields;
1140 {
1141         register const char             *cp;
1142         register const struct lookup    *lp;
1143         register int                    i, j;
1144         int                             year, month, day;
1145         long                            dayoff, tod;
1146         zic_t                           t;
1147 
1148         if (nfields != LEAP_FIELDS) {
1149                 error(gettext("wrong number of fields on Leap line"));
1150                 return;
1151         }
1152         dayoff = 0;
1153         cp = fields[LP_YEAR];
1154         if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1155                 /*
1156                  * Leapin' Lizards!
1157                  */
1158                 error(gettext("invalid leaping year"));
1159                 return;
1160         }
1161         j = EPOCH_YEAR;
1162         while (j != year) {
1163                 if (year > j) {
1164                         i = len_years[isleap(j)];
1165                         ++j;
1166                 } else {
1167                         --j;
1168                         i = -len_years[isleap(j)];
1169                 }
1170                 dayoff = oadd(dayoff, eitol(i));
1171         }
1172         if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1173                 error(gettext("invalid month name"));
1174                 return;
1175         }
1176         month = lp->l_value;
1177         j = TM_JANUARY;
1178         while (j != month) {
1179                 i = len_months[isleap(year)][j];
1180                 dayoff = oadd(dayoff, eitol(i));
1181                 ++j;
1182         }
1183         cp = fields[LP_DAY];
1184         if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1185                 day <= 0 || day > len_months[isleap(year)][month]) {
1186                         error(gettext("invalid day of month"));
1187                         return;
1188         }
1189         dayoff = oadd(dayoff, eitol(day - 1));
1190         if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1191                 error(gettext("time before zero"));
1192                 return;
1193         }
1194         if (dayoff < min_time / SECSPERDAY) {
1195                 error(gettext("time too small"));
1196                 return;
1197         }
1198         if (dayoff > max_time / SECSPERDAY) {
1199                 error(gettext("time too large"));
1200                 return;
1201         }
1202         t = (zic_t)dayoff * SECSPERDAY;
1203         tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE);
1204         cp = fields[LP_CORR];
1205         {
1206                 register int    positive;
1207                 int             count;
1208 
1209                 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1210                         positive = FALSE;
1211                         count = 1;
1212                 } else if (strcmp(cp, "--") == 0) {
1213                         positive = FALSE;
1214                         count = 2;
1215                 } else if (strcmp(cp, "+") == 0) {
1216                         positive = TRUE;
1217                         count = 1;
1218                 } else if (strcmp(cp, "++") == 0) {
1219                         positive = TRUE;
1220                         count = 2;
1221                 } else {
1222                         error(gettext("illegal CORRECTION field on Leap line"));
1223                         return;
1224                 }
1225                 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1226                         error(gettext(
1227                             "illegal Rolling/Stationary field on Leap line"));
1228                         return;
1229                 }
1230                 leapadd(tadd(t, tod), positive, lp->l_value, count);
1231         }
1232 }
1233 #endif /* LEAPSECOND_SUPPORT */
1234 
1235 static void
1236 inlink(fields, nfields)
1237 register char ** const  fields;
1238 const int               nfields;
1239 {
1240         struct link     l;
1241 
1242         if (nfields != LINK_FIELDS) {
1243                 error(gettext("wrong number of fields on Link line"));
1244                 return;
1245         }
1246         if (*fields[LF_FROM] == '\0') {
1247                 error(gettext("blank FROM field on Link line"));
1248                 return;
1249         }
1250         if (*fields[LF_TO] == '\0') {
1251                 error(gettext("blank TO field on Link line"));
1252                 return;
1253         }
1254         l.l_filename = filename;
1255         l.l_linenum = linenum;
1256         l.l_from = ecpyalloc(fields[LF_FROM]);
1257         l.l_to = ecpyalloc(fields[LF_TO]);
1258         links = (struct link *)(void *)erealloc((char *)links,
1259                 (int)((nlinks + 1) * sizeof (*links)));
1260         links[nlinks++] = l;
1261 }
1262 
1263 static void
1264 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1265 register struct rule * const    rp;
1266 const char * const              loyearp;
1267 const char * const              hiyearp;
1268 const char * const              typep;
1269 const char * const              monthp;
1270 const char * const              dayp;
1271 const char * const              timep;
1272 {
1273         register const struct lookup    *lp;
1274         register const char             *cp;
1275         register char                   *dp;
1276         register char                   *ep;
1277 
1278         if ((lp = byword(monthp, mon_names)) == NULL) {
1279                 error(gettext("invalid month name"));
1280                 return;
1281         }
1282         rp->r_month = lp->l_value;
1283         rp->r_todisstd = FALSE;
1284         rp->r_todisgmt = FALSE;
1285         dp = ecpyalloc(timep);
1286         if (*dp != '\0') {
1287                 ep = dp + strlen(dp) - 1;
1288                 switch (lowerit(*ep)) {
1289                         case 's':       /* Standard */
1290                                 rp->r_todisstd = TRUE;
1291                                 rp->r_todisgmt = FALSE;
1292                                 *ep = '\0';
1293                                 break;
1294                         case 'w':       /* Wall */
1295                                 rp->r_todisstd = FALSE;
1296                                 rp->r_todisgmt = FALSE;
1297                                 *ep = '\0';
1298                                 break;
1299                         case 'g':       /* Greenwich */
1300                         case 'u':       /* Universal */
1301                         case 'z':       /* Zulu */
1302                                 rp->r_todisstd = TRUE;
1303                                 rp->r_todisgmt = TRUE;
1304                                 *ep = '\0';
1305                                 break;
1306                 }
1307         }
1308         rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE);
1309         ifree(dp);
1310         /*
1311          * Year work.
1312          */
1313         cp = loyearp;
1314         lp = byword(cp, begin_years);
1315         if (lp != NULL) {
1316             switch ((int)lp->l_value) {
1317                 case YR_MINIMUM:
1318                         rp->r_loyear = INT_MIN;
1319                         break;
1320                 case YR_MAXIMUM:
1321                         rp->r_loyear = INT_MAX;
1322                         break;
1323                 default:        /* "cannot happen" */
1324                         (void) fprintf(stderr,
1325                                 gettext("%s: panic: Invalid l_value %d\n"),
1326                                 progname, lp->l_value);
1327                         exit(EXIT_FAILURE);
1328             }
1329         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1330                 error(gettext("invalid starting year"));
1331                 return;
1332         } else if (noise) {
1333                 if (rp->r_loyear < min_year_representable)
1334                         warning(gettext(
1335                             "starting year too low to be represented"));
1336                 else if (rp->r_loyear > max_year_representable)
1337                         warning(gettext(
1338                             "starting year too high to be represented"));
1339         }
1340         cp = hiyearp;
1341         if ((lp = byword(cp, end_years)) != NULL) {
1342             switch ((int)lp->l_value) {
1343                 case YR_MINIMUM:
1344                         rp->r_hiyear = INT_MIN;
1345                         break;
1346                 case YR_MAXIMUM:
1347                         rp->r_hiyear = INT_MAX;
1348                         break;
1349                 case YR_ONLY:
1350                         rp->r_hiyear = rp->r_loyear;
1351                         break;
1352                 default:        /* "cannot happen" */
1353                         (void) fprintf(stderr,
1354                                 gettext("%s: panic: Invalid l_value %d\n"),
1355                                 progname, lp->l_value);
1356                         exit(EXIT_FAILURE);
1357             }
1358         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1359                 error(gettext("invalid ending year"));
1360                 return;
1361         } else if (noise) {
1362                 if (rp->r_loyear < min_year_representable)
1363                         warning(gettext(
1364                             "ending year too low to be represented"));
1365                 else if (rp->r_loyear > max_year_representable)
1366                         warning(gettext(
1367                             "ending year too high to be represented"));
1368         }
1369         if (rp->r_loyear > rp->r_hiyear) {
1370                 error(gettext("starting year greater than ending year"));
1371                 return;
1372         }
1373         if (*typep == '\0')
1374                 rp->r_yrtype = NULL;
1375         else {
1376                 if (rp->r_loyear == rp->r_hiyear) {
1377                         error(gettext("typed single year"));
1378                         return;
1379                 }
1380                 rp->r_yrtype = ecpyalloc(typep);
1381         }
1382         if (rp->r_loyear < min_year && rp->r_loyear > 0)
1383                 min_year = rp->r_loyear;
1384         /*
1385          * Day work.
1386          * Accept things such as:
1387          *      1
1388          *      last-Sunday
1389          *      Sun<=20
1390          *      Sun>=7
1391          */
1392         dp = ecpyalloc(dayp);
1393         if ((lp = byword(dp, lasts)) != NULL) {
1394                 rp->r_dycode = DC_DOWLEQ;
1395                 rp->r_wday = lp->l_value;
1396                 rp->r_dayofmonth = len_months[1][rp->r_month];
1397         } else {
1398                 if ((ep = strchr(dp, '<')) != 0)
1399                         rp->r_dycode = DC_DOWLEQ;
1400                 else if ((ep = strchr(dp, '>')) != 0)
1401                         rp->r_dycode = DC_DOWGEQ;
1402                 else {
1403                         ep = dp;
1404                         rp->r_dycode = DC_DOM;
1405                 }
1406                 if (rp->r_dycode != DC_DOM) {
1407                         *ep++ = 0;
1408                         if (*ep++ != '=') {
1409                                 error(gettext("invalid day of month"));
1410                                 ifree(dp);
1411                                 return;
1412                         }
1413                         if ((lp = byword(dp, wday_names)) == NULL) {
1414                                 error(gettext("invalid weekday name"));
1415                                 ifree(dp);
1416                                 return;
1417                         }
1418                         rp->r_wday = lp->l_value;
1419                 }
1420                 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1421                         rp->r_dayofmonth <= 0 ||
1422                         (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1423                                 error(gettext("invalid day of month"));
1424                                 ifree(dp);
1425                                 return;
1426                 }
1427         }
1428         ifree(dp);
1429 }
1430 
1431 static void
1432 convert(val, buf)
1433 const long      val;
1434 char * const    buf;
1435 {
1436         register int    i;
1437         register long   shift;
1438 
1439         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1440                 buf[i] = val >> shift;
1441 }
1442 
1443 static void
1444 puttzcode(val, fp)
1445 const long      val;
1446 FILE * const    fp;
1447 {
1448         char    buf[4];
1449 
1450         convert(val, buf);
1451         (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp);
1452 }
1453 
1454 static int
1455 atcomp(avp, bvp)
1456 const void *avp;
1457 const void *bvp;
1458 {
1459         if (((struct attype *)avp)->at < ((struct attype *)bvp)->at)
1460                 return (-1);
1461         else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at)
1462                 return (1);
1463         else    return (0);
1464 }
1465 
1466 static void
1467 writezone(name)
1468 const char * const      name;
1469 {
1470         register FILE           *fp;
1471         register int            i, j;
1472         static char             *fullname;
1473         static struct tzhead    tzh;
1474         zic_t                   ats[TZ_MAX_TIMES];
1475         unsigned char           types[TZ_MAX_TIMES];
1476 
1477         /*
1478          * Sort.
1479          */
1480         if (timecnt > 1)
1481                 (void) qsort((void *)attypes, (size_t)timecnt,
1482                         (size_t)sizeof (*attypes), atcomp);
1483         /*
1484          * Optimize.
1485          */
1486         {
1487                 int     fromi;
1488                 int     toi;
1489 
1490                 toi = 0;
1491                 fromi = 0;
1492                 while (fromi < timecnt && attypes[fromi].at < min_time)
1493                         ++fromi;
1494                 if (isdsts[0] == 0)
1495                         while (fromi < timecnt && attypes[fromi].type == 0)
1496                                 ++fromi;        /* handled by default rule */
1497                 for (; fromi < timecnt; ++fromi) {
1498                         if (toi != 0 && ((attypes[fromi].at +
1499                                 gmtoffs[attypes[toi - 1].type]) <=
1500                                 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1501                                 : attypes[toi - 2].type]))) {
1502                                         attypes[toi - 1].type =
1503                                                 attypes[fromi].type;
1504                                         continue;
1505                         }
1506                         if (toi == 0 ||
1507                                 attypes[toi - 1].type != attypes[fromi].type)
1508                                         attypes[toi++] = attypes[fromi];
1509                 }
1510                 timecnt = toi;
1511         }
1512         /*
1513          * Transfer.
1514          */
1515         for (i = 0; i < timecnt; ++i) {
1516                 ats[i] = attypes[i].at;
1517                 types[i] = attypes[i].type;
1518         }
1519         fullname = erealloc(fullname,
1520                 (int)(strlen(directory) + 1 + strlen(name) + 1));
1521         (void) sprintf(fullname, "%s/%s", directory, name);
1522         /*
1523          * Remove old file, if any, to snap links.
1524          */
1525         if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1526                 const char *e = strerror(errno);
1527 
1528                 (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"),
1529                         progname, fullname, e);
1530                 exit(EXIT_FAILURE);
1531         }
1532         if ((fp = fopen(fullname, "wb")) == NULL) {
1533                 if (mkdirs(fullname) != 0)
1534                         exit(EXIT_FAILURE);
1535                 if ((fp = fopen(fullname, "wb")) == NULL) {
1536                         const char *e = strerror(errno);
1537                         (void) fprintf(stderr, gettext(
1538                                 "%s: Can't create %s: %s\n"),
1539                                 progname, fullname, e);
1540                         exit(EXIT_FAILURE);
1541                 }
1542         }
1543         convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1544         convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1545         convert(eitol(leapcnt), tzh.tzh_leapcnt);
1546         convert(eitol(timecnt), tzh.tzh_timecnt);
1547         convert(eitol(typecnt), tzh.tzh_typecnt);
1548         convert(eitol(charcnt), tzh.tzh_charcnt);
1549         (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic));
1550 #define DO(field)       (void) fwrite((void *) tzh.field, \
1551                         (size_t)sizeof (tzh.field), (size_t)1, fp)
1552         DO(tzh_magic);
1553         DO(tzh_reserved);
1554         DO(tzh_ttisgmtcnt);
1555         DO(tzh_ttisstdcnt);
1556         DO(tzh_leapcnt);
1557         DO(tzh_timecnt);
1558         DO(tzh_typecnt);
1559         DO(tzh_charcnt);
1560 #undef DO
1561         for (i = 0; i < timecnt; ++i) {
1562                 j = leapcnt;
1563                 while (--j >= 0)
1564                         if (ats[i] >= trans[j]) {
1565                                 ats[i] = tadd(ats[i], corr[j]);
1566                                 break;
1567                         }
1568                 puttzcode((long)ats[i], fp);
1569         }
1570         if (timecnt > 0)
1571                 (void) fwrite((void *)types, (size_t)sizeof (types[0]),
1572                         (size_t)timecnt, fp);
1573         for (i = 0; i < typecnt; ++i) {
1574                 puttzcode((long)gmtoffs[i], fp);
1575                 (void) putc(isdsts[i], fp);
1576                 (void) putc(abbrinds[i], fp);
1577         }
1578         if (charcnt != 0)
1579                 (void) fwrite((void *)chars, (size_t)sizeof (chars[0]),
1580                         (size_t)charcnt, fp);
1581         for (i = 0; i < leapcnt; ++i) {
1582                 if (roll[i]) {
1583                         if (timecnt == 0 || trans[i] < ats[0]) {
1584                                 j = 0;
1585                                 while (isdsts[j])
1586                                         if (++j >= typecnt) {
1587                                                 j = 0;
1588                                                 break;
1589                                         }
1590                         } else {
1591                                 j = 1;
1592                                 while (j < timecnt && trans[i] >= ats[j])
1593                                         ++j;
1594                                 j = types[j - 1];
1595                         }
1596                         puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp);
1597                 } else  puttzcode((long)trans[i], fp);
1598                 puttzcode((long)corr[i], fp);
1599         }
1600         for (i = 0; i < typecnt; ++i)
1601                 (void) putc(ttisstds[i], fp);
1602         for (i = 0; i < typecnt; ++i)
1603                 (void) putc(ttisgmts[i], fp);
1604         if (ferror(fp) || fclose(fp)) {
1605                 (void) fprintf(stderr, gettext("%s: Error writing %s\n"),
1606                         progname, fullname);
1607                 exit(EXIT_FAILURE);
1608         }
1609 }
1610 
1611 static void
1612 doabbr(abbr, format, letters, isdst)
1613 char * const            abbr;
1614 const char * const      format;
1615 const char * const      letters;
1616 const int               isdst;
1617 {
1618         if (strchr(format, '/') == NULL) {
1619                 if (letters == NULL)
1620                         (void) strcpy(abbr, format);
1621                 else
1622                         (void) sprintf(abbr, format, letters);
1623         } else if (isdst)
1624                 (void) strcpy(abbr, strchr(format, '/') + 1);
1625         else {
1626                 (void) strcpy(abbr, format);
1627                 *strchr(abbr, '/') = '\0';
1628         }
1629 }
1630 
1631 static void
1632 outzone(zpfirst, zonecount)
1633 const struct zone * const       zpfirst;
1634 const int                       zonecount;
1635 {
1636         register const struct zone      *zp;
1637         register struct rule            *rp;
1638         register int                    i, j;
1639         register int                    usestart, useuntil;
1640         register zic_t                  starttime, untiltime;
1641         register long                   gmtoff;
1642         register long                   stdoff;
1643         register int                    year;
1644         register long                   startoff;
1645         register int                    startttisstd;
1646         register int                    startttisgmt;
1647         register int                    type;
1648         char                            startbuf[BUFSIZ];
1649 
1650         INITIALIZE(untiltime);
1651         INITIALIZE(starttime);
1652         /*
1653          * Now. . .finally. . .generate some useful data!
1654          */
1655         timecnt = 0;
1656         typecnt = 0;
1657         charcnt = 0;
1658         /*
1659          * Thanks to Earl Chew
1660          * for noting the need to unconditionally initialize startttisstd.
1661          */
1662         startttisstd = FALSE;
1663         startttisgmt = FALSE;
1664         for (i = 0; i < zonecount; ++i) {
1665                 /*
1666                  * A guess that may well be corrected later.
1667                  */
1668                 stdoff = 0;
1669                 zp = &zpfirst[i];
1670                 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1671                 useuntil = i < (zonecount - 1);
1672                 if (useuntil && zp->z_untiltime <= min_time)
1673                         continue;
1674                 gmtoff = zp->z_gmtoff;
1675                 eat(zp->z_filename, zp->z_linenum);
1676                 *startbuf = '\0';
1677                 startoff = zp->z_gmtoff;
1678                 if (zp->z_nrules == 0) {
1679                         stdoff = zp->z_stdoff;
1680                         doabbr(startbuf, zp->z_format,
1681                                 (char *)NULL, stdoff != 0);
1682                         type = addtype(oadd(zp->z_gmtoff, stdoff),
1683                                 startbuf, stdoff != 0, startttisstd,
1684                                 startttisgmt);
1685                         if (usestart) {
1686                                 addtt(starttime, type);
1687                                 usestart = FALSE;
1688                         } else if (stdoff != 0)
1689                                 addtt(min_time, type);
1690                 } else
1691                     for (year = min_year; year <= max_year; ++year) {
1692                         if (useuntil && year > zp->z_untilrule.r_hiyear)
1693                                 break;
1694                         /*
1695                          * Mark which rules to do in the current year.
1696                          * For those to do, calculate rpytime(rp, year);
1697                          */
1698                         for (j = 0; j < zp->z_nrules; ++j) {
1699                                 rp = &zp->z_rules[j];
1700                                 eats(zp->z_filename, zp->z_linenum,
1701                                         rp->r_filename, rp->r_linenum);
1702                                 rp->r_todo = year >= rp->r_loyear &&
1703                                                 year <= rp->r_hiyear &&
1704                                                 yearistype(year, rp->r_yrtype);
1705                                 if (rp->r_todo)
1706                                         rp->r_temp = rpytime(rp, year);
1707                         }
1708                         for (;;) {
1709                                 register int    k;
1710                                 register zic_t  jtime, ktime;
1711                                 register long   offset;
1712                                 char            buf[BUFSIZ];
1713 
1714                                 INITIALIZE(ktime);
1715                                 if (useuntil) {
1716                                         /*
1717                                          * Turn untiltime into UTC * assuming
1718                                          * the current gmtoff and stdoff values.
1719                                          */
1720                                         untiltime = zp->z_untiltime;
1721                                         if (!zp->z_untilrule.r_todisgmt)
1722                                                 untiltime = tadd(untiltime,
1723                                                         -gmtoff);
1724                                         if (!zp->z_untilrule.r_todisstd)
1725                                                 untiltime = tadd(untiltime,
1726                                                         -stdoff);
1727                                 }
1728                                 /*
1729                                  * Find the rule (of those to do, if any)
1730                                  * that takes effect earliest in the year.
1731                                  */
1732                                 k = -1;
1733                                 for (j = 0; j < zp->z_nrules; ++j) {
1734                                         rp = &zp->z_rules[j];
1735                                         if (!rp->r_todo)
1736                                                 continue;
1737                                         eats(zp->z_filename, zp->z_linenum,
1738                                                 rp->r_filename, rp->r_linenum);
1739                                         offset = rp->r_todisgmt ? 0 : gmtoff;
1740                                         if (!rp->r_todisstd)
1741                                                 offset = oadd(offset, stdoff);
1742                                         jtime = rp->r_temp;
1743                                         if (jtime == min_time ||
1744                                                 jtime == max_time)
1745                                                         continue;
1746                                         jtime = tadd(jtime, -offset);
1747                                         if (k < 0 || jtime < ktime) {
1748                                                 k = j;
1749                                                 ktime = jtime;
1750                                         }
1751                                 }
1752                                 if (k < 0)
1753                                         break;  /* go on to next year */
1754                                 rp = &zp->z_rules[k];
1755                                 rp->r_todo = FALSE;
1756                                 if (useuntil && ktime >= untiltime)
1757                                         break;
1758                                 stdoff = rp->r_stdoff;
1759                                 if (usestart && ktime == starttime)
1760                                         usestart = FALSE;
1761                                 if (usestart) {
1762                                         if (ktime < starttime) {
1763                                                 startoff = oadd(zp->z_gmtoff,
1764                                                         stdoff);
1765                                                 doabbr(startbuf, zp->z_format,
1766                                                         rp->r_abbrvar,
1767                                                         rp->r_stdoff != 0);
1768                                                 continue;
1769                                         }
1770                                         if (*startbuf == '\0' &&
1771                                             startoff == oadd(zp->z_gmtoff,
1772                                             stdoff)) {
1773                                                 doabbr(startbuf, zp->z_format,
1774                                                         rp->r_abbrvar,
1775                                                         rp->r_stdoff != 0);
1776                                         }
1777                                 }
1778                                 eats(zp->z_filename, zp->z_linenum,
1779                                         rp->r_filename, rp->r_linenum);
1780                                 doabbr(buf, zp->z_format, rp->r_abbrvar,
1781                                         rp->r_stdoff != 0);
1782                                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1783                                 type = addtype(offset, buf, rp->r_stdoff != 0,
1784                                         rp->r_todisstd, rp->r_todisgmt);
1785                                 addtt(ktime, type);
1786                         }
1787                     }
1788                 if (usestart) {
1789                         if (*startbuf == '\0' &&
1790                                 zp->z_format != NULL &&
1791                                 strchr(zp->z_format, '%') == NULL &&
1792                                 strchr(zp->z_format, '/') == NULL)
1793                                         (void) strcpy(startbuf, zp->z_format);
1794                         eat(zp->z_filename, zp->z_linenum);
1795                         if (*startbuf == '\0')
1796                                 error(gettext(
1797 "can't determine time zone abbrevation to use just after until time"));
1798                         else    addtt(starttime,
1799                                         addtype(startoff, startbuf,
1800                                                 startoff != zp->z_gmtoff,
1801                                                 startttisstd,
1802                                                 startttisgmt));
1803                 }
1804                 /*
1805                  * Now we may get to set starttime for the next zone line.
1806                  */
1807                 if (useuntil) {
1808                         startttisstd = zp->z_untilrule.r_todisstd;
1809                         startttisgmt = zp->z_untilrule.r_todisgmt;
1810                         starttime = zp->z_untiltime;
1811                         if (!startttisstd)
1812                                 starttime = tadd(starttime, -stdoff);
1813                         if (!startttisgmt)
1814                                 starttime = tadd(starttime, -gmtoff);
1815                 }
1816         }
1817         writezone(zpfirst->z_name);
1818 }
1819 
1820 static void
1821 addtt(starttime, type)
1822 const zic_t     starttime;
1823 int             type;
1824 {
1825         if (starttime <= min_time ||
1826                 (timecnt == 1 && attypes[0].at < min_time)) {
1827                 gmtoffs[0] = gmtoffs[type];
1828                 isdsts[0] = isdsts[type];
1829                 ttisstds[0] = ttisstds[type];
1830                 ttisgmts[0] = ttisgmts[type];
1831                 if (abbrinds[type] != 0)
1832                         (void) strcpy(chars, &chars[abbrinds[type]]);
1833                 abbrinds[0] = 0;
1834                 charcnt = strlen(chars) + 1;
1835                 typecnt = 1;
1836                 timecnt = 0;
1837                 type = 0;
1838         }
1839         if (timecnt >= TZ_MAX_TIMES) {
1840                 error(gettext("too many transitions?!"));
1841                 exit(EXIT_FAILURE);
1842         }
1843         attypes[timecnt].at = starttime;
1844         attypes[timecnt].type = type;
1845         ++timecnt;
1846 }
1847 
1848 static int
1849 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
1850 const long              gmtoff;
1851 const char * const      abbr;
1852 const int               isdst;
1853 const int               ttisstd;
1854 const int               ttisgmt;
1855 {
1856         register int    i, j;
1857 
1858         if (isdst != TRUE && isdst != FALSE) {
1859                 error(gettext(
1860                     "internal error - addtype called with bad isdst"));
1861                 exit(EXIT_FAILURE);
1862         }
1863         if (ttisstd != TRUE && ttisstd != FALSE) {
1864                 error(gettext(
1865                     "internal error - addtype called with bad ttisstd"));
1866                 exit(EXIT_FAILURE);
1867         }
1868         if (ttisgmt != TRUE && ttisgmt != FALSE) {
1869                 error(gettext(
1870                     "internal error - addtype called with bad ttisgmt"));
1871                 exit(EXIT_FAILURE);
1872         }
1873         /*
1874          * See if there's already an entry for this zone type.
1875          * If so, just return its index.
1876          */
1877         for (i = 0; i < typecnt; ++i) {
1878                 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1879                         strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1880                         ttisstd == ttisstds[i] &&
1881                         ttisgmt == ttisgmts[i])
1882                                 return (i);
1883         }
1884         /*
1885          * There isn't one; add a new one, unless there are already too
1886          * many.
1887          */
1888         if (typecnt >= TZ_MAX_TYPES) {
1889                 error(gettext("too many local time types"));
1890                 exit(EXIT_FAILURE);
1891         }
1892         if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
1893                 error(gettext("UTC offset out of range"));
1894                 exit(EXIT_FAILURE);
1895         }
1896         gmtoffs[i] = gmtoff;
1897         isdsts[i] = isdst;
1898         ttisstds[i] = ttisstd;
1899         ttisgmts[i] = ttisgmt;
1900 
1901         for (j = 0; j < charcnt; ++j)
1902                 if (strcmp(&chars[j], abbr) == 0)
1903                         break;
1904         if (j == charcnt)
1905                 newabbr(abbr);
1906         abbrinds[i] = j;
1907         ++typecnt;
1908         return (i);
1909 }
1910 
1911 #ifdef LEAPSECOND_SUPPORT
1912 static void
1913 leapadd(t, positive, rolling, count)
1914 const zic_t     t;
1915 const int       positive;
1916 const int       rolling;
1917 int             count;
1918 {
1919         register int    i, j;
1920 
1921         if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1922                 error(gettext("too many leap seconds"));
1923                 exit(EXIT_FAILURE);
1924         }
1925         for (i = 0; i < leapcnt; ++i)
1926                 if (t <= trans[i]) {
1927                         if (t == trans[i]) {
1928                                 error(gettext("repeated leap second moment"));
1929                                 exit(EXIT_FAILURE);
1930                         }
1931                         break;
1932                 }
1933         do {
1934                 for (j = leapcnt; j > i; --j) {
1935                         trans[j] = trans[j - 1];
1936                         corr[j] = corr[j - 1];
1937                         roll[j] = roll[j - 1];
1938                 }
1939                 trans[i] = t;
1940                 corr[i] = positive ? 1L : eitol(-count);
1941                 roll[i] = rolling;
1942                 ++leapcnt;
1943         } while (positive && --count != 0);
1944 }
1945 #endif /* LEAPSECOND_SUPPORT */
1946 
1947 #ifdef LEAPSECOND_SUPPORT
1948 static void
1949 adjleap(void)
1950 {
1951         register int    i;
1952         register long   last = 0;
1953 
1954         /*
1955          * propagate leap seconds forward
1956          */
1957         for (i = 0; i < leapcnt; ++i) {
1958                 trans[i] = tadd(trans[i], last);
1959                 last = corr[i] += last;
1960         }
1961 }
1962 #endif /* LEAPSECOND_SUPPORT */
1963 
1964 static int
1965 yearistype(year, type)
1966 const int               year;
1967 const char * const      type;
1968 {
1969         static char     *buf;
1970         int             result;
1971 
1972         if (type == NULL || *type == '\0')
1973                 return (TRUE);
1974 #if defined(sun)
1975         if (strcmp(type, "uspres") == 0)
1976                 return ((year % 4) == 0);
1977         if (strcmp(type, "nonpres") == 0)
1978                 return ((year % 4) != 0);
1979         if (strcmp(type, "even") == 0)
1980                 return ((year % 2) == 0);
1981         if (strcmp(type, "odd") == 0)
1982                 return ((year % 2) != 0);
1983 #endif /* defined(sun) */
1984 
1985         buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type)));
1986         (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1987         result = system(buf);
1988         if (WIFEXITED(result)) {
1989                 switch (WEXITSTATUS(result)) {
1990                 case 0:
1991                         return (TRUE);
1992                 case 1:
1993                         return (FALSE);
1994                 }
1995         }
1996         error(gettext("Wild result from command execution"));
1997         (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"),
1998                 progname, buf, result);
1999         for (;;)
2000                 exit(EXIT_FAILURE);
2001 }
2002 
2003 static int
2004 lowerit(a)
2005 int     a;
2006 {
2007         a = (unsigned char) a;
2008         return ((isascii(a) && isupper(a)) ? tolower(a) : a);
2009 }
2010 
2011 static int
2012 ciequal(ap, bp)         /* case-insensitive equality */
2013 register const char *ap;
2014 register const char *bp;
2015 {
2016         while (lowerit(*ap) == lowerit(*bp++))
2017                 if (*ap++ == '\0')
2018                         return (TRUE);
2019         return (FALSE);
2020 }
2021 
2022 static int
2023 itsabbr(abbr, word)
2024 register const char *abbr;
2025 register const char *word;
2026 {
2027         if (lowerit(*abbr) != lowerit(*word))
2028                 return (FALSE);
2029         ++word;
2030         while (*++abbr != '\0')
2031                 do {
2032                         if (*word == '\0')
2033                                 return (FALSE);
2034                 } while (lowerit(*word++) != lowerit(*abbr));
2035         return (TRUE);
2036 }
2037 
2038 static const struct lookup *
2039 byword(word, table)
2040 register const char * const             word;
2041 register const struct lookup * const    table;
2042 {
2043         register const struct lookup *foundlp;
2044         register const struct lookup *lp;
2045 
2046         if (word == NULL || table == NULL)
2047                 return (NULL);
2048         /*
2049          * Look for exact match.
2050          */
2051         for (lp = table; lp->l_word != NULL; ++lp)
2052                 if (ciequal(word, lp->l_word))
2053                         return (lp);
2054         /*
2055          * Look for inexact match.
2056          */
2057         foundlp = NULL;
2058         for (lp = table; lp->l_word != NULL; ++lp)
2059                 if (itsabbr(word, lp->l_word)) {
2060                         if (foundlp == NULL)
2061                                 foundlp = lp;
2062                         else    return (NULL);  /* multiple inexact matches */
2063                 }
2064         return (foundlp);
2065 }
2066 
2067 static char **
2068 getfields(cp)
2069 register char *cp;
2070 {
2071         register char   *dp;
2072         register char   **array;
2073         register int    nsubs;
2074 
2075         if (cp == NULL)
2076                 return (NULL);
2077         array = (char **)(void *)
2078                 emalloc((int)((strlen(cp) + 1) * sizeof (*array)));
2079         nsubs = 0;
2080         for (;;) {
2081                 while (isascii(*cp) && isspace((unsigned char) *cp))
2082                         ++cp;
2083                 if (*cp == '\0' || *cp == '#')
2084                         break;
2085                 array[nsubs++] = dp = cp;
2086                 do {
2087                         if ((*dp = *cp++) != '"')
2088                                 ++dp;
2089                         else while ((*dp = *cp++) != '"')
2090                                 if (*dp != '\0')
2091                                         ++dp;
2092                                 else {
2093                                         error(gettext(
2094                                             "Odd number of quotation marks"));
2095                                         exit(1);
2096                                 }
2097                 } while (*cp != '\0' && *cp != '#' &&
2098                         (!isascii(*cp) || !isspace((unsigned char) *cp)));
2099                 if (isascii(*cp) && isspace((unsigned char) *cp))
2100                         ++cp;
2101                 *dp = '\0';
2102         }
2103         array[nsubs] = NULL;
2104         return (array);
2105 }
2106 
2107 static long
2108 oadd(t1, t2)
2109 const long      t1;
2110 const long      t2;
2111 {
2112         register long   t;
2113 
2114         t = t1 + t2;
2115         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2116                 error(gettext("time overflow"));
2117                 exit(EXIT_FAILURE);
2118         }
2119         return (t);
2120 }
2121 
2122 static zic_t
2123 tadd(t1, t2)
2124 const zic_t     t1;
2125 const long      t2;
2126 {
2127         register zic_t  t;
2128 
2129         if (t1 == max_time && t2 > 0)
2130                 return (max_time);
2131         if (t1 == min_time && t2 < 0)
2132                 return (min_time);
2133         t = t1 + t2;
2134         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2135                 error(gettext("time overflow"));
2136                 exit(EXIT_FAILURE);
2137         }
2138         return (t);
2139 }
2140 
2141 /*
2142  * Given a rule, and a year, compute the date - in seconds since January 1,
2143  * 1970, 00:00 LOCAL time - in that year that the rule refers to.
2144  */
2145 
2146 static zic_t
2147 rpytime(rp, wantedy)
2148 register const struct rule * const      rp;
2149 register const int                      wantedy;
2150 {
2151         register int    y, m, i;
2152         register long   dayoff;                 /* with a nod to Margaret O. */
2153         register zic_t  t;
2154 
2155         if (wantedy == INT_MIN)
2156                 return (min_time);
2157         if (wantedy == INT_MAX)
2158                 return (max_time);
2159         dayoff = 0;
2160         m = TM_JANUARY;
2161         y = EPOCH_YEAR;
2162         while (wantedy != y) {
2163                 if (wantedy > y) {
2164                         i = len_years[isleap(y)];
2165                         ++y;
2166                 } else {
2167                         --y;
2168                         i = -len_years[isleap(y)];
2169                 }
2170                 dayoff = oadd(dayoff, eitol(i));
2171         }
2172         while (m != rp->r_month) {
2173                 i = len_months[isleap(y)][m];
2174                 dayoff = oadd(dayoff, eitol(i));
2175                 ++m;
2176         }
2177         i = rp->r_dayofmonth;
2178         if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2179                 if (rp->r_dycode == DC_DOWLEQ)
2180                         --i;
2181                 else {
2182                         error(gettext("use of 2/29 in non leap-year"));
2183                         exit(EXIT_FAILURE);
2184                 }
2185         }
2186         --i;
2187         dayoff = oadd(dayoff, eitol(i));
2188         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2189                 register long   wday;
2190 
2191 #define LDAYSPERWEEK    ((long)DAYSPERWEEK)
2192                 wday = eitol(EPOCH_WDAY);
2193                 /*
2194                  * Don't trust mod of negative numbers.
2195                  */
2196                 if (dayoff >= 0)
2197                         wday = (wday + dayoff) % LDAYSPERWEEK;
2198                 else {
2199                         wday -= ((-dayoff) % LDAYSPERWEEK);
2200                         if (wday < 0)
2201                                 wday += LDAYSPERWEEK;
2202                 }
2203                 while (wday != eitol(rp->r_wday))
2204                         if (rp->r_dycode == DC_DOWGEQ) {
2205                                 dayoff = oadd(dayoff, (long)1);
2206                                 if (++wday >= LDAYSPERWEEK)
2207                                         wday = 0;
2208                                 ++i;
2209                         } else {
2210                                 dayoff = oadd(dayoff, (long)-1);
2211                                 if (--wday < 0)
2212                                         wday = LDAYSPERWEEK - 1;
2213                                 --i;
2214                         }
2215                 if (i < 0 || i >= len_months[isleap(y)][m]) {
2216                         if (noise)
2217                                 warning(gettext("rule goes past start/end of "
2218                                     "month--will not work with pre-2004 "
2219                                     "versions of zic"));
2220                 }
2221         }
2222         if (dayoff < 0 && !TYPE_SIGNED(zic_t))
2223                 return (min_time);
2224         if (dayoff < min_time / SECSPERDAY)
2225                 return (min_time);
2226         if (dayoff > max_time / SECSPERDAY)
2227                 return (max_time);
2228         t = (zic_t)dayoff * SECSPERDAY;
2229         return (tadd(t, rp->r_tod));
2230 }
2231 
2232 static void
2233 newabbr(const char * const string)
2234 {
2235         register int    i;
2236 
2237         if (strcmp(string, GRANDPARENTED) != 0) {
2238                 register const char *cp;
2239                 register char *wp;
2240 
2241                 cp = string;
2242                 wp = NULL;
2243                 while (isalpha(*cp) || ('0' <= *cp && *cp <= '9') ||
2244                     *cp == '-' || *cp == '+') {
2245                         ++cp;
2246                 }
2247                 if (noise && cp - string < 3)
2248                         wp = gettext(("time zone abbreviation has less than 3 "
2249                             "alphabetics"));
2250                 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2251                         wp = gettext(("time zone abbreviation has too many "
2252                             "characters"));
2253                 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2254                         ++cp;
2255                         if (isascii(*cp) && isdigit(*cp))
2256                                 if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
2257                                         ++cp;
2258                 }
2259                 if (*cp != '\0')
2260                         wp = gettext("time zone abbreviation differs from "
2261                             "POSIX standard");
2262                 if (wp != NULL) {
2263                         wp = ecpyalloc(wp);
2264                         wp = ecatalloc(wp, " (");
2265                         wp = ecatalloc(wp, string);
2266                         wp = ecatalloc(wp, ")");
2267                         warning(wp);
2268                         ifree(wp);
2269                 }
2270         }
2271         i = strlen(string) + 1;
2272         if (charcnt + i > TZ_MAX_CHARS) {
2273                 error(gettext("too many, or too long, time zone "
2274                     "abbreviations"));
2275                 exit(EXIT_FAILURE);
2276         }
2277         (void) strcpy(&chars[charcnt], string);
2278         charcnt += eitol(i);
2279 }
2280 
2281 static int
2282 mkdirs(argname)
2283 char *argname;
2284 {
2285         register char *name;
2286         register char *cp;
2287 
2288         if (argname == NULL || *argname == '\0')
2289                 return (0);
2290         cp = name = ecpyalloc(argname);
2291         while ((cp = strchr(cp + 1, '/')) != 0) {
2292                 *cp = '\0';
2293                 if (!itsdir(name)) {
2294                         /*
2295                          * It doesn't seem to exist, so we try to create it.
2296                          * Creation may fail because of the directory being
2297                          * created by some other multiprocessor, so we get
2298                          * to do extra checking.
2299                          */
2300                         if (mkdir(name, MKDIR_UMASK) != 0) {
2301                                 const char *e = strerror(errno);
2302 
2303                                 if (errno != EEXIST || !itsdir(name)) {
2304                                         (void) fprintf(stderr, gettext(
2305                                     "%s: Can't create directory %s: %s\n"),
2306                                                 progname, name, e);
2307                                         ifree(name);
2308                                         return (-1);
2309                                 }
2310                         }
2311                 }
2312                 *cp = '/';
2313         }
2314         ifree(name);
2315         return (0);
2316 }
2317 
2318 static long
2319 eitol(i)
2320 const int       i;
2321 {
2322         long    l;
2323 
2324         l = i;
2325         if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2326                 (void) fprintf(stderr,
2327                         gettext("%s: %d did not sign extend correctly\n"),
2328                         progname, i);
2329                 exit(EXIT_FAILURE);
2330         }
2331         return (l);
2332 }
2333 
2334 /*
2335  * UNIX was a registered trademark of The Open Group in 2003.
2336  */