usr/src/boot: add .PARALLEL to makefiles
[unleashed.git] / contrib / tzcode / zic.c
blob068fb4331821a222faf82e6618abd5e25f44440e
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 and printf format for line numbers. */
50 typedef intmax_t lineno;
51 #define PRIdLINENO PRIdMAX
53 struct rule {
54 const char * r_filename;
55 lineno r_linenum;
56 const char * r_name;
58 zic_t r_loyear; /* for example, 1986 */
59 zic_t r_hiyear; /* for example, 1986 */
60 const char * r_yrtype;
61 bool r_lowasnum;
62 bool r_hiwasnum;
64 int r_month; /* 0..11 */
66 int r_dycode; /* see below */
67 int r_dayofmonth;
68 int r_wday;
70 zic_t r_tod; /* time from midnight */
71 bool r_todisstd; /* above is standard time if 1 */
72 /* or wall clock time if 0 */
73 bool r_todisgmt; /* above is GMT if 1 */
74 /* or local time if 0 */
75 zic_t r_stdoff; /* offset from standard time */
76 const char * r_abbrvar; /* variable part of abbreviation */
78 bool r_todo; /* a rule to do (used in outzone) */
79 zic_t r_temp; /* used in outzone */
83 ** r_dycode r_dayofmonth r_wday
86 #define DC_DOM 0 /* 1..31 */ /* unused */
87 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
88 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
90 struct zone {
91 const char * z_filename;
92 lineno z_linenum;
94 const char * z_name;
95 zic_t z_gmtoff;
96 const char * z_rule;
97 const char * z_format;
98 char z_format_specifier;
100 zic_t z_stdoff;
102 struct rule * z_rules;
103 ptrdiff_t z_nrules;
105 struct rule z_untilrule;
106 zic_t z_untiltime;
109 #if !HAVE_POSIX_DECLS
110 extern int getopt(int argc, char * const argv[],
111 const char * options);
112 extern int link(const char * fromname, const char * toname);
113 extern char * optarg;
114 extern int optind;
115 #endif
117 #if ! HAVE_LINK
118 # define link(from, to) (errno = ENOTSUP, -1)
119 #endif
120 #if ! HAVE_SYMLINK
121 # define readlink(file, buf, size) (errno = ENOTSUP, -1)
122 # define symlink(from, to) (errno = ENOTSUP, -1)
123 # define S_ISLNK(m) 0
124 #endif
125 #ifndef AT_SYMLINK_FOLLOW
126 # define linkat(fromdir, from, todir, to, flag) \
127 (itssymlink(from) ? (errno = ENOTSUP, -1) : link(from, to))
128 #endif
130 static void addtt(zic_t starttime, int type);
131 static int addtype(zic_t, char const *, bool, bool, bool);
132 static void leapadd(zic_t, bool, int, int);
133 static void adjleap(void);
134 static void associate(void);
135 static void dolink(const char *, const char *, bool);
136 static char ** getfields(char * buf);
137 static zic_t gethms(const char * string, const char * errstring,
138 bool);
139 static void infile(const char * filename);
140 static void inleap(char ** fields, int nfields);
141 static void inlink(char ** fields, int nfields);
142 static void inrule(char ** fields, int nfields);
143 static bool inzcont(char ** fields, int nfields);
144 static bool inzone(char ** fields, int nfields);
145 static bool inzsub(char **, int, bool);
146 static bool itsdir(char const *);
147 static bool itssymlink(char const *);
148 static bool is_alpha(char a);
149 static char lowerit(char);
150 static void mkdirs(char const *, bool);
151 static void newabbr(const char * abbr);
152 static zic_t oadd(zic_t t1, zic_t t2);
153 static void outzone(const struct zone * zp, ptrdiff_t ntzones);
154 static zic_t rpytime(const struct rule * rp, zic_t wantedy);
155 static void rulesub(struct rule * rp,
156 const char * loyearp, const char * hiyearp,
157 const char * typep, const char * monthp,
158 const char * dayp, const char * timep);
159 static zic_t tadd(zic_t t1, zic_t t2);
160 static bool yearistype(zic_t year, const char * type);
162 /* Bound on length of what %z can expand to. */
163 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
165 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
166 tz binary files whose POSIX-TZ-style strings contain '<'; see
167 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
168 workaround will no longer be needed when Qt 5.6.1 and earlier are
169 obsolete, say in the year 2021. */
170 enum { WORK_AROUND_QTBUG_53071 = true };
172 static int charcnt;
173 static bool errors;
174 static bool warnings;
175 static const char * filename;
176 static int leapcnt;
177 static bool leapseen;
178 static zic_t leapminyear;
179 static zic_t leapmaxyear;
180 static lineno linenum;
181 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
182 static int max_format_len;
183 static zic_t max_year;
184 static zic_t min_year;
185 static bool noise;
186 static const char * rfilename;
187 static lineno rlinenum;
188 static const char * progname;
189 static ptrdiff_t timecnt;
190 static ptrdiff_t timecnt_alloc;
191 static int typecnt;
194 ** Line codes.
197 #define LC_RULE 0
198 #define LC_ZONE 1
199 #define LC_LINK 2
200 #define LC_LEAP 3
203 ** Which fields are which on a Zone line.
206 #define ZF_NAME 1
207 #define ZF_GMTOFF 2
208 #define ZF_RULE 3
209 #define ZF_FORMAT 4
210 #define ZF_TILYEAR 5
211 #define ZF_TILMONTH 6
212 #define ZF_TILDAY 7
213 #define ZF_TILTIME 8
214 #define ZONE_MINFIELDS 5
215 #define ZONE_MAXFIELDS 9
218 ** Which fields are which on a Zone continuation line.
221 #define ZFC_GMTOFF 0
222 #define ZFC_RULE 1
223 #define ZFC_FORMAT 2
224 #define ZFC_TILYEAR 3
225 #define ZFC_TILMONTH 4
226 #define ZFC_TILDAY 5
227 #define ZFC_TILTIME 6
228 #define ZONEC_MINFIELDS 3
229 #define ZONEC_MAXFIELDS 7
232 ** Which files are which on a Rule line.
235 #define RF_NAME 1
236 #define RF_LOYEAR 2
237 #define RF_HIYEAR 3
238 #define RF_COMMAND 4
239 #define RF_MONTH 5
240 #define RF_DAY 6
241 #define RF_TOD 7
242 #define RF_STDOFF 8
243 #define RF_ABBRVAR 9
244 #define RULE_FIELDS 10
247 ** Which fields are which on a Link line.
250 #define LF_FROM 1
251 #define LF_TO 2
252 #define LINK_FIELDS 3
255 ** Which fields are which on a Leap line.
258 #define LP_YEAR 1
259 #define LP_MONTH 2
260 #define LP_DAY 3
261 #define LP_TIME 4
262 #define LP_CORR 5
263 #define LP_ROLL 6
264 #define LEAP_FIELDS 7
267 ** Year synonyms.
270 #define YR_MINIMUM 0
271 #define YR_MAXIMUM 1
272 #define YR_ONLY 2
274 static struct rule * rules;
275 static ptrdiff_t nrules; /* number of rules */
276 static ptrdiff_t nrules_alloc;
278 static struct zone * zones;
279 static ptrdiff_t nzones; /* number of zones */
280 static ptrdiff_t nzones_alloc;
282 struct link {
283 const char * l_filename;
284 lineno l_linenum;
285 const char * l_from;
286 const char * l_to;
289 static struct link * links;
290 static ptrdiff_t nlinks;
291 static ptrdiff_t nlinks_alloc;
293 struct lookup {
294 const char * l_word;
295 const int l_value;
298 static struct lookup const * byword(const char * string,
299 const struct lookup * lp);
301 static struct lookup const line_codes[] = {
302 { "Rule", LC_RULE },
303 { "Zone", LC_ZONE },
304 { "Link", LC_LINK },
305 { "Leap", LC_LEAP },
306 { NULL, 0}
309 static struct lookup const mon_names[] = {
310 { "January", TM_JANUARY },
311 { "February", TM_FEBRUARY },
312 { "March", TM_MARCH },
313 { "April", TM_APRIL },
314 { "May", TM_MAY },
315 { "June", TM_JUNE },
316 { "July", TM_JULY },
317 { "August", TM_AUGUST },
318 { "September", TM_SEPTEMBER },
319 { "October", TM_OCTOBER },
320 { "November", TM_NOVEMBER },
321 { "December", TM_DECEMBER },
322 { NULL, 0 }
325 static struct lookup const wday_names[] = {
326 { "Sunday", TM_SUNDAY },
327 { "Monday", TM_MONDAY },
328 { "Tuesday", TM_TUESDAY },
329 { "Wednesday", TM_WEDNESDAY },
330 { "Thursday", TM_THURSDAY },
331 { "Friday", TM_FRIDAY },
332 { "Saturday", TM_SATURDAY },
333 { NULL, 0 }
336 static struct lookup const lasts[] = {
337 { "last-Sunday", TM_SUNDAY },
338 { "last-Monday", TM_MONDAY },
339 { "last-Tuesday", TM_TUESDAY },
340 { "last-Wednesday", TM_WEDNESDAY },
341 { "last-Thursday", TM_THURSDAY },
342 { "last-Friday", TM_FRIDAY },
343 { "last-Saturday", TM_SATURDAY },
344 { NULL, 0 }
347 static struct lookup const begin_years[] = {
348 { "minimum", YR_MINIMUM },
349 { "maximum", YR_MAXIMUM },
350 { NULL, 0 }
353 static struct lookup const end_years[] = {
354 { "minimum", YR_MINIMUM },
355 { "maximum", YR_MAXIMUM },
356 { "only", YR_ONLY },
357 { NULL, 0 }
360 static struct lookup const leap_types[] = {
361 { "Rolling", true },
362 { "Stationary", false },
363 { NULL, 0 }
366 static const int len_months[2][MONSPERYEAR] = {
367 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
368 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
371 static const int len_years[2] = {
372 DAYSPERNYEAR, DAYSPERLYEAR
375 static struct attype {
376 zic_t at;
377 bool dontmerge;
378 unsigned char type;
379 } * attypes;
380 static zic_t gmtoffs[TZ_MAX_TYPES];
381 static char isdsts[TZ_MAX_TYPES];
382 static unsigned char abbrinds[TZ_MAX_TYPES];
383 static bool ttisstds[TZ_MAX_TYPES];
384 static bool ttisgmts[TZ_MAX_TYPES];
385 static char chars[TZ_MAX_CHARS];
386 static zic_t trans[TZ_MAX_LEAPS];
387 static zic_t corr[TZ_MAX_LEAPS];
388 static char roll[TZ_MAX_LEAPS];
391 ** Memory allocation.
394 static _Noreturn void
395 memory_exhausted(const char *msg)
397 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
398 exit(EXIT_FAILURE);
401 static ATTRIBUTE_PURE size_t
402 size_product(size_t nitems, size_t itemsize)
404 if (SIZE_MAX / itemsize < nitems)
405 memory_exhausted(_("size overflow"));
406 return nitems * itemsize;
409 #if !HAVE_STRDUP
410 static char *
411 strdup(char const *str)
413 char *result = malloc(strlen(str) + 1);
414 return result ? strcpy(result, str) : result;
416 #endif
418 static ATTRIBUTE_PURE void *
419 memcheck(void *ptr)
421 if (ptr == NULL)
422 memory_exhausted(strerror(errno));
423 return ptr;
426 static void *
427 emalloc(size_t size)
429 return memcheck(malloc(size));
432 static void *
433 erealloc(void *ptr, size_t size)
435 return memcheck(realloc(ptr, size));
438 static char *
439 ecpyalloc (char const *str)
441 return memcheck(strdup(str));
444 static void *
445 growalloc(void *ptr, size_t itemsize, ptrdiff_t nitems, ptrdiff_t *nitems_alloc)
447 if (nitems < *nitems_alloc)
448 return ptr;
449 else {
450 ptrdiff_t nitems_max = PTRDIFF_MAX - WORK_AROUND_QTBUG_53071;
451 ptrdiff_t amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
452 if ((amax - 1) / 3 * 2 < *nitems_alloc)
453 memory_exhausted(_("integer overflow"));
454 *nitems_alloc += (*nitems_alloc >> 1) + 1;
455 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
460 ** Error handling.
463 static void
464 eats(char const *name, lineno num, char const *rname, lineno rnum)
466 filename = name;
467 linenum = num;
468 rfilename = rname;
469 rlinenum = rnum;
472 static void
473 eat(char const *name, lineno num)
475 eats(name, num, NULL, -1);
478 static void ATTRIBUTE_FORMAT((printf, 1, 0))
479 verror(const char *const string, va_list args)
482 ** Match the format of "cc" to allow sh users to
483 ** zic ... 2>&1 | error -t "*" -v
484 ** on BSD systems.
486 if (filename)
487 fprintf(stderr, _("\"%s\", line %"PRIdLINENO": "), filename, linenum);
488 vfprintf(stderr, string, args);
489 if (rfilename != NULL)
490 fprintf(stderr, _(" (rule from \"%s\", line %"PRIdLINENO")"),
491 rfilename, rlinenum);
492 fprintf(stderr, "\n");
495 static void ATTRIBUTE_FORMAT((printf, 1, 2))
496 error(const char *const string, ...)
498 va_list args;
499 va_start(args, string);
500 verror(string, args);
501 va_end(args);
502 errors = true;
505 static void ATTRIBUTE_FORMAT((printf, 1, 2))
506 warning(const char *const string, ...)
508 va_list args;
509 fprintf(stderr, _("warning: "));
510 va_start(args, string);
511 verror(string, args);
512 va_end(args);
513 warnings = true;
516 static void
517 close_file(FILE *stream, char const *dir, char const *name)
519 char const *e = (ferror(stream) ? _("I/O error")
520 : fclose(stream) != 0 ? strerror(errno) : NULL);
521 if (e) {
522 fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
523 dir ? dir : "", dir ? "/" : "",
524 name ? name : "", name ? ": " : "",
526 exit(EXIT_FAILURE);
530 static _Noreturn void
531 usage(FILE *stream, int status)
533 fprintf(stream,
534 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
535 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
536 "\t[ -L leapseconds ] [ filename ... ]\n\n"
537 "Report bugs to %s.\n"),
538 progname, progname, REPORT_BUGS_TO);
539 if (status == EXIT_SUCCESS)
540 close_file(stream, NULL, NULL);
541 exit(status);
544 /* Change the working directory to DIR, possibly creating DIR and its
545 ancestors. After this is done, all files are accessed with names
546 relative to DIR. */
547 static void
548 change_directory (char const *dir)
550 if (chdir(dir) != 0) {
551 int chdir_errno = errno;
552 if (chdir_errno == ENOENT) {
553 mkdirs(dir, false);
554 chdir_errno = chdir(dir) == 0 ? 0 : errno;
556 if (chdir_errno != 0) {
557 fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
558 progname, dir, strerror(chdir_errno));
559 exit(EXIT_FAILURE);
564 static const char * psxrules;
565 static const char * lcltime;
566 static const char * directory;
567 static const char * leapsec;
568 static const char * yitcommand;
571 main(int argc, char **argv)
573 register int c, k;
574 register ptrdiff_t i, j;
576 #ifdef S_IWGRP
577 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
578 #endif
579 #if HAVE_GETTEXT
580 setlocale(LC_ALL, "");
581 #ifdef TZ_DOMAINDIR
582 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
583 #endif /* defined TEXTDOMAINDIR */
584 textdomain(TZ_DOMAIN);
585 #endif /* HAVE_GETTEXT */
586 progname = argv[0];
587 if (TYPE_BIT(zic_t) < 64) {
588 fprintf(stderr, "%s: %s\n", progname,
589 _("wild compilation-time specification of zic_t"));
590 return EXIT_FAILURE;
592 for (k = 1; k < argc; k++)
593 if (strcmp(argv[k], "--version") == 0) {
594 printf("zic %s%s\n", PKGVERSION, TZVERSION);
595 close_file(stdout, NULL, NULL);
596 return EXIT_SUCCESS;
597 } else if (strcmp(argv[k], "--help") == 0) {
598 usage(stdout, EXIT_SUCCESS);
600 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
601 switch (c) {
602 default:
603 usage(stderr, EXIT_FAILURE);
604 case 'd':
605 if (directory == NULL)
606 directory = optarg;
607 else {
608 fprintf(stderr,
609 _("%s: More than one -d option specified\n"),
610 progname);
611 return EXIT_FAILURE;
613 break;
614 case 'l':
615 if (lcltime == NULL)
616 lcltime = optarg;
617 else {
618 fprintf(stderr,
619 _("%s: More than one -l option specified\n"),
620 progname);
621 return EXIT_FAILURE;
623 break;
624 case 'p':
625 if (psxrules == NULL)
626 psxrules = optarg;
627 else {
628 fprintf(stderr,
629 _("%s: More than one -p option specified\n"),
630 progname);
631 return EXIT_FAILURE;
633 break;
634 case 'y':
635 if (yitcommand == NULL)
636 yitcommand = optarg;
637 else {
638 fprintf(stderr,
639 _("%s: More than one -y option specified\n"),
640 progname);
641 return EXIT_FAILURE;
643 break;
644 case 'L':
645 if (leapsec == NULL)
646 leapsec = optarg;
647 else {
648 fprintf(stderr,
649 _("%s: More than one -L option specified\n"),
650 progname);
651 return EXIT_FAILURE;
653 break;
654 case 'v':
655 noise = true;
656 break;
657 case 's':
658 warning(_("-s ignored"));
659 break;
661 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
662 usage(stderr, EXIT_FAILURE); /* usage message by request */
663 if (directory == NULL)
664 directory = TZDIR;
665 if (yitcommand == NULL)
666 yitcommand = "yearistype";
668 if (optind < argc && leapsec != NULL) {
669 infile(leapsec);
670 adjleap();
673 for (k = optind; k < argc; k++)
674 infile(argv[k]);
675 if (errors)
676 return EXIT_FAILURE;
677 associate();
678 change_directory(directory);
679 for (i = 0; i < nzones; i = j) {
681 ** Find the next non-continuation zone entry.
683 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
684 continue;
685 outzone(&zones[i], j - i);
688 ** Make links.
690 for (i = 0; i < nlinks; ++i) {
691 eat(links[i].l_filename, links[i].l_linenum);
692 dolink(links[i].l_from, links[i].l_to, false);
693 if (noise)
694 for (j = 0; j < nlinks; ++j)
695 if (strcmp(links[i].l_to,
696 links[j].l_from) == 0)
697 warning(_("link to link"));
699 if (lcltime != NULL) {
700 eat(_("command line"), 1);
701 dolink(lcltime, TZDEFAULT, true);
703 if (psxrules != NULL) {
704 eat(_("command line"), 1);
705 dolink(psxrules, TZDEFRULES, true);
707 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
708 return EXIT_FAILURE;
709 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
712 static bool
713 componentcheck(char const *name, char const *component,
714 char const *component_end)
716 enum { component_len_max = 14 };
717 ptrdiff_t component_len = component_end - component;
718 if (component_len == 0) {
719 if (!*name)
720 error (_("empty file name"));
721 else
722 error (_(component == name
723 ? "file name '%s' begins with '/'"
724 : *component_end
725 ? "file name '%s' contains '//'"
726 : "file name '%s' ends with '/'"),
727 name);
728 return false;
730 if (0 < component_len && component_len <= 2
731 && component[0] == '.' && component_end[-1] == '.') {
732 int len = component_len;
733 error(_("file name '%s' contains '%.*s' component"),
734 name, len, component);
735 return false;
737 if (noise) {
738 if (0 < component_len && component[0] == '-')
739 warning(_("file name '%s' component contains leading '-'"),
740 name);
741 if (component_len_max < component_len)
742 warning(_("file name '%s' contains overlength component"
743 " '%.*s...'"),
744 name, component_len_max, component);
746 return true;
749 static bool
750 namecheck(const char *name)
752 register char const *cp;
754 /* Benign characters in a portable file name. */
755 static char const benign[] =
756 "-/_"
757 "abcdefghijklmnopqrstuvwxyz"
758 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
760 /* Non-control chars in the POSIX portable character set,
761 excluding the benign characters. */
762 static char const printable_and_not_benign[] =
763 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
765 register char const *component = name;
766 for (cp = name; *cp; cp++) {
767 unsigned char c = *cp;
768 if (noise && !strchr(benign, c)) {
769 warning((strchr(printable_and_not_benign, c)
770 ? _("file name '%s' contains byte '%c'")
771 : _("file name '%s' contains byte '\\%o'")),
772 name, c);
774 if (c == '/') {
775 if (!componentcheck(name, component, cp))
776 return false;
777 component = cp + 1;
780 return componentcheck(name, component, cp);
783 /* Create symlink contents suitable for symlinking FROM to TO, as a
784 freshly allocated string. FROM should be a relative file name, and
785 is relative to the global variable DIRECTORY. TO can be either
786 relative or absolute. */
787 static char *
788 relname(char const *from, char const *to)
790 size_t i, taillen, dotdotetcsize;
791 size_t dir_len = 0, dotdots = 0, linksize = SIZE_MAX;
792 char const *f = from;
793 char *result = NULL;
794 if (*to == '/') {
795 /* Make F absolute too. */
796 size_t len = strlen(directory);
797 bool needslash = len && directory[len - 1] != '/';
798 linksize = len + needslash + strlen(from) + 1;
799 f = result = emalloc(linksize);
800 strcpy(result, directory);
801 result[len] = '/';
802 strcpy(result + len + needslash, from);
804 for (i = 0; f[i] && f[i] == to[i]; i++)
805 if (f[i] == '/')
806 dir_len = i + 1;
807 for (; to[i]; i++)
808 dotdots += to[i] == '/' && to[i - 1] != '/';
809 taillen = strlen(f + dir_len);
810 dotdotetcsize = 3 * dotdots + taillen + 1;
811 if (dotdotetcsize <= linksize) {
812 if (!result)
813 result = emalloc(dotdotetcsize);
814 for (i = 0; i < dotdots; i++)
815 memcpy(result + 3 * i, "../", 3);
816 memmove(result + 3 * dotdots, f + dir_len, taillen + 1);
818 return result;
821 /* Hard link FROM to TO, following any symbolic links.
822 Return 0 if successful, an error number otherwise. */
823 static int
824 hardlinkerr(char const *from, char const *to)
826 int r = linkat(AT_FDCWD, from, AT_FDCWD, to, AT_SYMLINK_FOLLOW);
827 return r == 0 ? 0 : errno;
830 static void
831 dolink(char const *fromfield, char const *tofield, bool staysymlink)
833 bool todirs_made = false;
834 int link_errno;
837 ** We get to be careful here since
838 ** there's a fair chance of root running us.
840 if (itsdir(fromfield)) {
841 fprintf(stderr, _("%s: link from %s/%s failed: %s\n"),
842 progname, directory, fromfield, strerror(EPERM));
843 exit(EXIT_FAILURE);
845 if (staysymlink)
846 staysymlink = itssymlink(tofield);
847 if (remove(tofield) == 0)
848 todirs_made = true;
849 else if (errno != ENOENT) {
850 char const *e = strerror(errno);
851 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
852 progname, directory, tofield, e);
853 exit(EXIT_FAILURE);
855 link_errno = staysymlink ? ENOTSUP : hardlinkerr(fromfield, tofield);
856 if (link_errno == ENOENT && !todirs_made) {
857 mkdirs(tofield, true);
858 todirs_made = true;
859 link_errno = hardlinkerr(fromfield, tofield);
861 if (link_errno != 0) {
862 bool absolute = *fromfield == '/';
863 char *linkalloc = absolute ? NULL : relname(fromfield, tofield);
864 char const *contents = absolute ? fromfield : linkalloc;
865 int symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
866 if (symlink_errno == ENOENT && !todirs_made) {
867 mkdirs(tofield, true);
868 symlink_errno = symlink(contents, tofield) == 0 ? 0 : errno;
870 free(linkalloc);
871 if (symlink_errno == 0) {
872 if (link_errno != ENOTSUP)
873 warning(_("symbolic link used because hard link failed: %s"),
874 strerror(link_errno));
875 } else {
876 FILE *fp, *tp;
877 int c;
878 fp = fopen(fromfield, "rb");
879 if (!fp) {
880 char const *e = strerror(errno);
881 fprintf(stderr, _("%s: Can't read %s/%s: %s\n"),
882 progname, directory, fromfield, e);
883 exit(EXIT_FAILURE);
885 tp = fopen(tofield, "wb");
886 if (!tp) {
887 char const *e = strerror(errno);
888 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
889 progname, directory, tofield, e);
890 exit(EXIT_FAILURE);
892 while ((c = getc(fp)) != EOF)
893 putc(c, tp);
894 close_file(fp, directory, fromfield);
895 close_file(tp, directory, tofield);
896 if (link_errno != ENOTSUP)
897 warning(_("copy used because hard link failed: %s"),
898 strerror(link_errno));
899 else if (symlink_errno != ENOTSUP)
900 warning(_("copy used because symbolic link failed: %s"),
901 strerror(symlink_errno));
906 #define TIME_T_BITS_IN_FILE 64
908 static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
909 static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
911 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
912 rounded downward to the negation of a power of two that is
913 comfortably outside the error bounds.
915 For the time of the Big Bang, see:
917 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
918 I. Overview of products and scientific results.
919 arXiv:1303.5062 2013-03-20 20:10:01 UTC
920 <http://arxiv.org/pdf/1303.5062v1> [PDF]
922 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
923 gives the value 13.798 plus-or-minus 0.037 billion years.
924 Multiplying this by 1000000000 and then by 31557600 (the number of
925 seconds in an astronomical year) gives a value that is comfortably
926 less than 2**59, so BIG_BANG is - 2**59.
928 BIG_BANG is approximate, and may change in future versions.
929 Please do not rely on its exact value. */
931 #ifndef BIG_BANG
932 #define BIG_BANG (- (1LL << 59))
933 #endif
935 /* If true, work around GNOME bug 730332
936 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
937 by refusing to output time stamps before BIG_BANG.
938 Such time stamps are physically suspect anyway.
940 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
941 this workaround will no longer be needed when GNOME 3.21 and
942 earlier are obsolete, say in the year 2021. */
943 enum { WORK_AROUND_GNOME_BUG_730332 = true };
945 static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
946 ? BIG_BANG
947 : MINVAL(zic_t, TIME_T_BITS_IN_FILE));
949 /* Return true if NAME is a directory. */
950 static bool
951 itsdir(char const *name)
953 struct stat st;
954 int res = stat(name, &st);
955 #ifdef S_ISDIR
956 if (res == 0)
957 return S_ISDIR(st.st_mode) != 0;
958 #endif
959 if (res == 0 || errno == EOVERFLOW) {
960 size_t n = strlen(name);
961 char *nameslashdot = emalloc(n + 3);
962 bool dir;
963 memcpy(nameslashdot, name, n);
964 strcpy(&nameslashdot[n], &"/."[! (n && name[n - 1] != '/')]);
965 dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
966 free(nameslashdot);
967 return dir;
969 return false;
972 /* Return true if NAME is a symbolic link. */
973 static bool
974 itssymlink(char const *name)
976 char c;
977 return 0 <= readlink(name, &c, 1);
981 ** Associate sets of rules with zones.
985 ** Sort by rule name.
988 static int
989 rcomp(const void *cp1, const void *cp2)
991 return strcmp(((const struct rule *) cp1)->r_name,
992 ((const struct rule *) cp2)->r_name);
995 static void
996 associate(void)
998 register struct zone * zp;
999 register struct rule * rp;
1000 register ptrdiff_t i, j, base, out;
1002 if (nrules != 0) {
1003 qsort(rules, nrules, sizeof *rules, rcomp);
1004 for (i = 0; i < nrules - 1; ++i) {
1005 if (strcmp(rules[i].r_name,
1006 rules[i + 1].r_name) != 0)
1007 continue;
1008 if (strcmp(rules[i].r_filename,
1009 rules[i + 1].r_filename) == 0)
1010 continue;
1011 eat(rules[i].r_filename, rules[i].r_linenum);
1012 warning(_("same rule name in multiple files"));
1013 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
1014 warning(_("same rule name in multiple files"));
1015 for (j = i + 2; j < nrules; ++j) {
1016 if (strcmp(rules[i].r_name,
1017 rules[j].r_name) != 0)
1018 break;
1019 if (strcmp(rules[i].r_filename,
1020 rules[j].r_filename) == 0)
1021 continue;
1022 if (strcmp(rules[i + 1].r_filename,
1023 rules[j].r_filename) == 0)
1024 continue;
1025 break;
1027 i = j - 1;
1030 for (i = 0; i < nzones; ++i) {
1031 zp = &zones[i];
1032 zp->z_rules = NULL;
1033 zp->z_nrules = 0;
1035 for (base = 0; base < nrules; base = out) {
1036 rp = &rules[base];
1037 for (out = base + 1; out < nrules; ++out)
1038 if (strcmp(rp->r_name, rules[out].r_name) != 0)
1039 break;
1040 for (i = 0; i < nzones; ++i) {
1041 zp = &zones[i];
1042 if (strcmp(zp->z_rule, rp->r_name) != 0)
1043 continue;
1044 zp->z_rules = rp;
1045 zp->z_nrules = out - base;
1048 for (i = 0; i < nzones; ++i) {
1049 zp = &zones[i];
1050 if (zp->z_nrules == 0) {
1052 ** Maybe we have a local standard time offset.
1054 eat(zp->z_filename, zp->z_linenum);
1055 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
1056 true);
1058 ** Note, though, that if there's no rule,
1059 ** a '%s' in the format is a bad thing.
1061 if (zp->z_format_specifier == 's')
1062 error("%s", _("%s in ruleless zone"));
1065 if (errors)
1066 exit(EXIT_FAILURE);
1069 static void
1070 infile(const char *name)
1072 register FILE * fp;
1073 register char ** fields;
1074 register char * cp;
1075 register const struct lookup * lp;
1076 register int nfields;
1077 register bool wantcont;
1078 register lineno num;
1079 char buf[BUFSIZ];
1081 if (strcmp(name, "-") == 0) {
1082 name = _("standard input");
1083 fp = stdin;
1084 } else if ((fp = fopen(name, "r")) == NULL) {
1085 const char *e = strerror(errno);
1087 fprintf(stderr, _("%s: Can't open %s: %s\n"),
1088 progname, name, e);
1089 exit(EXIT_FAILURE);
1091 wantcont = false;
1092 for (num = 1; ; ++num) {
1093 eat(name, num);
1094 if (fgets(buf, sizeof buf, fp) != buf)
1095 break;
1096 cp = strchr(buf, '\n');
1097 if (cp == NULL) {
1098 error(_("line too long"));
1099 exit(EXIT_FAILURE);
1101 *cp = '\0';
1102 fields = getfields(buf);
1103 nfields = 0;
1104 while (fields[nfields] != NULL) {
1105 static char nada;
1107 if (strcmp(fields[nfields], "-") == 0)
1108 fields[nfields] = &nada;
1109 ++nfields;
1111 if (nfields == 0) {
1112 /* nothing to do */
1113 } else if (wantcont) {
1114 wantcont = inzcont(fields, nfields);
1115 } else {
1116 lp = byword(fields[0], line_codes);
1117 if (lp == NULL)
1118 error(_("input line of unknown type"));
1119 else switch (lp->l_value) {
1120 case LC_RULE:
1121 inrule(fields, nfields);
1122 wantcont = false;
1123 break;
1124 case LC_ZONE:
1125 wantcont = inzone(fields, nfields);
1126 break;
1127 case LC_LINK:
1128 inlink(fields, nfields);
1129 wantcont = false;
1130 break;
1131 case LC_LEAP:
1132 if (name != leapsec)
1133 warning(_("%s: Leap line in non leap"
1134 " seconds file %s"),
1135 progname, name);
1136 else inleap(fields, nfields);
1137 wantcont = false;
1138 break;
1139 default: /* "cannot happen" */
1140 fprintf(stderr,
1141 _("%s: panic: Invalid l_value %d\n"),
1142 progname, lp->l_value);
1143 exit(EXIT_FAILURE);
1146 free(fields);
1148 close_file(fp, NULL, filename);
1149 if (wantcont)
1150 error(_("expected continuation line not found"));
1154 ** Convert a string of one of the forms
1155 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1156 ** into a number of seconds.
1157 ** A null string maps to zero.
1158 ** Call error with errstring and return zero on errors.
1161 static zic_t
1162 gethms(char const *string, char const *errstring, bool signable)
1164 zic_t hh;
1165 int mm, ss, sign;
1166 char xs;
1168 if (string == NULL || *string == '\0')
1169 return 0;
1170 if (!signable)
1171 sign = 1;
1172 else if (*string == '-') {
1173 sign = -1;
1174 ++string;
1175 } else sign = 1;
1176 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
1177 mm = ss = 0;
1178 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
1179 ss = 0;
1180 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
1181 != 3) {
1182 error("%s", errstring);
1183 return 0;
1185 if (hh < 0 ||
1186 mm < 0 || mm >= MINSPERHOUR ||
1187 ss < 0 || ss > SECSPERMIN) {
1188 error("%s", errstring);
1189 return 0;
1191 if (ZIC_MAX / SECSPERHOUR < hh) {
1192 error(_("time overflow"));
1193 return 0;
1195 if (noise && (hh > HOURSPERDAY ||
1196 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1197 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1198 return oadd(sign * hh * SECSPERHOUR,
1199 sign * (mm * SECSPERMIN + ss));
1202 static void
1203 inrule(char **fields, int nfields)
1205 static struct rule r;
1207 if (nfields != RULE_FIELDS) {
1208 error(_("wrong number of fields on Rule line"));
1209 return;
1211 if (*fields[RF_NAME] == '\0') {
1212 error(_("nameless rule"));
1213 return;
1215 r.r_filename = filename;
1216 r.r_linenum = linenum;
1217 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1218 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1219 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1220 r.r_name = ecpyalloc(fields[RF_NAME]);
1221 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1222 if (max_abbrvar_len < strlen(r.r_abbrvar))
1223 max_abbrvar_len = strlen(r.r_abbrvar);
1224 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1225 rules[nrules++] = r;
1228 static bool
1229 inzone(char **fields, int nfields)
1231 register ptrdiff_t i;
1233 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1234 error(_("wrong number of fields on Zone line"));
1235 return false;
1237 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1238 error(
1239 _("\"Zone %s\" line and -l option are mutually exclusive"),
1240 TZDEFAULT);
1241 return false;
1243 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1244 error(
1245 _("\"Zone %s\" line and -p option are mutually exclusive"),
1246 TZDEFRULES);
1247 return false;
1249 for (i = 0; i < nzones; ++i)
1250 if (zones[i].z_name != NULL &&
1251 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1252 error(_("duplicate zone name %s"
1253 " (file \"%s\", line %"PRIdLINENO")"),
1254 fields[ZF_NAME],
1255 zones[i].z_filename,
1256 zones[i].z_linenum);
1257 return false;
1259 return inzsub(fields, nfields, false);
1262 static bool
1263 inzcont(char **fields, int nfields)
1265 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1266 error(_("wrong number of fields on Zone continuation line"));
1267 return false;
1269 return inzsub(fields, nfields, true);
1272 static bool
1273 inzsub(char **fields, int nfields, bool iscont)
1275 register char * cp;
1276 char * cp1;
1277 static struct zone z;
1278 register int i_gmtoff, i_rule, i_format;
1279 register int i_untilyear, i_untilmonth;
1280 register int i_untilday, i_untiltime;
1281 register bool hasuntil;
1283 if (iscont) {
1284 i_gmtoff = ZFC_GMTOFF;
1285 i_rule = ZFC_RULE;
1286 i_format = ZFC_FORMAT;
1287 i_untilyear = ZFC_TILYEAR;
1288 i_untilmonth = ZFC_TILMONTH;
1289 i_untilday = ZFC_TILDAY;
1290 i_untiltime = ZFC_TILTIME;
1291 z.z_name = NULL;
1292 } else if (!namecheck(fields[ZF_NAME]))
1293 return false;
1294 else {
1295 i_gmtoff = ZF_GMTOFF;
1296 i_rule = ZF_RULE;
1297 i_format = ZF_FORMAT;
1298 i_untilyear = ZF_TILYEAR;
1299 i_untilmonth = ZF_TILMONTH;
1300 i_untilday = ZF_TILDAY;
1301 i_untiltime = ZF_TILTIME;
1302 z.z_name = ecpyalloc(fields[ZF_NAME]);
1304 z.z_filename = filename;
1305 z.z_linenum = linenum;
1306 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1307 if ((cp = strchr(fields[i_format], '%')) != 0) {
1308 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1309 || strchr(fields[i_format], '/')) {
1310 error(_("invalid abbreviation format"));
1311 return false;
1314 z.z_rule = ecpyalloc(fields[i_rule]);
1315 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1316 z.z_format_specifier = cp ? *cp : '\0';
1317 if (z.z_format_specifier == 'z') {
1318 if (noise)
1319 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1320 z.z_format);
1321 cp1[cp - fields[i_format]] = 's';
1323 if (max_format_len < strlen(z.z_format))
1324 max_format_len = strlen(z.z_format);
1325 hasuntil = nfields > i_untilyear;
1326 if (hasuntil) {
1327 z.z_untilrule.r_filename = filename;
1328 z.z_untilrule.r_linenum = linenum;
1329 rulesub(&z.z_untilrule,
1330 fields[i_untilyear],
1331 "only",
1333 (nfields > i_untilmonth) ?
1334 fields[i_untilmonth] : "Jan",
1335 (nfields > i_untilday) ? fields[i_untilday] : "1",
1336 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1337 z.z_untiltime = rpytime(&z.z_untilrule,
1338 z.z_untilrule.r_loyear);
1339 if (iscont && nzones > 0 &&
1340 z.z_untiltime > min_time &&
1341 z.z_untiltime < max_time &&
1342 zones[nzones - 1].z_untiltime > min_time &&
1343 zones[nzones - 1].z_untiltime < max_time &&
1344 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1345 error(_(
1346 "Zone continuation line end time is not after end time of previous line"
1348 return false;
1351 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1352 zones[nzones++] = z;
1354 ** If there was an UNTIL field on this line,
1355 ** there's more information about the zone on the next line.
1357 return hasuntil;
1360 static void
1361 inleap(char **fields, int nfields)
1363 register const char * cp;
1364 register const struct lookup * lp;
1365 register zic_t i, j;
1366 zic_t year;
1367 int month, day;
1368 zic_t dayoff, tod;
1369 zic_t t;
1370 char xs;
1372 if (nfields != LEAP_FIELDS) {
1373 error(_("wrong number of fields on Leap line"));
1374 return;
1376 dayoff = 0;
1377 cp = fields[LP_YEAR];
1378 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1380 ** Leapin' Lizards!
1382 error(_("invalid leaping year"));
1383 return;
1385 if (!leapseen || leapmaxyear < year)
1386 leapmaxyear = year;
1387 if (!leapseen || leapminyear > year)
1388 leapminyear = year;
1389 leapseen = true;
1390 j = EPOCH_YEAR;
1391 while (j != year) {
1392 if (year > j) {
1393 i = len_years[isleap(j)];
1394 ++j;
1395 } else {
1396 --j;
1397 i = -len_years[isleap(j)];
1399 dayoff = oadd(dayoff, i);
1401 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1402 error(_("invalid month name"));
1403 return;
1405 month = lp->l_value;
1406 j = TM_JANUARY;
1407 while (j != month) {
1408 i = len_months[isleap(year)][j];
1409 dayoff = oadd(dayoff, i);
1410 ++j;
1412 cp = fields[LP_DAY];
1413 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1414 day <= 0 || day > len_months[isleap(year)][month]) {
1415 error(_("invalid day of month"));
1416 return;
1418 dayoff = oadd(dayoff, day - 1);
1419 if (dayoff < min_time / SECSPERDAY) {
1420 error(_("time too small"));
1421 return;
1423 if (dayoff > max_time / SECSPERDAY) {
1424 error(_("time too large"));
1425 return;
1427 t = dayoff * SECSPERDAY;
1428 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1429 cp = fields[LP_CORR];
1431 register bool positive;
1432 int count;
1434 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1435 positive = false;
1436 count = 1;
1437 } else if (strcmp(cp, "--") == 0) {
1438 positive = false;
1439 count = 2;
1440 } else if (strcmp(cp, "+") == 0) {
1441 positive = true;
1442 count = 1;
1443 } else if (strcmp(cp, "++") == 0) {
1444 positive = true;
1445 count = 2;
1446 } else {
1447 error(_("illegal CORRECTION field on Leap line"));
1448 return;
1450 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1451 error(_(
1452 "illegal Rolling/Stationary field on Leap line"
1454 return;
1456 t = tadd(t, tod);
1457 if (t < early_time) {
1458 error(_("leap second precedes Big Bang"));
1459 return;
1461 leapadd(t, positive, lp->l_value, count);
1465 static void
1466 inlink(char **fields, int nfields)
1468 struct link l;
1470 if (nfields != LINK_FIELDS) {
1471 error(_("wrong number of fields on Link line"));
1472 return;
1474 if (*fields[LF_FROM] == '\0') {
1475 error(_("blank FROM field on Link line"));
1476 return;
1478 if (! namecheck(fields[LF_TO]))
1479 return;
1480 l.l_filename = filename;
1481 l.l_linenum = linenum;
1482 l.l_from = ecpyalloc(fields[LF_FROM]);
1483 l.l_to = ecpyalloc(fields[LF_TO]);
1484 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1485 links[nlinks++] = l;
1488 static void
1489 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1490 const char *typep, const char *monthp, const char *dayp,
1491 const char *timep)
1493 register const struct lookup * lp;
1494 register const char * cp;
1495 register char * dp;
1496 register char * ep;
1497 char xs;
1499 if ((lp = byword(monthp, mon_names)) == NULL) {
1500 error(_("invalid month name"));
1501 return;
1503 rp->r_month = lp->l_value;
1504 rp->r_todisstd = false;
1505 rp->r_todisgmt = false;
1506 dp = ecpyalloc(timep);
1507 if (*dp != '\0') {
1508 ep = dp + strlen(dp) - 1;
1509 switch (lowerit(*ep)) {
1510 case 's': /* Standard */
1511 rp->r_todisstd = true;
1512 rp->r_todisgmt = false;
1513 *ep = '\0';
1514 break;
1515 case 'w': /* Wall */
1516 rp->r_todisstd = false;
1517 rp->r_todisgmt = false;
1518 *ep = '\0';
1519 break;
1520 case 'g': /* Greenwich */
1521 case 'u': /* Universal */
1522 case 'z': /* Zulu */
1523 rp->r_todisstd = true;
1524 rp->r_todisgmt = true;
1525 *ep = '\0';
1526 break;
1529 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1530 free(dp);
1532 ** Year work.
1534 cp = loyearp;
1535 lp = byword(cp, begin_years);
1536 rp->r_lowasnum = lp == NULL;
1537 if (!rp->r_lowasnum) switch (lp->l_value) {
1538 case YR_MINIMUM:
1539 rp->r_loyear = ZIC_MIN;
1540 break;
1541 case YR_MAXIMUM:
1542 rp->r_loyear = ZIC_MAX;
1543 break;
1544 default: /* "cannot happen" */
1545 fprintf(stderr,
1546 _("%s: panic: Invalid l_value %d\n"),
1547 progname, lp->l_value);
1548 exit(EXIT_FAILURE);
1549 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1550 error(_("invalid starting year"));
1551 return;
1553 cp = hiyearp;
1554 lp = byword(cp, end_years);
1555 rp->r_hiwasnum = lp == NULL;
1556 if (!rp->r_hiwasnum) switch (lp->l_value) {
1557 case YR_MINIMUM:
1558 rp->r_hiyear = ZIC_MIN;
1559 break;
1560 case YR_MAXIMUM:
1561 rp->r_hiyear = ZIC_MAX;
1562 break;
1563 case YR_ONLY:
1564 rp->r_hiyear = rp->r_loyear;
1565 break;
1566 default: /* "cannot happen" */
1567 fprintf(stderr,
1568 _("%s: panic: Invalid l_value %d\n"),
1569 progname, lp->l_value);
1570 exit(EXIT_FAILURE);
1571 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1572 error(_("invalid ending year"));
1573 return;
1575 if (rp->r_loyear > rp->r_hiyear) {
1576 error(_("starting year greater than ending year"));
1577 return;
1579 if (*typep == '\0')
1580 rp->r_yrtype = NULL;
1581 else {
1582 if (rp->r_loyear == rp->r_hiyear) {
1583 error(_("typed single year"));
1584 return;
1586 rp->r_yrtype = ecpyalloc(typep);
1589 ** Day work.
1590 ** Accept things such as:
1591 ** 1
1592 ** last-Sunday
1593 ** Sun<=20
1594 ** Sun>=7
1596 dp = ecpyalloc(dayp);
1597 if ((lp = byword(dp, lasts)) != NULL) {
1598 rp->r_dycode = DC_DOWLEQ;
1599 rp->r_wday = lp->l_value;
1600 rp->r_dayofmonth = len_months[1][rp->r_month];
1601 } else {
1602 if ((ep = strchr(dp, '<')) != 0)
1603 rp->r_dycode = DC_DOWLEQ;
1604 else if ((ep = strchr(dp, '>')) != 0)
1605 rp->r_dycode = DC_DOWGEQ;
1606 else {
1607 ep = dp;
1608 rp->r_dycode = DC_DOM;
1610 if (rp->r_dycode != DC_DOM) {
1611 *ep++ = 0;
1612 if (*ep++ != '=') {
1613 error(_("invalid day of month"));
1614 free(dp);
1615 return;
1617 if ((lp = byword(dp, wday_names)) == NULL) {
1618 error(_("invalid weekday name"));
1619 free(dp);
1620 return;
1622 rp->r_wday = lp->l_value;
1624 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1625 rp->r_dayofmonth <= 0 ||
1626 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1627 error(_("invalid day of month"));
1628 free(dp);
1629 return;
1632 free(dp);
1635 static void
1636 convert(const int_fast32_t val, char *const buf)
1638 register int i;
1639 register int shift;
1640 unsigned char *const b = (unsigned char *) buf;
1642 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1643 b[i] = val >> shift;
1646 static void
1647 convert64(const zic_t val, char *const buf)
1649 register int i;
1650 register int shift;
1651 unsigned char *const b = (unsigned char *) buf;
1653 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1654 b[i] = val >> shift;
1657 static void
1658 puttzcode(const int_fast32_t val, FILE *const fp)
1660 char buf[4];
1662 convert(val, buf);
1663 fwrite(buf, sizeof buf, 1, fp);
1666 static void
1667 puttzcode64(const zic_t val, FILE *const fp)
1669 char buf[8];
1671 convert64(val, buf);
1672 fwrite(buf, sizeof buf, 1, fp);
1675 static int
1676 atcomp(const void *avp, const void *bvp)
1678 const zic_t a = ((const struct attype *) avp)->at;
1679 const zic_t b = ((const struct attype *) bvp)->at;
1681 return (a < b) ? -1 : (a > b);
1684 static bool
1685 is32(const zic_t x)
1687 return INT32_MIN <= x && x <= INT32_MAX;
1690 static void
1691 writezone(const char *const name, const char *const string, char version)
1693 register FILE * fp;
1694 register ptrdiff_t i, j;
1695 register int leapcnt32, leapi32;
1696 register ptrdiff_t timecnt32, timei32;
1697 register int pass;
1698 static const struct tzhead tzh0;
1699 static struct tzhead tzh;
1700 bool dir_checked = false;
1701 zic_t one = 1;
1702 zic_t y2038_boundary = one << 31;
1703 ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
1704 zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
1705 void *typesptr = ats + nats;
1706 unsigned char *types = typesptr;
1709 ** Sort.
1711 if (timecnt > 1)
1712 qsort(attypes, timecnt, sizeof *attypes, atcomp);
1714 ** Optimize.
1717 ptrdiff_t fromi, toi;
1719 toi = 0;
1720 fromi = 0;
1721 while (fromi < timecnt && attypes[fromi].at < early_time)
1722 ++fromi;
1723 for ( ; fromi < timecnt; ++fromi) {
1724 if (toi > 1 && ((attypes[fromi].at +
1725 gmtoffs[attypes[toi - 1].type]) <=
1726 (attypes[toi - 1].at +
1727 gmtoffs[attypes[toi - 2].type]))) {
1728 attypes[toi - 1].type =
1729 attypes[fromi].type;
1730 continue;
1732 if (toi == 0
1733 || attypes[fromi].dontmerge
1734 || attypes[toi - 1].type != attypes[fromi].type)
1735 attypes[toi++] = attypes[fromi];
1737 timecnt = toi;
1740 if (noise && timecnt > 1200) {
1741 if (timecnt > TZ_MAX_TIMES)
1742 warning(_("reference clients mishandle"
1743 " more than %d transition times"),
1744 TZ_MAX_TIMES);
1745 else
1746 warning(_("pre-2014 clients may mishandle"
1747 " more than 1200 transition times"));
1750 ** Transfer.
1752 for (i = 0; i < timecnt; ++i) {
1753 ats[i] = attypes[i].at;
1754 types[i] = attypes[i].type;
1757 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1758 by inserting a no-op transition at time y2038_boundary - 1.
1759 This works only for timestamps before the boundary, which
1760 should be good enough in practice as QTBUG-53071 should be
1761 long-dead by 2038. */
1762 if (WORK_AROUND_QTBUG_53071 && timecnt != 0
1763 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
1764 ats[timecnt] = y2038_boundary - 1;
1765 types[timecnt] = types[timecnt - 1];
1766 timecnt++;
1770 ** Correct for leap seconds.
1772 for (i = 0; i < timecnt; ++i) {
1773 j = leapcnt;
1774 while (--j >= 0)
1775 if (ats[i] > trans[j] - corr[j]) {
1776 ats[i] = tadd(ats[i], corr[j]);
1777 break;
1781 ** Figure out 32-bit-limited starts and counts.
1783 timecnt32 = timecnt;
1784 timei32 = 0;
1785 leapcnt32 = leapcnt;
1786 leapi32 = 0;
1787 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1788 --timecnt32;
1789 while (timecnt32 > 0 && !is32(ats[timei32])) {
1790 --timecnt32;
1791 ++timei32;
1794 ** Output an INT32_MIN "transition" if appropriate; see below.
1796 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1797 --timei32;
1798 ++timecnt32;
1800 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1801 --leapcnt32;
1802 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1803 --leapcnt32;
1804 ++leapi32;
1807 ** Remove old file, if any, to snap links.
1809 if (remove(name) == 0)
1810 dir_checked = true;
1811 else if (errno != ENOENT) {
1812 const char *e = strerror(errno);
1814 fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"),
1815 progname, directory, name, e);
1816 exit(EXIT_FAILURE);
1818 fp = fopen(name, "wb");
1819 if (!fp) {
1820 int fopen_errno = errno;
1821 if (fopen_errno == ENOENT && !dir_checked) {
1822 mkdirs(name, true);
1823 fp = fopen(name, "wb");
1824 fopen_errno = errno;
1826 if (!fp) {
1827 fprintf(stderr, _("%s: Can't create %s/%s: %s\n"),
1828 progname, directory, name, strerror(fopen_errno));
1829 exit(EXIT_FAILURE);
1832 for (pass = 1; pass <= 2; ++pass) {
1833 register ptrdiff_t thistimei, thistimecnt, thistimelim;
1834 register int thisleapi, thisleapcnt, thisleaplim;
1835 int writetype[TZ_MAX_TYPES];
1836 int typemap[TZ_MAX_TYPES];
1837 register int thistypecnt;
1838 char thischars[TZ_MAX_CHARS];
1839 int thischarcnt;
1840 bool toomanytimes;
1841 int indmap[TZ_MAX_CHARS];
1843 if (pass == 1) {
1844 thistimei = timei32;
1845 thistimecnt = timecnt32;
1846 toomanytimes = thistimecnt >> 31 >> 1 != 0;
1847 thisleapi = leapi32;
1848 thisleapcnt = leapcnt32;
1849 } else {
1850 thistimei = 0;
1851 thistimecnt = timecnt;
1852 toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
1853 thisleapi = 0;
1854 thisleapcnt = leapcnt;
1856 if (toomanytimes)
1857 error(_("too many transition times"));
1858 thistimelim = thistimei + thistimecnt;
1859 thisleaplim = thisleapi + thisleapcnt;
1860 for (i = 0; i < typecnt; ++i)
1861 writetype[i] = thistimecnt == timecnt;
1862 if (thistimecnt == 0) {
1864 ** No transition times fall in the current
1865 ** (32- or 64-bit) window.
1867 if (typecnt != 0)
1868 writetype[typecnt - 1] = true;
1869 } else {
1870 for (i = thistimei - 1; i < thistimelim; ++i)
1871 if (i >= 0)
1872 writetype[types[i]] = true;
1874 ** For America/Godthab and Antarctica/Palmer
1876 if (thistimei == 0)
1877 writetype[0] = true;
1879 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1881 ** For some pre-2011 systems: if the last-to-be-written
1882 ** standard (or daylight) type has an offset different from the
1883 ** most recently used offset,
1884 ** append an (unused) copy of the most recently used type
1885 ** (to help get global "altzone" and "timezone" variables
1886 ** set correctly).
1889 register int mrudst, mrustd, hidst, histd, type;
1891 hidst = histd = mrudst = mrustd = -1;
1892 for (i = thistimei; i < thistimelim; ++i)
1893 if (isdsts[types[i]])
1894 mrudst = types[i];
1895 else mrustd = types[i];
1896 for (i = 0; i < typecnt; ++i)
1897 if (writetype[i]) {
1898 if (isdsts[i])
1899 hidst = i;
1900 else histd = i;
1902 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1903 gmtoffs[hidst] != gmtoffs[mrudst]) {
1904 isdsts[mrudst] = -1;
1905 type = addtype(gmtoffs[mrudst],
1906 &chars[abbrinds[mrudst]],
1907 true,
1908 ttisstds[mrudst],
1909 ttisgmts[mrudst]);
1910 isdsts[mrudst] = 1;
1911 writetype[type] = true;
1913 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1914 gmtoffs[histd] != gmtoffs[mrustd]) {
1915 isdsts[mrustd] = -1;
1916 type = addtype(gmtoffs[mrustd],
1917 &chars[abbrinds[mrustd]],
1918 false,
1919 ttisstds[mrustd],
1920 ttisgmts[mrustd]);
1921 isdsts[mrustd] = 0;
1922 writetype[type] = true;
1925 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1926 thistypecnt = 0;
1927 for (i = 0; i < typecnt; ++i)
1928 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1929 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1930 indmap[i] = -1;
1931 thischarcnt = 0;
1932 for (i = 0; i < typecnt; ++i) {
1933 register char * thisabbr;
1935 if (!writetype[i])
1936 continue;
1937 if (indmap[abbrinds[i]] >= 0)
1938 continue;
1939 thisabbr = &chars[abbrinds[i]];
1940 for (j = 0; j < thischarcnt; ++j)
1941 if (strcmp(&thischars[j], thisabbr) == 0)
1942 break;
1943 if (j == thischarcnt) {
1944 strcpy(&thischars[thischarcnt], thisabbr);
1945 thischarcnt += strlen(thisabbr) + 1;
1947 indmap[abbrinds[i]] = j;
1949 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1950 tzh = tzh0;
1951 strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1952 tzh.tzh_version[0] = version;
1953 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1954 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1955 convert(thisleapcnt, tzh.tzh_leapcnt);
1956 convert(thistimecnt, tzh.tzh_timecnt);
1957 convert(thistypecnt, tzh.tzh_typecnt);
1958 convert(thischarcnt, tzh.tzh_charcnt);
1959 DO(tzh_magic);
1960 DO(tzh_version);
1961 DO(tzh_reserved);
1962 DO(tzh_ttisgmtcnt);
1963 DO(tzh_ttisstdcnt);
1964 DO(tzh_leapcnt);
1965 DO(tzh_timecnt);
1966 DO(tzh_typecnt);
1967 DO(tzh_charcnt);
1968 #undef DO
1969 for (i = thistimei; i < thistimelim; ++i)
1970 if (pass == 1)
1972 ** Output an INT32_MIN "transition"
1973 ** if appropriate; see above.
1975 puttzcode(((ats[i] < INT32_MIN) ?
1976 INT32_MIN : ats[i]), fp);
1977 else puttzcode64(ats[i], fp);
1978 for (i = thistimei; i < thistimelim; ++i) {
1979 unsigned char uc;
1981 uc = typemap[types[i]];
1982 fwrite(&uc, sizeof uc, 1, fp);
1984 for (i = 0; i < typecnt; ++i)
1985 if (writetype[i]) {
1986 puttzcode(gmtoffs[i], fp);
1987 putc(isdsts[i], fp);
1988 putc((unsigned char) indmap[abbrinds[i]], fp);
1990 if (thischarcnt != 0)
1991 fwrite(thischars, sizeof thischars[0],
1992 thischarcnt, fp);
1993 for (i = thisleapi; i < thisleaplim; ++i) {
1994 register zic_t todo;
1996 if (roll[i]) {
1997 if (timecnt == 0 || trans[i] < ats[0]) {
1998 j = 0;
1999 while (isdsts[j])
2000 if (++j >= typecnt) {
2001 j = 0;
2002 break;
2004 } else {
2005 j = 1;
2006 while (j < timecnt &&
2007 trans[i] >= ats[j])
2008 ++j;
2009 j = types[j - 1];
2011 todo = tadd(trans[i], -gmtoffs[j]);
2012 } else todo = trans[i];
2013 if (pass == 1)
2014 puttzcode(todo, fp);
2015 else puttzcode64(todo, fp);
2016 puttzcode(corr[i], fp);
2018 for (i = 0; i < typecnt; ++i)
2019 if (writetype[i])
2020 putc(ttisstds[i], fp);
2021 for (i = 0; i < typecnt; ++i)
2022 if (writetype[i])
2023 putc(ttisgmts[i], fp);
2025 fprintf(fp, "\n%s\n", string);
2026 close_file(fp, directory, name);
2027 free(ats);
2030 static char const *
2031 abbroffset(char *buf, zic_t offset)
2033 char sign = '+';
2034 int seconds, minutes;
2036 if (offset < 0) {
2037 offset = -offset;
2038 sign = '-';
2041 seconds = offset % SECSPERMIN;
2042 offset /= SECSPERMIN;
2043 minutes = offset % MINSPERHOUR;
2044 offset /= MINSPERHOUR;
2045 if (100 <= offset) {
2046 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
2047 return "%z";
2048 } else {
2049 char *p = buf;
2050 *p++ = sign;
2051 *p++ = '0' + offset / 10;
2052 *p++ = '0' + offset % 10;
2053 if (minutes | seconds) {
2054 *p++ = '0' + minutes / 10;
2055 *p++ = '0' + minutes % 10;
2056 if (seconds) {
2057 *p++ = '0' + seconds / 10;
2058 *p++ = '0' + seconds % 10;
2061 *p = '\0';
2062 return buf;
2066 static size_t
2067 doabbr(char *abbr, struct zone const *zp, char const *letters,
2068 zic_t stdoff, bool doquotes)
2070 register char * cp;
2071 register char * slashp;
2072 register size_t len;
2073 char const *format = zp->z_format;
2075 slashp = strchr(format, '/');
2076 if (slashp == NULL) {
2077 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
2078 if (zp->z_format_specifier == 'z')
2079 letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
2080 else if (!letters)
2081 letters = "%s";
2082 sprintf(abbr, format, letters);
2083 } else if (stdoff != 0) {
2084 strcpy(abbr, slashp + 1);
2085 } else {
2086 memcpy(abbr, format, slashp - format);
2087 abbr[slashp - format] = '\0';
2089 len = strlen(abbr);
2090 if (!doquotes)
2091 return len;
2092 for (cp = abbr; is_alpha(*cp); cp++)
2093 continue;
2094 if (len > 0 && *cp == '\0')
2095 return len;
2096 abbr[len + 2] = '\0';
2097 abbr[len + 1] = '>';
2098 memmove(abbr + 1, abbr, len);
2099 abbr[0] = '<';
2100 return len + 2;
2103 static void
2104 updateminmax(const zic_t x)
2106 if (min_year > x)
2107 min_year = x;
2108 if (max_year < x)
2109 max_year = x;
2112 static int
2113 stringoffset(char *result, zic_t offset)
2115 register int hours;
2116 register int minutes;
2117 register int seconds;
2118 bool negative = offset < 0;
2119 int len = negative;
2121 if (negative) {
2122 offset = -offset;
2123 result[0] = '-';
2125 seconds = offset % SECSPERMIN;
2126 offset /= SECSPERMIN;
2127 minutes = offset % MINSPERHOUR;
2128 offset /= MINSPERHOUR;
2129 hours = offset;
2130 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2131 result[0] = '\0';
2132 return 0;
2134 len += sprintf(result + len, "%d", hours);
2135 if (minutes != 0 || seconds != 0) {
2136 len += sprintf(result + len, ":%02d", minutes);
2137 if (seconds != 0)
2138 len += sprintf(result + len, ":%02d", seconds);
2140 return len;
2143 static int
2144 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2145 const zic_t gmtoff)
2147 register zic_t tod = rp->r_tod;
2148 register int compat = 0;
2150 if (rp->r_dycode == DC_DOM) {
2151 register int month, total;
2153 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2154 return -1;
2155 total = 0;
2156 for (month = 0; month < rp->r_month; ++month)
2157 total += len_months[0][month];
2158 /* Omit the "J" in Jan and Feb, as that's shorter. */
2159 if (rp->r_month <= 1)
2160 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2161 else
2162 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2163 } else {
2164 register int week;
2165 register int wday = rp->r_wday;
2166 register int wdayoff;
2168 if (rp->r_dycode == DC_DOWGEQ) {
2169 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2170 if (wdayoff)
2171 compat = 2013;
2172 wday -= wdayoff;
2173 tod += wdayoff * SECSPERDAY;
2174 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2175 } else if (rp->r_dycode == DC_DOWLEQ) {
2176 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2177 week = 5;
2178 else {
2179 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2180 if (wdayoff)
2181 compat = 2013;
2182 wday -= wdayoff;
2183 tod += wdayoff * SECSPERDAY;
2184 week = rp->r_dayofmonth / DAYSPERWEEK;
2186 } else return -1; /* "cannot happen" */
2187 if (wday < 0)
2188 wday += DAYSPERWEEK;
2189 result += sprintf(result, "M%d.%d.%d",
2190 rp->r_month + 1, week, wday);
2192 if (rp->r_todisgmt)
2193 tod += gmtoff;
2194 if (rp->r_todisstd && rp->r_stdoff == 0)
2195 tod += dstoff;
2196 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2197 *result++ = '/';
2198 if (! stringoffset(result, tod))
2199 return -1;
2200 if (tod < 0) {
2201 if (compat < 2013)
2202 compat = 2013;
2203 } else if (SECSPERDAY <= tod) {
2204 if (compat < 1994)
2205 compat = 1994;
2208 return compat;
2211 static int
2212 rule_cmp(struct rule const *a, struct rule const *b)
2214 if (!a)
2215 return -!!b;
2216 if (!b)
2217 return 1;
2218 if (a->r_hiyear != b->r_hiyear)
2219 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2220 if (a->r_month - b->r_month != 0)
2221 return a->r_month - b->r_month;
2222 return a->r_dayofmonth - b->r_dayofmonth;
2225 enum { YEAR_BY_YEAR_ZONE = 1 };
2227 static int
2228 stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
2230 register const struct zone * zp;
2231 register struct rule * rp;
2232 register struct rule * stdrp;
2233 register struct rule * dstrp;
2234 register ptrdiff_t i;
2235 register const char * abbrvar;
2236 register int compat = 0;
2237 register int c;
2238 size_t len;
2239 int offsetlen;
2240 struct rule stdr, dstr;
2242 result[0] = '\0';
2243 zp = zpfirst + zonecount - 1;
2244 stdrp = dstrp = NULL;
2245 for (i = 0; i < zp->z_nrules; ++i) {
2246 rp = &zp->z_rules[i];
2247 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2248 continue;
2249 if (rp->r_yrtype != NULL)
2250 continue;
2251 if (rp->r_stdoff == 0) {
2252 if (stdrp == NULL)
2253 stdrp = rp;
2254 else return -1;
2255 } else {
2256 if (dstrp == NULL)
2257 dstrp = rp;
2258 else return -1;
2261 if (stdrp == NULL && dstrp == NULL) {
2263 ** There are no rules running through "max".
2264 ** Find the latest std rule in stdabbrrp
2265 ** and latest rule of any type in stdrp.
2267 register struct rule *stdabbrrp = NULL;
2268 for (i = 0; i < zp->z_nrules; ++i) {
2269 rp = &zp->z_rules[i];
2270 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2271 stdabbrrp = rp;
2272 if (rule_cmp(stdrp, rp) < 0)
2273 stdrp = rp;
2276 ** Horrid special case: if year is 2037,
2277 ** presume this is a zone handled on a year-by-year basis;
2278 ** do not try to apply a rule to the zone.
2280 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2281 return YEAR_BY_YEAR_ZONE;
2283 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2284 /* Perpetual DST. */
2285 dstr.r_month = TM_JANUARY;
2286 dstr.r_dycode = DC_DOM;
2287 dstr.r_dayofmonth = 1;
2288 dstr.r_tod = 0;
2289 dstr.r_todisstd = dstr.r_todisgmt = false;
2290 dstr.r_stdoff = stdrp->r_stdoff;
2291 dstr.r_abbrvar = stdrp->r_abbrvar;
2292 stdr.r_month = TM_DECEMBER;
2293 stdr.r_dycode = DC_DOM;
2294 stdr.r_dayofmonth = 31;
2295 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2296 stdr.r_todisstd = stdr.r_todisgmt = false;
2297 stdr.r_stdoff = 0;
2298 stdr.r_abbrvar
2299 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2300 dstrp = &dstr;
2301 stdrp = &stdr;
2304 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2305 return -1;
2306 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2307 len = doabbr(result, zp, abbrvar, 0, true);
2308 offsetlen = stringoffset(result + len, -zp->z_gmtoff);
2309 if (! offsetlen) {
2310 result[0] = '\0';
2311 return -1;
2313 len += offsetlen;
2314 if (dstrp == NULL)
2315 return compat;
2316 len += doabbr(result + len, zp, dstrp->r_abbrvar, dstrp->r_stdoff, true);
2317 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
2318 offsetlen = stringoffset(result + len,
2319 -(zp->z_gmtoff + dstrp->r_stdoff));
2320 if (! offsetlen) {
2321 result[0] = '\0';
2322 return -1;
2324 len += offsetlen;
2326 result[len++] = ',';
2327 c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2328 if (c < 0) {
2329 result[0] = '\0';
2330 return -1;
2332 if (compat < c)
2333 compat = c;
2334 len += strlen(result + len);
2335 result[len++] = ',';
2336 c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2337 if (c < 0) {
2338 result[0] = '\0';
2339 return -1;
2341 if (compat < c)
2342 compat = c;
2343 return compat;
2346 static void
2347 outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
2349 register const struct zone * zp;
2350 register struct rule * rp;
2351 register ptrdiff_t i, j;
2352 register bool usestart, useuntil;
2353 register zic_t starttime, untiltime;
2354 register zic_t gmtoff;
2355 register zic_t stdoff;
2356 register zic_t year;
2357 register zic_t startoff;
2358 register bool startttisstd;
2359 register bool startttisgmt;
2360 register int type;
2361 register char * startbuf;
2362 register char * ab;
2363 register char * envvar;
2364 register int max_abbr_len;
2365 register int max_envvar_len;
2366 register bool prodstic; /* all rules are min to max */
2367 register int compat;
2368 register bool do_extend;
2369 register char version;
2370 ptrdiff_t lastatmax = -1;
2371 zic_t one = 1;
2372 zic_t y2038_boundary = one << 31;
2373 zic_t max_year0;
2375 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2376 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2377 startbuf = emalloc(max_abbr_len + 1);
2378 ab = emalloc(max_abbr_len + 1);
2379 envvar = emalloc(max_envvar_len + 1);
2380 INITIALIZE(untiltime);
2381 INITIALIZE(starttime);
2383 ** Now. . .finally. . .generate some useful data!
2385 timecnt = 0;
2386 typecnt = 0;
2387 charcnt = 0;
2388 prodstic = zonecount == 1;
2390 ** Thanks to Earl Chew
2391 ** for noting the need to unconditionally initialize startttisstd.
2393 startttisstd = false;
2394 startttisgmt = false;
2395 min_year = max_year = EPOCH_YEAR;
2396 if (leapseen) {
2397 updateminmax(leapminyear);
2398 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2400 for (i = 0; i < zonecount; ++i) {
2401 zp = &zpfirst[i];
2402 if (i < zonecount - 1)
2403 updateminmax(zp->z_untilrule.r_loyear);
2404 for (j = 0; j < zp->z_nrules; ++j) {
2405 rp = &zp->z_rules[j];
2406 if (rp->r_lowasnum)
2407 updateminmax(rp->r_loyear);
2408 if (rp->r_hiwasnum)
2409 updateminmax(rp->r_hiyear);
2410 if (rp->r_lowasnum || rp->r_hiwasnum)
2411 prodstic = false;
2415 ** Generate lots of data if a rule can't cover all future times.
2417 compat = stringzone(envvar, zpfirst, zonecount);
2418 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2419 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2420 if (noise) {
2421 if (!*envvar)
2422 warning("%s %s",
2423 _("no POSIX environment variable for zone"),
2424 zpfirst->z_name);
2425 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2426 /* Circa-COMPAT clients, and earlier clients, might
2427 not work for this zone when given dates before
2428 1970 or after 2038. */
2429 warning(_("%s: pre-%d clients may mishandle"
2430 " distant timestamps"),
2431 zpfirst->z_name, compat);
2434 if (do_extend) {
2436 ** Search through a couple of extra years past the obvious
2437 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2438 ** rule applies from 2012 onwards and has transitions in March
2439 ** and September, plus some one-off transitions in November
2440 ** 2013. If zic looked only at the last 400 years, it would
2441 ** set max_year=2413, with the intent that the 400 years 2014
2442 ** through 2413 will be repeated. The last transition listed
2443 ** in the tzfile would be in 2413-09, less than 400 years
2444 ** after the last one-off transition in 2013-11. Two years
2445 ** might be overkill, but with the kind of edge cases
2446 ** available we're not sure that one year would suffice.
2448 enum { years_of_observations = YEARSPERREPEAT + 2 };
2450 if (min_year >= ZIC_MIN + years_of_observations)
2451 min_year -= years_of_observations;
2452 else min_year = ZIC_MIN;
2453 if (max_year <= ZIC_MAX - years_of_observations)
2454 max_year += years_of_observations;
2455 else max_year = ZIC_MAX;
2457 ** Regardless of any of the above,
2458 ** for a "proDSTic" zone which specifies that its rules
2459 ** always have and always will be in effect,
2460 ** we only need one cycle to define the zone.
2462 if (prodstic) {
2463 min_year = 1900;
2464 max_year = min_year + years_of_observations;
2468 ** For the benefit of older systems,
2469 ** generate data from 1900 through 2038.
2471 if (min_year > 1900)
2472 min_year = 1900;
2473 max_year0 = max_year;
2474 if (max_year < 2038)
2475 max_year = 2038;
2476 for (i = 0; i < zonecount; ++i) {
2478 ** A guess that may well be corrected later.
2480 stdoff = 0;
2481 zp = &zpfirst[i];
2482 usestart = i > 0 && (zp - 1)->z_untiltime > early_time;
2483 useuntil = i < (zonecount - 1);
2484 if (useuntil && zp->z_untiltime <= early_time)
2485 continue;
2486 gmtoff = zp->z_gmtoff;
2487 eat(zp->z_filename, zp->z_linenum);
2488 *startbuf = '\0';
2489 startoff = zp->z_gmtoff;
2490 if (zp->z_nrules == 0) {
2491 stdoff = zp->z_stdoff;
2492 doabbr(startbuf, zp, NULL, stdoff, false);
2493 type = addtype(oadd(zp->z_gmtoff, stdoff),
2494 startbuf, stdoff != 0, startttisstd,
2495 startttisgmt);
2496 if (usestart) {
2497 addtt(starttime, type);
2498 usestart = false;
2499 } else addtt(early_time, type);
2500 } else for (year = min_year; year <= max_year; ++year) {
2501 if (useuntil && year > zp->z_untilrule.r_hiyear)
2502 break;
2504 ** Mark which rules to do in the current year.
2505 ** For those to do, calculate rpytime(rp, year);
2507 for (j = 0; j < zp->z_nrules; ++j) {
2508 rp = &zp->z_rules[j];
2509 eats(zp->z_filename, zp->z_linenum,
2510 rp->r_filename, rp->r_linenum);
2511 rp->r_todo = year >= rp->r_loyear &&
2512 year <= rp->r_hiyear &&
2513 yearistype(year, rp->r_yrtype);
2514 if (rp->r_todo) {
2515 rp->r_temp = rpytime(rp, year);
2516 rp->r_todo
2517 = (rp->r_temp < y2038_boundary
2518 || year <= max_year0);
2521 for ( ; ; ) {
2522 register ptrdiff_t k;
2523 register zic_t jtime, ktime;
2524 register zic_t offset;
2526 INITIALIZE(ktime);
2527 if (useuntil) {
2529 ** Turn untiltime into UT
2530 ** assuming the current gmtoff and
2531 ** stdoff values.
2533 untiltime = zp->z_untiltime;
2534 if (!zp->z_untilrule.r_todisgmt)
2535 untiltime = tadd(untiltime,
2536 -gmtoff);
2537 if (!zp->z_untilrule.r_todisstd)
2538 untiltime = tadd(untiltime,
2539 -stdoff);
2542 ** Find the rule (of those to do, if any)
2543 ** that takes effect earliest in the year.
2545 k = -1;
2546 for (j = 0; j < zp->z_nrules; ++j) {
2547 rp = &zp->z_rules[j];
2548 if (!rp->r_todo)
2549 continue;
2550 eats(zp->z_filename, zp->z_linenum,
2551 rp->r_filename, rp->r_linenum);
2552 offset = rp->r_todisgmt ? 0 : gmtoff;
2553 if (!rp->r_todisstd)
2554 offset = oadd(offset, stdoff);
2555 jtime = rp->r_temp;
2556 if (jtime == min_time ||
2557 jtime == max_time)
2558 continue;
2559 jtime = tadd(jtime, -offset);
2560 if (k < 0 || jtime < ktime) {
2561 k = j;
2562 ktime = jtime;
2563 } else if (jtime == ktime) {
2564 char const *dup_rules_msg =
2565 _("two rules for same instant");
2566 eats(zp->z_filename, zp->z_linenum,
2567 rp->r_filename, rp->r_linenum);
2568 warning("%s", dup_rules_msg);
2569 rp = &zp->z_rules[k];
2570 eats(zp->z_filename, zp->z_linenum,
2571 rp->r_filename, rp->r_linenum);
2572 error("%s", dup_rules_msg);
2575 if (k < 0)
2576 break; /* go on to next year */
2577 rp = &zp->z_rules[k];
2578 rp->r_todo = false;
2579 if (useuntil && ktime >= untiltime)
2580 break;
2581 stdoff = rp->r_stdoff;
2582 if (usestart && ktime == starttime)
2583 usestart = false;
2584 if (usestart) {
2585 if (ktime < starttime) {
2586 startoff = oadd(zp->z_gmtoff,
2587 stdoff);
2588 doabbr(startbuf, zp,
2589 rp->r_abbrvar,
2590 rp->r_stdoff,
2591 false);
2592 continue;
2594 if (*startbuf == '\0' &&
2595 startoff == oadd(zp->z_gmtoff,
2596 stdoff)) {
2597 doabbr(startbuf,
2599 rp->r_abbrvar,
2600 rp->r_stdoff,
2601 false);
2604 eats(zp->z_filename, zp->z_linenum,
2605 rp->r_filename, rp->r_linenum);
2606 doabbr(ab, zp, rp->r_abbrvar,
2607 rp->r_stdoff, false);
2608 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2609 type = addtype(offset, ab, rp->r_stdoff != 0,
2610 rp->r_todisstd, rp->r_todisgmt);
2611 if (rp->r_hiyear == ZIC_MAX
2612 && ! (0 <= lastatmax
2613 && ktime < attypes[lastatmax].at))
2614 lastatmax = timecnt;
2615 addtt(ktime, type);
2618 if (usestart) {
2619 if (*startbuf == '\0' &&
2620 zp->z_format != NULL &&
2621 strchr(zp->z_format, '%') == NULL &&
2622 strchr(zp->z_format, '/') == NULL)
2623 strcpy(startbuf, zp->z_format);
2624 eat(zp->z_filename, zp->z_linenum);
2625 if (*startbuf == '\0')
2626 error(_("can't determine time zone abbreviation to use just after until time"));
2627 else addtt(starttime,
2628 addtype(startoff, startbuf,
2629 startoff != zp->z_gmtoff,
2630 startttisstd,
2631 startttisgmt));
2634 ** Now we may get to set starttime for the next zone line.
2636 if (useuntil) {
2637 startttisstd = zp->z_untilrule.r_todisstd;
2638 startttisgmt = zp->z_untilrule.r_todisgmt;
2639 starttime = zp->z_untiltime;
2640 if (!startttisstd)
2641 starttime = tadd(starttime, -stdoff);
2642 if (!startttisgmt)
2643 starttime = tadd(starttime, -gmtoff);
2646 if (0 <= lastatmax)
2647 attypes[lastatmax].dontmerge = true;
2648 if (do_extend) {
2650 ** If we're extending the explicitly listed observations
2651 ** for 400 years because we can't fill the POSIX-TZ field,
2652 ** check whether we actually ended up explicitly listing
2653 ** observations through that period. If there aren't any
2654 ** near the end of the 400-year period, add a redundant
2655 ** one at the end of the final year, to make it clear
2656 ** that we are claiming to have definite knowledge of
2657 ** the lack of transitions up to that point.
2659 struct rule xr;
2660 struct attype *lastat;
2661 xr.r_month = TM_JANUARY;
2662 xr.r_dycode = DC_DOM;
2663 xr.r_dayofmonth = 1;
2664 xr.r_tod = 0;
2665 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2666 if (attypes[i].at > lastat->at)
2667 lastat = &attypes[i];
2668 if (lastat->at < rpytime(&xr, max_year - 1)) {
2669 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2670 attypes[timecnt - 1].dontmerge = true;
2673 writezone(zpfirst->z_name, envvar, version);
2674 free(startbuf);
2675 free(ab);
2676 free(envvar);
2679 static void
2680 addtt(zic_t starttime, int type)
2682 if (starttime <= early_time
2683 || (timecnt == 1 && attypes[0].at < early_time)) {
2684 gmtoffs[0] = gmtoffs[type];
2685 isdsts[0] = isdsts[type];
2686 ttisstds[0] = ttisstds[type];
2687 ttisgmts[0] = ttisgmts[type];
2688 if (abbrinds[type] != 0)
2689 strcpy(chars, &chars[abbrinds[type]]);
2690 abbrinds[0] = 0;
2691 charcnt = strlen(chars) + 1;
2692 typecnt = 1;
2693 timecnt = 0;
2694 type = 0;
2696 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2697 attypes[timecnt].at = starttime;
2698 attypes[timecnt].dontmerge = false;
2699 attypes[timecnt].type = type;
2700 ++timecnt;
2703 static int
2704 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
2706 register int i, j;
2709 ** See if there's already an entry for this zone type.
2710 ** If so, just return its index.
2712 for (i = 0; i < typecnt; ++i) {
2713 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2714 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2715 ttisstd == ttisstds[i] &&
2716 ttisgmt == ttisgmts[i])
2717 return i;
2720 ** There isn't one; add a new one, unless there are already too
2721 ** many.
2723 if (typecnt >= TZ_MAX_TYPES) {
2724 error(_("too many local time types"));
2725 exit(EXIT_FAILURE);
2727 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2728 error(_("UT offset out of range"));
2729 exit(EXIT_FAILURE);
2731 gmtoffs[i] = gmtoff;
2732 isdsts[i] = isdst;
2733 ttisstds[i] = ttisstd;
2734 ttisgmts[i] = ttisgmt;
2736 for (j = 0; j < charcnt; ++j)
2737 if (strcmp(&chars[j], abbr) == 0)
2738 break;
2739 if (j == charcnt)
2740 newabbr(abbr);
2741 abbrinds[i] = j;
2742 ++typecnt;
2743 return i;
2746 static void
2747 leapadd(zic_t t, bool positive, int rolling, int count)
2749 register int i, j;
2751 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2752 error(_("too many leap seconds"));
2753 exit(EXIT_FAILURE);
2755 for (i = 0; i < leapcnt; ++i)
2756 if (t <= trans[i]) {
2757 if (t == trans[i]) {
2758 error(_("repeated leap second moment"));
2759 exit(EXIT_FAILURE);
2761 break;
2763 do {
2764 for (j = leapcnt; j > i; --j) {
2765 trans[j] = trans[j - 1];
2766 corr[j] = corr[j - 1];
2767 roll[j] = roll[j - 1];
2769 trans[i] = t;
2770 corr[i] = positive ? 1 : -count;
2771 roll[i] = rolling;
2772 ++leapcnt;
2773 } while (positive && --count != 0);
2776 static void
2777 adjleap(void)
2779 register int i;
2780 register zic_t last = 0;
2783 ** propagate leap seconds forward
2785 for (i = 0; i < leapcnt; ++i) {
2786 trans[i] = tadd(trans[i], last);
2787 last = corr[i] += last;
2791 static char *
2792 shellquote(char *b, char const *s)
2794 *b++ = '\'';
2795 while (*s) {
2796 if (*s == '\'')
2797 *b++ = '\'', *b++ = '\\', *b++ = '\'';
2798 *b++ = *s++;
2800 *b++ = '\'';
2801 return b;
2804 static bool
2805 yearistype(zic_t year, const char *type)
2807 char *buf;
2808 char *b;
2809 int result;
2811 if (type == NULL || *type == '\0')
2812 return true;
2813 buf = emalloc(1 + 4 * strlen(yitcommand) + 2
2814 + INT_STRLEN_MAXIMUM(zic_t) + 2 + 4 * strlen(type) + 2);
2815 b = shellquote(buf, yitcommand);
2816 *b++ = ' ';
2817 b += sprintf(b, "%"PRIdZIC, year);
2818 *b++ = ' ';
2819 b = shellquote(b, type);
2820 *b = '\0';
2821 result = system(buf);
2822 if (WIFEXITED(result)) {
2823 int status = WEXITSTATUS(result);
2824 if (status <= 1) {
2825 free(buf);
2826 return status == 0;
2829 error(_("Wild result from command execution"));
2830 fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2831 progname, buf, result);
2832 exit(EXIT_FAILURE);
2835 /* Is A a space character in the C locale? */
2836 static bool
2837 is_space(char a)
2839 switch (a) {
2840 default:
2841 return false;
2842 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2843 return true;
2847 /* Is A an alphabetic character in the C locale? */
2848 static bool
2849 is_alpha(char a)
2851 switch (a) {
2852 default:
2853 return false;
2854 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2855 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2856 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2857 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2858 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2859 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2860 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2861 case 'v': case 'w': case 'x': case 'y': case 'z':
2862 return true;
2866 /* If A is an uppercase character in the C locale, return its lowercase
2867 counterpart. Otherwise, return A. */
2868 static char
2869 lowerit(char a)
2871 switch (a) {
2872 default: return a;
2873 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2874 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2875 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2876 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2877 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2878 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2879 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2880 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2881 case 'Y': return 'y'; case 'Z': return 'z';
2885 /* case-insensitive equality */
2886 static ATTRIBUTE_PURE bool
2887 ciequal(register const char *ap, register const char *bp)
2889 while (lowerit(*ap) == lowerit(*bp++))
2890 if (*ap++ == '\0')
2891 return true;
2892 return false;
2895 static ATTRIBUTE_PURE bool
2896 itsabbr(register const char *abbr, register const char *word)
2898 if (lowerit(*abbr) != lowerit(*word))
2899 return false;
2900 ++word;
2901 while (*++abbr != '\0')
2902 do {
2903 if (*word == '\0')
2904 return false;
2905 } while (lowerit(*word++) != lowerit(*abbr));
2906 return true;
2909 static ATTRIBUTE_PURE const struct lookup *
2910 byword(const char *word, const struct lookup *table)
2912 register const struct lookup * foundlp;
2913 register const struct lookup * lp;
2915 if (word == NULL || table == NULL)
2916 return NULL;
2918 ** Look for exact match.
2920 for (lp = table; lp->l_word != NULL; ++lp)
2921 if (ciequal(word, lp->l_word))
2922 return lp;
2924 ** Look for inexact match.
2926 foundlp = NULL;
2927 for (lp = table; lp->l_word != NULL; ++lp)
2928 if (itsabbr(word, lp->l_word)) {
2929 if (foundlp == NULL)
2930 foundlp = lp;
2931 else return NULL; /* multiple inexact matches */
2933 return foundlp;
2936 static char **
2937 getfields(register char *cp)
2939 register char * dp;
2940 register char ** array;
2941 register int nsubs;
2943 if (cp == NULL)
2944 return NULL;
2945 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
2946 nsubs = 0;
2947 for ( ; ; ) {
2948 while (is_space(*cp))
2949 ++cp;
2950 if (*cp == '\0' || *cp == '#')
2951 break;
2952 array[nsubs++] = dp = cp;
2953 do {
2954 if ((*dp = *cp++) != '"')
2955 ++dp;
2956 else while ((*dp = *cp++) != '"')
2957 if (*dp != '\0')
2958 ++dp;
2959 else {
2960 error(_("Odd number of quotation marks"));
2961 exit(EXIT_FAILURE);
2963 } while (*cp && *cp != '#' && !is_space(*cp));
2964 if (is_space(*cp))
2965 ++cp;
2966 *dp = '\0';
2968 array[nsubs] = NULL;
2969 return array;
2972 static _Noreturn void
2973 time_overflow(void)
2975 error(_("time overflow"));
2976 exit(EXIT_FAILURE);
2979 static ATTRIBUTE_PURE zic_t
2980 oadd(zic_t t1, zic_t t2)
2982 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
2983 time_overflow();
2984 return t1 + t2;
2987 static ATTRIBUTE_PURE zic_t
2988 tadd(zic_t t1, zic_t t2)
2990 if (t1 < 0) {
2991 if (t2 < min_time - t1) {
2992 if (t1 != min_time)
2993 time_overflow();
2994 return min_time;
2996 } else {
2997 if (max_time - t1 < t2) {
2998 if (t1 != max_time)
2999 time_overflow();
3000 return max_time;
3003 return t1 + t2;
3007 ** Given a rule, and a year, compute the date (in seconds since January 1,
3008 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
3011 static zic_t
3012 rpytime(const struct rule *rp, zic_t wantedy)
3014 register int m, i;
3015 register zic_t dayoff; /* with a nod to Margaret O. */
3016 register zic_t t, y;
3018 if (wantedy == ZIC_MIN)
3019 return min_time;
3020 if (wantedy == ZIC_MAX)
3021 return max_time;
3022 dayoff = 0;
3023 m = TM_JANUARY;
3024 y = EPOCH_YEAR;
3025 while (wantedy != y) {
3026 if (wantedy > y) {
3027 i = len_years[isleap(y)];
3028 ++y;
3029 } else {
3030 --y;
3031 i = -len_years[isleap(y)];
3033 dayoff = oadd(dayoff, i);
3035 while (m != rp->r_month) {
3036 i = len_months[isleap(y)][m];
3037 dayoff = oadd(dayoff, i);
3038 ++m;
3040 i = rp->r_dayofmonth;
3041 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3042 if (rp->r_dycode == DC_DOWLEQ)
3043 --i;
3044 else {
3045 error(_("use of 2/29 in non leap-year"));
3046 exit(EXIT_FAILURE);
3049 --i;
3050 dayoff = oadd(dayoff, i);
3051 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
3052 register zic_t wday;
3054 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3055 wday = EPOCH_WDAY;
3057 ** Don't trust mod of negative numbers.
3059 if (dayoff >= 0)
3060 wday = (wday + dayoff) % LDAYSPERWEEK;
3061 else {
3062 wday -= ((-dayoff) % LDAYSPERWEEK);
3063 if (wday < 0)
3064 wday += LDAYSPERWEEK;
3066 while (wday != rp->r_wday)
3067 if (rp->r_dycode == DC_DOWGEQ) {
3068 dayoff = oadd(dayoff, 1);
3069 if (++wday >= LDAYSPERWEEK)
3070 wday = 0;
3071 ++i;
3072 } else {
3073 dayoff = oadd(dayoff, -1);
3074 if (--wday < 0)
3075 wday = LDAYSPERWEEK - 1;
3076 --i;
3078 if (i < 0 || i >= len_months[isleap(y)][m]) {
3079 if (noise)
3080 warning(_("rule goes past start/end of month; \
3081 will not work with pre-2004 versions of zic"));
3084 if (dayoff < min_time / SECSPERDAY)
3085 return min_time;
3086 if (dayoff > max_time / SECSPERDAY)
3087 return max_time;
3088 t = (zic_t) dayoff * SECSPERDAY;
3089 return tadd(t, rp->r_tod);
3092 static void
3093 newabbr(const char *string)
3095 register int i;
3097 if (strcmp(string, GRANDPARENTED) != 0) {
3098 register const char * cp;
3099 const char * mp;
3101 cp = string;
3102 mp = NULL;
3103 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3104 || *cp == '-' || *cp == '+')
3105 ++cp;
3106 if (noise && cp - string < 3)
3107 mp = _("time zone abbreviation has fewer than 3 characters");
3108 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3109 mp = _("time zone abbreviation has too many characters");
3110 if (*cp != '\0')
3111 mp = _("time zone abbreviation differs from POSIX standard");
3112 if (mp != NULL)
3113 warning("%s (%s)", mp, string);
3115 i = strlen(string) + 1;
3116 if (charcnt + i > TZ_MAX_CHARS) {
3117 error(_("too many, or too long, time zone abbreviations"));
3118 exit(EXIT_FAILURE);
3120 strcpy(&chars[charcnt], string);
3121 charcnt += i;
3124 /* Ensure that the directories of ARGNAME exist, by making any missing
3125 ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
3126 do it for ARGNAME too. Exit with failure if there is trouble.
3127 Do not consider an existing non-directory to be trouble. */
3128 static void
3129 mkdirs(char const *argname, bool ancestors)
3131 register char * name;
3132 register char * cp;
3134 cp = name = ecpyalloc(argname);
3136 /* Do not mkdir a root directory, as it must exist. */
3137 #ifdef HAVE_DOS_FILE_NAMES
3138 if (is_alpha(name[0]) && name[1] == ':')
3139 cp += 2;
3140 #endif
3141 while (*cp == '/')
3142 cp++;
3144 while (cp && ((cp = strchr(cp, '/')) || !ancestors)) {
3145 if (cp)
3146 *cp = '\0';
3148 ** Try to create it. It's OK if creation fails because
3149 ** the directory already exists, perhaps because some
3150 ** other process just created it. For simplicity do
3151 ** not check first whether it already exists, as that
3152 ** is checked anyway if the mkdir fails.
3154 if (mkdir(name, MKDIR_UMASK) != 0) {
3155 /* For speed, skip itsdir if errno == EEXIST. Since
3156 mkdirs is called only after open fails with ENOENT
3157 on a subfile, EEXIST implies itsdir here. */
3158 int err = errno;
3159 if (err != EEXIST && !itsdir(name)) {
3160 error(_("%s: Can't create directory %s: %s"),
3161 progname, name, strerror(err));
3162 exit(EXIT_FAILURE);
3165 if (cp)
3166 *cp++ = '/';
3168 free(name);