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