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