S390: Optimize stpcpy and wcpcpy.
[glibc.git] / timezone / zic.c
blob07d6c30ae226098916acd6dff9f60d889a3ff6f2
1 /*
2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
4 */
6 #include "version.h"
7 #include "private.h"
8 #include "locale.h"
9 #include "tzfile.h"
11 #include <stdarg.h>
13 #define ZIC_VERSION_PRE_2013 '2'
14 #define ZIC_VERSION '3'
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
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 */
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
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.
42 #include "ctype.h"
43 #ifndef isascii
44 #define isascii(x) 1
45 #endif
47 #define end(cp) (strchr((cp), '\0'))
49 struct rule {
50 const char * r_filename;
51 int r_linenum;
52 const char * r_name;
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;
60 int r_month; /* 0..11 */
62 int r_dycode; /* see below */
63 int r_dayofmonth;
64 int r_wday;
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 */
74 int r_todo; /* a rule to do (used in outzone) */
75 zic_t r_temp; /* used in outzone */
79 ** r_dycode r_dayofmonth r_wday
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) */
86 struct zone {
87 const char * z_filename;
88 int z_linenum;
90 const char * z_name;
91 zic_t z_gmtoff;
92 const char * z_rule;
93 const char * z_format;
95 zic_t z_stdoff;
97 struct rule * z_rules;
98 int z_nrules;
100 struct rule z_untilrule;
101 zic_t z_untiltime;
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;
110 #if ! HAVE_LINK
111 # define link(from, to) (-1)
112 #endif
113 #if ! HAVE_SYMLINK
114 # define symlink(from, to) (-1)
115 #endif
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);
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;
169 ** Line codes.
172 #define LC_RULE 0
173 #define LC_ZONE 1
174 #define LC_LINK 2
175 #define LC_LEAP 3
178 ** Which fields are which on a Zone line.
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
193 ** Which fields are which on a Zone continuation line.
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
207 ** Which files are which on a Rule line.
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
222 ** Which fields are which on a Link line.
225 #define LF_FROM 1
226 #define LF_TO 2
227 #define LINK_FIELDS 3
230 ** Which fields are which on a Leap line.
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
242 ** Year synonyms.
245 #define YR_MINIMUM 0
246 #define YR_MAXIMUM 1
247 #define YR_ONLY 2
249 static struct rule * rules;
250 static int nrules; /* number of rules */
251 static int nrules_alloc;
253 static struct zone * zones;
254 static int nzones; /* number of zones */
255 static int nzones_alloc;
257 struct link {
258 const char * l_filename;
259 int l_linenum;
260 const char * l_from;
261 const char * l_to;
264 static struct link * links;
265 static int nlinks;
266 static int nlinks_alloc;
268 struct lookup {
269 const char * l_word;
270 const int l_value;
273 static struct lookup const * byword(const char * string,
274 const struct lookup * lp);
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}
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 }
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 }
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 }
322 static struct lookup const begin_years[] = {
323 { "minimum", YR_MINIMUM },
324 { "maximum", YR_MAXIMUM },
325 { NULL, 0 }
328 static struct lookup const end_years[] = {
329 { "minimum", YR_MINIMUM },
330 { "maximum", YR_MAXIMUM },
331 { "only", YR_ONLY },
332 { NULL, 0 }
335 static struct lookup const leap_types[] = {
336 { "Rolling", TRUE },
337 { "Stationary", FALSE },
338 { NULL, 0 }
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 }
346 static const int len_years[2] = {
347 DAYSPERNYEAR, DAYSPERLYEAR
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];
365 ** Memory allocation.
368 static _Noreturn void
369 memory_exhausted(const char *msg)
371 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
372 exit(EXIT_FAILURE);
375 static ATTRIBUTE_PURE size_t
376 size_product(size_t nitems, size_t itemsize)
378 if (SIZE_MAX / itemsize < nitems)
379 memory_exhausted("size overflow");
380 return nitems * itemsize;
383 static ATTRIBUTE_PURE void *
384 memcheck(void *const ptr)
386 if (ptr == NULL)
387 memory_exhausted(strerror(errno));
388 return ptr;
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)))
396 static void *
397 growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
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));
411 ** Error handling.
414 static void
415 eats(const char *const name, const int num, const char *const rname,
416 const int rnum)
418 filename = name;
419 linenum = num;
420 rfilename = rname;
421 rlinenum = rnum;
424 static void
425 eat(const char *const name, const int num)
427 eats(name, num, NULL, -1);
430 static void ATTRIBUTE_FORMAT((printf, 1, 0))
431 verror(const char *const string, va_list args)
434 ** Match the format of "cc" to allow sh users to
435 ** zic ... 2>&1 | error -t "*" -v
436 ** on BSD systems.
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;
447 static void ATTRIBUTE_FORMAT((printf, 1, 2))
448 error(const char *const string, ...)
450 va_list args;
451 va_start(args, string);
452 verror(string, args);
453 va_end(args);
456 static void ATTRIBUTE_FORMAT((printf, 1, 2))
457 warning(const char *const string, ...)
459 va_list args;
460 fprintf(stderr, _("warning: "));
461 va_start(args, string);
462 verror(string, args);
463 va_end(args);
464 --errors;
467 static _Noreturn void
468 usage(FILE *stream, int status)
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\
474 Report bugs to %s.\n"),
475 progname, progname, REPORT_BUGS_TO);
476 exit(status);
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;
486 main(int argc, char **argv)
488 register int i;
489 register int j;
490 register int c;
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);
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);
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);
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);
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);
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);
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);
568 break;
569 case 'v':
570 noise = TRUE;
571 break;
572 case 's':
573 (void) printf("%s: -s ignored\n", progname);
574 break;
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";
583 if (optind < argc && leapsec != NULL) {
584 infile(leapsec);
585 adjleap();
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) {
595 ** Find the next non-continuation zone entry.
597 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
598 continue;
599 outzone(&zones[i], j - i);
602 ** Make links.
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"));
613 if (lcltime != NULL) {
614 eat("command line", 1);
615 dolink(lcltime, TZDEFAULT);
617 if (psxrules != NULL) {
618 eat("command line", 1);
619 dolink(psxrules, TZDEFRULES);
621 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
624 static void
625 dolink(const char *const fromfield, const char *const tofield)
627 register char * fromname;
628 register char * toname;
630 if (fromfield[0] == '/')
631 fromname = ecpyalloc(fromfield);
632 else {
633 fromname = ecpyalloc(directory);
634 fromname = ecatalloc(fromname, "/");
635 fromname = ecatalloc(fromname, fromfield);
637 if (tofield[0] == '/')
638 toname = ecpyalloc(tofield);
639 else {
640 toname = ecpyalloc(directory);
641 toname = ecatalloc(toname, "/");
642 toname = ecatalloc(toname, tofield);
645 ** We get to be careful here since
646 ** there's a fair chance of root running us.
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;
654 if (mkdirs(toname) != 0)
655 exit(EXIT_FAILURE);
657 result = link(fromname, toname);
658 if (result != 0) {
659 const char *s = fromfield;
660 const char *t;
661 register char * symlinkcontents = NULL;
664 t = s;
665 while ((s = strchr(s, '/'))
666 && ! strncmp (fromfield, tofield,
667 ++s - fromfield));
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);
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);
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);
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);
708 if (ferror(tp) || fclose(tp)) {
709 (void) fprintf(stderr,
710 _("%s: Error writing %s\n"),
711 progname, toname);
712 exit(EXIT_FAILURE);
714 warning(_("link failed, copy used"));
717 free(fromname);
718 free(toname);
721 #define TIME_T_BITS_IN_FILE 64
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));
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.
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>.
734 For the time of the Big Bang, see:
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]
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.
747 BIG_BANG is approximate, and may change in future versions.
748 Please do not rely on its exact value. */
750 #ifndef BIG_BANG
751 #define BIG_BANG (- (1LL << 59))
752 #endif
754 static const zic_t big_bang_time = BIG_BANG;
756 static int
757 itsdir(const char *const name)
759 register char * myname;
760 register int accres;
762 myname = ecpyalloc(name);
763 myname = ecatalloc(myname, "/.");
764 accres = access(myname, F_OK);
765 free(myname);
766 return accres == 0;
770 ** Associate sets of rules with zones.
774 ** Sort by rule name.
777 static int
778 rcomp(const void *cp1, const void *cp2)
780 return strcmp(((const struct rule *) cp1)->r_name,
781 ((const struct rule *) cp2)->r_name);
784 static void
785 associate(void)
787 register struct zone * zp;
788 register struct rule * rp;
789 register int base, out;
790 register int i, j;
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;
817 i = j - 1;
820 for (i = 0; i < nzones; ++i) {
821 zp = &zones[i];
822 zp->z_rules = NULL;
823 zp->z_nrules = 0;
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;
838 for (i = 0; i < nzones; ++i) {
839 zp = &zones[i];
840 if (zp->z_nrules == 0) {
842 ** Maybe we have a local standard time offset.
844 eat(zp->z_filename, zp->z_linenum);
845 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
846 TRUE);
848 ** Note, though, that if there's no rule,
849 ** a '%s' in the format is a bad thing.
851 if (strchr(zp->z_format, '%') != 0)
852 error("%s", _("%s in ruleless zone"));
855 if (errors)
856 exit(EXIT_FAILURE);
859 static void
860 infile(const char *name)
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];
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);
877 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
878 progname, name, e);
879 exit(EXIT_FAILURE);
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);
891 *cp = '\0';
892 fields = getfields(buf);
893 nfields = 0;
894 while (fields[nfields] != NULL) {
895 static char nada;
897 if (strcmp(fields[nfields], "-") == 0)
898 fields[nfields] = &nada;
899 ++nfields;
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);
936 free(fields);
938 if (ferror(fp)) {
939 (void) fprintf(stderr, _("%s: Error reading %s\n"),
940 progname, filename);
941 exit(EXIT_FAILURE);
943 if (fp != stdin && fclose(fp)) {
944 const char *e = strerror(errno);
946 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
947 progname, filename, e);
948 exit(EXIT_FAILURE);
950 if (wantcont)
951 error(_("expected continuation line not found"));
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.
962 static zic_t
963 gethms(const char *string, const char *const errstring, const int signable)
965 zic_t hh;
966 int mm, ss, sign;
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;
985 if (hh < 0 ||
986 mm < 0 || mm >= MINSPERHOUR ||
987 ss < 0 || ss > SECSPERMIN) {
988 error("%s", errstring);
989 return 0;
991 if (ZIC_MAX / SECSPERHOUR < hh) {
992 error(_("time overflow"));
993 return 0;
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));
1002 static void
1003 inrule(register char **const fields, const int nfields)
1005 static struct rule r;
1007 if (nfields != RULE_FIELDS) {
1008 error(_("wrong number of fields on Rule line"));
1009 return;
1011 if (*fields[RF_NAME] == '\0') {
1012 error(_("nameless rule"));
1013 return;
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;
1028 static int
1029 inzone(register char **const fields, const int nfields)
1031 register int i;
1033 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1034 error(_("wrong number of fields on Zone line"));
1035 return FALSE;
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;
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;
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;
1059 return inzsub(fields, nfields, FALSE);
1062 static int
1063 inzcont(register char **const fields, const int nfields)
1065 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1066 error(_("wrong number of fields on Zone continuation line"));
1067 return FALSE;
1069 return inzsub(fields, nfields, TRUE);
1072 static int
1073 inzsub(register char **const fields, const int nfields, const int iscont)
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;
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]);
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;
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",
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"
1137 return FALSE;
1140 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1141 zones[nzones++] = z;
1143 ** If there was an UNTIL field on this line,
1144 ** there's more information about the zone on the next line.
1146 return hasuntil;
1149 static void
1150 inleap(register char ** const fields, const int nfields)
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;
1160 if (nfields != LEAP_FIELDS) {
1161 error(_("wrong number of fields on Leap line"));
1162 return;
1164 dayoff = 0;
1165 cp = fields[LP_YEAR];
1166 if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) {
1168 ** Leapin' Lizards!
1170 error(_("invalid leaping year"));
1171 return;
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)];
1187 dayoff = oadd(dayoff, i);
1189 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1190 error(_("invalid month name"));
1191 return;
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;
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;
1206 dayoff = oadd(dayoff, day - 1);
1207 if (dayoff < min_time / SECSPERDAY) {
1208 error(_("time too small"));
1209 return;
1211 if (dayoff > max_time / SECSPERDAY) {
1212 error(_("time too large"));
1213 return;
1215 t = dayoff * SECSPERDAY;
1216 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1217 cp = fields[LP_CORR];
1219 register int positive;
1220 int count;
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;
1238 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1239 error(_(
1240 "illegal Rolling/Stationary field on Leap line"
1242 return;
1244 t = tadd(t, tod);
1245 if (t < big_bang_time) {
1246 error(_("leap second precedes Big Bang"));
1247 return;
1249 leapadd(t, positive, lp->l_value, count);
1253 static void
1254 inlink(register char **const fields, const int nfields)
1256 struct link l;
1258 if (nfields != LINK_FIELDS) {
1259 error(_("wrong number of fields on Link line"));
1260 return;
1262 if (*fields[LF_FROM] == '\0') {
1263 error(_("blank FROM field on Link line"));
1264 return;
1266 if (*fields[LF_TO] == '\0') {
1267 error(_("blank TO field on Link line"));
1268 return;
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;
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)
1287 register const struct lookup * lp;
1288 register const char * cp;
1289 register char * dp;
1290 register char * ep;
1292 if ((lp = byword(monthp, mon_names)) == NULL) {
1293 error(_("invalid month name"));
1294 return;
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;
1322 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1323 free(dp);
1325 ** Year work.
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;
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;
1368 if (rp->r_loyear > rp->r_hiyear) {
1369 error(_("starting year greater than ending year"));
1370 return;
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;
1379 rp->r_yrtype = ecpyalloc(typep);
1382 ** Day work.
1383 ** Accept things such as:
1384 ** 1
1385 ** last-Sunday
1386 ** Sun<=20
1387 ** Sun>=7
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;
1403 if (rp->r_dycode != DC_DOM) {
1404 *ep++ = 0;
1405 if (*ep++ != '=') {
1406 error(_("invalid day of month"));
1407 free(dp);
1408 return;
1410 if ((lp = byword(dp, wday_names)) == NULL) {
1411 error(_("invalid weekday name"));
1412 free(dp);
1413 return;
1415 rp->r_wday = lp->l_value;
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;
1425 free(dp);
1428 static void
1429 convert(const int_fast32_t val, char *const buf)
1431 register int i;
1432 register int shift;
1433 unsigned char *const b = (unsigned char *) buf;
1435 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1436 b[i] = val >> shift;
1439 static void
1440 convert64(const zic_t val, char *const buf)
1442 register int i;
1443 register int shift;
1444 unsigned char *const b = (unsigned char *) buf;
1446 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1447 b[i] = val >> shift;
1450 static void
1451 puttzcode(const int_fast32_t val, FILE *const fp)
1453 char buf[4];
1455 convert(val, buf);
1456 (void) fwrite(buf, sizeof buf, 1, fp);
1459 static void
1460 puttzcode64(const zic_t val, FILE *const fp)
1462 char buf[8];
1464 convert64(val, buf);
1465 (void) fwrite(buf, sizeof buf, 1, fp);
1468 static int
1469 atcomp(const void *avp, const void *bvp)
1471 const zic_t a = ((const struct attype *) avp)->at;
1472 const zic_t b = ((const struct attype *) bvp)->at;
1474 return (a < b) ? -1 : (a > b);
1477 static int
1478 is32(const zic_t x)
1480 return INT32_MIN <= x && x <= INT32_MAX;
1483 static void
1484 writezone(const char *const name, const char *const string, char version)
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;
1499 ** Sort.
1501 if (timecnt > 1)
1502 (void) qsort(attypes, timecnt, sizeof *attypes, atcomp);
1504 ** Optimize.
1507 int fromi;
1508 int toi;
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;
1523 if (toi == 0 ||
1524 attypes[toi - 1].type != attypes[fromi].type)
1525 attypes[toi++] = attypes[fromi];
1527 timecnt = toi;
1529 if (noise && timecnt > 1200)
1530 warning(_("pre-2014 clients may mishandle"
1531 " more than 1200 transition times"));
1533 ** Transfer.
1535 for (i = 0; i < timecnt; ++i) {
1536 ats[i] = attypes[i].at;
1537 types[i] = attypes[i].type;
1540 ** Correct for leap seconds.
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;
1551 ** Figure out 32-bit-limited starts and counts.
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;
1564 ** Output an INT32_MIN "transition" if appropriate--see below.
1566 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1567 --timei32;
1568 ++timecnt32;
1570 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1571 --leapcnt32;
1572 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1573 --leapcnt32;
1574 ++leapi32;
1576 fullname = erealloc(fullname,
1577 strlen(directory) + 1 + strlen(name) + 1);
1578 (void) sprintf(fullname, "%s/%s", directory, name);
1580 ** Remove old file, if any, to snap links.
1582 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1583 const char *e = strerror(errno);
1585 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1586 progname, fullname, e);
1587 exit(EXIT_FAILURE);
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);
1595 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1596 progname, fullname, e);
1597 exit(EXIT_FAILURE);
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];
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;
1622 thistimelim = thistimei + thistimecnt;
1623 thisleaplim = thisleapi + thisleapcnt;
1624 for (i = 0; i < typecnt; ++i)
1625 writetype[i] = thistimecnt == timecnt;
1626 if (thistimecnt == 0) {
1628 ** No transition times fall in the current
1629 ** (32- or 64-bit) window.
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;
1638 ** For America/Godthab and Antarctica/Palmer
1640 if (thistimei == 0)
1641 writetype[0] = TRUE;
1643 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
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).
1653 register int mrudst, mrustd, hidst, histd, type;
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;
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;
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;
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;
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;
1712 indmap[abbrinds[i]] = j;
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)
1737 ** Output an INT32_MIN "transition"
1738 ** if appropriate--see above.
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;
1746 uc = typemap[types[i]];
1747 (void) fwrite(&uc, sizeof uc, 1, fp);
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);
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;
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;
1769 } else {
1770 j = 1;
1771 while (j < timecnt &&
1772 trans[i] >= ats[j])
1773 ++j;
1774 j = types[j - 1];
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);
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);
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);
1796 free(ats);
1799 static void
1800 doabbr(char *const abbr, const char *const format, const char *const letters,
1801 const int isdst, const int doquotes)
1803 register char * cp;
1804 register char * slashp;
1805 register int len;
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';
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] = '<';
1835 static void
1836 updateminmax(const zic_t x)
1838 if (min_year > x)
1839 min_year = x;
1840 if (max_year < x)
1841 max_year = x;
1844 static int
1845 stringoffset(char *result, zic_t offset)
1847 register int hours;
1848 register int minutes;
1849 register int seconds;
1851 result[0] = '\0';
1852 if (offset < 0) {
1853 (void) strcpy(result, "-");
1854 offset = -offset;
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;
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);
1871 return 0;
1874 static int
1875 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
1876 const zic_t gmtoff)
1878 register zic_t tod = rp->r_tod;
1879 register int compat = 0;
1881 result = end(result);
1882 if (rp->r_dycode == DC_DOM) {
1883 register int month, total;
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;
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;
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);
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;
1940 return compat;
1943 static int
1944 rule_cmp(struct rule const *a, struct rule const *b)
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;
1957 enum { YEAR_BY_YEAR_ZONE = 1 };
1959 static int
1960 stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
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;
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;
1991 if (stdrp == NULL && dstrp == NULL) {
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.
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;
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.
2010 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2011 return YEAR_BY_YEAR_ZONE;
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;
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;
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;
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;
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;
2065 if (compat < c)
2066 compat = c;
2067 return compat;
2070 static void
2071 outzone(const struct zone * const zpfirst, const int zonecount)
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;
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);
2103 ** Now. . .finally. . .generate some useful data!
2105 timecnt = 0;
2106 typecnt = 0;
2107 charcnt = 0;
2108 prodstic = zonecount == 1;
2110 ** Thanks to Earl Chew
2111 ** for noting the need to unconditionally initialize startttisstd.
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));
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;
2135 ** Generate lots of data if a rule can't cover all future times.
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);
2154 if (do_extend) {
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.
2168 enum { years_of_observations = YEARSPERREPEAT + 2 };
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;
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.
2182 if (prodstic) {
2183 min_year = 1900;
2184 max_year = min_year + years_of_observations;
2188 ** For the benefit of older systems,
2189 ** generate data from 1900 through 2037.
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) {
2197 ** A guess that may well be corrected later.
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;
2224 ** Mark which rules to do in the current year.
2225 ** For those to do, calculate rpytime(rp, year);
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);
2237 for ( ; ; ) {
2238 register int k;
2239 register zic_t jtime, ktime;
2240 register zic_t offset;
2242 INITIALIZE(ktime);
2243 if (useuntil) {
2245 ** Turn untiltime into UT
2246 ** assuming the current gmtoff and
2247 ** stdoff values.
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);
2258 ** Find the rule (of those to do, if any)
2259 ** that takes effect earliest in the year.
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;
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;
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 !=
2308 FALSE);
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);
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));
2337 ** Now we may get to set starttime for the next zone line.
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);
2349 if (do_extend) {
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.
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)) {
2371 ** Create new type code for the redundant entry,
2372 ** to prevent it being optimised away.
2374 if (typecnt >= TZ_MAX_TYPES) {
2375 error(_("too many local time types"));
2376 exit(EXIT_FAILURE);
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);
2387 writezone(zpfirst->z_name, envvar, version);
2388 free(startbuf);
2389 free(ab);
2390 free(envvar);
2393 static void
2394 addtt(const zic_t starttime, int type)
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;
2410 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2411 attypes[timecnt].at = starttime;
2412 attypes[timecnt].type = type;
2413 ++timecnt;
2416 static int
2417 addtype(const zic_t gmtoff, const char *const abbr, const int isdst,
2418 const int ttisstd, const int ttisgmt)
2420 register int i, j;
2422 if (isdst != TRUE && isdst != FALSE) {
2423 error(_("internal error - addtype called with bad isdst"));
2424 exit(EXIT_FAILURE);
2426 if (ttisstd != TRUE && ttisstd != FALSE) {
2427 error(_("internal error - addtype called with bad ttisstd"));
2428 exit(EXIT_FAILURE);
2430 if (ttisgmt != TRUE && ttisgmt != FALSE) {
2431 error(_("internal error - addtype called with bad ttisgmt"));
2432 exit(EXIT_FAILURE);
2435 ** See if there's already an entry for this zone type.
2436 ** If so, just return its index.
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;
2446 ** There isn't one; add a new one, unless there are already too
2447 ** many.
2449 if (typecnt >= TZ_MAX_TYPES) {
2450 error(_("too many local time types"));
2451 exit(EXIT_FAILURE);
2453 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2454 error(_("UT offset out of range"));
2455 exit(EXIT_FAILURE);
2457 gmtoffs[i] = gmtoff;
2458 isdsts[i] = isdst;
2459 ttisstds[i] = ttisstd;
2460 ttisgmts[i] = ttisgmt;
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;
2472 static void
2473 leapadd(const zic_t t, const int positive, const int rolling, int count)
2475 register int i, j;
2477 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2478 error(_("too many leap seconds"));
2479 exit(EXIT_FAILURE);
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);
2487 break;
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];
2495 trans[i] = t;
2496 corr[i] = positive ? 1 : -count;
2497 roll[i] = rolling;
2498 ++leapcnt;
2499 } while (positive && --count != 0);
2502 static void
2503 adjleap(void)
2505 register int i;
2506 register zic_t last = 0;
2509 ** propagate leap seconds forward
2511 for (i = 0; i < leapcnt; ++i) {
2512 trans[i] = tadd(trans[i], last);
2513 last = corr[i] += last;
2517 static int
2518 yearistype(const int year, const char *const type)
2520 static char * buf;
2521 int result;
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;
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);
2541 static int
2542 lowerit(int a)
2544 a = (unsigned char) a;
2545 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2548 /* case-insensitive equality */
2549 static ATTRIBUTE_PURE int
2550 ciequal(register const char *ap, register const char *bp)
2552 while (lowerit(*ap) == lowerit(*bp++))
2553 if (*ap++ == '\0')
2554 return TRUE;
2555 return FALSE;
2558 static ATTRIBUTE_PURE int
2559 itsabbr(register const char *abbr, register const char *word)
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;
2572 static ATTRIBUTE_PURE const struct lookup *
2573 byword(register const char *const word,
2574 register const struct lookup *const table)
2576 register const struct lookup * foundlp;
2577 register const struct lookup * lp;
2579 if (word == NULL || table == NULL)
2580 return NULL;
2582 ** Look for exact match.
2584 for (lp = table; lp->l_word != NULL; ++lp)
2585 if (ciequal(word, lp->l_word))
2586 return lp;
2588 ** Look for inexact match.
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 */
2597 return foundlp;
2600 static char **
2601 getfields(register char *cp)
2603 register char * dp;
2604 register char ** array;
2605 register int nsubs;
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"
2628 exit(1);
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';
2636 array[nsubs] = NULL;
2637 return array;
2640 static ATTRIBUTE_PURE zic_t
2641 oadd(const zic_t t1, const zic_t t2)
2643 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) {
2644 error(_("time overflow"));
2645 exit(EXIT_FAILURE);
2647 return t1 + t2;
2650 static ATTRIBUTE_PURE zic_t
2651 tadd(const zic_t t1, const zic_t t2)
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);
2661 return t1 + t2;
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.
2669 static zic_t
2670 rpytime(register const struct rule *const rp, register const zic_t wantedy)
2672 register int m, i;
2673 register zic_t dayoff; /* with a nod to Margaret O. */
2674 register zic_t t, y;
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)];
2691 dayoff = oadd(dayoff, i);
2693 while (m != rp->r_month) {
2694 i = len_months[isleap(y)][m];
2695 dayoff = oadd(dayoff, i);
2696 ++m;
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);
2707 --i;
2708 dayoff = oadd(dayoff, i);
2709 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2710 register zic_t wday;
2712 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2713 wday = EPOCH_WDAY;
2715 ** Don't trust mod of negative numbers.
2717 if (dayoff >= 0)
2718 wday = (wday + dayoff) % LDAYSPERWEEK;
2719 else {
2720 wday -= ((-dayoff) % LDAYSPERWEEK);
2721 if (wday < 0)
2722 wday += LDAYSPERWEEK;
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;
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"));
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);
2750 static void
2751 newabbr(const char *const string)
2753 register int i;
2755 if (strcmp(string, GRANDPARENTED) != 0) {
2756 register const char * cp;
2757 const char * mp;
2760 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2761 ** optionally followed by a + or - and a number from 1 to 14.
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;
2782 if (*cp != '\0')
2783 mp = _("time zone abbreviation differs from POSIX standard");
2784 if (mp != NULL)
2785 warning("%s (%s)", mp, string);
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);
2792 (void) strcpy(&chars[charcnt], string);
2793 charcnt += i;
2796 static int
2797 mkdirs(char *argname)
2799 register char * name;
2800 register char * cp;
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
2809 ** DOS drive specifier?
2811 if (isalpha((unsigned char) name[0]) &&
2812 name[1] == ':' && name[2] == '\0') {
2813 *cp = '/';
2814 continue;
2816 #endif
2817 if (!itsdir(name)) {
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.
2824 if (mkdir(name, MKDIR_UMASK) != 0) {
2825 const char *e = strerror(errno);
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;
2836 *cp = '/';
2838 free(name);
2839 return 0;
2843 ** UNIX was a registered trademark of The Open Group in 2003.