Add --enable-static-pie configure option to build static PIE [BZ #19574]
[glibc.git] / timezone / zic.c
blobe738386600c2383f6abbe097648f8c89ca6d96b4
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 "tzfile.h"
10 #include <fcntl.h>
11 #include <locale.h>
12 #include <stdarg.h>
13 #include <stddef.h>
15 #define ZIC_VERSION_PRE_2013 '2'
16 #define ZIC_VERSION '3'
18 typedef int_fast64_t zic_t;
19 #define ZIC_MIN INT_FAST64_MIN
20 #define ZIC_MAX INT_FAST64_MAX
21 #define PRIdZIC PRIdFAST64
22 #define SCNdZIC SCNdFAST64
24 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
25 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
26 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
28 #ifdef HAVE_DIRECT_H
29 # include <direct.h>
30 # include <io.h>
31 # undef mkdir
32 # define mkdir(name, mode) _mkdir(name)
33 #endif
35 #if HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38 #ifdef S_IRUSR
39 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
40 #else
41 #define MKDIR_UMASK 0755
42 #endif
44 /* The maximum ptrdiff_t value, for pre-C99 platforms. */
45 #ifndef PTRDIFF_MAX
46 static ptrdiff_t const PTRDIFF_MAX = MAXVAL(ptrdiff_t, TYPE_BIT(ptrdiff_t));
47 #endif
49 /* The type for line numbers. Use PRIdMAX to format them; formerly
50 there was also "#define PRIdLINENO PRIdMAX" and formats used
51 PRIdLINENO, but xgettext cannot grok that. */
52 typedef intmax_t lineno;
54 struct rule {
55 const char * r_filename;
56 lineno r_linenum;
57 const char * r_name;
59 zic_t r_loyear; /* for example, 1986 */
60 zic_t r_hiyear; /* for example, 1986 */
61 const char * r_yrtype;
62 bool r_lowasnum;
63 bool r_hiwasnum;
65 int r_month; /* 0..11 */
67 int r_dycode; /* see below */
68 int r_dayofmonth;
69 int r_wday;
71 zic_t r_tod; /* time from midnight */
72 bool r_todisstd; /* above is standard time if 1 */
73 /* or wall clock time if 0 */
74 bool r_todisgmt; /* above is GMT if 1 */
75 /* or local time if 0 */
76 zic_t r_stdoff; /* offset from standard time */
77 const char * r_abbrvar; /* variable part of abbreviation */
79 bool r_todo; /* a rule to do (used in outzone) */
80 zic_t r_temp; /* used in outzone */
84 ** r_dycode r_dayofmonth r_wday
87 #define DC_DOM 0 /* 1..31 */ /* unused */
88 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
89 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
91 struct zone {
92 const char * z_filename;
93 lineno z_linenum;
95 const char * z_name;
96 zic_t z_gmtoff;
97 const char * z_rule;
98 const char * z_format;
99 char z_format_specifier;
101 zic_t z_stdoff;
103 struct rule * z_rules;
104 ptrdiff_t z_nrules;
106 struct rule z_untilrule;
107 zic_t z_untiltime;
110 #if !HAVE_POSIX_DECLS
111 extern int getopt(int argc, char * const argv[],
112 const char * options);
113 extern int link(const char * fromname, const char * toname);
114 extern char * optarg;
115 extern int optind;
116 #endif
118 #if ! HAVE_LINK
119 # define link(from, to) (errno = ENOTSUP, -1)
120 #endif
121 #if ! HAVE_SYMLINK
122 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
123 # define symlink(from, to) (errno = ENOTSUP, -1)
124 # define S_ISLNK(m) 0
125 #endif
126 #ifndef AT_SYMLINK_FOLLOW
127 # define linkat(fromdir, from, todir, to, flag) \
128 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
129 #endif
131 static void addtt(zic_t starttime, int type);
132 static int addtype(zic_t, char const *, bool, bool, bool);
133 static void leapadd(zic_t, bool, int, int);
134 static void adjleap(void);
135 static void associate(void);
136 static void dolink(const char *, const char *, bool);
137 static char ** getfields(char * buf);
138 static zic_t gethms(const char * string, const char * errstring,
139 bool);
140 static void infile(const char * filename);
141 static void inleap(char ** fields, int nfields);
142 static void inlink(char ** fields, int nfields);
143 static void inrule(char ** fields, int nfields);
144 static bool inzcont(char ** fields, int nfields);
145 static bool inzone(char ** fields, int nfields);
146 static bool inzsub(char **, int, bool);
147 static bool itsdir(char const *);
148 static bool itssymlink(char const *);
149 static bool is_alpha(char a);
150 static char lowerit(char);
151 static void mkdirs(char const *, bool);
152 static void newabbr(const char * abbr);
153 static zic_t oadd(zic_t t1, zic_t t2);
154 static void outzone(const struct zone * zp, ptrdiff_t ntzones);
155 static zic_t rpytime(const struct rule * rp, zic_t wantedy);
156 static void rulesub(struct rule * rp,
157 const char * loyearp, const char * hiyearp,
158 const char * typep, const char * monthp,
159 const char * dayp, const char * timep);
160 static zic_t tadd(zic_t t1, zic_t t2);
161 static bool yearistype(zic_t year, const char * type);
163 /* Bound on length of what %z can expand to. */
164 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
166 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
167 tz binary files whose POSIX-TZ-style strings contain '<'; see
168 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
169 workaround will no longer be needed when Qt 5.6.1 and earlier are
170 obsolete, say in the year 2021. */
171 enum { WORK_AROUND_QTBUG_53071 = true };
173 static int charcnt;
174 static bool errors;
175 static bool warnings;
176 static const char * filename;
177 static int leapcnt;
178 static bool leapseen;
179 static zic_t leapminyear;
180 static zic_t leapmaxyear;
181 static lineno linenum;
182 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
183 static int max_format_len;
184 static zic_t max_year;
185 static zic_t min_year;
186 static bool noise;
187 static const char * rfilename;
188 static lineno rlinenum;
189 static const char * progname;
190 static ptrdiff_t timecnt;
191 static ptrdiff_t timecnt_alloc;
192 static int typecnt;
195 ** Line codes.
198 #define LC_RULE 0
199 #define LC_ZONE 1
200 #define LC_LINK 2
201 #define LC_LEAP 3
204 ** Which fields are which on a Zone line.
207 #define ZF_NAME 1
208 #define ZF_GMTOFF 2
209 #define ZF_RULE 3
210 #define ZF_FORMAT 4
211 #define ZF_TILYEAR 5
212 #define ZF_TILMONTH 6
213 #define ZF_TILDAY 7
214 #define ZF_TILTIME 8
215 #define ZONE_MINFIELDS 5
216 #define ZONE_MAXFIELDS 9
219 ** Which fields are which on a Zone continuation line.
222 #define ZFC_GMTOFF 0
223 #define ZFC_RULE 1
224 #define ZFC_FORMAT 2
225 #define ZFC_TILYEAR 3
226 #define ZFC_TILMONTH 4
227 #define ZFC_TILDAY 5
228 #define ZFC_TILTIME 6
229 #define ZONEC_MINFIELDS 3
230 #define ZONEC_MAXFIELDS 7
233 ** Which files are which on a Rule line.
236 #define RF_NAME 1
237 #define RF_LOYEAR 2
238 #define RF_HIYEAR 3
239 #define RF_COMMAND 4
240 #define RF_MONTH 5
241 #define RF_DAY 6
242 #define RF_TOD 7
243 #define RF_STDOFF 8
244 #define RF_ABBRVAR 9
245 #define RULE_FIELDS 10
248 ** Which fields are which on a Link line.
251 #define LF_FROM 1
252 #define LF_TO 2
253 #define LINK_FIELDS 3
256 ** Which fields are which on a Leap line.
259 #define LP_YEAR 1
260 #define LP_MONTH 2
261 #define LP_DAY 3
262 #define LP_TIME 4
263 #define LP_CORR 5
264 #define LP_ROLL 6
265 #define LEAP_FIELDS 7
268 ** Year synonyms.
271 #define YR_MINIMUM 0
272 #define YR_MAXIMUM 1
273 #define YR_ONLY 2
275 static struct rule * rules;
276 static ptrdiff_t nrules; /* number of rules */
277 static ptrdiff_t nrules_alloc;
279 static struct zone * zones;
280 static ptrdiff_t nzones; /* number of zones */
281 static ptrdiff_t nzones_alloc;
283 struct link {
284 const char * l_filename;
285 lineno l_linenum;
286 const char * l_from;
287 const char * l_to;
290 static struct link * links;
291 static ptrdiff_t nlinks;
292 static ptrdiff_t nlinks_alloc;
294 struct lookup {
295 const char * l_word;
296 const int l_value;
299 static struct lookup const * byword(const char * string,
300 const struct lookup * lp);
302 static struct lookup const line_codes[] = {
303 { "Rule", LC_RULE },
304 { "Zone", LC_ZONE },
305 { "Link", LC_LINK },
306 { "Leap", LC_LEAP },
307 { NULL, 0}
310 static struct lookup const mon_names[] = {
311 { "January", TM_JANUARY },
312 { "February", TM_FEBRUARY },
313 { "March", TM_MARCH },
314 { "April", TM_APRIL },
315 { "May", TM_MAY },
316 { "June", TM_JUNE },
317 { "July", TM_JULY },
318 { "August", TM_AUGUST },
319 { "September", TM_SEPTEMBER },
320 { "October", TM_OCTOBER },
321 { "November", TM_NOVEMBER },
322 { "December", TM_DECEMBER },
323 { NULL, 0 }
326 static struct lookup const wday_names[] = {
327 { "Sunday", TM_SUNDAY },
328 { "Monday", TM_MONDAY },
329 { "Tuesday", TM_TUESDAY },
330 { "Wednesday", TM_WEDNESDAY },
331 { "Thursday", TM_THURSDAY },
332 { "Friday", TM_FRIDAY },
333 { "Saturday", TM_SATURDAY },
334 { NULL, 0 }
337 static struct lookup const lasts[] = {
338 { "last-Sunday", TM_SUNDAY },
339 { "last-Monday", TM_MONDAY },
340 { "last-Tuesday", TM_TUESDAY },
341 { "last-Wednesday", TM_WEDNESDAY },
342 { "last-Thursday", TM_THURSDAY },
343 { "last-Friday", TM_FRIDAY },
344 { "last-Saturday", TM_SATURDAY },
345 { NULL, 0 }
348 static struct lookup const begin_years[] = {
349 { "minimum", YR_MINIMUM },
350 { "maximum", YR_MAXIMUM },
351 { NULL, 0 }
354 static struct lookup const end_years[] = {
355 { "minimum", YR_MINIMUM },
356 { "maximum", YR_MAXIMUM },
357 { "only", YR_ONLY },
358 { NULL, 0 }
361 static struct lookup const leap_types[] = {
362 { "Rolling", true },
363 { "Stationary", false },
364 { NULL, 0 }
367 static const int len_months[2][MONSPERYEAR] = {
368 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
369 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
372 static const int len_years[2] = {
373 DAYSPERNYEAR, DAYSPERLYEAR
376 static struct attype {
377 zic_t at;
378 bool dontmerge;
379 unsigned char type;
380 } * attypes;
381 static zic_t gmtoffs[TZ_MAX_TYPES];
382 static char isdsts[TZ_MAX_TYPES];
383 static unsigned char abbrinds[TZ_MAX_TYPES];
384 static bool ttisstds[TZ_MAX_TYPES];
385 static bool ttisgmts[TZ_MAX_TYPES];
386 static char chars[TZ_MAX_CHARS];
387 static zic_t trans[TZ_MAX_LEAPS];
388 static zic_t corr[TZ_MAX_LEAPS];
389 static char roll[TZ_MAX_LEAPS];
392 ** Memory allocation.
395 static _Noreturn void
396 memory_exhausted(const char *msg)
398 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
399 exit(EXIT_FAILURE);
402 static ATTRIBUTE_PURE size_t
403 size_product(size_t nitems, size_t itemsize)
405 if (SIZE_MAX / itemsize < nitems)
406 memory_exhausted(_("size overflow"));
407 return nitems * itemsize;
410 #if !HAVE_STRDUP
411 static char *
412 strdup(char const *str)
414 char *result = malloc(strlen(str) + 1);
415 return result ? strcpy(result, str) : result;
417 #endif
419 static ATTRIBUTE_PURE void *
420 memcheck(void *ptr)
422 if (ptr == NULL)
423 memory_exhausted(strerror(errno));
424 return ptr;
427 static void *
428 emalloc(size_t size)
430 return memcheck(malloc(size));
433 static void *
434 erealloc(void *ptr, size_t size)
436 return memcheck(realloc(ptr, size));
439 static char *
440 ecpyalloc (char const *str)
442 return memcheck(strdup(str));
445 static void *
446 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
448 if (nitems < *nitems_alloc)
449 return ptr;
450 else {
451 ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
452 ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
453 if ((amax - 1) / 3 * 2 < *nitems_alloc)
454 memory_exhausted(_("integer overflow"));
455 *nitems_alloc += (*nitems_alloc >> 1) + 1;
456 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
461 ** Error handling.
464 static void
465 eats(char const *name, lineno num, char const *rname, lineno rnum)
467 filename = name;
468 linenum = num;
469 rfilename = rname;
470 rlinenum = rnum;
473 static void
474 eat(char const *name, lineno num)
476 eats(name, num, NULL, -1);
479 static void ATTRIBUTE_FORMAT((printf, 1, 0))
480 verror(const char *const string, va_list args)
483 ** Match the format of "cc" to allow sh users to
484 ** zic ... 2>&1 | error -t "*" -v
485 ** on BSD systems.
487 if (filename)
488 fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), filename, linenum);
489 vfprintf(stderr, string, args);
490 if (rfilename != NULL)
491 fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"),
492 rfilename, rlinenum);
493 fprintf(stderr, "\n");
496 static void ATTRIBUTE_FORMAT((printf, 1, 2))
497 error(const char *const string, ...)
499 va_list args;
500 va_start(args, string);
501 verror(string, args);
502 va_end(args);
503 errors = true;
506 static void ATTRIBUTE_FORMAT((printf, 1, 2))
507 warning(const char *const string, ...)
509 va_list args;
510 fprintf(stderr, _("warning: "));
511 va_start(args, string);
512 verror(string, args);
513 va_end(args);
514 warnings = true;
517 static void
518 close_file(FILE *stream, char const *dir, char const *name)
520 char const *e = (ferror(stream) ? _("I/O error")
521 : fclose(stream) != 0 ? strerror(errno) : NULL);
522 if (e) {
523 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
524 dir ? dir : "", dir ? "/" : "",
525 name ? name : "", name ? ": " : "",
527 exit(EXIT_FAILURE);
531 static _Noreturn void
532 usage(FILE *stream, int status)
534 fprintf(stream,
535 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
536 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
537 "\t[ -L leapseconds ] [ filename ... ]\n\n"
538 "Report bugs to %s.\n"),
539 progname, progname, REPORT_BUGS_TO);
540 if (status == EXIT_SUCCESS)
541 close_file(stream, NULL, NULL);
542 exit(status);
545 /* Change the working directory to DIR, possibly creating DIR and its
546 ancestors. After this is done, all files are accessed with names
547 relative to DIR. */
548 static void
549 change_directory (char const *dir)
551 if (chdir(dir) != 0) {
552 int chdir_errno = errno;
553 if (chdir_errno == ENOENT) {
554 mkdirs(dir, false);
555 chdir_errno = chdir(dir) == 0 ? 0 : errno;
557 if (chdir_errno != 0) {
558 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
559 progname, dir, strerror(chdir_errno));
560 exit(EXIT_FAILURE);
565 static const char * psxrules;
566 static const char * lcltime;
567 static const char * directory;
568 static const char * leapsec;
569 static const char * yitcommand;
572 main(int argc, char **argv)
574 register int c, k;
575 register ptrdiff_t i, j;
577 #ifdef S_IWGRP
578 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
579 #endif
580 #if HAVE_GETTEXT
581 setlocale(LC_ALL, "");
582 #ifdef TZ_DOMAINDIR
583 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
584 #endif /* defined TEXTDOMAINDIR */
585 textdomain(TZ_DOMAIN);
586 #endif /* HAVE_GETTEXT */
587 progname = argv[0];
588 if (TYPE_BIT(zic_t) < 64) {
589 fprintf(stderr, "%s: %s\n", progname,
590 _("wild compilation-time specification of zic_t"));
591 return EXIT_FAILURE;
593 for (k = 1; k < argc; k++)
594 if (strcmp(argv[k], "--version") == 0) {
595 printf("zic %s%s\n", PKGVERSION, TZVERSION);
596 close_file(stdout, NULL, NULL);
597 return EXIT_SUCCESS;
598 } else if (strcmp(argv[k], "--help") == 0) {
599 usage(stdout, EXIT_SUCCESS);
601 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
602 switch (c) {
603 default:
604 usage(stderr, EXIT_FAILURE);
605 case 'd':
606 if (directory == NULL)
607 directory = optarg;
608 else {
609 fprintf(stderr,
610 _("%s: More than one -d option specified\n"),
611 progname);
612 return EXIT_FAILURE;
614 break;
615 case 'l':
616 if (lcltime == NULL)
617 lcltime = optarg;
618 else {
619 fprintf(stderr,
620 _("%s: More than one -l option specified\n"),
621 progname);
622 return EXIT_FAILURE;
624 break;
625 case 'p':
626 if (psxrules == NULL)
627 psxrules = optarg;
628 else {
629 fprintf(stderr,
630 _("%s: More than one -p option specified\n"),
631 progname);
632 return EXIT_FAILURE;
634 break;
635 case 'y':
636 if (yitcommand == NULL)
637 yitcommand = optarg;
638 else {
639 fprintf(stderr,
640 _("%s: More than one -y option specified\n"),
641 progname);
642 return EXIT_FAILURE;
644 break;
645 case 'L':
646 if (leapsec == NULL)
647 leapsec = optarg;
648 else {
649 fprintf(stderr,
650 _("%s: More than one -L option specified\n"),
651 progname);
652 return EXIT_FAILURE;
654 break;
655 case 'v':
656 noise = true;
657 break;
658 case 's':
659 warning(_("-s ignored"));
660 break;
662 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
663 usage(stderr, EXIT_FAILURE); /* usage message by request */
664 if (directory == NULL)
665 directory = TZDIR;
666 if (yitcommand == NULL)
667 yitcommand = "yearistype";
669 if (optind < argc && leapsec != NULL) {
670 infile(leapsec);
671 adjleap();
674 for (k = optind; k < argc; k++)
675 infile(argv[k]);
676 if (errors)
677 return EXIT_FAILURE;
678 associate();
679 change_directory(directory);
680 for (i = 0; i < nzones; i = j) {
682 ** Find the next non-continuation zone entry.
684 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
685 continue;
686 outzone(&zones[i], j - i);
689 ** Make links.
691 for (i = 0; i < nlinks; ++i) {
692 eat(links[i].l_filename, links[i].l_linenum);
693 dolink(links[i].l_from, links[i].l_to, false);
694 if (noise)
695 for (j = 0; j < nlinks; ++j)
696 if (strcmp(links[i].l_to,
697 links[j].l_from) == 0)
698 warning(_("link to link"));
700 if (lcltime != NULL) {
701 eat(_("command line"), 1);
702 dolink(lcltime, TZDEFAULT, true);
704 if (psxrules != NULL) {
705 eat(_("command line"), 1);
706 dolink(psxrules, TZDEFRULES, true);
708 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
709 return EXIT_FAILURE;
710 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
713 static bool
714 componentcheck(char const *name, char const *component,
715 char const *component_end)
717 enum { component_len_max = 14 };
718 ptrdiff_t component_len = component_end - component;
719 if (component_len == 0) {
720 if (!*name)
721 error (_("empty file name"));
722 else
723 error (_(component == name
724 ? "file name '%s' begins with '/'"
725 : *component_end
726 ? "file name '%s' contains '//'"
727 : "file name '%s' ends with '/'"),
728 name);
729 return false;
731 if (0 < component_len && component_len <= 2
732 && component[0] == '.' && component_end[-1] == '.') {
733 int len = component_len;
734 error(_("file name '%s' contains '%.*s' component"),
735 name, len, component);
736 return false;
738 if (noise) {
739 if (0 < component_len && component[0] == '-')
740 warning(_("file name '%s' component contains leading '-'"),
741 name);
742 if (component_len_max < component_len)
743 warning(_("file name '%s' contains overlength component"
744 " '%.*s...'"),
745 name, component_len_max, component);
747 return true;
750 static bool
751 namecheck(const char *name)
753 register char const *cp;
755 /* Benign characters in a portable file name. */
756 static char const benign[] =
757 "-/_"
758 "abcdefghijklmnopqrstuvwxyz"
759 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
761 /* Non-control chars in the POSIX portable character set,
762 excluding the benign characters. */
763 static char const printable_and_not_benign[] =
764 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
766 register char const *component = name;
767 for (cp = name; *cp; cp++) {
768 unsigned char c = *cp;
769 if (noise && !strchr(benign, c)) {
770 warning((strchr(printable_and_not_benign, c)
771 ? _("file name '%s' contains byte '%c'")
772 : _("file name '%s' contains byte '\\%o'")),
773 name, c);
775 if (c == '/') {
776 if (!componentcheck(name, component, cp))
777 return false;
778 component = cp + 1;
781 return componentcheck(name, component, cp);
784 /* Create symlink contents suitable for symlinking FROM to TO, as a
785 freshly allocated string. FROM should be a relative file name, and
786 is relative to the global variable DIRECTORY. TO can be either
787 relative or absolute. */
788 static char *
789 relname(char const *from, char const *to)
791 size_t i, taillen, dotdotetcsize;
792 size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
793 char const *f = from;
794 char *result = NULL;
795 if (*to == '/') {
796 /* Make F absolute too. */
797 size_t len = strlen(directory);
798 bool needslash = len && directory[len - 1] != '/';
799 linksize = len + needslash + strlen(from) + 1;
800 f = result = emalloc(linksize);
801 strcpy(result, directory);
802 result[len] = '/';
803 strcpy(result + len + needslash, from);
805 for (i = 0; f[i] && f[i] == to[i]; i++)
806 if (f[i] == '/')
807 dir_len = i + 1;
808 for (; to[i]; i++)
809 dotdots += to[i] == '/' && to[i - 1] != '/';
810 taillen = strlen(f + dir_len);
811 dotdotetcsize = 3 * dotdots + taillen + 1;
812 if (dotdotetcsize <= linksize) {
813 if (!result)
814 result = emalloc(dotdotetcsize);
815 for (i = 0; i < dotdots; i++)
816 memcpy(result + 3 * i, "../", 3);
817 memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
819 return result;
822 /* Hard link FROM to TO, following any symbolic links.
823 Return 0 if successful, an error number otherwise. */
824 static int
825 hardlinkerr(char const *from, char const *to)
827 int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
828 return r == 0 ? 0 : errno;
831 static void
832 dolink(char const *fromfield, char const *tofield, bool staysymlink)
834 bool todirs_made = false;
835 int link_errno;
838 ** We get to be careful here since
839 ** there's a fair chance of root running us.
841 if (itsdir(fromfield)) {
842 fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
843 progname, directory, fromfield, strerror(EPERM));
844 exit(EXIT_FAILURE);
846 if (staysymlink)
847 staysymlink = itssymlink(tofield);
848 if (remove(tofield) == 0)
849 todirs_made = true;
850 else if (errno != ENOENT) {
851 char const *e = strerror(errno);
852 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
853 progname, directory, tofield, e);
854 exit(EXIT_FAILURE);
856 link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
857 if (link_errno == ENOENT && !todirs_made) {
858 mkdirs(tofield, true);
859 todirs_made = true;
860 link_errno = hardlinkerr(fromfield, tofield);
862 if (link_errno != 0) {
863 bool absolute = *fromfield == '/';
864 char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
865 char const *contents = absolute ? fromfield : linkalloc;
866 int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
867 if (symlink_errno == ENOENT && !todirs_made) {
868 mkdirs(tofield, true);
869 symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
871 free(linkalloc);
872 if (symlink_errno == 0) {
873 if (link_errno != ENOTSUP)
874 warning(_("symbolic link used because hard link failed: %s"),
875 strerror(link_errno));
876 } else {
877 FILE *fp, *tp;
878 int c;
879 fp = fopen(fromfield, "rb");
880 if (!fp) {
881 char const *e = strerror(errno);
882 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
883 progname, directory, fromfield, e);
884 exit(EXIT_FAILURE);
886 tp = fopen(tofield, "wb");
887 if (!tp) {
888 char const *e = strerror(errno);
889 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
890 progname, directory, tofield, e);
891 exit(EXIT_FAILURE);
893 while ((c = getc(fp)) != EOF)
894 putc(c, tp);
895 close_file(fp, directory, fromfield);
896 close_file(tp, directory, tofield);
897 if (link_errno != ENOTSUP)
898 warning(_("copy used because hard link failed: %s"),
899 strerror(link_errno));
900 else if (symlink_errno != ENOTSUP)
901 warning(_("copy used because symbolic link failed: %s"),
902 strerror(symlink_errno));
907 #define TIME_T_BITS_IN_FILE 64
909 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
910 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
912 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
913 rounded downward to the negation of a power of two that is
914 comfortably outside the error bounds.
916 For the time of the Big Bang, see:
918 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
919 I. Overview of products and scientific results.
920 arXiv:1303.5062 2013-03-20 20:10:01 UTC
921 <http://arxiv.org/pdf/1303.5062v1> [PDF]
923 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
924 gives the value 13.798 plus-or-minus 0.037 billion years.
925 Multiplying this by 1000000000 and then by 31557600 (the number of
926 seconds in an astronomical year) gives a value that is comfortably
927 less than 2**59, so BIG_BANG is - 2**59.
929 BIG_BANG is approximate, and may change in future versions.
930 Please do not rely on its exact value. */
932 #ifndef BIG_BANG
933 #define BIG_BANG (- (1LL << 59))
934 #endif
936 /* If true, work around GNOME bug 730332
937 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
938 by refusing to output time stamps before BIG_BANG.
939 Such time stamps are physically suspect anyway.
941 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
942 this workaround will no longer be needed when GNOME 3.21 and
943 earlier are obsolete, say in the year 2021. */
944 enum { WORK_AROUND_GNOME_BUG_730332 = true };
946 static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
947 ? BIG_BANG
948 : MINVAL(zic_t, TIME_T_BITS_IN_FILE));
950 /* Return true if NAME is a directory. */
951 static bool
952 itsdir(char const *name)
954 struct stat st;
955 int res = stat(name, &st);
956 #ifdef S_ISDIR
957 if (res == 0)
958 return S_ISDIR(st.st_mode) != 0;
959 #endif
960 if (res == 0 || errno == EOVERFLOW) {
961 size_t n = strlen(name);
962 char *nameslashdot = emalloc(n + 3);
963 bool dir;
964 memcpy(nameslashdot, name, n);
965 strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]);
966 dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
967 free(nameslashdot);
968 return dir;
970 return false;
973 /* Return true if NAME is a symbolic link. */
974 static bool
975 itssymlink(char const *name)
977 char c;
978 return 0 <= readlink(name, &c, 1);
982 ** Associate sets of rules with zones.
986 ** Sort by rule name.
989 static int
990 rcomp(const void *cp1, const void *cp2)
992 return strcmp(((const struct rule *) cp1)->r_name,
993 ((const struct rule *) cp2)->r_name);
996 static void
997 associate(void)
999 register struct zone * zp;
1000 register struct rule * rp;
1001 register ptrdiff_t i, j, base, out;
1003 if (nrules != 0) {
1004 qsort(rules, nrules, sizeof *rules, rcomp);
1005 for (i = 0; i < nrules - 1; ++i) {
1006 if (strcmp(rules[i].r_name,
1007 rules[i + 1].r_name) != 0)
1008 continue;
1009 if (strcmp(rules[i].r_filename,
1010 rules[i + 1].r_filename) == 0)
1011 continue;
1012 eat(rules[i].r_filename, rules[i].r_linenum);
1013 warning(_("same rule name in multiple files"));
1014 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1015 warning(_("same rule name in multiple files"));
1016 for (j = i + 2; j < nrules; ++j) {
1017 if (strcmp(rules[i].r_name,
1018 rules[j].r_name) != 0)
1019 break;
1020 if (strcmp(rules[i].r_filename,
1021 rules[j].r_filename) == 0)
1022 continue;
1023 if (strcmp(rules[i + 1].r_filename,
1024 rules[j].r_filename) == 0)
1025 continue;
1026 break;
1028 i = j - 1;
1031 for (i = 0; i < nzones; ++i) {
1032 zp = &zones[i];
1033 zp->z_rules = NULL;
1034 zp->z_nrules = 0;
1036 for (base = 0; base < nrules; base = out) {
1037 rp = &rules[base];
1038 for (out = base + 1; out < nrules; ++out)
1039 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1040 break;
1041 for (i = 0; i < nzones; ++i) {
1042 zp = &zones[i];
1043 if (strcmp(zp->z_rule, rp->r_name) != 0)
1044 continue;
1045 zp->z_rules = rp;
1046 zp->z_nrules = out - base;
1049 for (i = 0; i < nzones; ++i) {
1050 zp = &zones[i];
1051 if (zp->z_nrules == 0) {
1053 ** Maybe we have a local standard time offset.
1055 eat(zp->z_filename, zp->z_linenum);
1056 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
1057 true);
1059 ** Note, though, that if there's no rule,
1060 ** a '%s' in the format is a bad thing.
1062 if (zp->z_format_specifier == 's')
1063 error("%s", _("%s in ruleless zone"));
1066 if (errors)
1067 exit(EXIT_FAILURE);
1070 static void
1071 infile(const char *name)
1073 register FILE * fp;
1074 register char ** fields;
1075 register char * cp;
1076 register const struct lookup * lp;
1077 register int nfields;
1078 register bool wantcont;
1079 register lineno num;
1080 char buf[BUFSIZ];
1082 if (strcmp(name, "-") == 0) {
1083 name = _("standard input");
1084 fp = stdin;
1085 } else if ((fp = fopen(name, "r")) == NULL) {
1086 const char *e = strerror(errno);
1088 fprintf(stderr, _("%s: Can't open %s: %s\n"),
1089 progname, name, e);
1090 exit(EXIT_FAILURE);
1092 wantcont = false;
1093 for (num = 1; ; ++num) {
1094 eat(name, num);
1095 if (fgets(buf, sizeof buf, fp) != buf)
1096 break;
1097 cp = strchr(buf, '\n');
1098 if (cp == NULL) {
1099 error(_("line too long"));
1100 exit(EXIT_FAILURE);
1102 *cp = '\0';
1103 fields = getfields(buf);
1104 nfields = 0;
1105 while (fields[nfields] != NULL) {
1106 static char nada;
1108 if (strcmp(fields[nfields], "-") == 0)
1109 fields[nfields] = &nada;
1110 ++nfields;
1112 if (nfields == 0) {
1113 /* nothing to do */
1114 } else if (wantcont) {
1115 wantcont = inzcont(fields, nfields);
1116 } else {
1117 lp = byword(fields[0], line_codes);
1118 if (lp == NULL)
1119 error(_("input line of unknown type"));
1120 else switch (lp->l_value) {
1121 case LC_RULE:
1122 inrule(fields, nfields);
1123 wantcont = false;
1124 break;
1125 case LC_ZONE:
1126 wantcont = inzone(fields, nfields);
1127 break;
1128 case LC_LINK:
1129 inlink(fields, nfields);
1130 wantcont = false;
1131 break;
1132 case LC_LEAP:
1133 if (name != leapsec)
1134 warning(_("%s: Leap line in non leap"
1135 " seconds file %s"),
1136 progname, name);
1137 else inleap(fields, nfields);
1138 wantcont = false;
1139 break;
1140 default: /* "cannot happen" */
1141 fprintf(stderr,
1142 _("%s: panic: Invalid l_value %d\n"),
1143 progname, lp->l_value);
1144 exit(EXIT_FAILURE);
1147 free(fields);
1149 close_file(fp, NULL, filename);
1150 if (wantcont)
1151 error(_("expected continuation line not found"));
1155 ** Convert a string of one of the forms
1156 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1157 ** into a number of seconds.
1158 ** A null string maps to zero.
1159 ** Call error with errstring and return zero on errors.
1162 static zic_t
1163 gethms(char const *string, char const *errstring, bool signable)
1165 zic_t hh;
1166 int mm, ss, sign;
1167 char xs;
1169 if (string == NULL || *string == '\0')
1170 return 0;
1171 if (!signable)
1172 sign = 1;
1173 else if (*string == '-') {
1174 sign = -1;
1175 ++string;
1176 } else sign = 1;
1177 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
1178 mm = ss = 0;
1179 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
1180 ss = 0;
1181 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
1182 != 3) {
1183 error("%s", errstring);
1184 return 0;
1186 if (hh < 0 ||
1187 mm < 0 || mm >= MINSPERHOUR ||
1188 ss < 0 || ss > SECSPERMIN) {
1189 error("%s", errstring);
1190 return 0;
1192 if (ZIC_MAX / SECSPERHOUR < hh) {
1193 error(_("time overflow"));
1194 return 0;
1196 if (noise && (hh > HOURSPERDAY ||
1197 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1198 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1199 return oadd(sign * hh * SECSPERHOUR,
1200 sign * (mm * SECSPERMIN + ss));
1203 static void
1204 inrule(char **fields, int nfields)
1206 static struct rule r;
1208 if (nfields != RULE_FIELDS) {
1209 error(_("wrong number of fields on Rule line"));
1210 return;
1212 if (*fields[RF_NAME] == '\0') {
1213 error(_("nameless rule"));
1214 return;
1216 r.r_filename = filename;
1217 r.r_linenum = linenum;
1218 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1219 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1220 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1221 r.r_name = ecpyalloc(fields[RF_NAME]);
1222 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1223 if (max_abbrvar_len < strlen(r.r_abbrvar))
1224 max_abbrvar_len = strlen(r.r_abbrvar);
1225 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1226 rules[nrules++] = r;
1229 static bool
1230 inzone(char **fields, int nfields)
1232 register ptrdiff_t i;
1234 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1235 error(_("wrong number of fields on Zone line"));
1236 return false;
1238 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1239 error(
1240 _("\"Zone %s\" line and -l option are mutually exclusive"),
1241 TZDEFAULT);
1242 return false;
1244 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1245 error(
1246 _("\"Zone %s\" line and -p option are mutually exclusive"),
1247 TZDEFRULES);
1248 return false;
1250 for (i = 0; i < nzones; ++i)
1251 if (zones[i].z_name != NULL &&
1252 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1253 error(_("duplicate zone name %s"
1254 " (file \"%s\", line %"PRIdMAX")"),
1255 fields[ZF_NAME],
1256 zones[i].z_filename,
1257 zones[i].z_linenum);
1258 return false;
1260 return inzsub(fields, nfields, false);
1263 static bool
1264 inzcont(char **fields, int nfields)
1266 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1267 error(_("wrong number of fields on Zone continuation line"));
1268 return false;
1270 return inzsub(fields, nfields, true);
1273 static bool
1274 inzsub(char **fields, int nfields, bool iscont)
1276 register char * cp;
1277 char * cp1;
1278 static struct zone z;
1279 register int i_gmtoff, i_rule, i_format;
1280 register int i_untilyear, i_untilmonth;
1281 register int i_untilday, i_untiltime;
1282 register bool hasuntil;
1284 if (iscont) {
1285 i_gmtoff = ZFC_GMTOFF;
1286 i_rule = ZFC_RULE;
1287 i_format = ZFC_FORMAT;
1288 i_untilyear = ZFC_TILYEAR;
1289 i_untilmonth = ZFC_TILMONTH;
1290 i_untilday = ZFC_TILDAY;
1291 i_untiltime = ZFC_TILTIME;
1292 z.z_name = NULL;
1293 } else if (!namecheck(fields[ZF_NAME]))
1294 return false;
1295 else {
1296 i_gmtoff = ZF_GMTOFF;
1297 i_rule = ZF_RULE;
1298 i_format = ZF_FORMAT;
1299 i_untilyear = ZF_TILYEAR;
1300 i_untilmonth = ZF_TILMONTH;
1301 i_untilday = ZF_TILDAY;
1302 i_untiltime = ZF_TILTIME;
1303 z.z_name = ecpyalloc(fields[ZF_NAME]);
1305 z.z_filename = filename;
1306 z.z_linenum = linenum;
1307 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1308 if ((cp = strchr(fields[i_format], '%')) != 0) {
1309 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1310 || strchr(fields[i_format], '/')) {
1311 error(_("invalid abbreviation format"));
1312 return false;
1315 z.z_rule = ecpyalloc(fields[i_rule]);
1316 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1317 z.z_format_specifier = cp ? *cp : '\0';
1318 if (z.z_format_specifier == 'z') {
1319 if (noise)
1320 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1321 z.z_format);
1322 cp1[cp - fields[i_format]] = 's';
1324 if (max_format_len < strlen(z.z_format))
1325 max_format_len = strlen(z.z_format);
1326 hasuntil = nfields > i_untilyear;
1327 if (hasuntil) {
1328 z.z_untilrule.r_filename = filename;
1329 z.z_untilrule.r_linenum = linenum;
1330 rulesub(&z.z_untilrule,
1331 fields[i_untilyear],
1332 "only",
1334 (nfields > i_untilmonth) ?
1335 fields[i_untilmonth] : "Jan",
1336 (nfields > i_untilday) ? fields[i_untilday] : "1",
1337 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1338 z.z_untiltime = rpytime(&z.z_untilrule,
1339 z.z_untilrule.r_loyear);
1340 if (iscont && nzones > 0 &&
1341 z.z_untiltime > min_time &&
1342 z.z_untiltime < max_time &&
1343 zones[nzones - 1].z_untiltime > min_time &&
1344 zones[nzones - 1].z_untiltime < max_time &&
1345 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1346 error(_(
1347 "Zone continuation line end time is not after end time of previous line"
1349 return false;
1352 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1353 zones[nzones++] = z;
1355 ** If there was an UNTIL field on this line,
1356 ** there's more information about the zone on the next line.
1358 return hasuntil;
1361 static void
1362 inleap(char **fields, int nfields)
1364 register const char * cp;
1365 register const struct lookup * lp;
1366 register zic_t i, j;
1367 zic_t year;
1368 int month, day;
1369 zic_t dayoff, tod;
1370 zic_t t;
1371 char xs;
1373 if (nfields != LEAP_FIELDS) {
1374 error(_("wrong number of fields on Leap line"));
1375 return;
1377 dayoff = 0;
1378 cp = fields[LP_YEAR];
1379 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1381 ** Leapin' Lizards!
1383 error(_("invalid leaping year"));
1384 return;
1386 if (!leapseen || leapmaxyear < year)
1387 leapmaxyear = year;
1388 if (!leapseen || leapminyear > year)
1389 leapminyear = year;
1390 leapseen = true;
1391 j = EPOCH_YEAR;
1392 while (j != year) {
1393 if (year > j) {
1394 i = len_years[isleap(j)];
1395 ++j;
1396 } else {
1397 --j;
1398 i = -len_years[isleap(j)];
1400 dayoff = oadd(dayoff, i);
1402 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1403 error(_("invalid month name"));
1404 return;
1406 month = lp->l_value;
1407 j = TM_JANUARY;
1408 while (j != month) {
1409 i = len_months[isleap(year)][j];
1410 dayoff = oadd(dayoff, i);
1411 ++j;
1413 cp = fields[LP_DAY];
1414 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1415 day <= 0 || day > len_months[isleap(year)][month]) {
1416 error(_("invalid day of month"));
1417 return;
1419 dayoff = oadd(dayoff, day - 1);
1420 if (dayoff < min_time / SECSPERDAY) {
1421 error(_("time too small"));
1422 return;
1424 if (dayoff > max_time / SECSPERDAY) {
1425 error(_("time too large"));
1426 return;
1428 t = dayoff * SECSPERDAY;
1429 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1430 cp = fields[LP_CORR];
1432 register bool positive;
1433 int count;
1435 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1436 positive = false;
1437 count = 1;
1438 } else if (strcmp(cp, "--") == 0) {
1439 positive = false;
1440 count = 2;
1441 } else if (strcmp(cp, "+") == 0) {
1442 positive = true;
1443 count = 1;
1444 } else if (strcmp(cp, "++") == 0) {
1445 positive = true;
1446 count = 2;
1447 } else {
1448 error(_("illegal CORRECTION field on Leap line"));
1449 return;
1451 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1452 error(_(
1453 "illegal Rolling/Stationary field on Leap line"
1455 return;
1457 t = tadd(t, tod);
1458 if (t < early_time) {
1459 error(_("leap second precedes Big Bang"));
1460 return;
1462 leapadd(t, positive, lp->l_value, count);
1466 static void
1467 inlink(char **fields, int nfields)
1469 struct link l;
1471 if (nfields != LINK_FIELDS) {
1472 error(_("wrong number of fields on Link line"));
1473 return;
1475 if (*fields[LF_FROM] == '\0') {
1476 error(_("blank FROM field on Link line"));
1477 return;
1479 if (! namecheck(fields[LF_TO]))
1480 return;
1481 l.l_filename = filename;
1482 l.l_linenum = linenum;
1483 l.l_from = ecpyalloc(fields[LF_FROM]);
1484 l.l_to = ecpyalloc(fields[LF_TO]);
1485 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1486 links[nlinks++] = l;
1489 static void
1490 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1491 const char *typep, const char *monthp, const char *dayp,
1492 const char *timep)
1494 register const struct lookup * lp;
1495 register const char * cp;
1496 register char * dp;
1497 register char * ep;
1498 char xs;
1500 if ((lp = byword(monthp, mon_names)) == NULL) {
1501 error(_("invalid month name"));
1502 return;
1504 rp->r_month = lp->l_value;
1505 rp->r_todisstd = false;
1506 rp->r_todisgmt = false;
1507 dp = ecpyalloc(timep);
1508 if (*dp != '\0') {
1509 ep = dp + strlen(dp) - 1;
1510 switch (lowerit(*ep)) {
1511 case 's': /* Standard */
1512 rp->r_todisstd = true;
1513 rp->r_todisgmt = false;
1514 *ep = '\0';
1515 break;
1516 case 'w': /* Wall */
1517 rp->r_todisstd = false;
1518 rp->r_todisgmt = false;
1519 *ep = '\0';
1520 break;
1521 case 'g': /* Greenwich */
1522 case 'u': /* Universal */
1523 case 'z': /* Zulu */
1524 rp->r_todisstd = true;
1525 rp->r_todisgmt = true;
1526 *ep = '\0';
1527 break;
1530 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1531 free(dp);
1533 ** Year work.
1535 cp = loyearp;
1536 lp = byword(cp, begin_years);
1537 rp->r_lowasnum = lp == NULL;
1538 if (!rp->r_lowasnum) switch (lp->l_value) {
1539 case YR_MINIMUM:
1540 rp->r_loyear = ZIC_MIN;
1541 break;
1542 case YR_MAXIMUM:
1543 rp->r_loyear = ZIC_MAX;
1544 break;
1545 default: /* "cannot happen" */
1546 fprintf(stderr,
1547 _("%s: panic: Invalid l_value %d\n"),
1548 progname, lp->l_value);
1549 exit(EXIT_FAILURE);
1550 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1551 error(_("invalid starting year"));
1552 return;
1554 cp = hiyearp;
1555 lp = byword(cp, end_years);
1556 rp->r_hiwasnum = lp == NULL;
1557 if (!rp->r_hiwasnum) switch (lp->l_value) {
1558 case YR_MINIMUM:
1559 rp->r_hiyear = ZIC_MIN;
1560 break;
1561 case YR_MAXIMUM:
1562 rp->r_hiyear = ZIC_MAX;
1563 break;
1564 case YR_ONLY:
1565 rp->r_hiyear = rp->r_loyear;
1566 break;
1567 default: /* "cannot happen" */
1568 fprintf(stderr,
1569 _("%s: panic: Invalid l_value %d\n"),
1570 progname, lp->l_value);
1571 exit(EXIT_FAILURE);
1572 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1573 error(_("invalid ending year"));
1574 return;
1576 if (rp->r_loyear > rp->r_hiyear) {
1577 error(_("starting year greater than ending year"));
1578 return;
1580 if (*typep == '\0')
1581 rp->r_yrtype = NULL;
1582 else {
1583 if (rp->r_loyear == rp->r_hiyear) {
1584 error(_("typed single year"));
1585 return;
1587 rp->r_yrtype = ecpyalloc(typep);
1590 ** Day work.
1591 ** Accept things such as:
1592 ** 1
1593 ** last-Sunday
1594 ** Sun<=20
1595 ** Sun>=7
1597 dp = ecpyalloc(dayp);
1598 if ((lp = byword(dp, lasts)) != NULL) {
1599 rp->r_dycode = DC_DOWLEQ;
1600 rp->r_wday = lp->l_value;
1601 rp->r_dayofmonth = len_months[1][rp->r_month];
1602 } else {
1603 if ((ep = strchr(dp, '<')) != 0)
1604 rp->r_dycode = DC_DOWLEQ;
1605 else if ((ep = strchr(dp, '>')) != 0)
1606 rp->r_dycode = DC_DOWGEQ;
1607 else {
1608 ep = dp;
1609 rp->r_dycode = DC_DOM;
1611 if (rp->r_dycode != DC_DOM) {
1612 *ep++ = 0;
1613 if (*ep++ != '=') {
1614 error(_("invalid day of month"));
1615 free(dp);
1616 return;
1618 if ((lp = byword(dp, wday_names)) == NULL) {
1619 error(_("invalid weekday name"));
1620 free(dp);
1621 return;
1623 rp->r_wday = lp->l_value;
1625 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1626 rp->r_dayofmonth <= 0 ||
1627 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1628 error(_("invalid day of month"));
1629 free(dp);
1630 return;
1633 free(dp);
1636 static void
1637 convert(const int_fast32_t val, char *const buf)
1639 register int i;
1640 register int shift;
1641 unsigned char *const b = (unsigned char *) buf;
1643 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1644 b[i] = val >> shift;
1647 static void
1648 convert64(const zic_t val, char *const buf)
1650 register int i;
1651 register int shift;
1652 unsigned char *const b = (unsigned char *) buf;
1654 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1655 b[i] = val >> shift;
1658 static void
1659 puttzcode(const int_fast32_t val, FILE *const fp)
1661 char buf[4];
1663 convert(val, buf);
1664 fwrite(buf, sizeof buf, 1, fp);
1667 static void
1668 puttzcode64(const zic_t val, FILE *const fp)
1670 char buf[8];
1672 convert64(val, buf);
1673 fwrite(buf, sizeof buf, 1, fp);
1676 static int
1677 atcomp(const void *avp, const void *bvp)
1679 const zic_t a = ((const struct attype *) avp)->at;
1680 const zic_t b = ((const struct attype *) bvp)->at;
1682 return (a < b) ? -1 : (a > b);
1685 static bool
1686 is32(const zic_t x)
1688 return INT32_MIN <= x && x <= INT32_MAX;
1691 static void
1692 writezone(const char *const name, const char *const string, char version)
1694 register FILE * fp;
1695 register ptrdiff_t i, j;
1696 register int leapcnt32, leapi32;
1697 register ptrdiff_t timecnt32, timei32;
1698 register int pass;
1699 static const struct tzhead tzh0;
1700 static struct tzhead tzh;
1701 bool dir_checked = false;
1702 zic_t one = 1;
1703 zic_t y2038_boundary = one << 31;
1704 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
1705 zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
1706 void *typesptr = ats + nats;
1707 unsigned char *types = typesptr;
1710 ** Sort.
1712 if (timecnt > 1)
1713 qsort(attypes, timecnt, sizeof *attypes, atcomp);
1715 ** Optimize.
1718 ptrdiff_t fromi, toi;
1720 toi = 0;
1721 fromi = 0;
1722 while (fromi < timecnt && attypes[fromi].at < early_time)
1723 ++fromi;
1724 for ( ; fromi < timecnt; ++fromi) {
1725 if (toi > 1 && ((attypes[fromi].at +
1726 gmtoffs[attypes[toi - 1].type]) <=
1727 (attypes[toi - 1].at +
1728 gmtoffs[attypes[toi - 2].type]))) {
1729 attypes[toi - 1].type =
1730 attypes[fromi].type;
1731 continue;
1733 if (toi == 0
1734 || attypes[fromi].dontmerge
1735 || attypes[toi - 1].type != attypes[fromi].type)
1736 attypes[toi++] = attypes[fromi];
1738 timecnt = toi;
1741 if (noise && timecnt > 1200) {
1742 if (timecnt > TZ_MAX_TIMES)
1743 warning(_("reference clients mishandle"
1744 " more than %d transition times"),
1745 TZ_MAX_TIMES);
1746 else
1747 warning(_("pre-2014 clients may mishandle"
1748 " more than 1200 transition times"));
1751 ** Transfer.
1753 for (i = 0; i < timecnt; ++i) {
1754 ats[i] = attypes[i].at;
1755 types[i] = attypes[i].type;
1758 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1759 by inserting a no-op transition at time y2038_boundary - 1.
1760 This works only for timestamps before the boundary, which
1761 should be good enough in practice as QTBUG-53071 should be
1762 long-dead by 2038. */
1763 if (WORK_AROUND_QTBUG_53071 && timecnt != 0
1764 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
1765 ats[timecnt] = y2038_boundary - 1;
1766 types[timecnt] = types[timecnt - 1];
1767 timecnt++;
1771 ** Correct for leap seconds.
1773 for (i = 0; i < timecnt; ++i) {
1774 j = leapcnt;
1775 while (--j >= 0)
1776 if (ats[i] > trans[j] - corr[j]) {
1777 ats[i] = tadd(ats[i], corr[j]);
1778 break;
1782 ** Figure out 32-bit-limited starts and counts.
1784 timecnt32 = timecnt;
1785 timei32 = 0;
1786 leapcnt32 = leapcnt;
1787 leapi32 = 0;
1788 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1789 --timecnt32;
1790 while (timecnt32 > 0 && !is32(ats[timei32])) {
1791 --timecnt32;
1792 ++timei32;
1795 ** Output an INT32_MIN "transition" if appropriate; see below.
1797 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1798 --timei32;
1799 ++timecnt32;
1801 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1802 --leapcnt32;
1803 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1804 --leapcnt32;
1805 ++leapi32;
1808 ** Remove old file, if any, to snap links.
1810 if (remove(name) == 0)
1811 dir_checked = true;
1812 else if (errno != ENOENT) {
1813 const char *e = strerror(errno);
1815 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1816 progname, directory, name, e);
1817 exit(EXIT_FAILURE);
1819 fp = fopen(name, "wb");
1820 if (!fp) {
1821 int fopen_errno = errno;
1822 if (fopen_errno == ENOENT && !dir_checked) {
1823 mkdirs(name, true);
1824 fp = fopen(name, "wb");
1825 fopen_errno = errno;
1827 if (!fp) {
1828 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1829 progname, directory, name, strerror(fopen_errno));
1830 exit(EXIT_FAILURE);
1833 for (pass = 1; pass <= 2; ++pass) {
1834 register ptrdiff_t thistimei, thistimecnt, thistimelim;
1835 register int thisleapi, thisleapcnt, thisleaplim;
1836 int writetype[TZ_MAX_TYPES];
1837 int typemap[TZ_MAX_TYPES];
1838 register int thistypecnt;
1839 char thischars[TZ_MAX_CHARS];
1840 int thischarcnt;
1841 bool toomanytimes;
1842 int indmap[TZ_MAX_CHARS];
1844 if (pass == 1) {
1845 thistimei = timei32;
1846 thistimecnt = timecnt32;
1847 toomanytimes = thistimecnt >> 31 >> 1 != 0;
1848 thisleapi = leapi32;
1849 thisleapcnt = leapcnt32;
1850 } else {
1851 thistimei = 0;
1852 thistimecnt = timecnt;
1853 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
1854 thisleapi = 0;
1855 thisleapcnt = leapcnt;
1857 if (toomanytimes)
1858 error(_("too many transition times"));
1859 thistimelim = thistimei + thistimecnt;
1860 thisleaplim = thisleapi + thisleapcnt;
1861 for (i = 0; i < typecnt; ++i)
1862 writetype[i] = thistimecnt == timecnt;
1863 if (thistimecnt == 0) {
1865 ** No transition times fall in the current
1866 ** (32- or 64-bit) window.
1868 if (typecnt != 0)
1869 writetype[typecnt - 1] = true;
1870 } else {
1871 for (i = thistimei - 1; i < thistimelim; ++i)
1872 if (i >= 0)
1873 writetype[types[i]] = true;
1875 ** For America/Godthab and Antarctica/Palmer
1877 if (thistimei == 0)
1878 writetype[0] = true;
1880 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1882 ** For some pre-2011 systems: if the last-to-be-written
1883 ** standard (or daylight) type has an offset different from the
1884 ** most recently used offset,
1885 ** append an (unused) copy of the most recently used type
1886 ** (to help get global "altzone" and "timezone" variables
1887 ** set correctly).
1890 register int mrudst, mrustd, hidst, histd, type;
1892 hidst = histd = mrudst = mrustd = -1;
1893 for (i = thistimei; i < thistimelim; ++i)
1894 if (isdsts[types[i]])
1895 mrudst = types[i];
1896 else mrustd = types[i];
1897 for (i = 0; i < typecnt; ++i)
1898 if (writetype[i]) {
1899 if (isdsts[i])
1900 hidst = i;
1901 else histd = i;
1903 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1904 gmtoffs[hidst] != gmtoffs[mrudst]) {
1905 isdsts[mrudst] = -1;
1906 type = addtype(gmtoffs[mrudst],
1907 &chars[abbrinds[mrudst]],
1908 true,
1909 ttisstds[mrudst],
1910 ttisgmts[mrudst]);
1911 isdsts[mrudst] = 1;
1912 writetype[type] = true;
1914 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1915 gmtoffs[histd] != gmtoffs[mrustd]) {
1916 isdsts[mrustd] = -1;
1917 type = addtype(gmtoffs[mrustd],
1918 &chars[abbrinds[mrustd]],
1919 false,
1920 ttisstds[mrustd],
1921 ttisgmts[mrustd]);
1922 isdsts[mrustd] = 0;
1923 writetype[type] = true;
1926 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1927 thistypecnt = 0;
1928 for (i = 0; i < typecnt; ++i)
1929 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1930 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1931 indmap[i] = -1;
1932 thischarcnt = 0;
1933 for (i = 0; i < typecnt; ++i) {
1934 register char * thisabbr;
1936 if (!writetype[i])
1937 continue;
1938 if (indmap[abbrinds[i]] >= 0)
1939 continue;
1940 thisabbr = &chars[abbrinds[i]];
1941 for (j = 0; j < thischarcnt; ++j)
1942 if (strcmp(&thischars[j], thisabbr) == 0)
1943 break;
1944 if (j == thischarcnt) {
1945 strcpy(&thischars[thischarcnt], thisabbr);
1946 thischarcnt += strlen(thisabbr) + 1;
1948 indmap[abbrinds[i]] = j;
1950 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1951 tzh = tzh0;
1952 memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1953 tzh.tzh_version[0] = version;
1954 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1955 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1956 convert(thisleapcnt, tzh.tzh_leapcnt);
1957 convert(thistimecnt, tzh.tzh_timecnt);
1958 convert(thistypecnt, tzh.tzh_typecnt);
1959 convert(thischarcnt, tzh.tzh_charcnt);
1960 DO(tzh_magic);
1961 DO(tzh_version);
1962 DO(tzh_reserved);
1963 DO(tzh_ttisgmtcnt);
1964 DO(tzh_ttisstdcnt);
1965 DO(tzh_leapcnt);
1966 DO(tzh_timecnt);
1967 DO(tzh_typecnt);
1968 DO(tzh_charcnt);
1969 #undef DO
1970 for (i = thistimei; i < thistimelim; ++i)
1971 if (pass == 1)
1973 ** Output an INT32_MIN "transition"
1974 ** if appropriate; see above.
1976 puttzcode(((ats[i] < INT32_MIN) ?
1977 INT32_MIN : ats[i]), fp);
1978 else puttzcode64(ats[i], fp);
1979 for (i = thistimei; i < thistimelim; ++i) {
1980 unsigned char uc;
1982 uc = typemap[types[i]];
1983 fwrite(&uc, sizeof uc, 1, fp);
1985 for (i = 0; i < typecnt; ++i)
1986 if (writetype[i]) {
1987 puttzcode(gmtoffs[i], fp);
1988 putc(isdsts[i], fp);
1989 putc((unsigned char) indmap[abbrinds[i]], fp);
1991 if (thischarcnt != 0)
1992 fwrite(thischars, sizeof thischars[0],
1993 thischarcnt, fp);
1994 for (i = thisleapi; i < thisleaplim; ++i) {
1995 register zic_t todo;
1997 if (roll[i]) {
1998 if (timecnt == 0 || trans[i] < ats[0]) {
1999 j = 0;
2000 while (isdsts[j])
2001 if (++j >= typecnt) {
2002 j = 0;
2003 break;
2005 } else {
2006 j = 1;
2007 while (j < timecnt &&
2008 trans[i] >= ats[j])
2009 ++j;
2010 j = types[j - 1];
2012 todo = tadd(trans[i], -gmtoffs[j]);
2013 } else todo = trans[i];
2014 if (pass == 1)
2015 puttzcode(todo, fp);
2016 else puttzcode64(todo, fp);
2017 puttzcode(corr[i], fp);
2019 for (i = 0; i < typecnt; ++i)
2020 if (writetype[i])
2021 putc(ttisstds[i], fp);
2022 for (i = 0; i < typecnt; ++i)
2023 if (writetype[i])
2024 putc(ttisgmts[i], fp);
2026 fprintf(fp, "\n%s\n", string);
2027 close_file(fp, directory, name);
2028 free(ats);
2031 static char const *
2032 abbroffset(char *buf, zic_t offset)
2034 char sign = '+';
2035 int seconds, minutes;
2037 if (offset < 0) {
2038 offset = -offset;
2039 sign = '-';
2042 seconds = offset % SECSPERMIN;
2043 offset /= SECSPERMIN;
2044 minutes = offset % MINSPERHOUR;
2045 offset /= MINSPERHOUR;
2046 if (100 <= offset) {
2047 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
2048 return "%z";
2049 } else {
2050 char *p = buf;
2051 *p++ = sign;
2052 *p++ = '0' + offset / 10;
2053 *p++ = '0' + offset % 10;
2054 if (minutes | seconds) {
2055 *p++ = '0' + minutes / 10;
2056 *p++ = '0' + minutes % 10;
2057 if (seconds) {
2058 *p++ = '0' + seconds / 10;
2059 *p++ = '0' + seconds % 10;
2062 *p = '\0';
2063 return buf;
2067 static size_t
2068 doabbr(char *abbr, struct zone const *zp, char const *letters,
2069 zic_t stdoff, bool doquotes)
2071 register char * cp;
2072 register char * slashp;
2073 register size_t len;
2074 char const *format = zp->z_format;
2076 slashp = strchr(format, '/');
2077 if (slashp == NULL) {
2078 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2079 if (zp->z_format_specifier == 'z')
2080 letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
2081 else if (!letters)
2082 letters = "%s";
2083 sprintf(abbr, format, letters);
2084 } else if (stdoff != 0) {
2085 strcpy(abbr, slashp + 1);
2086 } else {
2087 memcpy(abbr, format, slashp - format);
2088 abbr[slashp - format] = '\0';
2090 len = strlen(abbr);
2091 if (!doquotes)
2092 return len;
2093 for (cp = abbr; is_alpha(*cp); cp++)
2094 continue;
2095 if (len > 0 && *cp == '\0')
2096 return len;
2097 abbr[len + 2] = '\0';
2098 abbr[len + 1] = '>';
2099 memmove(abbr + 1, abbr, len);
2100 abbr[0] = '<';
2101 return len + 2;
2104 static void
2105 updateminmax(const zic_t x)
2107 if (min_year > x)
2108 min_year = x;
2109 if (max_year < x)
2110 max_year = x;
2113 static int
2114 stringoffset(char *result, zic_t offset)
2116 register int hours;
2117 register int minutes;
2118 register int seconds;
2119 bool negative = offset < 0;
2120 int len = negative;
2122 if (negative) {
2123 offset = -offset;
2124 result[0] = '-';
2126 seconds = offset % SECSPERMIN;
2127 offset /= SECSPERMIN;
2128 minutes = offset % MINSPERHOUR;
2129 offset /= MINSPERHOUR;
2130 hours = offset;
2131 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2132 result[0] = '\0';
2133 return 0;
2135 len += sprintf(result + len, "%d", hours);
2136 if (minutes != 0 || seconds != 0) {
2137 len += sprintf(result + len, ":%02d", minutes);
2138 if (seconds != 0)
2139 len += sprintf(result + len, ":%02d", seconds);
2141 return len;
2144 static int
2145 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2146 const zic_t gmtoff)
2148 register zic_t tod = rp->r_tod;
2149 register int compat = 0;
2151 if (rp->r_dycode == DC_DOM) {
2152 register int month, total;
2154 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2155 return -1;
2156 total = 0;
2157 for (month = 0; month < rp->r_month; ++month)
2158 total += len_months[0][month];
2159 /* Omit the "J" in Jan and Feb, as that's shorter. */
2160 if (rp->r_month <= 1)
2161 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2162 else
2163 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2164 } else {
2165 register int week;
2166 register int wday = rp->r_wday;
2167 register int wdayoff;
2169 if (rp->r_dycode == DC_DOWGEQ) {
2170 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2171 if (wdayoff)
2172 compat = 2013;
2173 wday -= wdayoff;
2174 tod += wdayoff * SECSPERDAY;
2175 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2176 } else if (rp->r_dycode == DC_DOWLEQ) {
2177 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2178 week = 5;
2179 else {
2180 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2181 if (wdayoff)
2182 compat = 2013;
2183 wday -= wdayoff;
2184 tod += wdayoff * SECSPERDAY;
2185 week = rp->r_dayofmonth / DAYSPERWEEK;
2187 } else return -1; /* "cannot happen" */
2188 if (wday < 0)
2189 wday += DAYSPERWEEK;
2190 result += sprintf(result, "M%d.%d.%d",
2191 rp->r_month + 1, week, wday);
2193 if (rp->r_todisgmt)
2194 tod += gmtoff;
2195 if (rp->r_todisstd && rp->r_stdoff == 0)
2196 tod += dstoff;
2197 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2198 *result++ = '/';
2199 if (! stringoffset(result, tod))
2200 return -1;
2201 if (tod < 0) {
2202 if (compat < 2013)
2203 compat = 2013;
2204 } else if (SECSPERDAY <= tod) {
2205 if (compat < 1994)
2206 compat = 1994;
2209 return compat;
2212 static int
2213 rule_cmp(struct rule const *a, struct rule const *b)
2215 if (!a)
2216 return -!!b;
2217 if (!b)
2218 return 1;
2219 if (a->r_hiyear != b->r_hiyear)
2220 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2221 if (a->r_month - b->r_month != 0)
2222 return a->r_month - b->r_month;
2223 return a->r_dayofmonth - b->r_dayofmonth;
2226 enum { YEAR_BY_YEAR_ZONE = 1 };
2228 static int
2229 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2231 register const struct zone * zp;
2232 register struct rule * rp;
2233 register struct rule * stdrp;
2234 register struct rule * dstrp;
2235 register ptrdiff_t i;
2236 register const char * abbrvar;
2237 register int compat = 0;
2238 register int c;
2239 size_t len;
2240 int offsetlen;
2241 struct rule stdr, dstr;
2243 result[0] = '\0';
2244 zp = zpfirst + zonecount - 1;
2245 stdrp = dstrp = NULL;
2246 for (i = 0; i < zp->z_nrules; ++i) {
2247 rp = &zp->z_rules[i];
2248 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2249 continue;
2250 if (rp->r_yrtype != NULL)
2251 continue;
2252 if (rp->r_stdoff == 0) {
2253 if (stdrp == NULL)
2254 stdrp = rp;
2255 else return -1;
2256 } else {
2257 if (dstrp == NULL)
2258 dstrp = rp;
2259 else return -1;
2262 if (stdrp == NULL && dstrp == NULL) {
2264 ** There are no rules running through "max".
2265 ** Find the latest std rule in stdabbrrp
2266 ** and latest rule of any type in stdrp.
2268 register struct rule *stdabbrrp = NULL;
2269 for (i = 0; i < zp->z_nrules; ++i) {
2270 rp = &zp->z_rules[i];
2271 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2272 stdabbrrp = rp;
2273 if (rule_cmp(stdrp, rp) < 0)
2274 stdrp = rp;
2277 ** Horrid special case: if year is 2037,
2278 ** presume this is a zone handled on a year-by-year basis;
2279 ** do not try to apply a rule to the zone.
2281 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2282 return YEAR_BY_YEAR_ZONE;
2284 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2285 /* Perpetual DST. */
2286 dstr.r_month = TM_JANUARY;
2287 dstr.r_dycode = DC_DOM;
2288 dstr.r_dayofmonth = 1;
2289 dstr.r_tod = 0;
2290 dstr.r_todisstd = dstr.r_todisgmt = false;
2291 dstr.r_stdoff = stdrp->r_stdoff;
2292 dstr.r_abbrvar = stdrp->r_abbrvar;
2293 stdr.r_month = TM_DECEMBER;
2294 stdr.r_dycode = DC_DOM;
2295 stdr.r_dayofmonth = 31;
2296 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2297 stdr.r_todisstd = stdr.r_todisgmt = false;
2298 stdr.r_stdoff = 0;
2299 stdr.r_abbrvar
2300 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2301 dstrp = &dstr;
2302 stdrp = &stdr;
2305 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2306 return -1;
2307 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2308 len = doabbr(result, zp, abbrvar, 0, true);
2309 offsetlen = stringoffset(result + len, -zp->z_gmtoff);
2310 if (! offsetlen) {
2311 result[0] = '\0';
2312 return -1;
2314 len += offsetlen;
2315 if (dstrp == NULL)
2316 return compat;
2317 len += doabbr(result + len, zp, dstrp->r_abbrvar, dstrp->r_stdoff, true);
2318 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
2319 offsetlen = stringoffset(result + len,
2320 -(zp->z_gmtoff + dstrp->r_stdoff));
2321 if (! offsetlen) {
2322 result[0] = '\0';
2323 return -1;
2325 len += offsetlen;
2327 result[len++] = ',';
2328 c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2329 if (c < 0) {
2330 result[0] = '\0';
2331 return -1;
2333 if (compat < c)
2334 compat = c;
2335 len += strlen(result + len);
2336 result[len++] = ',';
2337 c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2338 if (c < 0) {
2339 result[0] = '\0';
2340 return -1;
2342 if (compat < c)
2343 compat = c;
2344 return compat;
2347 static void
2348 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2350 register const struct zone * zp;
2351 register struct rule * rp;
2352 register ptrdiff_t i, j;
2353 register bool usestart, useuntil;
2354 register zic_t starttime, untiltime;
2355 register zic_t gmtoff;
2356 register zic_t stdoff;
2357 register zic_t year;
2358 register zic_t startoff;
2359 register bool startttisstd;
2360 register bool startttisgmt;
2361 register int type;
2362 register char * startbuf;
2363 register char * ab;
2364 register char * envvar;
2365 register int max_abbr_len;
2366 register int max_envvar_len;
2367 register bool prodstic; /* all rules are min to max */
2368 register int compat;
2369 register bool do_extend;
2370 register char version;
2371 ptrdiff_t lastatmax = -1;
2372 zic_t one = 1;
2373 zic_t y2038_boundary = one << 31;
2374 zic_t max_year0;
2376 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2377 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2378 startbuf = emalloc(max_abbr_len + 1);
2379 ab = emalloc(max_abbr_len + 1);
2380 envvar = emalloc(max_envvar_len + 1);
2381 INITIALIZE(untiltime);
2382 INITIALIZE(starttime);
2384 ** Now. . .finally. . .generate some useful data!
2386 timecnt = 0;
2387 typecnt = 0;
2388 charcnt = 0;
2389 prodstic = zonecount == 1;
2391 ** Thanks to Earl Chew
2392 ** for noting the need to unconditionally initialize startttisstd.
2394 startttisstd = false;
2395 startttisgmt = false;
2396 min_year = max_year = EPOCH_YEAR;
2397 if (leapseen) {
2398 updateminmax(leapminyear);
2399 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2401 for (i = 0; i < zonecount; ++i) {
2402 zp = &zpfirst[i];
2403 if (i < zonecount - 1)
2404 updateminmax(zp->z_untilrule.r_loyear);
2405 for (j = 0; j < zp->z_nrules; ++j) {
2406 rp = &zp->z_rules[j];
2407 if (rp->r_lowasnum)
2408 updateminmax(rp->r_loyear);
2409 if (rp->r_hiwasnum)
2410 updateminmax(rp->r_hiyear);
2411 if (rp->r_lowasnum || rp->r_hiwasnum)
2412 prodstic = false;
2416 ** Generate lots of data if a rule can't cover all future times.
2418 compat = stringzone(envvar, zpfirst, zonecount);
2419 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2420 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2421 if (noise) {
2422 if (!*envvar)
2423 warning("%s %s",
2424 _("no POSIX environment variable for zone"),
2425 zpfirst->z_name);
2426 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2427 /* Circa-COMPAT clients, and earlier clients, might
2428 not work for this zone when given dates before
2429 1970 or after 2038. */
2430 warning(_("%s: pre-%d clients may mishandle"
2431 " distant timestamps"),
2432 zpfirst->z_name, compat);
2435 if (do_extend) {
2437 ** Search through a couple of extra years past the obvious
2438 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2439 ** rule applies from 2012 onwards and has transitions in March
2440 ** and September, plus some one-off transitions in November
2441 ** 2013. If zic looked only at the last 400 years, it would
2442 ** set max_year=2413, with the intent that the 400 years 2014
2443 ** through 2413 will be repeated. The last transition listed
2444 ** in the tzfile would be in 2413-09, less than 400 years
2445 ** after the last one-off transition in 2013-11. Two years
2446 ** might be overkill, but with the kind of edge cases
2447 ** available we're not sure that one year would suffice.
2449 enum { years_of_observations = YEARSPERREPEAT + 2 };
2451 if (min_year >= ZIC_MIN + years_of_observations)
2452 min_year -= years_of_observations;
2453 else min_year = ZIC_MIN;
2454 if (max_year <= ZIC_MAX - years_of_observations)
2455 max_year += years_of_observations;
2456 else max_year = ZIC_MAX;
2458 ** Regardless of any of the above,
2459 ** for a "proDSTic" zone which specifies that its rules
2460 ** always have and always will be in effect,
2461 ** we only need one cycle to define the zone.
2463 if (prodstic) {
2464 min_year = 1900;
2465 max_year = min_year + years_of_observations;
2469 ** For the benefit of older systems,
2470 ** generate data from 1900 through 2038.
2472 if (min_year > 1900)
2473 min_year = 1900;
2474 max_year0 = max_year;
2475 if (max_year < 2038)
2476 max_year = 2038;
2477 for (i = 0; i < zonecount; ++i) {
2479 ** A guess that may well be corrected later.
2481 stdoff = 0;
2482 zp = &zpfirst[i];
2483 usestart = i > 0 && (zp - 1)->z_untiltime > early_time;
2484 useuntil = i < (zonecount - 1);
2485 if (useuntil && zp->z_untiltime <= early_time)
2486 continue;
2487 gmtoff = zp->z_gmtoff;
2488 eat(zp->z_filename, zp->z_linenum);
2489 *startbuf = '\0';
2490 startoff = zp->z_gmtoff;
2491 if (zp->z_nrules == 0) {
2492 stdoff = zp->z_stdoff;
2493 doabbr(startbuf, zp, NULL, stdoff, false);
2494 type = addtype(oadd(zp->z_gmtoff, stdoff),
2495 startbuf, stdoff != 0, startttisstd,
2496 startttisgmt);
2497 if (usestart) {
2498 addtt(starttime, type);
2499 usestart = false;
2500 } else addtt(early_time, type);
2501 } else for (year = min_year; year <= max_year; ++year) {
2502 if (useuntil && year > zp->z_untilrule.r_hiyear)
2503 break;
2505 ** Mark which rules to do in the current year.
2506 ** For those to do, calculate rpytime(rp, year);
2508 for (j = 0; j < zp->z_nrules; ++j) {
2509 rp = &zp->z_rules[j];
2510 eats(zp->z_filename, zp->z_linenum,
2511 rp->r_filename, rp->r_linenum);
2512 rp->r_todo = year >= rp->r_loyear &&
2513 year <= rp->r_hiyear &&
2514 yearistype(year, rp->r_yrtype);
2515 if (rp->r_todo) {
2516 rp->r_temp = rpytime(rp, year);
2517 rp->r_todo
2518 = (rp->r_temp < y2038_boundary
2519 || year <= max_year0);
2522 for ( ; ; ) {
2523 register ptrdiff_t k;
2524 register zic_t jtime, ktime;
2525 register zic_t offset;
2527 INITIALIZE(ktime);
2528 if (useuntil) {
2530 ** Turn untiltime into UT
2531 ** assuming the current gmtoff and
2532 ** stdoff values.
2534 untiltime = zp->z_untiltime;
2535 if (!zp->z_untilrule.r_todisgmt)
2536 untiltime = tadd(untiltime,
2537 -gmtoff);
2538 if (!zp->z_untilrule.r_todisstd)
2539 untiltime = tadd(untiltime,
2540 -stdoff);
2543 ** Find the rule (of those to do, if any)
2544 ** that takes effect earliest in the year.
2546 k = -1;
2547 for (j = 0; j < zp->z_nrules; ++j) {
2548 rp = &zp->z_rules[j];
2549 if (!rp->r_todo)
2550 continue;
2551 eats(zp->z_filename, zp->z_linenum,
2552 rp->r_filename, rp->r_linenum);
2553 offset = rp->r_todisgmt ? 0 : gmtoff;
2554 if (!rp->r_todisstd)
2555 offset = oadd(offset, stdoff);
2556 jtime = rp->r_temp;
2557 if (jtime == min_time ||
2558 jtime == max_time)
2559 continue;
2560 jtime = tadd(jtime, -offset);
2561 if (k < 0 || jtime < ktime) {
2562 k = j;
2563 ktime = jtime;
2564 } else if (jtime == ktime) {
2565 char const *dup_rules_msg =
2566 _("two rules for same instant");
2567 eats(zp->z_filename, zp->z_linenum,
2568 rp->r_filename, rp->r_linenum);
2569 warning("%s", dup_rules_msg);
2570 rp = &zp->z_rules[k];
2571 eats(zp->z_filename, zp->z_linenum,
2572 rp->r_filename, rp->r_linenum);
2573 error("%s", dup_rules_msg);
2576 if (k < 0)
2577 break; /* go on to next year */
2578 rp = &zp->z_rules[k];
2579 rp->r_todo = false;
2580 if (useuntil && ktime >= untiltime)
2581 break;
2582 stdoff = rp->r_stdoff;
2583 if (usestart && ktime == starttime)
2584 usestart = false;
2585 if (usestart) {
2586 if (ktime < starttime) {
2587 startoff = oadd(zp->z_gmtoff,
2588 stdoff);
2589 doabbr(startbuf, zp,
2590 rp->r_abbrvar,
2591 rp->r_stdoff,
2592 false);
2593 continue;
2595 if (*startbuf == '\0' &&
2596 startoff == oadd(zp->z_gmtoff,
2597 stdoff)) {
2598 doabbr(startbuf,
2600 rp->r_abbrvar,
2601 rp->r_stdoff,
2602 false);
2605 eats(zp->z_filename, zp->z_linenum,
2606 rp->r_filename, rp->r_linenum);
2607 doabbr(ab, zp, rp->r_abbrvar,
2608 rp->r_stdoff, false);
2609 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2610 type = addtype(offset, ab, rp->r_stdoff != 0,
2611 rp->r_todisstd, rp->r_todisgmt);
2612 if (rp->r_hiyear == ZIC_MAX
2613 && ! (0 <= lastatmax
2614 && ktime < attypes[lastatmax].at))
2615 lastatmax = timecnt;
2616 addtt(ktime, type);
2619 if (usestart) {
2620 if (*startbuf == '\0' &&
2621 zp->z_format != NULL &&
2622 strchr(zp->z_format, '%') == NULL &&
2623 strchr(zp->z_format, '/') == NULL)
2624 strcpy(startbuf, zp->z_format);
2625 eat(zp->z_filename, zp->z_linenum);
2626 if (*startbuf == '\0')
2627 error(_("can't determine time zone abbreviation to use just after until time"));
2628 else addtt(starttime,
2629 addtype(startoff, startbuf,
2630 startoff != zp->z_gmtoff,
2631 startttisstd,
2632 startttisgmt));
2635 ** Now we may get to set starttime for the next zone line.
2637 if (useuntil) {
2638 startttisstd = zp->z_untilrule.r_todisstd;
2639 startttisgmt = zp->z_untilrule.r_todisgmt;
2640 starttime = zp->z_untiltime;
2641 if (!startttisstd)
2642 starttime = tadd(starttime, -stdoff);
2643 if (!startttisgmt)
2644 starttime = tadd(starttime, -gmtoff);
2647 if (0 <= lastatmax)
2648 attypes[lastatmax].dontmerge = true;
2649 if (do_extend) {
2651 ** If we're extending the explicitly listed observations
2652 ** for 400 years because we can't fill the POSIX-TZ field,
2653 ** check whether we actually ended up explicitly listing
2654 ** observations through that period. If there aren't any
2655 ** near the end of the 400-year period, add a redundant
2656 ** one at the end of the final year, to make it clear
2657 ** that we are claiming to have definite knowledge of
2658 ** the lack of transitions up to that point.
2660 struct rule xr;
2661 struct attype *lastat;
2662 xr.r_month = TM_JANUARY;
2663 xr.r_dycode = DC_DOM;
2664 xr.r_dayofmonth = 1;
2665 xr.r_tod = 0;
2666 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2667 if (attypes[i].at > lastat->at)
2668 lastat = &attypes[i];
2669 if (lastat->at < rpytime(&xr, max_year - 1)) {
2670 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2671 attypes[timecnt - 1].dontmerge = true;
2674 writezone(zpfirst->z_name, envvar, version);
2675 free(startbuf);
2676 free(ab);
2677 free(envvar);
2680 static void
2681 addtt(zic_t starttime, int type)
2683 if (starttime <= early_time
2684 || (timecnt == 1 && attypes[0].at < early_time)) {
2685 gmtoffs[0] = gmtoffs[type];
2686 isdsts[0] = isdsts[type];
2687 ttisstds[0] = ttisstds[type];
2688 ttisgmts[0] = ttisgmts[type];
2689 if (abbrinds[type] != 0)
2690 strcpy(chars, &chars[abbrinds[type]]);
2691 abbrinds[0] = 0;
2692 charcnt = strlen(chars) + 1;
2693 typecnt = 1;
2694 timecnt = 0;
2695 type = 0;
2697 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2698 attypes[timecnt].at = starttime;
2699 attypes[timecnt].dontmerge = false;
2700 attypes[timecnt].type = type;
2701 ++timecnt;
2704 static int
2705 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
2707 register int i, j;
2710 ** See if there's already an entry for this zone type.
2711 ** If so, just return its index.
2713 for (i = 0; i < typecnt; ++i) {
2714 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2715 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2716 ttisstd == ttisstds[i] &&
2717 ttisgmt == ttisgmts[i])
2718 return i;
2721 ** There isn't one; add a new one, unless there are already too
2722 ** many.
2724 if (typecnt >= TZ_MAX_TYPES) {
2725 error(_("too many local time types"));
2726 exit(EXIT_FAILURE);
2728 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2729 error(_("UT offset out of range"));
2730 exit(EXIT_FAILURE);
2732 gmtoffs[i] = gmtoff;
2733 isdsts[i] = isdst;
2734 ttisstds[i] = ttisstd;
2735 ttisgmts[i] = ttisgmt;
2737 for (j = 0; j < charcnt; ++j)
2738 if (strcmp(&chars[j], abbr) == 0)
2739 break;
2740 if (j == charcnt)
2741 newabbr(abbr);
2742 abbrinds[i] = j;
2743 ++typecnt;
2744 return i;
2747 static void
2748 leapadd(zic_t t, bool positive, int rolling, int count)
2750 register int i, j;
2752 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2753 error(_("too many leap seconds"));
2754 exit(EXIT_FAILURE);
2756 for (i = 0; i < leapcnt; ++i)
2757 if (t <= trans[i]) {
2758 if (t == trans[i]) {
2759 error(_("repeated leap second moment"));
2760 exit(EXIT_FAILURE);
2762 break;
2764 do {
2765 for (j = leapcnt; j > i; --j) {
2766 trans[j] = trans[j - 1];
2767 corr[j] = corr[j - 1];
2768 roll[j] = roll[j - 1];
2770 trans[i] = t;
2771 corr[i] = positive ? 1 : -count;
2772 roll[i] = rolling;
2773 ++leapcnt;
2774 } while (positive && --count != 0);
2777 static void
2778 adjleap(void)
2780 register int i;
2781 register zic_t last = 0;
2784 ** propagate leap seconds forward
2786 for (i = 0; i < leapcnt; ++i) {
2787 trans[i] = tadd(trans[i], last);
2788 last = corr[i] += last;
2792 static char *
2793 shellquote(char *b, char const *s)
2795 *b++ = '\'';
2796 while (*s) {
2797 if (*s == '\'')
2798 *b++ = '\'', *b++ = '\\', *b++ = '\'';
2799 *b++ = *s++;
2801 *b++ = '\'';
2802 return b;
2805 static bool
2806 yearistype(zic_t year, const char *type)
2808 char *buf;
2809 char *b;
2810 int result;
2812 if (type == NULL || *type == '\0')
2813 return true;
2814 buf = emalloc(1 + 4 * strlen(yitcommand) + 2
2815 + INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2);
2816 b = shellquote(buf, yitcommand);
2817 *b++ = ' ';
2818 b += sprintf(b, "%"PRIdZIC, year);
2819 *b++ = ' ';
2820 b = shellquote(b, type);
2821 *b = '\0';
2822 result = system(buf);
2823 if (WIFEXITED(result)) {
2824 int status = WEXITSTATUS(result);
2825 if (status <= 1) {
2826 free(buf);
2827 return status == 0;
2830 error(_("Wild result from command execution"));
2831 fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2832 progname, buf, result);
2833 exit(EXIT_FAILURE);
2836 /* Is A a space character in the C locale? */
2837 static bool
2838 is_space(char a)
2840 switch (a) {
2841 default:
2842 return false;
2843 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2844 return true;
2848 /* Is A an alphabetic character in the C locale? */
2849 static bool
2850 is_alpha(char a)
2852 switch (a) {
2853 default:
2854 return false;
2855 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2856 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2857 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2858 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2859 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2860 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2861 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2862 case 'v': case 'w': case 'x': case 'y': case 'z':
2863 return true;
2867 /* If A is an uppercase character in the C locale, return its lowercase
2868 counterpart. Otherwise, return A. */
2869 static char
2870 lowerit(char a)
2872 switch (a) {
2873 default: return a;
2874 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2875 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2876 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2877 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2878 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2879 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2880 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2881 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2882 case 'Y': return 'y'; case 'Z': return 'z';
2886 /* case-insensitive equality */
2887 static ATTRIBUTE_PURE bool
2888 ciequal(register const char *ap, register const char *bp)
2890 while (lowerit(*ap) == lowerit(*bp++))
2891 if (*ap++ == '\0')
2892 return true;
2893 return false;
2896 static ATTRIBUTE_PURE bool
2897 itsabbr(register const char *abbr, register const char *word)
2899 if (lowerit(*abbr) != lowerit(*word))
2900 return false;
2901 ++word;
2902 while (*++abbr != '\0')
2903 do {
2904 if (*word == '\0')
2905 return false;
2906 } while (lowerit(*word++) != lowerit(*abbr));
2907 return true;
2910 static ATTRIBUTE_PURE const struct lookup *
2911 byword(const char *word, const struct lookup *table)
2913 register const struct lookup * foundlp;
2914 register const struct lookup * lp;
2916 if (word == NULL || table == NULL)
2917 return NULL;
2919 ** Look for exact match.
2921 for (lp = table; lp->l_word != NULL; ++lp)
2922 if (ciequal(word, lp->l_word))
2923 return lp;
2925 ** Look for inexact match.
2927 foundlp = NULL;
2928 for (lp = table; lp->l_word != NULL; ++lp)
2929 if (itsabbr(word, lp->l_word)) {
2930 if (foundlp == NULL)
2931 foundlp = lp;
2932 else return NULL; /* multiple inexact matches */
2934 return foundlp;
2937 static char **
2938 getfields(register char *cp)
2940 register char * dp;
2941 register char ** array;
2942 register int nsubs;
2944 if (cp == NULL)
2945 return NULL;
2946 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
2947 nsubs = 0;
2948 for ( ; ; ) {
2949 while (is_space(*cp))
2950 ++cp;
2951 if (*cp == '\0' || *cp == '#')
2952 break;
2953 array[nsubs++] = dp = cp;
2954 do {
2955 if ((*dp = *cp++) != '"')
2956 ++dp;
2957 else while ((*dp = *cp++) != '"')
2958 if (*dp != '\0')
2959 ++dp;
2960 else {
2961 error(_("Odd number of quotation marks"));
2962 exit(EXIT_FAILURE);
2964 } while (*cp && *cp != '#' && !is_space(*cp));
2965 if (is_space(*cp))
2966 ++cp;
2967 *dp = '\0';
2969 array[nsubs] = NULL;
2970 return array;
2973 static _Noreturn void
2974 time_overflow(void)
2976 error(_("time overflow"));
2977 exit(EXIT_FAILURE);
2980 static ATTRIBUTE_PURE zic_t
2981 oadd(zic_t t1, zic_t t2)
2983 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
2984 time_overflow();
2985 return t1 + t2;
2988 static ATTRIBUTE_PURE zic_t
2989 tadd(zic_t t1, zic_t t2)
2991 if (t1 < 0) {
2992 if (t2 < min_time - t1) {
2993 if (t1 != min_time)
2994 time_overflow();
2995 return min_time;
2997 } else {
2998 if (max_time - t1 < t2) {
2999 if (t1 != max_time)
3000 time_overflow();
3001 return max_time;
3004 return t1 + t2;
3008 ** Given a rule, and a year, compute the date (in seconds since January 1,
3009 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3012 static zic_t
3013 rpytime(const struct rule *rp, zic_t wantedy)
3015 register int m, i;
3016 register zic_t dayoff; /* with a nod to Margaret O. */
3017 register zic_t t, y;
3019 if (wantedy == ZIC_MIN)
3020 return min_time;
3021 if (wantedy == ZIC_MAX)
3022 return max_time;
3023 dayoff = 0;
3024 m = TM_JANUARY;
3025 y = EPOCH_YEAR;
3026 while (wantedy != y) {
3027 if (wantedy > y) {
3028 i = len_years[isleap(y)];
3029 ++y;
3030 } else {
3031 --y;
3032 i = -len_years[isleap(y)];
3034 dayoff = oadd(dayoff, i);
3036 while (m != rp->r_month) {
3037 i = len_months[isleap(y)][m];
3038 dayoff = oadd(dayoff, i);
3039 ++m;
3041 i = rp->r_dayofmonth;
3042 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3043 if (rp->r_dycode == DC_DOWLEQ)
3044 --i;
3045 else {
3046 error(_("use of 2/29 in non leap-year"));
3047 exit(EXIT_FAILURE);
3050 --i;
3051 dayoff = oadd(dayoff, i);
3052 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3053 register zic_t wday;
3055 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3056 wday = EPOCH_WDAY;
3058 ** Don't trust mod of negative numbers.
3060 if (dayoff >= 0)
3061 wday = (wday + dayoff) % LDAYSPERWEEK;
3062 else {
3063 wday -= ((-dayoff) % LDAYSPERWEEK);
3064 if (wday < 0)
3065 wday += LDAYSPERWEEK;
3067 while (wday != rp->r_wday)
3068 if (rp->r_dycode == DC_DOWGEQ) {
3069 dayoff = oadd(dayoff, 1);
3070 if (++wday >= LDAYSPERWEEK)
3071 wday = 0;
3072 ++i;
3073 } else {
3074 dayoff = oadd(dayoff, -1);
3075 if (--wday < 0)
3076 wday = LDAYSPERWEEK - 1;
3077 --i;
3079 if (i < 0 || i >= len_months[isleap(y)][m]) {
3080 if (noise)
3081 warning(_("rule goes past start/end of month; \
3082 will not work with pre-2004 versions of zic"));
3085 if (dayoff < min_time / SECSPERDAY)
3086 return min_time;
3087 if (dayoff > max_time / SECSPERDAY)
3088 return max_time;
3089 t = (zic_t) dayoff * SECSPERDAY;
3090 return tadd(t, rp->r_tod);
3093 static void
3094 newabbr(const char *string)
3096 register int i;
3098 if (strcmp(string, GRANDPARENTED) != 0) {
3099 register const char * cp;
3100 const char * mp;
3102 cp = string;
3103 mp = NULL;
3104 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3105 || *cp == '-' || *cp == '+')
3106 ++cp;
3107 if (noise && cp - string < 3)
3108 mp = _("time zone abbreviation has fewer than 3 characters");
3109 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3110 mp = _("time zone abbreviation has too many characters");
3111 if (*cp != '\0')
3112 mp = _("time zone abbreviation differs from POSIX standard");
3113 if (mp != NULL)
3114 warning("%s (%s)", mp, string);
3116 i = strlen(string) + 1;
3117 if (charcnt + i > TZ_MAX_CHARS) {
3118 error(_("too many, or too long, time zone abbreviations"));
3119 exit(EXIT_FAILURE);
3121 strcpy(&chars[charcnt], string);
3122 charcnt += i;
3125 /* Ensure that the directories of ARGNAME exist, by making any missing
3126 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3127 do it for ARGNAME too. Exit with failure if there is trouble.
3128 Do not consider an existing non-directory to be trouble. */
3129 static void
3130 mkdirs(char const *argname, bool ancestors)
3132 register char * name;
3133 register char * cp;
3135 cp = name = ecpyalloc(argname);
3137 /* Do not mkdir a root directory, as it must exist. */
3138 #ifdef HAVE_DOS_FILE_NAMES
3139 if (is_alpha(name[0]) && name[1] == ':')
3140 cp += 2;
3141 #endif
3142 while (*cp == '/')
3143 cp++;
3145 while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3146 if (cp)
3147 *cp = '\0';
3149 ** Try to create it. It's OK if creation fails because
3150 ** the directory already exists, perhaps because some
3151 ** other process just created it. For simplicity do
3152 ** not check first whether it already exists, as that
3153 ** is checked anyway if the mkdir fails.
3155 if (mkdir(name, MKDIR_UMASK) != 0) {
3156 /* For speed, skip itsdir if errno == EEXIST. Since
3157 mkdirs is called only after open fails with ENOENT
3158 on a subfile, EEXIST implies itsdir here. */
3159 int err = errno;
3160 if (err != EEXIST && !itsdir(name)) {
3161 error(_("%s: Can't create directory %s: %s"),
3162 progname, name, strerror(err));
3163 exit(EXIT_FAILURE);
3166 if (cp)
3167 *cp++ = '/';
3169 free(name);