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