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