Fix generic fmax, fmin sNaN handling (bug 20947).
[glibc.git] / timezone / zic.c
blob78ab870941e906b10f7c374cea210be065f51561
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
34 struct rule {
35 const char * r_filename;
36 int r_linenum;
37 const char * r_name;
39 zic_t r_loyear; /* for example, 1986 */
40 zic_t r_hiyear; /* for example, 1986 */
41 const char * r_yrtype;
42 bool r_lowasnum;
43 bool r_hiwasnum;
45 int r_month; /* 0..11 */
47 int r_dycode; /* see below */
48 int r_dayofmonth;
49 int r_wday;
51 zic_t r_tod; /* time from midnight */
52 bool r_todisstd; /* above is standard time if 1 */
53 /* or wall clock time if 0 */
54 bool r_todisgmt; /* above is GMT if 1 */
55 /* or local time if 0 */
56 zic_t r_stdoff; /* offset from standard time */
57 const char * r_abbrvar; /* variable part of abbreviation */
59 int r_todo; /* a rule to do (used in outzone) */
60 zic_t r_temp; /* used in outzone */
64 ** r_dycode r_dayofmonth r_wday
67 #define DC_DOM 0 /* 1..31 */ /* unused */
68 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
69 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
71 struct zone {
72 const char * z_filename;
73 int z_linenum;
75 const char * z_name;
76 zic_t z_gmtoff;
77 const char * z_rule;
78 const char * z_format;
79 char z_format_specifier;
81 zic_t z_stdoff;
83 struct rule * z_rules;
84 int z_nrules;
86 struct rule z_untilrule;
87 zic_t z_untiltime;
90 extern int getopt(int argc, char * const argv[],
91 const char * options);
92 extern int link(const char * fromname, const char * toname);
93 extern char * optarg;
94 extern int optind;
96 #if ! HAVE_LINK
97 # define link(from, to) (-1)
98 #endif
99 #if ! HAVE_SYMLINK
100 # define symlink(from, to) (-1)
101 #endif
103 static void addtt(zic_t starttime, int type);
104 static int addtype(zic_t, char const *, bool, bool, bool);
105 static void leapadd(zic_t, bool, int, int);
106 static void adjleap(void);
107 static void associate(void);
108 static void dolink(const char * fromfield, const char * tofield);
109 static char ** getfields(char * buf);
110 static zic_t gethms(const char * string, const char * errstring,
111 bool);
112 static void infile(const char * filename);
113 static void inleap(char ** fields, int nfields);
114 static void inlink(char ** fields, int nfields);
115 static void inrule(char ** fields, int nfields);
116 static bool inzcont(char ** fields, int nfields);
117 static bool inzone(char ** fields, int nfields);
118 static bool inzsub(char **, int, bool);
119 static int itsdir(const char * name);
120 static bool is_alpha(char a);
121 static char lowerit(char);
122 static bool mkdirs(char *);
123 static void newabbr(const char * abbr);
124 static zic_t oadd(zic_t t1, zic_t t2);
125 static void outzone(const struct zone * zp, int ntzones);
126 static zic_t rpytime(const struct rule * rp, zic_t wantedy);
127 static void rulesub(struct rule * rp,
128 const char * loyearp, const char * hiyearp,
129 const char * typep, const char * monthp,
130 const char * dayp, const char * timep);
131 static zic_t tadd(zic_t t1, zic_t t2);
132 static bool yearistype(int year, const char * type);
134 /* Bound on length of what %z can expand to. */
135 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
137 static int charcnt;
138 static bool errors;
139 static bool warnings;
140 static const char * filename;
141 static int leapcnt;
142 static bool leapseen;
143 static zic_t leapminyear;
144 static zic_t leapmaxyear;
145 static int linenum;
146 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
147 static int max_format_len;
148 static zic_t max_year;
149 static zic_t min_year;
150 static bool noise;
151 static const char * rfilename;
152 static int rlinenum;
153 static const char * progname;
154 static int timecnt;
155 static int timecnt_alloc;
156 static int typecnt;
159 ** Line codes.
162 #define LC_RULE 0
163 #define LC_ZONE 1
164 #define LC_LINK 2
165 #define LC_LEAP 3
168 ** Which fields are which on a Zone line.
171 #define ZF_NAME 1
172 #define ZF_GMTOFF 2
173 #define ZF_RULE 3
174 #define ZF_FORMAT 4
175 #define ZF_TILYEAR 5
176 #define ZF_TILMONTH 6
177 #define ZF_TILDAY 7
178 #define ZF_TILTIME 8
179 #define ZONE_MINFIELDS 5
180 #define ZONE_MAXFIELDS 9
183 ** Which fields are which on a Zone continuation line.
186 #define ZFC_GMTOFF 0
187 #define ZFC_RULE 1
188 #define ZFC_FORMAT 2
189 #define ZFC_TILYEAR 3
190 #define ZFC_TILMONTH 4
191 #define ZFC_TILDAY 5
192 #define ZFC_TILTIME 6
193 #define ZONEC_MINFIELDS 3
194 #define ZONEC_MAXFIELDS 7
197 ** Which files are which on a Rule line.
200 #define RF_NAME 1
201 #define RF_LOYEAR 2
202 #define RF_HIYEAR 3
203 #define RF_COMMAND 4
204 #define RF_MONTH 5
205 #define RF_DAY 6
206 #define RF_TOD 7
207 #define RF_STDOFF 8
208 #define RF_ABBRVAR 9
209 #define RULE_FIELDS 10
212 ** Which fields are which on a Link line.
215 #define LF_FROM 1
216 #define LF_TO 2
217 #define LINK_FIELDS 3
220 ** Which fields are which on a Leap line.
223 #define LP_YEAR 1
224 #define LP_MONTH 2
225 #define LP_DAY 3
226 #define LP_TIME 4
227 #define LP_CORR 5
228 #define LP_ROLL 6
229 #define LEAP_FIELDS 7
232 ** Year synonyms.
235 #define YR_MINIMUM 0
236 #define YR_MAXIMUM 1
237 #define YR_ONLY 2
239 static struct rule * rules;
240 static int nrules; /* number of rules */
241 static int nrules_alloc;
243 static struct zone * zones;
244 static int nzones; /* number of zones */
245 static int nzones_alloc;
247 struct link {
248 const char * l_filename;
249 int l_linenum;
250 const char * l_from;
251 const char * l_to;
254 static struct link * links;
255 static int nlinks;
256 static int nlinks_alloc;
258 struct lookup {
259 const char * l_word;
260 const int l_value;
263 static struct lookup const * byword(const char * string,
264 const struct lookup * lp);
266 static struct lookup const line_codes[] = {
267 { "Rule", LC_RULE },
268 { "Zone", LC_ZONE },
269 { "Link", LC_LINK },
270 { "Leap", LC_LEAP },
271 { NULL, 0}
274 static struct lookup const mon_names[] = {
275 { "January", TM_JANUARY },
276 { "February", TM_FEBRUARY },
277 { "March", TM_MARCH },
278 { "April", TM_APRIL },
279 { "May", TM_MAY },
280 { "June", TM_JUNE },
281 { "July", TM_JULY },
282 { "August", TM_AUGUST },
283 { "September", TM_SEPTEMBER },
284 { "October", TM_OCTOBER },
285 { "November", TM_NOVEMBER },
286 { "December", TM_DECEMBER },
287 { NULL, 0 }
290 static struct lookup const wday_names[] = {
291 { "Sunday", TM_SUNDAY },
292 { "Monday", TM_MONDAY },
293 { "Tuesday", TM_TUESDAY },
294 { "Wednesday", TM_WEDNESDAY },
295 { "Thursday", TM_THURSDAY },
296 { "Friday", TM_FRIDAY },
297 { "Saturday", TM_SATURDAY },
298 { NULL, 0 }
301 static struct lookup const lasts[] = {
302 { "last-Sunday", TM_SUNDAY },
303 { "last-Monday", TM_MONDAY },
304 { "last-Tuesday", TM_TUESDAY },
305 { "last-Wednesday", TM_WEDNESDAY },
306 { "last-Thursday", TM_THURSDAY },
307 { "last-Friday", TM_FRIDAY },
308 { "last-Saturday", TM_SATURDAY },
309 { NULL, 0 }
312 static struct lookup const begin_years[] = {
313 { "minimum", YR_MINIMUM },
314 { "maximum", YR_MAXIMUM },
315 { NULL, 0 }
318 static struct lookup const end_years[] = {
319 { "minimum", YR_MINIMUM },
320 { "maximum", YR_MAXIMUM },
321 { "only", YR_ONLY },
322 { NULL, 0 }
325 static struct lookup const leap_types[] = {
326 { "Rolling", true },
327 { "Stationary", false },
328 { NULL, 0 }
331 static const int len_months[2][MONSPERYEAR] = {
332 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
333 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
336 static const int len_years[2] = {
337 DAYSPERNYEAR, DAYSPERLYEAR
340 static struct attype {
341 zic_t at;
342 unsigned char type;
343 } * attypes;
344 static zic_t gmtoffs[TZ_MAX_TYPES];
345 static char isdsts[TZ_MAX_TYPES];
346 static unsigned char abbrinds[TZ_MAX_TYPES];
347 static bool ttisstds[TZ_MAX_TYPES];
348 static bool ttisgmts[TZ_MAX_TYPES];
349 static char chars[TZ_MAX_CHARS];
350 static zic_t trans[TZ_MAX_LEAPS];
351 static zic_t corr[TZ_MAX_LEAPS];
352 static char roll[TZ_MAX_LEAPS];
355 ** Memory allocation.
358 static _Noreturn void
359 memory_exhausted(const char *msg)
361 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
362 exit(EXIT_FAILURE);
365 static ATTRIBUTE_PURE size_t
366 size_product(size_t nitems, size_t itemsize)
368 if (SIZE_MAX / itemsize < nitems)
369 memory_exhausted(_("size overflow"));
370 return nitems * itemsize;
373 #if !HAVE_STRDUP
374 static char *
375 strdup(char const *str)
377 char *result = malloc(strlen(str) + 1);
378 return result ? strcpy(result, str) : result;
380 #endif
382 static ATTRIBUTE_PURE void *
383 memcheck(void *ptr)
385 if (ptr == NULL)
386 memory_exhausted(strerror(errno));
387 return ptr;
390 static void *
391 emalloc(size_t size)
393 return memcheck(malloc(size));
396 static void *
397 erealloc(void *ptr, size_t size)
399 return memcheck(realloc(ptr, size));
402 static char *
403 ecpyalloc (char const *str)
405 return memcheck(strdup(str));
408 static void *
409 growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
411 if (nitems < *nitems_alloc)
412 return ptr;
413 else {
414 int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX;
415 if ((amax - 1) / 3 * 2 < *nitems_alloc)
416 memory_exhausted(_("int overflow"));
417 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
418 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
423 ** Error handling.
426 static void
427 eats(const char *const name, const int num, const char *const rname,
428 const int rnum)
430 filename = name;
431 linenum = num;
432 rfilename = rname;
433 rlinenum = rnum;
436 static void
437 eat(const char *const name, const int num)
439 eats(name, num, NULL, -1);
442 static void ATTRIBUTE_FORMAT((printf, 1, 0))
443 verror(const char *const string, va_list args)
446 ** Match the format of "cc" to allow sh users to
447 ** zic ... 2>&1 | error -t "*" -v
448 ** on BSD systems.
450 if (filename)
451 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
452 vfprintf(stderr, string, args);
453 if (rfilename != NULL)
454 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
455 rfilename, rlinenum);
456 fprintf(stderr, "\n");
459 static void ATTRIBUTE_FORMAT((printf, 1, 2))
460 error(const char *const string, ...)
462 va_list args;
463 va_start(args, string);
464 verror(string, args);
465 va_end(args);
466 errors = true;
469 static void ATTRIBUTE_FORMAT((printf, 1, 2))
470 warning(const char *const string, ...)
472 va_list args;
473 fprintf(stderr, _("warning: "));
474 va_start(args, string);
475 verror(string, args);
476 va_end(args);
477 warnings = true;
480 static void
481 close_file(FILE *stream, char const *name)
483 char const *e = (ferror(stream) ? _("I/O error")
484 : fclose(stream) != 0 ? strerror(errno) : NULL);
485 if (e) {
486 fprintf(stderr, "%s: ", progname);
487 if (name)
488 fprintf(stderr, "%s: ", name);
489 fprintf(stderr, "%s\n", e);
490 exit(EXIT_FAILURE);
494 static _Noreturn void
495 usage(FILE *stream, int status)
497 fprintf(stream,
498 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
499 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
500 "\t[ -L leapseconds ] [ filename ... ]\n\n"
501 "Report bugs to %s.\n"),
502 progname, progname, REPORT_BUGS_TO);
503 if (status == EXIT_SUCCESS)
504 close_file(stream, NULL);
505 exit(status);
508 static const char * psxrules;
509 static const char * lcltime;
510 static const char * directory;
511 static const char * leapsec;
512 static const char * yitcommand;
515 main(int argc, char **argv)
517 register int i;
518 register int j;
519 register int c;
521 #ifdef S_IWGRP
522 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
523 #endif
524 #if HAVE_GETTEXT
525 setlocale(LC_ALL, "");
526 #ifdef TZ_DOMAINDIR
527 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
528 #endif /* defined TEXTDOMAINDIR */
529 textdomain(TZ_DOMAIN);
530 #endif /* HAVE_GETTEXT */
531 progname = argv[0];
532 if (TYPE_BIT(zic_t) < 64) {
533 fprintf(stderr, "%s: %s\n", progname,
534 _("wild compilation-time specification of zic_t"));
535 return EXIT_FAILURE;
537 for (i = 1; i < argc; ++i)
538 if (strcmp(argv[i], "--version") == 0) {
539 printf("zic %s%s\n", PKGVERSION, TZVERSION);
540 close_file(stdout, NULL);
541 return EXIT_SUCCESS;
542 } else if (strcmp(argv[i], "--help") == 0) {
543 usage(stdout, EXIT_SUCCESS);
545 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
546 switch (c) {
547 default:
548 usage(stderr, EXIT_FAILURE);
549 case 'd':
550 if (directory == NULL)
551 directory = optarg;
552 else {
553 fprintf(stderr,
554 _("%s: More than one -d option specified\n"),
555 progname);
556 return EXIT_FAILURE;
558 break;
559 case 'l':
560 if (lcltime == NULL)
561 lcltime = optarg;
562 else {
563 fprintf(stderr,
564 _("%s: More than one -l option specified\n"),
565 progname);
566 return EXIT_FAILURE;
568 break;
569 case 'p':
570 if (psxrules == NULL)
571 psxrules = optarg;
572 else {
573 fprintf(stderr,
574 _("%s: More than one -p option specified\n"),
575 progname);
576 return EXIT_FAILURE;
578 break;
579 case 'y':
580 if (yitcommand == NULL)
581 yitcommand = optarg;
582 else {
583 fprintf(stderr,
584 _("%s: More than one -y option specified\n"),
585 progname);
586 return EXIT_FAILURE;
588 break;
589 case 'L':
590 if (leapsec == NULL)
591 leapsec = optarg;
592 else {
593 fprintf(stderr,
594 _("%s: More than one -L option specified\n"),
595 progname);
596 return EXIT_FAILURE;
598 break;
599 case 'v':
600 noise = true;
601 break;
602 case 's':
603 warning(_("-s ignored"));
604 break;
606 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
607 usage(stderr, EXIT_FAILURE); /* usage message by request */
608 if (directory == NULL)
609 directory = TZDIR;
610 if (yitcommand == NULL)
611 yitcommand = "yearistype";
613 if (optind < argc && leapsec != NULL) {
614 infile(leapsec);
615 adjleap();
618 for (i = optind; i < argc; ++i)
619 infile(argv[i]);
620 if (errors)
621 return EXIT_FAILURE;
622 associate();
623 for (i = 0; i < nzones; i = j) {
625 ** Find the next non-continuation zone entry.
627 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
628 continue;
629 outzone(&zones[i], j - i);
632 ** Make links.
634 for (i = 0; i < nlinks; ++i) {
635 eat(links[i].l_filename, links[i].l_linenum);
636 dolink(links[i].l_from, links[i].l_to);
637 if (noise)
638 for (j = 0; j < nlinks; ++j)
639 if (strcmp(links[i].l_to,
640 links[j].l_from) == 0)
641 warning(_("link to link"));
643 if (lcltime != NULL) {
644 eat(_("command line"), 1);
645 dolink(lcltime, TZDEFAULT);
647 if (psxrules != NULL) {
648 eat(_("command line"), 1);
649 dolink(psxrules, TZDEFRULES);
651 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
652 return EXIT_FAILURE;
653 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
656 static bool
657 componentcheck(char const *name, char const *component,
658 char const *component_end)
660 enum { component_len_max = 14 };
661 size_t component_len = component_end - component;
662 if (component_len == 0) {
663 if (!*name)
664 error (_("empty file name"));
665 else
666 error (_(component == name
667 ? "file name '%s' begins with '/'"
668 : *component_end
669 ? "file name '%s' contains '//'"
670 : "file name '%s' ends with '/'"),
671 name);
672 return false;
674 if (0 < component_len && component_len <= 2
675 && component[0] == '.' && component_end[-1] == '.') {
676 error(_("file name '%s' contains '%.*s' component"),
677 name, (int) component_len, component);
678 return false;
680 if (noise) {
681 if (0 < component_len && component[0] == '-')
682 warning(_("file name '%s' component contains leading '-'"),
683 name);
684 if (component_len_max < component_len)
685 warning(_("file name '%s' contains overlength component"
686 " '%.*s...'"),
687 name, component_len_max, component);
689 return true;
692 static bool
693 namecheck(const char *name)
695 register char const *cp;
697 /* Benign characters in a portable file name. */
698 static char const benign[] =
699 "-/_"
700 "abcdefghijklmnopqrstuvwxyz"
701 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
703 /* Non-control chars in the POSIX portable character set,
704 excluding the benign characters. */
705 static char const printable_and_not_benign[] =
706 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
708 register char const *component = name;
709 for (cp = name; *cp; cp++) {
710 unsigned char c = *cp;
711 if (noise && !strchr(benign, c)) {
712 warning((strchr(printable_and_not_benign, c)
713 ? _("file name '%s' contains byte '%c'")
714 : _("file name '%s' contains byte '\\%o'")),
715 name, c);
717 if (c == '/') {
718 if (!componentcheck(name, component, cp))
719 return false;
720 component = cp + 1;
723 return componentcheck(name, component, cp);
726 static char *
727 relname(char const *dir, char const *base)
729 if (*base == '/')
730 return ecpyalloc(base);
731 else {
732 size_t dir_len = strlen(dir);
733 bool needs_slash = dir_len && dir[dir_len - 1] != '/';
734 char *result = emalloc(dir_len + needs_slash + strlen(base) + 1);
735 result[dir_len] = '/';
736 strcpy(result + dir_len + needs_slash, base);
737 return memcpy(result, dir, dir_len);
741 static void
742 dolink(char const *fromfield, char const *tofield)
744 register char * fromname;
745 register char * toname;
746 register int fromisdir;
748 fromname = relname(directory, fromfield);
749 toname = relname(directory, tofield);
751 ** We get to be careful here since
752 ** there's a fair chance of root running us.
754 fromisdir = itsdir(fromname);
755 if (fromisdir) {
756 char const *e = strerror(fromisdir < 0 ? errno : EPERM);
757 fprintf(stderr, _("%s: link from %s failed: %s"),
758 progname, fromname, e);
759 exit(EXIT_FAILURE);
761 if (itsdir(toname) <= 0)
762 remove(toname);
763 if (link(fromname, toname) != 0) {
764 int result;
766 if (! mkdirs(toname))
767 exit(EXIT_FAILURE);
769 result = link(fromname, toname);
770 if (result != 0) {
771 const char *s = fromfield;
772 const char *t;
773 char *p;
774 size_t dotdots = 0;
775 register char * symlinkcontents = NULL;
778 t = s;
779 while ((s = strchr(s, '/'))
780 && ! strncmp (fromfield, tofield,
781 ++s - fromfield));
783 for (s = tofield + (t - fromfield); *s; s++)
784 dotdots += *s == '/';
785 symlinkcontents
786 = emalloc(3 * dotdots + strlen(t) + 1);
787 for (p = symlinkcontents; dotdots-- != 0; p += 3)
788 memcpy(p, "../", 3);
789 strcpy(p, t);
790 result = symlink(symlinkcontents, toname);
791 if (result == 0)
792 warning(_("hard link failed, symbolic link used"));
793 free(symlinkcontents);
795 if (result != 0) {
796 FILE *fp, *tp;
797 int c;
798 fp = fopen(fromname, "rb");
799 if (!fp) {
800 const char *e = strerror(errno);
801 fprintf(stderr,
802 _("%s: Can't read %s: %s\n"),
803 progname, fromname, e);
804 exit(EXIT_FAILURE);
806 tp = fopen(toname, "wb");
807 if (!tp) {
808 const char *e = strerror(errno);
809 fprintf(stderr,
810 _("%s: Can't create %s: %s\n"),
811 progname, toname, e);
812 exit(EXIT_FAILURE);
814 while ((c = getc(fp)) != EOF)
815 putc(c, tp);
816 close_file(fp, fromname);
817 close_file(tp, toname);
818 warning(_("link failed, copy used"));
821 free(fromname);
822 free(toname);
825 #define TIME_T_BITS_IN_FILE 64
827 static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE);
828 static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE);
830 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
831 rounded downward to the negation of a power of two that is
832 comfortably outside the error bounds.
834 zic does not output time stamps before this, partly because they
835 are physically suspect, and partly because GNOME mishandles them; see
836 GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
838 For the time of the Big Bang, see:
840 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
841 I. Overview of products and scientific results.
842 arXiv:1303.5062 2013-03-20 20:10:01 UTC
843 <http://arxiv.org/pdf/1303.5062v1> [PDF]
845 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
846 gives the value 13.798 plus-or-minus 0.037 billion years.
847 Multiplying this by 1000000000 and then by 31557600 (the number of
848 seconds in an astronomical year) gives a value that is comfortably
849 less than 2**59, so BIG_BANG is - 2**59.
851 BIG_BANG is approximate, and may change in future versions.
852 Please do not rely on its exact value. */
854 #ifndef BIG_BANG
855 #define BIG_BANG (- (1LL << 59))
856 #endif
858 static const zic_t big_bang_time = BIG_BANG;
860 /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
861 static int
862 itsdir(char const *name)
864 struct stat st;
865 int res = stat(name, &st);
866 if (res != 0)
867 return res;
868 #ifdef S_ISDIR
869 return S_ISDIR(st.st_mode) != 0;
870 #else
872 char *nameslashdot = relname(name, ".");
873 res = stat(nameslashdot, &st);
874 free(nameslashdot);
875 return res == 0;
877 #endif
881 ** Associate sets of rules with zones.
885 ** Sort by rule name.
888 static int
889 rcomp(const void *cp1, const void *cp2)
891 return strcmp(((const struct rule *) cp1)->r_name,
892 ((const struct rule *) cp2)->r_name);
895 static void
896 associate(void)
898 register struct zone * zp;
899 register struct rule * rp;
900 register int base, out;
901 register int i, j;
903 if (nrules != 0) {
904 qsort(rules, nrules, sizeof *rules, rcomp);
905 for (i = 0; i < nrules - 1; ++i) {
906 if (strcmp(rules[i].r_name,
907 rules[i + 1].r_name) != 0)
908 continue;
909 if (strcmp(rules[i].r_filename,
910 rules[i + 1].r_filename) == 0)
911 continue;
912 eat(rules[i].r_filename, rules[i].r_linenum);
913 warning(_("same rule name in multiple files"));
914 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
915 warning(_("same rule name in multiple files"));
916 for (j = i + 2; j < nrules; ++j) {
917 if (strcmp(rules[i].r_name,
918 rules[j].r_name) != 0)
919 break;
920 if (strcmp(rules[i].r_filename,
921 rules[j].r_filename) == 0)
922 continue;
923 if (strcmp(rules[i + 1].r_filename,
924 rules[j].r_filename) == 0)
925 continue;
926 break;
928 i = j - 1;
931 for (i = 0; i < nzones; ++i) {
932 zp = &zones[i];
933 zp->z_rules = NULL;
934 zp->z_nrules = 0;
936 for (base = 0; base < nrules; base = out) {
937 rp = &rules[base];
938 for (out = base + 1; out < nrules; ++out)
939 if (strcmp(rp->r_name, rules[out].r_name) != 0)
940 break;
941 for (i = 0; i < nzones; ++i) {
942 zp = &zones[i];
943 if (strcmp(zp->z_rule, rp->r_name) != 0)
944 continue;
945 zp->z_rules = rp;
946 zp->z_nrules = out - base;
949 for (i = 0; i < nzones; ++i) {
950 zp = &zones[i];
951 if (zp->z_nrules == 0) {
953 ** Maybe we have a local standard time offset.
955 eat(zp->z_filename, zp->z_linenum);
956 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
957 true);
959 ** Note, though, that if there's no rule,
960 ** a '%s' in the format is a bad thing.
962 if (zp->z_format_specifier == 's')
963 error("%s", _("%s in ruleless zone"));
966 if (errors)
967 exit(EXIT_FAILURE);
970 static void
971 infile(const char *name)
973 register FILE * fp;
974 register char ** fields;
975 register char * cp;
976 register const struct lookup * lp;
977 register int nfields;
978 register bool wantcont;
979 register int num;
980 char buf[BUFSIZ];
982 if (strcmp(name, "-") == 0) {
983 name = _("standard input");
984 fp = stdin;
985 } else if ((fp = fopen(name, "r")) == NULL) {
986 const char *e = strerror(errno);
988 fprintf(stderr, _("%s: Can't open %s: %s\n"),
989 progname, name, e);
990 exit(EXIT_FAILURE);
992 wantcont = false;
993 for (num = 1; ; ++num) {
994 eat(name, num);
995 if (fgets(buf, sizeof buf, fp) != buf)
996 break;
997 cp = strchr(buf, '\n');
998 if (cp == NULL) {
999 error(_("line too long"));
1000 exit(EXIT_FAILURE);
1002 *cp = '\0';
1003 fields = getfields(buf);
1004 nfields = 0;
1005 while (fields[nfields] != NULL) {
1006 static char nada;
1008 if (strcmp(fields[nfields], "-") == 0)
1009 fields[nfields] = &nada;
1010 ++nfields;
1012 if (nfields == 0) {
1013 /* nothing to do */
1014 } else if (wantcont) {
1015 wantcont = inzcont(fields, nfields);
1016 } else {
1017 lp = byword(fields[0], line_codes);
1018 if (lp == NULL)
1019 error(_("input line of unknown type"));
1020 else switch ((int) (lp->l_value)) {
1021 case LC_RULE:
1022 inrule(fields, nfields);
1023 wantcont = false;
1024 break;
1025 case LC_ZONE:
1026 wantcont = inzone(fields, nfields);
1027 break;
1028 case LC_LINK:
1029 inlink(fields, nfields);
1030 wantcont = false;
1031 break;
1032 case LC_LEAP:
1033 if (name != leapsec)
1034 warning(_("%s: Leap line in non leap"
1035 " seconds file %s"),
1036 progname, name);
1037 else inleap(fields, nfields);
1038 wantcont = false;
1039 break;
1040 default: /* "cannot happen" */
1041 fprintf(stderr,
1042 _("%s: panic: Invalid l_value %d\n"),
1043 progname, lp->l_value);
1044 exit(EXIT_FAILURE);
1047 free(fields);
1049 close_file(fp, filename);
1050 if (wantcont)
1051 error(_("expected continuation line not found"));
1055 ** Convert a string of one of the forms
1056 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1057 ** into a number of seconds.
1058 ** A null string maps to zero.
1059 ** Call error with errstring and return zero on errors.
1062 static zic_t
1063 gethms(char const *string, char const *errstring, bool signable)
1065 zic_t hh;
1066 int mm, ss, sign;
1067 char xs;
1069 if (string == NULL || *string == '\0')
1070 return 0;
1071 if (!signable)
1072 sign = 1;
1073 else if (*string == '-') {
1074 sign = -1;
1075 ++string;
1076 } else sign = 1;
1077 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
1078 mm = ss = 0;
1079 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
1080 ss = 0;
1081 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
1082 != 3) {
1083 error("%s", errstring);
1084 return 0;
1086 if (hh < 0 ||
1087 mm < 0 || mm >= MINSPERHOUR ||
1088 ss < 0 || ss > SECSPERMIN) {
1089 error("%s", errstring);
1090 return 0;
1092 if (ZIC_MAX / SECSPERHOUR < hh) {
1093 error(_("time overflow"));
1094 return 0;
1096 if (noise && (hh > HOURSPERDAY ||
1097 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1098 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1099 return oadd(sign * hh * SECSPERHOUR,
1100 sign * (mm * SECSPERMIN + ss));
1103 static void
1104 inrule(char **fields, int nfields)
1106 static struct rule r;
1108 if (nfields != RULE_FIELDS) {
1109 error(_("wrong number of fields on Rule line"));
1110 return;
1112 if (*fields[RF_NAME] == '\0') {
1113 error(_("nameless rule"));
1114 return;
1116 r.r_filename = filename;
1117 r.r_linenum = linenum;
1118 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1119 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1120 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1121 r.r_name = ecpyalloc(fields[RF_NAME]);
1122 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1123 if (max_abbrvar_len < strlen(r.r_abbrvar))
1124 max_abbrvar_len = strlen(r.r_abbrvar);
1125 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1126 rules[nrules++] = r;
1129 static bool
1130 inzone(char **fields, int nfields)
1132 register int i;
1134 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1135 error(_("wrong number of fields on Zone line"));
1136 return false;
1138 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1139 error(
1140 _("\"Zone %s\" line and -l option are mutually exclusive"),
1141 TZDEFAULT);
1142 return false;
1144 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1145 error(
1146 _("\"Zone %s\" line and -p option are mutually exclusive"),
1147 TZDEFRULES);
1148 return false;
1150 for (i = 0; i < nzones; ++i)
1151 if (zones[i].z_name != NULL &&
1152 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1153 error(
1154 _("duplicate zone name %s (file \"%s\", line %d)"),
1155 fields[ZF_NAME],
1156 zones[i].z_filename,
1157 zones[i].z_linenum);
1158 return false;
1160 return inzsub(fields, nfields, false);
1163 static bool
1164 inzcont(char **fields, int nfields)
1166 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1167 error(_("wrong number of fields on Zone continuation line"));
1168 return false;
1170 return inzsub(fields, nfields, true);
1173 static bool
1174 inzsub(char **fields, int nfields, bool iscont)
1176 register char * cp;
1177 char * cp1;
1178 static struct zone z;
1179 register int i_gmtoff, i_rule, i_format;
1180 register int i_untilyear, i_untilmonth;
1181 register int i_untilday, i_untiltime;
1182 register bool hasuntil;
1184 if (iscont) {
1185 i_gmtoff = ZFC_GMTOFF;
1186 i_rule = ZFC_RULE;
1187 i_format = ZFC_FORMAT;
1188 i_untilyear = ZFC_TILYEAR;
1189 i_untilmonth = ZFC_TILMONTH;
1190 i_untilday = ZFC_TILDAY;
1191 i_untiltime = ZFC_TILTIME;
1192 z.z_name = NULL;
1193 } else if (!namecheck(fields[ZF_NAME]))
1194 return false;
1195 else {
1196 i_gmtoff = ZF_GMTOFF;
1197 i_rule = ZF_RULE;
1198 i_format = ZF_FORMAT;
1199 i_untilyear = ZF_TILYEAR;
1200 i_untilmonth = ZF_TILMONTH;
1201 i_untilday = ZF_TILDAY;
1202 i_untiltime = ZF_TILTIME;
1203 z.z_name = ecpyalloc(fields[ZF_NAME]);
1205 z.z_filename = filename;
1206 z.z_linenum = linenum;
1207 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1208 if ((cp = strchr(fields[i_format], '%')) != 0) {
1209 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1210 || strchr(fields[i_format], '/')) {
1211 error(_("invalid abbreviation format"));
1212 return false;
1215 z.z_rule = ecpyalloc(fields[i_rule]);
1216 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1217 z.z_format_specifier = cp ? *cp : '\0';
1218 if (z.z_format_specifier == 'z') {
1219 if (noise)
1220 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1221 z.z_format);
1222 cp1[cp - fields[i_format]] = 's';
1224 if (max_format_len < strlen(z.z_format))
1225 max_format_len = strlen(z.z_format);
1226 hasuntil = nfields > i_untilyear;
1227 if (hasuntil) {
1228 z.z_untilrule.r_filename = filename;
1229 z.z_untilrule.r_linenum = linenum;
1230 rulesub(&z.z_untilrule,
1231 fields[i_untilyear],
1232 "only",
1234 (nfields > i_untilmonth) ?
1235 fields[i_untilmonth] : "Jan",
1236 (nfields > i_untilday) ? fields[i_untilday] : "1",
1237 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1238 z.z_untiltime = rpytime(&z.z_untilrule,
1239 z.z_untilrule.r_loyear);
1240 if (iscont && nzones > 0 &&
1241 z.z_untiltime > min_time &&
1242 z.z_untiltime < max_time &&
1243 zones[nzones - 1].z_untiltime > min_time &&
1244 zones[nzones - 1].z_untiltime < max_time &&
1245 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1246 error(_(
1247 "Zone continuation line end time is not after end time of previous line"
1249 return false;
1252 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1253 zones[nzones++] = z;
1255 ** If there was an UNTIL field on this line,
1256 ** there's more information about the zone on the next line.
1258 return hasuntil;
1261 static void
1262 inleap(char **fields, int nfields)
1264 register const char * cp;
1265 register const struct lookup * lp;
1266 register int i, j;
1267 zic_t year;
1268 int month, day;
1269 zic_t dayoff, tod;
1270 zic_t t;
1271 char xs;
1273 if (nfields != LEAP_FIELDS) {
1274 error(_("wrong number of fields on Leap line"));
1275 return;
1277 dayoff = 0;
1278 cp = fields[LP_YEAR];
1279 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1281 ** Leapin' Lizards!
1283 error(_("invalid leaping year"));
1284 return;
1286 if (!leapseen || leapmaxyear < year)
1287 leapmaxyear = year;
1288 if (!leapseen || leapminyear > year)
1289 leapminyear = year;
1290 leapseen = true;
1291 j = EPOCH_YEAR;
1292 while (j != year) {
1293 if (year > j) {
1294 i = len_years[isleap(j)];
1295 ++j;
1296 } else {
1297 --j;
1298 i = -len_years[isleap(j)];
1300 dayoff = oadd(dayoff, i);
1302 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1303 error(_("invalid month name"));
1304 return;
1306 month = lp->l_value;
1307 j = TM_JANUARY;
1308 while (j != month) {
1309 i = len_months[isleap(year)][j];
1310 dayoff = oadd(dayoff, i);
1311 ++j;
1313 cp = fields[LP_DAY];
1314 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1315 day <= 0 || day > len_months[isleap(year)][month]) {
1316 error(_("invalid day of month"));
1317 return;
1319 dayoff = oadd(dayoff, day - 1);
1320 if (dayoff < min_time / SECSPERDAY) {
1321 error(_("time too small"));
1322 return;
1324 if (dayoff > max_time / SECSPERDAY) {
1325 error(_("time too large"));
1326 return;
1328 t = dayoff * SECSPERDAY;
1329 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1330 cp = fields[LP_CORR];
1332 register bool positive;
1333 int count;
1335 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1336 positive = false;
1337 count = 1;
1338 } else if (strcmp(cp, "--") == 0) {
1339 positive = false;
1340 count = 2;
1341 } else if (strcmp(cp, "+") == 0) {
1342 positive = true;
1343 count = 1;
1344 } else if (strcmp(cp, "++") == 0) {
1345 positive = true;
1346 count = 2;
1347 } else {
1348 error(_("illegal CORRECTION field on Leap line"));
1349 return;
1351 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1352 error(_(
1353 "illegal Rolling/Stationary field on Leap line"
1355 return;
1357 t = tadd(t, tod);
1358 if (t < big_bang_time) {
1359 error(_("leap second precedes Big Bang"));
1360 return;
1362 leapadd(t, positive, lp->l_value, count);
1366 static void
1367 inlink(char **fields, int nfields)
1369 struct link l;
1371 if (nfields != LINK_FIELDS) {
1372 error(_("wrong number of fields on Link line"));
1373 return;
1375 if (*fields[LF_FROM] == '\0') {
1376 error(_("blank FROM field on Link line"));
1377 return;
1379 if (! namecheck(fields[LF_TO]))
1380 return;
1381 l.l_filename = filename;
1382 l.l_linenum = linenum;
1383 l.l_from = ecpyalloc(fields[LF_FROM]);
1384 l.l_to = ecpyalloc(fields[LF_TO]);
1385 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1386 links[nlinks++] = l;
1389 static void
1390 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1391 const char *typep, const char *monthp, const char *dayp,
1392 const char *timep)
1394 register const struct lookup * lp;
1395 register const char * cp;
1396 register char * dp;
1397 register char * ep;
1398 char xs;
1400 if ((lp = byword(monthp, mon_names)) == NULL) {
1401 error(_("invalid month name"));
1402 return;
1404 rp->r_month = lp->l_value;
1405 rp->r_todisstd = false;
1406 rp->r_todisgmt = false;
1407 dp = ecpyalloc(timep);
1408 if (*dp != '\0') {
1409 ep = dp + strlen(dp) - 1;
1410 switch (lowerit(*ep)) {
1411 case 's': /* Standard */
1412 rp->r_todisstd = true;
1413 rp->r_todisgmt = false;
1414 *ep = '\0';
1415 break;
1416 case 'w': /* Wall */
1417 rp->r_todisstd = false;
1418 rp->r_todisgmt = false;
1419 *ep = '\0';
1420 break;
1421 case 'g': /* Greenwich */
1422 case 'u': /* Universal */
1423 case 'z': /* Zulu */
1424 rp->r_todisstd = true;
1425 rp->r_todisgmt = true;
1426 *ep = '\0';
1427 break;
1430 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1431 free(dp);
1433 ** Year work.
1435 cp = loyearp;
1436 lp = byword(cp, begin_years);
1437 rp->r_lowasnum = lp == NULL;
1438 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1439 case YR_MINIMUM:
1440 rp->r_loyear = ZIC_MIN;
1441 break;
1442 case YR_MAXIMUM:
1443 rp->r_loyear = ZIC_MAX;
1444 break;
1445 default: /* "cannot happen" */
1446 fprintf(stderr,
1447 _("%s: panic: Invalid l_value %d\n"),
1448 progname, lp->l_value);
1449 exit(EXIT_FAILURE);
1450 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1451 error(_("invalid starting year"));
1452 return;
1454 cp = hiyearp;
1455 lp = byword(cp, end_years);
1456 rp->r_hiwasnum = lp == NULL;
1457 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1458 case YR_MINIMUM:
1459 rp->r_hiyear = ZIC_MIN;
1460 break;
1461 case YR_MAXIMUM:
1462 rp->r_hiyear = ZIC_MAX;
1463 break;
1464 case YR_ONLY:
1465 rp->r_hiyear = rp->r_loyear;
1466 break;
1467 default: /* "cannot happen" */
1468 fprintf(stderr,
1469 _("%s: panic: Invalid l_value %d\n"),
1470 progname, lp->l_value);
1471 exit(EXIT_FAILURE);
1472 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1473 error(_("invalid ending year"));
1474 return;
1476 if (rp->r_loyear > rp->r_hiyear) {
1477 error(_("starting year greater than ending year"));
1478 return;
1480 if (*typep == '\0')
1481 rp->r_yrtype = NULL;
1482 else {
1483 if (rp->r_loyear == rp->r_hiyear) {
1484 error(_("typed single year"));
1485 return;
1487 rp->r_yrtype = ecpyalloc(typep);
1490 ** Day work.
1491 ** Accept things such as:
1492 ** 1
1493 ** last-Sunday
1494 ** Sun<=20
1495 ** Sun>=7
1497 dp = ecpyalloc(dayp);
1498 if ((lp = byword(dp, lasts)) != NULL) {
1499 rp->r_dycode = DC_DOWLEQ;
1500 rp->r_wday = lp->l_value;
1501 rp->r_dayofmonth = len_months[1][rp->r_month];
1502 } else {
1503 if ((ep = strchr(dp, '<')) != 0)
1504 rp->r_dycode = DC_DOWLEQ;
1505 else if ((ep = strchr(dp, '>')) != 0)
1506 rp->r_dycode = DC_DOWGEQ;
1507 else {
1508 ep = dp;
1509 rp->r_dycode = DC_DOM;
1511 if (rp->r_dycode != DC_DOM) {
1512 *ep++ = 0;
1513 if (*ep++ != '=') {
1514 error(_("invalid day of month"));
1515 free(dp);
1516 return;
1518 if ((lp = byword(dp, wday_names)) == NULL) {
1519 error(_("invalid weekday name"));
1520 free(dp);
1521 return;
1523 rp->r_wday = lp->l_value;
1525 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1526 rp->r_dayofmonth <= 0 ||
1527 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1528 error(_("invalid day of month"));
1529 free(dp);
1530 return;
1533 free(dp);
1536 static void
1537 convert(const int_fast32_t val, char *const buf)
1539 register int i;
1540 register int shift;
1541 unsigned char *const b = (unsigned char *) buf;
1543 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1544 b[i] = val >> shift;
1547 static void
1548 convert64(const zic_t val, char *const buf)
1550 register int i;
1551 register int shift;
1552 unsigned char *const b = (unsigned char *) buf;
1554 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1555 b[i] = val >> shift;
1558 static void
1559 puttzcode(const int_fast32_t val, FILE *const fp)
1561 char buf[4];
1563 convert(val, buf);
1564 fwrite(buf, sizeof buf, 1, fp);
1567 static void
1568 puttzcode64(const zic_t val, FILE *const fp)
1570 char buf[8];
1572 convert64(val, buf);
1573 fwrite(buf, sizeof buf, 1, fp);
1576 static int
1577 atcomp(const void *avp, const void *bvp)
1579 const zic_t a = ((const struct attype *) avp)->at;
1580 const zic_t b = ((const struct attype *) bvp)->at;
1582 return (a < b) ? -1 : (a > b);
1585 static bool
1586 is32(const zic_t x)
1588 return INT32_MIN <= x && x <= INT32_MAX;
1591 static void
1592 writezone(const char *const name, const char *const string, char version)
1594 register FILE * fp;
1595 register int i, j;
1596 register int leapcnt32, leapi32;
1597 register int timecnt32, timei32;
1598 register int pass;
1599 char * fullname;
1600 static const struct tzhead tzh0;
1601 static struct tzhead tzh;
1602 zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
1603 void *typesptr = ats + timecnt;
1604 unsigned char *types = typesptr;
1607 ** Sort.
1609 if (timecnt > 1)
1610 qsort(attypes, timecnt, sizeof *attypes, atcomp);
1612 ** Optimize.
1615 int fromi;
1616 int toi;
1618 toi = 0;
1619 fromi = 0;
1620 while (fromi < timecnt && attypes[fromi].at < big_bang_time)
1621 ++fromi;
1622 for ( ; fromi < timecnt; ++fromi) {
1623 if (toi > 1 && ((attypes[fromi].at +
1624 gmtoffs[attypes[toi - 1].type]) <=
1625 (attypes[toi - 1].at +
1626 gmtoffs[attypes[toi - 2].type]))) {
1627 attypes[toi - 1].type =
1628 attypes[fromi].type;
1629 continue;
1631 if (toi == 0 ||
1632 attypes[toi - 1].type != attypes[fromi].type)
1633 attypes[toi++] = attypes[fromi];
1635 timecnt = toi;
1637 if (noise && timecnt > 1200)
1638 warning(_("pre-2014 clients may mishandle"
1639 " more than 1200 transition times"));
1641 ** Transfer.
1643 for (i = 0; i < timecnt; ++i) {
1644 ats[i] = attypes[i].at;
1645 types[i] = attypes[i].type;
1648 ** Correct for leap seconds.
1650 for (i = 0; i < timecnt; ++i) {
1651 j = leapcnt;
1652 while (--j >= 0)
1653 if (ats[i] > trans[j] - corr[j]) {
1654 ats[i] = tadd(ats[i], corr[j]);
1655 break;
1659 ** Figure out 32-bit-limited starts and counts.
1661 timecnt32 = timecnt;
1662 timei32 = 0;
1663 leapcnt32 = leapcnt;
1664 leapi32 = 0;
1665 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1666 --timecnt32;
1667 while (timecnt32 > 0 && !is32(ats[timei32])) {
1668 --timecnt32;
1669 ++timei32;
1672 ** Output an INT32_MIN "transition" if appropriate; see below.
1674 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1675 --timei32;
1676 ++timecnt32;
1678 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1679 --leapcnt32;
1680 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1681 --leapcnt32;
1682 ++leapi32;
1684 fullname = relname(directory, name);
1686 ** Remove old file, if any, to snap links.
1688 if (itsdir(fullname) <= 0 && remove(fullname) != 0 && errno != ENOENT) {
1689 const char *e = strerror(errno);
1691 fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1692 progname, fullname, e);
1693 exit(EXIT_FAILURE);
1695 if ((fp = fopen(fullname, "wb")) == NULL) {
1696 if (! mkdirs(fullname))
1697 exit(EXIT_FAILURE);
1698 if ((fp = fopen(fullname, "wb")) == NULL) {
1699 const char *e = strerror(errno);
1701 fprintf(stderr, _("%s: Can't create %s: %s\n"),
1702 progname, fullname, e);
1703 exit(EXIT_FAILURE);
1706 for (pass = 1; pass <= 2; ++pass) {
1707 register int thistimei, thistimecnt;
1708 register int thisleapi, thisleapcnt;
1709 register int thistimelim, thisleaplim;
1710 int writetype[TZ_MAX_TYPES];
1711 int typemap[TZ_MAX_TYPES];
1712 register int thistypecnt;
1713 char thischars[TZ_MAX_CHARS];
1714 char thischarcnt;
1715 int indmap[TZ_MAX_CHARS];
1717 if (pass == 1) {
1718 thistimei = timei32;
1719 thistimecnt = timecnt32;
1720 thisleapi = leapi32;
1721 thisleapcnt = leapcnt32;
1722 } else {
1723 thistimei = 0;
1724 thistimecnt = timecnt;
1725 thisleapi = 0;
1726 thisleapcnt = leapcnt;
1728 thistimelim = thistimei + thistimecnt;
1729 thisleaplim = thisleapi + thisleapcnt;
1730 for (i = 0; i < typecnt; ++i)
1731 writetype[i] = thistimecnt == timecnt;
1732 if (thistimecnt == 0) {
1734 ** No transition times fall in the current
1735 ** (32- or 64-bit) window.
1737 if (typecnt != 0)
1738 writetype[typecnt - 1] = true;
1739 } else {
1740 for (i = thistimei - 1; i < thistimelim; ++i)
1741 if (i >= 0)
1742 writetype[types[i]] = true;
1744 ** For America/Godthab and Antarctica/Palmer
1746 if (thistimei == 0)
1747 writetype[0] = true;
1749 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1751 ** For some pre-2011 systems: if the last-to-be-written
1752 ** standard (or daylight) type has an offset different from the
1753 ** most recently used offset,
1754 ** append an (unused) copy of the most recently used type
1755 ** (to help get global "altzone" and "timezone" variables
1756 ** set correctly).
1759 register int mrudst, mrustd, hidst, histd, type;
1761 hidst = histd = mrudst = mrustd = -1;
1762 for (i = thistimei; i < thistimelim; ++i)
1763 if (isdsts[types[i]])
1764 mrudst = types[i];
1765 else mrustd = types[i];
1766 for (i = 0; i < typecnt; ++i)
1767 if (writetype[i]) {
1768 if (isdsts[i])
1769 hidst = i;
1770 else histd = i;
1772 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1773 gmtoffs[hidst] != gmtoffs[mrudst]) {
1774 isdsts[mrudst] = -1;
1775 type = addtype(gmtoffs[mrudst],
1776 &chars[abbrinds[mrudst]],
1777 true,
1778 ttisstds[mrudst],
1779 ttisgmts[mrudst]);
1780 isdsts[mrudst] = 1;
1781 writetype[type] = true;
1783 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1784 gmtoffs[histd] != gmtoffs[mrustd]) {
1785 isdsts[mrustd] = -1;
1786 type = addtype(gmtoffs[mrustd],
1787 &chars[abbrinds[mrustd]],
1788 false,
1789 ttisstds[mrustd],
1790 ttisgmts[mrustd]);
1791 isdsts[mrustd] = 0;
1792 writetype[type] = true;
1795 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1796 thistypecnt = 0;
1797 for (i = 0; i < typecnt; ++i)
1798 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1799 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1800 indmap[i] = -1;
1801 thischarcnt = 0;
1802 for (i = 0; i < typecnt; ++i) {
1803 register char * thisabbr;
1805 if (!writetype[i])
1806 continue;
1807 if (indmap[abbrinds[i]] >= 0)
1808 continue;
1809 thisabbr = &chars[abbrinds[i]];
1810 for (j = 0; j < thischarcnt; ++j)
1811 if (strcmp(&thischars[j], thisabbr) == 0)
1812 break;
1813 if (j == thischarcnt) {
1814 strcpy(&thischars[(int) thischarcnt],
1815 thisabbr);
1816 thischarcnt += strlen(thisabbr) + 1;
1818 indmap[abbrinds[i]] = j;
1820 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1821 tzh = tzh0;
1822 strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1823 tzh.tzh_version[0] = version;
1824 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1825 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1826 convert(thisleapcnt, tzh.tzh_leapcnt);
1827 convert(thistimecnt, tzh.tzh_timecnt);
1828 convert(thistypecnt, tzh.tzh_typecnt);
1829 convert(thischarcnt, tzh.tzh_charcnt);
1830 DO(tzh_magic);
1831 DO(tzh_version);
1832 DO(tzh_reserved);
1833 DO(tzh_ttisgmtcnt);
1834 DO(tzh_ttisstdcnt);
1835 DO(tzh_leapcnt);
1836 DO(tzh_timecnt);
1837 DO(tzh_typecnt);
1838 DO(tzh_charcnt);
1839 #undef DO
1840 for (i = thistimei; i < thistimelim; ++i)
1841 if (pass == 1)
1843 ** Output an INT32_MIN "transition"
1844 ** if appropriate; see above.
1846 puttzcode(((ats[i] < INT32_MIN) ?
1847 INT32_MIN : ats[i]), fp);
1848 else puttzcode64(ats[i], fp);
1849 for (i = thistimei; i < thistimelim; ++i) {
1850 unsigned char uc;
1852 uc = typemap[types[i]];
1853 fwrite(&uc, sizeof uc, 1, fp);
1855 for (i = 0; i < typecnt; ++i)
1856 if (writetype[i]) {
1857 puttzcode(gmtoffs[i], fp);
1858 putc(isdsts[i], fp);
1859 putc((unsigned char) indmap[abbrinds[i]], fp);
1861 if (thischarcnt != 0)
1862 fwrite(thischars, sizeof thischars[0],
1863 thischarcnt, fp);
1864 for (i = thisleapi; i < thisleaplim; ++i) {
1865 register zic_t todo;
1867 if (roll[i]) {
1868 if (timecnt == 0 || trans[i] < ats[0]) {
1869 j = 0;
1870 while (isdsts[j])
1871 if (++j >= typecnt) {
1872 j = 0;
1873 break;
1875 } else {
1876 j = 1;
1877 while (j < timecnt &&
1878 trans[i] >= ats[j])
1879 ++j;
1880 j = types[j - 1];
1882 todo = tadd(trans[i], -gmtoffs[j]);
1883 } else todo = trans[i];
1884 if (pass == 1)
1885 puttzcode(todo, fp);
1886 else puttzcode64(todo, fp);
1887 puttzcode(corr[i], fp);
1889 for (i = 0; i < typecnt; ++i)
1890 if (writetype[i])
1891 putc(ttisstds[i], fp);
1892 for (i = 0; i < typecnt; ++i)
1893 if (writetype[i])
1894 putc(ttisgmts[i], fp);
1896 fprintf(fp, "\n%s\n", string);
1897 close_file(fp, fullname);
1898 free(ats);
1899 free(fullname);
1902 static char const *
1903 abbroffset(char *buf, zic_t offset)
1905 char sign = '+';
1906 int seconds, minutes;
1908 if (offset < 0) {
1909 offset = -offset;
1910 sign = '-';
1913 seconds = offset % SECSPERMIN;
1914 offset /= SECSPERMIN;
1915 minutes = offset % MINSPERHOUR;
1916 offset /= MINSPERHOUR;
1917 if (100 <= offset) {
1918 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
1919 return "%z";
1920 } else {
1921 char *p = buf;
1922 *p++ = sign;
1923 *p++ = '0' + offset / 10;
1924 *p++ = '0' + offset % 10;
1925 if (minutes | seconds) {
1926 *p++ = '0' + minutes / 10;
1927 *p++ = '0' + minutes % 10;
1928 if (seconds) {
1929 *p++ = '0' + seconds / 10;
1930 *p++ = '0' + seconds % 10;
1933 *p = '\0';
1934 return buf;
1938 static size_t
1939 doabbr(char *abbr, struct zone const *zp, char const *letters,
1940 zic_t stdoff, bool doquotes)
1942 register char * cp;
1943 register char * slashp;
1944 register size_t len;
1945 char const *format = zp->z_format;
1947 slashp = strchr(format, '/');
1948 if (slashp == NULL) {
1949 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
1950 if (zp->z_format_specifier == 'z')
1951 letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
1952 else if (!letters)
1953 letters = "%s";
1954 sprintf(abbr, format, letters);
1955 } else if (stdoff != 0) {
1956 strcpy(abbr, slashp + 1);
1957 } else {
1958 memcpy(abbr, format, slashp - format);
1959 abbr[slashp - format] = '\0';
1961 len = strlen(abbr);
1962 if (!doquotes)
1963 return len;
1964 for (cp = abbr; is_alpha(*cp); cp++)
1965 continue;
1966 if (len > 0 && *cp == '\0')
1967 return len;
1968 abbr[len + 2] = '\0';
1969 abbr[len + 1] = '>';
1970 memmove(abbr + 1, abbr, len);
1971 abbr[0] = '<';
1972 return len + 2;
1975 static void
1976 updateminmax(const zic_t x)
1978 if (min_year > x)
1979 min_year = x;
1980 if (max_year < x)
1981 max_year = x;
1984 static int
1985 stringoffset(char *result, zic_t offset)
1987 register int hours;
1988 register int minutes;
1989 register int seconds;
1990 bool negative = offset < 0;
1991 int len = negative;
1993 if (negative) {
1994 offset = -offset;
1995 result[0] = '-';
1997 seconds = offset % SECSPERMIN;
1998 offset /= SECSPERMIN;
1999 minutes = offset % MINSPERHOUR;
2000 offset /= MINSPERHOUR;
2001 hours = offset;
2002 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2003 result[0] = '\0';
2004 return 0;
2006 len += sprintf(result + len, "%d", hours);
2007 if (minutes != 0 || seconds != 0) {
2008 len += sprintf(result + len, ":%02d", minutes);
2009 if (seconds != 0)
2010 len += sprintf(result + len, ":%02d", seconds);
2012 return len;
2015 static int
2016 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2017 const zic_t gmtoff)
2019 register zic_t tod = rp->r_tod;
2020 register int compat = 0;
2022 if (rp->r_dycode == DC_DOM) {
2023 register int month, total;
2025 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2026 return -1;
2027 total = 0;
2028 for (month = 0; month < rp->r_month; ++month)
2029 total += len_months[0][month];
2030 /* Omit the "J" in Jan and Feb, as that's shorter. */
2031 if (rp->r_month <= 1)
2032 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2033 else
2034 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2035 } else {
2036 register int week;
2037 register int wday = rp->r_wday;
2038 register int wdayoff;
2040 if (rp->r_dycode == DC_DOWGEQ) {
2041 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2042 if (wdayoff)
2043 compat = 2013;
2044 wday -= wdayoff;
2045 tod += wdayoff * SECSPERDAY;
2046 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2047 } else if (rp->r_dycode == DC_DOWLEQ) {
2048 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2049 week = 5;
2050 else {
2051 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2052 if (wdayoff)
2053 compat = 2013;
2054 wday -= wdayoff;
2055 tod += wdayoff * SECSPERDAY;
2056 week = rp->r_dayofmonth / DAYSPERWEEK;
2058 } else return -1; /* "cannot happen" */
2059 if (wday < 0)
2060 wday += DAYSPERWEEK;
2061 result += sprintf(result, "M%d.%d.%d",
2062 rp->r_month + 1, week, wday);
2064 if (rp->r_todisgmt)
2065 tod += gmtoff;
2066 if (rp->r_todisstd && rp->r_stdoff == 0)
2067 tod += dstoff;
2068 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2069 *result++ = '/';
2070 if (! stringoffset(result, tod))
2071 return -1;
2072 if (tod < 0) {
2073 if (compat < 2013)
2074 compat = 2013;
2075 } else if (SECSPERDAY <= tod) {
2076 if (compat < 1994)
2077 compat = 1994;
2080 return compat;
2083 static int
2084 rule_cmp(struct rule const *a, struct rule const *b)
2086 if (!a)
2087 return -!!b;
2088 if (!b)
2089 return 1;
2090 if (a->r_hiyear != b->r_hiyear)
2091 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2092 if (a->r_month - b->r_month != 0)
2093 return a->r_month - b->r_month;
2094 return a->r_dayofmonth - b->r_dayofmonth;
2097 enum { YEAR_BY_YEAR_ZONE = 1 };
2099 static int
2100 stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
2102 register const struct zone * zp;
2103 register struct rule * rp;
2104 register struct rule * stdrp;
2105 register struct rule * dstrp;
2106 register int i;
2107 register const char * abbrvar;
2108 register int compat = 0;
2109 register int c;
2110 size_t len;
2111 int offsetlen;
2112 struct rule stdr, dstr;
2114 result[0] = '\0';
2115 zp = zpfirst + zonecount - 1;
2116 stdrp = dstrp = NULL;
2117 for (i = 0; i < zp->z_nrules; ++i) {
2118 rp = &zp->z_rules[i];
2119 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2120 continue;
2121 if (rp->r_yrtype != NULL)
2122 continue;
2123 if (rp->r_stdoff == 0) {
2124 if (stdrp == NULL)
2125 stdrp = rp;
2126 else return -1;
2127 } else {
2128 if (dstrp == NULL)
2129 dstrp = rp;
2130 else return -1;
2133 if (stdrp == NULL && dstrp == NULL) {
2135 ** There are no rules running through "max".
2136 ** Find the latest std rule in stdabbrrp
2137 ** and latest rule of any type in stdrp.
2139 register struct rule *stdabbrrp = NULL;
2140 for (i = 0; i < zp->z_nrules; ++i) {
2141 rp = &zp->z_rules[i];
2142 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2143 stdabbrrp = rp;
2144 if (rule_cmp(stdrp, rp) < 0)
2145 stdrp = rp;
2148 ** Horrid special case: if year is 2037,
2149 ** presume this is a zone handled on a year-by-year basis;
2150 ** do not try to apply a rule to the zone.
2152 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2153 return YEAR_BY_YEAR_ZONE;
2155 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2156 /* Perpetual DST. */
2157 dstr.r_month = TM_JANUARY;
2158 dstr.r_dycode = DC_DOM;
2159 dstr.r_dayofmonth = 1;
2160 dstr.r_tod = 0;
2161 dstr.r_todisstd = dstr.r_todisgmt = false;
2162 dstr.r_stdoff = stdrp->r_stdoff;
2163 dstr.r_abbrvar = stdrp->r_abbrvar;
2164 stdr.r_month = TM_DECEMBER;
2165 stdr.r_dycode = DC_DOM;
2166 stdr.r_dayofmonth = 31;
2167 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2168 stdr.r_todisstd = stdr.r_todisgmt = false;
2169 stdr.r_stdoff = 0;
2170 stdr.r_abbrvar
2171 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2172 dstrp = &dstr;
2173 stdrp = &stdr;
2176 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2177 return -1;
2178 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2179 len = doabbr(result, zp, abbrvar, 0, true);
2180 offsetlen = stringoffset(result + len, -zp->z_gmtoff);
2181 if (! offsetlen) {
2182 result[0] = '\0';
2183 return -1;
2185 len += offsetlen;
2186 if (dstrp == NULL)
2187 return compat;
2188 len += doabbr(result + len, zp, dstrp->r_abbrvar, dstrp->r_stdoff, true);
2189 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
2190 offsetlen = stringoffset(result + len,
2191 -(zp->z_gmtoff + dstrp->r_stdoff));
2192 if (! offsetlen) {
2193 result[0] = '\0';
2194 return -1;
2196 len += offsetlen;
2198 result[len++] = ',';
2199 c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2200 if (c < 0) {
2201 result[0] = '\0';
2202 return -1;
2204 if (compat < c)
2205 compat = c;
2206 len += strlen(result + len);
2207 result[len++] = ',';
2208 c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2209 if (c < 0) {
2210 result[0] = '\0';
2211 return -1;
2213 if (compat < c)
2214 compat = c;
2215 return compat;
2218 static void
2219 outzone(const struct zone *zpfirst, int zonecount)
2221 register const struct zone * zp;
2222 register struct rule * rp;
2223 register int i, j;
2224 register bool usestart, useuntil;
2225 register zic_t starttime, untiltime;
2226 register zic_t gmtoff;
2227 register zic_t stdoff;
2228 register zic_t year;
2229 register zic_t startoff;
2230 register bool startttisstd;
2231 register bool startttisgmt;
2232 register int type;
2233 register char * startbuf;
2234 register char * ab;
2235 register char * envvar;
2236 register int max_abbr_len;
2237 register int max_envvar_len;
2238 register bool prodstic; /* all rules are min to max */
2239 register int compat;
2240 register bool do_extend;
2241 register char version;
2243 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2244 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2245 startbuf = emalloc(max_abbr_len + 1);
2246 ab = emalloc(max_abbr_len + 1);
2247 envvar = emalloc(max_envvar_len + 1);
2248 INITIALIZE(untiltime);
2249 INITIALIZE(starttime);
2251 ** Now. . .finally. . .generate some useful data!
2253 timecnt = 0;
2254 typecnt = 0;
2255 charcnt = 0;
2256 prodstic = zonecount == 1;
2258 ** Thanks to Earl Chew
2259 ** for noting the need to unconditionally initialize startttisstd.
2261 startttisstd = false;
2262 startttisgmt = false;
2263 min_year = max_year = EPOCH_YEAR;
2264 if (leapseen) {
2265 updateminmax(leapminyear);
2266 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2268 for (i = 0; i < zonecount; ++i) {
2269 zp = &zpfirst[i];
2270 if (i < zonecount - 1)
2271 updateminmax(zp->z_untilrule.r_loyear);
2272 for (j = 0; j < zp->z_nrules; ++j) {
2273 rp = &zp->z_rules[j];
2274 if (rp->r_lowasnum)
2275 updateminmax(rp->r_loyear);
2276 if (rp->r_hiwasnum)
2277 updateminmax(rp->r_hiyear);
2278 if (rp->r_lowasnum || rp->r_hiwasnum)
2279 prodstic = false;
2283 ** Generate lots of data if a rule can't cover all future times.
2285 compat = stringzone(envvar, zpfirst, zonecount);
2286 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2287 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2288 if (noise) {
2289 if (!*envvar)
2290 warning("%s %s",
2291 _("no POSIX environment variable for zone"),
2292 zpfirst->z_name);
2293 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2294 /* Circa-COMPAT clients, and earlier clients, might
2295 not work for this zone when given dates before
2296 1970 or after 2038. */
2297 warning(_("%s: pre-%d clients may mishandle"
2298 " distant timestamps"),
2299 zpfirst->z_name, compat);
2302 if (do_extend) {
2304 ** Search through a couple of extra years past the obvious
2305 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2306 ** rule applies from 2012 onwards and has transitions in March
2307 ** and September, plus some one-off transitions in November
2308 ** 2013. If zic looked only at the last 400 years, it would
2309 ** set max_year=2413, with the intent that the 400 years 2014
2310 ** through 2413 will be repeated. The last transition listed
2311 ** in the tzfile would be in 2413-09, less than 400 years
2312 ** after the last one-off transition in 2013-11. Two years
2313 ** might be overkill, but with the kind of edge cases
2314 ** available we're not sure that one year would suffice.
2316 enum { years_of_observations = YEARSPERREPEAT + 2 };
2318 if (min_year >= ZIC_MIN + years_of_observations)
2319 min_year -= years_of_observations;
2320 else min_year = ZIC_MIN;
2321 if (max_year <= ZIC_MAX - years_of_observations)
2322 max_year += years_of_observations;
2323 else max_year = ZIC_MAX;
2325 ** Regardless of any of the above,
2326 ** for a "proDSTic" zone which specifies that its rules
2327 ** always have and always will be in effect,
2328 ** we only need one cycle to define the zone.
2330 if (prodstic) {
2331 min_year = 1900;
2332 max_year = min_year + years_of_observations;
2336 ** For the benefit of older systems,
2337 ** generate data from 1900 through 2037.
2339 if (min_year > 1900)
2340 min_year = 1900;
2341 if (max_year < 2037)
2342 max_year = 2037;
2343 for (i = 0; i < zonecount; ++i) {
2345 ** A guess that may well be corrected later.
2347 stdoff = 0;
2348 zp = &zpfirst[i];
2349 usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time;
2350 useuntil = i < (zonecount - 1);
2351 if (useuntil && zp->z_untiltime <= big_bang_time)
2352 continue;
2353 gmtoff = zp->z_gmtoff;
2354 eat(zp->z_filename, zp->z_linenum);
2355 *startbuf = '\0';
2356 startoff = zp->z_gmtoff;
2357 if (zp->z_nrules == 0) {
2358 stdoff = zp->z_stdoff;
2359 doabbr(startbuf, zp, NULL, stdoff, false);
2360 type = addtype(oadd(zp->z_gmtoff, stdoff),
2361 startbuf, stdoff != 0, startttisstd,
2362 startttisgmt);
2363 if (usestart) {
2364 addtt(starttime, type);
2365 usestart = false;
2366 } else addtt(big_bang_time, type);
2367 } else for (year = min_year; year <= max_year; ++year) {
2368 if (useuntil && year > zp->z_untilrule.r_hiyear)
2369 break;
2371 ** Mark which rules to do in the current year.
2372 ** For those to do, calculate rpytime(rp, year);
2374 for (j = 0; j < zp->z_nrules; ++j) {
2375 rp = &zp->z_rules[j];
2376 eats(zp->z_filename, zp->z_linenum,
2377 rp->r_filename, rp->r_linenum);
2378 rp->r_todo = year >= rp->r_loyear &&
2379 year <= rp->r_hiyear &&
2380 yearistype(year, rp->r_yrtype);
2381 if (rp->r_todo)
2382 rp->r_temp = rpytime(rp, year);
2384 for ( ; ; ) {
2385 register int k;
2386 register zic_t jtime, ktime;
2387 register zic_t offset;
2389 INITIALIZE(ktime);
2390 if (useuntil) {
2392 ** Turn untiltime into UT
2393 ** assuming the current gmtoff and
2394 ** stdoff values.
2396 untiltime = zp->z_untiltime;
2397 if (!zp->z_untilrule.r_todisgmt)
2398 untiltime = tadd(untiltime,
2399 -gmtoff);
2400 if (!zp->z_untilrule.r_todisstd)
2401 untiltime = tadd(untiltime,
2402 -stdoff);
2405 ** Find the rule (of those to do, if any)
2406 ** that takes effect earliest in the year.
2408 k = -1;
2409 for (j = 0; j < zp->z_nrules; ++j) {
2410 rp = &zp->z_rules[j];
2411 if (!rp->r_todo)
2412 continue;
2413 eats(zp->z_filename, zp->z_linenum,
2414 rp->r_filename, rp->r_linenum);
2415 offset = rp->r_todisgmt ? 0 : gmtoff;
2416 if (!rp->r_todisstd)
2417 offset = oadd(offset, stdoff);
2418 jtime = rp->r_temp;
2419 if (jtime == min_time ||
2420 jtime == max_time)
2421 continue;
2422 jtime = tadd(jtime, -offset);
2423 if (k < 0 || jtime < ktime) {
2424 k = j;
2425 ktime = jtime;
2426 } else if (jtime == ktime) {
2427 char const *dup_rules_msg =
2428 _("two rules for same instant");
2429 eats(zp->z_filename, zp->z_linenum,
2430 rp->r_filename, rp->r_linenum);
2431 warning("%s", dup_rules_msg);
2432 rp = &zp->z_rules[k];
2433 eats(zp->z_filename, zp->z_linenum,
2434 rp->r_filename, rp->r_linenum);
2435 error("%s", dup_rules_msg);
2438 if (k < 0)
2439 break; /* go on to next year */
2440 rp = &zp->z_rules[k];
2441 rp->r_todo = false;
2442 if (useuntil && ktime >= untiltime)
2443 break;
2444 stdoff = rp->r_stdoff;
2445 if (usestart && ktime == starttime)
2446 usestart = false;
2447 if (usestart) {
2448 if (ktime < starttime) {
2449 startoff = oadd(zp->z_gmtoff,
2450 stdoff);
2451 doabbr(startbuf, zp,
2452 rp->r_abbrvar,
2453 rp->r_stdoff,
2454 false);
2455 continue;
2457 if (*startbuf == '\0' &&
2458 startoff == oadd(zp->z_gmtoff,
2459 stdoff)) {
2460 doabbr(startbuf,
2462 rp->r_abbrvar,
2463 rp->r_stdoff,
2464 false);
2467 eats(zp->z_filename, zp->z_linenum,
2468 rp->r_filename, rp->r_linenum);
2469 doabbr(ab, zp, rp->r_abbrvar,
2470 rp->r_stdoff, false);
2471 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2472 type = addtype(offset, ab, rp->r_stdoff != 0,
2473 rp->r_todisstd, rp->r_todisgmt);
2474 addtt(ktime, type);
2477 if (usestart) {
2478 if (*startbuf == '\0' &&
2479 zp->z_format != NULL &&
2480 strchr(zp->z_format, '%') == NULL &&
2481 strchr(zp->z_format, '/') == NULL)
2482 strcpy(startbuf, zp->z_format);
2483 eat(zp->z_filename, zp->z_linenum);
2484 if (*startbuf == '\0')
2485 error(_("can't determine time zone abbreviation to use just after until time"));
2486 else addtt(starttime,
2487 addtype(startoff, startbuf,
2488 startoff != zp->z_gmtoff,
2489 startttisstd,
2490 startttisgmt));
2493 ** Now we may get to set starttime for the next zone line.
2495 if (useuntil) {
2496 startttisstd = zp->z_untilrule.r_todisstd;
2497 startttisgmt = zp->z_untilrule.r_todisgmt;
2498 starttime = zp->z_untiltime;
2499 if (!startttisstd)
2500 starttime = tadd(starttime, -stdoff);
2501 if (!startttisgmt)
2502 starttime = tadd(starttime, -gmtoff);
2505 if (do_extend) {
2507 ** If we're extending the explicitly listed observations
2508 ** for 400 years because we can't fill the POSIX-TZ field,
2509 ** check whether we actually ended up explicitly listing
2510 ** observations through that period. If there aren't any
2511 ** near the end of the 400-year period, add a redundant
2512 ** one at the end of the final year, to make it clear
2513 ** that we are claiming to have definite knowledge of
2514 ** the lack of transitions up to that point.
2516 struct rule xr;
2517 struct attype *lastat;
2518 xr.r_month = TM_JANUARY;
2519 xr.r_dycode = DC_DOM;
2520 xr.r_dayofmonth = 1;
2521 xr.r_tod = 0;
2522 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2523 if (attypes[i].at > lastat->at)
2524 lastat = &attypes[i];
2525 if (lastat->at < rpytime(&xr, max_year - 1)) {
2527 ** Create new type code for the redundant entry,
2528 ** to prevent it being optimized away.
2530 if (typecnt >= TZ_MAX_TYPES) {
2531 error(_("too many local time types"));
2532 exit(EXIT_FAILURE);
2534 gmtoffs[typecnt] = gmtoffs[lastat->type];
2535 isdsts[typecnt] = isdsts[lastat->type];
2536 ttisstds[typecnt] = ttisstds[lastat->type];
2537 ttisgmts[typecnt] = ttisgmts[lastat->type];
2538 abbrinds[typecnt] = abbrinds[lastat->type];
2539 ++typecnt;
2540 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2543 writezone(zpfirst->z_name, envvar, version);
2544 free(startbuf);
2545 free(ab);
2546 free(envvar);
2549 static void
2550 addtt(zic_t starttime, int type)
2552 if (starttime <= big_bang_time ||
2553 (timecnt == 1 && attypes[0].at < big_bang_time)) {
2554 gmtoffs[0] = gmtoffs[type];
2555 isdsts[0] = isdsts[type];
2556 ttisstds[0] = ttisstds[type];
2557 ttisgmts[0] = ttisgmts[type];
2558 if (abbrinds[type] != 0)
2559 strcpy(chars, &chars[abbrinds[type]]);
2560 abbrinds[0] = 0;
2561 charcnt = strlen(chars) + 1;
2562 typecnt = 1;
2563 timecnt = 0;
2564 type = 0;
2566 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2567 attypes[timecnt].at = starttime;
2568 attypes[timecnt].type = type;
2569 ++timecnt;
2572 static int
2573 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
2575 register int i, j;
2578 ** See if there's already an entry for this zone type.
2579 ** If so, just return its index.
2581 for (i = 0; i < typecnt; ++i) {
2582 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2583 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2584 ttisstd == ttisstds[i] &&
2585 ttisgmt == ttisgmts[i])
2586 return i;
2589 ** There isn't one; add a new one, unless there are already too
2590 ** many.
2592 if (typecnt >= TZ_MAX_TYPES) {
2593 error(_("too many local time types"));
2594 exit(EXIT_FAILURE);
2596 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2597 error(_("UT offset out of range"));
2598 exit(EXIT_FAILURE);
2600 gmtoffs[i] = gmtoff;
2601 isdsts[i] = isdst;
2602 ttisstds[i] = ttisstd;
2603 ttisgmts[i] = ttisgmt;
2605 for (j = 0; j < charcnt; ++j)
2606 if (strcmp(&chars[j], abbr) == 0)
2607 break;
2608 if (j == charcnt)
2609 newabbr(abbr);
2610 abbrinds[i] = j;
2611 ++typecnt;
2612 return i;
2615 static void
2616 leapadd(zic_t t, bool positive, int rolling, int count)
2618 register int i, j;
2620 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2621 error(_("too many leap seconds"));
2622 exit(EXIT_FAILURE);
2624 for (i = 0; i < leapcnt; ++i)
2625 if (t <= trans[i]) {
2626 if (t == trans[i]) {
2627 error(_("repeated leap second moment"));
2628 exit(EXIT_FAILURE);
2630 break;
2632 do {
2633 for (j = leapcnt; j > i; --j) {
2634 trans[j] = trans[j - 1];
2635 corr[j] = corr[j - 1];
2636 roll[j] = roll[j - 1];
2638 trans[i] = t;
2639 corr[i] = positive ? 1 : -count;
2640 roll[i] = rolling;
2641 ++leapcnt;
2642 } while (positive && --count != 0);
2645 static void
2646 adjleap(void)
2648 register int i;
2649 register zic_t last = 0;
2652 ** propagate leap seconds forward
2654 for (i = 0; i < leapcnt; ++i) {
2655 trans[i] = tadd(trans[i], last);
2656 last = corr[i] += last;
2660 static bool
2661 yearistype(int year, const char *type)
2663 static char * buf;
2664 int result;
2666 if (type == NULL || *type == '\0')
2667 return true;
2668 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
2669 sprintf(buf, "%s %d %s", yitcommand, year, type);
2670 result = system(buf);
2671 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2672 case 0:
2673 return true;
2674 case 1:
2675 return false;
2677 error(_("Wild result from command execution"));
2678 fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2679 progname, buf, result);
2680 for ( ; ; )
2681 exit(EXIT_FAILURE);
2684 /* Is A a space character in the C locale? */
2685 static bool
2686 is_space(char a)
2688 switch (a) {
2689 default:
2690 return false;
2691 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2692 return true;
2696 /* Is A an alphabetic character in the C locale? */
2697 static bool
2698 is_alpha(char a)
2700 switch (a) {
2701 default:
2702 return false;
2703 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2704 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2705 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2706 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2707 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2708 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2709 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2710 case 'v': case 'w': case 'x': case 'y': case 'z':
2711 return true;
2715 /* If A is an uppercase character in the C locale, return its lowercase
2716 counterpart. Otherwise, return A. */
2717 static char
2718 lowerit(char a)
2720 switch (a) {
2721 default: return a;
2722 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2723 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2724 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2725 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2726 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2727 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2728 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2729 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2730 case 'Y': return 'y'; case 'Z': return 'z';
2734 /* case-insensitive equality */
2735 static ATTRIBUTE_PURE bool
2736 ciequal(register const char *ap, register const char *bp)
2738 while (lowerit(*ap) == lowerit(*bp++))
2739 if (*ap++ == '\0')
2740 return true;
2741 return false;
2744 static ATTRIBUTE_PURE bool
2745 itsabbr(register const char *abbr, register const char *word)
2747 if (lowerit(*abbr) != lowerit(*word))
2748 return false;
2749 ++word;
2750 while (*++abbr != '\0')
2751 do {
2752 if (*word == '\0')
2753 return false;
2754 } while (lowerit(*word++) != lowerit(*abbr));
2755 return true;
2758 static ATTRIBUTE_PURE const struct lookup *
2759 byword(const char *word, const struct lookup *table)
2761 register const struct lookup * foundlp;
2762 register const struct lookup * lp;
2764 if (word == NULL || table == NULL)
2765 return NULL;
2767 ** Look for exact match.
2769 for (lp = table; lp->l_word != NULL; ++lp)
2770 if (ciequal(word, lp->l_word))
2771 return lp;
2773 ** Look for inexact match.
2775 foundlp = NULL;
2776 for (lp = table; lp->l_word != NULL; ++lp)
2777 if (itsabbr(word, lp->l_word)) {
2778 if (foundlp == NULL)
2779 foundlp = lp;
2780 else return NULL; /* multiple inexact matches */
2782 return foundlp;
2785 static char **
2786 getfields(register char *cp)
2788 register char * dp;
2789 register char ** array;
2790 register int nsubs;
2792 if (cp == NULL)
2793 return NULL;
2794 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
2795 nsubs = 0;
2796 for ( ; ; ) {
2797 while (is_space(*cp))
2798 ++cp;
2799 if (*cp == '\0' || *cp == '#')
2800 break;
2801 array[nsubs++] = dp = cp;
2802 do {
2803 if ((*dp = *cp++) != '"')
2804 ++dp;
2805 else while ((*dp = *cp++) != '"')
2806 if (*dp != '\0')
2807 ++dp;
2808 else {
2809 error(_(
2810 "Odd number of quotation marks"
2812 exit(1);
2814 } while (*cp && *cp != '#' && !is_space(*cp));
2815 if (is_space(*cp))
2816 ++cp;
2817 *dp = '\0';
2819 array[nsubs] = NULL;
2820 return array;
2823 static _Noreturn void
2824 time_overflow(void)
2826 error(_("time overflow"));
2827 exit(EXIT_FAILURE);
2830 static ATTRIBUTE_PURE zic_t
2831 oadd(zic_t t1, zic_t t2)
2833 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
2834 time_overflow();
2835 return t1 + t2;
2838 static ATTRIBUTE_PURE zic_t
2839 tadd(zic_t t1, zic_t t2)
2841 if (t1 < 0) {
2842 if (t2 < min_time - t1) {
2843 if (t1 != min_time)
2844 time_overflow();
2845 return min_time;
2847 } else {
2848 if (max_time - t1 < t2) {
2849 if (t1 != max_time)
2850 time_overflow();
2851 return max_time;
2854 return t1 + t2;
2858 ** Given a rule, and a year, compute the date (in seconds since January 1,
2859 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
2862 static zic_t
2863 rpytime(const struct rule *rp, zic_t wantedy)
2865 register int m, i;
2866 register zic_t dayoff; /* with a nod to Margaret O. */
2867 register zic_t t, y;
2869 if (wantedy == ZIC_MIN)
2870 return min_time;
2871 if (wantedy == ZIC_MAX)
2872 return max_time;
2873 dayoff = 0;
2874 m = TM_JANUARY;
2875 y = EPOCH_YEAR;
2876 while (wantedy != y) {
2877 if (wantedy > y) {
2878 i = len_years[isleap(y)];
2879 ++y;
2880 } else {
2881 --y;
2882 i = -len_years[isleap(y)];
2884 dayoff = oadd(dayoff, i);
2886 while (m != rp->r_month) {
2887 i = len_months[isleap(y)][m];
2888 dayoff = oadd(dayoff, i);
2889 ++m;
2891 i = rp->r_dayofmonth;
2892 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2893 if (rp->r_dycode == DC_DOWLEQ)
2894 --i;
2895 else {
2896 error(_("use of 2/29 in non leap-year"));
2897 exit(EXIT_FAILURE);
2900 --i;
2901 dayoff = oadd(dayoff, i);
2902 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2903 register zic_t wday;
2905 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2906 wday = EPOCH_WDAY;
2908 ** Don't trust mod of negative numbers.
2910 if (dayoff >= 0)
2911 wday = (wday + dayoff) % LDAYSPERWEEK;
2912 else {
2913 wday -= ((-dayoff) % LDAYSPERWEEK);
2914 if (wday < 0)
2915 wday += LDAYSPERWEEK;
2917 while (wday != rp->r_wday)
2918 if (rp->r_dycode == DC_DOWGEQ) {
2919 dayoff = oadd(dayoff, 1);
2920 if (++wday >= LDAYSPERWEEK)
2921 wday = 0;
2922 ++i;
2923 } else {
2924 dayoff = oadd(dayoff, -1);
2925 if (--wday < 0)
2926 wday = LDAYSPERWEEK - 1;
2927 --i;
2929 if (i < 0 || i >= len_months[isleap(y)][m]) {
2930 if (noise)
2931 warning(_("rule goes past start/end of month; \
2932 will not work with pre-2004 versions of zic"));
2935 if (dayoff < min_time / SECSPERDAY)
2936 return min_time;
2937 if (dayoff > max_time / SECSPERDAY)
2938 return max_time;
2939 t = (zic_t) dayoff * SECSPERDAY;
2940 return tadd(t, rp->r_tod);
2943 static void
2944 newabbr(const char *string)
2946 register int i;
2948 if (strcmp(string, GRANDPARENTED) != 0) {
2949 register const char * cp;
2950 const char * mp;
2952 cp = string;
2953 mp = NULL;
2954 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
2955 || *cp == '-' || *cp == '+')
2956 ++cp;
2957 if (noise && cp - string < 3)
2958 mp = _("time zone abbreviation has fewer than 3 characters");
2959 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2960 mp = _("time zone abbreviation has too many characters");
2961 if (*cp != '\0')
2962 mp = _("time zone abbreviation differs from POSIX standard");
2963 if (mp != NULL)
2964 warning("%s (%s)", mp, string);
2966 i = strlen(string) + 1;
2967 if (charcnt + i > TZ_MAX_CHARS) {
2968 error(_("too many, or too long, time zone abbreviations"));
2969 exit(EXIT_FAILURE);
2971 strcpy(&chars[charcnt], string);
2972 charcnt += i;
2975 static bool
2976 mkdirs(char *argname)
2978 register char * name;
2979 register char * cp;
2981 if (argname == NULL || *argname == '\0')
2982 return true;
2983 cp = name = ecpyalloc(argname);
2984 while ((cp = strchr(cp + 1, '/')) != 0) {
2985 *cp = '\0';
2986 #ifdef HAVE_DOS_FILE_NAMES
2988 ** DOS drive specifier?
2990 if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0') {
2991 *cp = '/';
2992 continue;
2994 #endif
2996 ** Try to create it. It's OK if creation fails because
2997 ** the directory already exists, perhaps because some
2998 ** other process just created it.
3000 if (mkdir(name, MKDIR_UMASK) != 0) {
3001 int err = errno;
3002 if (itsdir(name) <= 0) {
3003 char const *e = strerror(err);
3004 warning(_("%s: Can't create directory"
3005 " %s: %s"),
3006 progname, name, e);
3007 free(name);
3008 return false;
3011 *cp = '/';
3013 free(name);
3014 return true;