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