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