2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
13 #define ZIC_VERSION_PRE_2013 '2'
14 #define ZIC_VERSION '3'
16 typedef int_fast64_t zic_t;
17 #define ZIC_MIN INT_FAST64_MIN
18 #define ZIC_MAX INT_FAST64_MAX
19 #define SCNdZIC SCNdFAST64
21 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
22 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
23 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
29 # define mkdir(name, mode) _mkdir(name)
36 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
38 #define MKDIR_UMASK 0755
42 const char * r_filename;
46 zic_t r_loyear; /* for example, 1986 */
47 zic_t r_hiyear; /* for example, 1986 */
48 const char * r_yrtype;
52 int r_month; /* 0..11 */
54 int r_dycode; /* see below */
58 zic_t r_tod; /* time from midnight */
59 bool r_todisstd; /* above is standard time if 1 */
60 /* or wall clock time if 0 */
61 bool r_todisgmt; /* above is GMT if 1 */
62 /* or local time if 0 */
63 zic_t r_stdoff; /* offset from standard time */
64 const char * r_abbrvar; /* variable part of abbreviation */
66 int r_todo; /* a rule to do (used in outzone) */
67 zic_t r_temp; /* used in outzone */
71 ** r_dycode r_dayofmonth r_wday
74 #define DC_DOM 0 /* 1..31 */ /* unused */
75 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
76 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
79 const char * z_filename;
85 const char * z_format;
86 char z_format_specifier;
90 struct rule * z_rules;
93 struct rule z_untilrule;
98 extern int getopt(int argc, char * const argv[],
99 const char * options);
100 extern int link(const char * fromname, const char * toname);
101 extern char * optarg;
106 # define link(from, to) (errno = ENOTSUP, -1)
109 # define symlink(from, to) (errno = ENOTSUP, -1)
112 static void addtt(zic_t starttime, int type);
113 static int addtype(zic_t, char const *, bool, bool, bool);
114 static void leapadd(zic_t, bool, int, int);
115 static void adjleap(void);
116 static void associate(void);
117 static void dolink(const char * fromfield, const char * tofield);
118 static char ** getfields(char * buf);
119 static zic_t gethms(const char * string, const char * errstring,
121 static void infile(const char * filename);
122 static void inleap(char ** fields, int nfields);
123 static void inlink(char ** fields, int nfields);
124 static void inrule(char ** fields, int nfields);
125 static bool inzcont(char ** fields, int nfields);
126 static bool inzone(char ** fields, int nfields);
127 static bool inzsub(char **, int, bool);
128 static int itsdir(const char * name);
129 static bool is_alpha(char a);
130 static char lowerit(char);
131 static bool mkdirs(char *);
132 static void newabbr(const char * abbr);
133 static zic_t oadd(zic_t t1, zic_t t2);
134 static void outzone(const struct zone * zp, int ntzones);
135 static zic_t rpytime(const struct rule * rp, zic_t wantedy);
136 static void rulesub(struct rule * rp,
137 const char * loyearp, const char * hiyearp,
138 const char * typep, const char * monthp,
139 const char * dayp, const char * timep);
140 static zic_t tadd(zic_t t1, zic_t t2);
141 static bool yearistype(int year, const char * type);
143 /* Bound on length of what %z can expand to. */
144 enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 };
146 /* If true, work around a bug in Qt 5.6.1 and earlier, which mishandles
147 tzdata binary files whose POSIX-TZ-style strings contain '<'; see
148 QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
149 workaround will no longer be needed when Qt 5.6.1 and earlier are
150 obsolete, say in the year 2021. */
151 enum { WORK_AROUND_QTBUG_53071 = true };
155 static bool warnings;
156 static const char * filename;
158 static bool leapseen;
159 static zic_t leapminyear;
160 static zic_t leapmaxyear;
162 static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
163 static int max_format_len;
164 static zic_t max_year;
165 static zic_t min_year;
167 static const char * rfilename;
169 static const char * progname;
171 static int timecnt_alloc;
184 ** Which fields are which on a Zone line.
192 #define ZF_TILMONTH 6
195 #define ZONE_MINFIELDS 5
196 #define ZONE_MAXFIELDS 9
199 ** Which fields are which on a Zone continuation line.
205 #define ZFC_TILYEAR 3
206 #define ZFC_TILMONTH 4
208 #define ZFC_TILTIME 6
209 #define ZONEC_MINFIELDS 3
210 #define ZONEC_MAXFIELDS 7
213 ** Which files are which on a Rule line.
225 #define RULE_FIELDS 10
228 ** Which fields are which on a Link line.
233 #define LINK_FIELDS 3
236 ** Which fields are which on a Leap line.
245 #define LEAP_FIELDS 7
255 static struct rule * rules;
256 static int nrules; /* number of rules */
257 static int nrules_alloc;
259 static struct zone * zones;
260 static int nzones; /* number of zones */
261 static int nzones_alloc;
264 const char * l_filename;
270 static struct link * links;
272 static int nlinks_alloc;
279 static struct lookup const * byword(const char * string,
280 const struct lookup * lp);
282 static struct lookup const line_codes[] = {
290 static struct lookup const mon_names[] = {
291 { "January", TM_JANUARY },
292 { "February", TM_FEBRUARY },
293 { "March", TM_MARCH },
294 { "April", TM_APRIL },
298 { "August", TM_AUGUST },
299 { "September", TM_SEPTEMBER },
300 { "October", TM_OCTOBER },
301 { "November", TM_NOVEMBER },
302 { "December", TM_DECEMBER },
306 static struct lookup const wday_names[] = {
307 { "Sunday", TM_SUNDAY },
308 { "Monday", TM_MONDAY },
309 { "Tuesday", TM_TUESDAY },
310 { "Wednesday", TM_WEDNESDAY },
311 { "Thursday", TM_THURSDAY },
312 { "Friday", TM_FRIDAY },
313 { "Saturday", TM_SATURDAY },
317 static struct lookup const lasts[] = {
318 { "last-Sunday", TM_SUNDAY },
319 { "last-Monday", TM_MONDAY },
320 { "last-Tuesday", TM_TUESDAY },
321 { "last-Wednesday", TM_WEDNESDAY },
322 { "last-Thursday", TM_THURSDAY },
323 { "last-Friday", TM_FRIDAY },
324 { "last-Saturday", TM_SATURDAY },
328 static struct lookup const begin_years[] = {
329 { "minimum", YR_MINIMUM },
330 { "maximum", YR_MAXIMUM },
334 static struct lookup const end_years[] = {
335 { "minimum", YR_MINIMUM },
336 { "maximum", YR_MAXIMUM },
341 static struct lookup const leap_types[] = {
343 { "Stationary", false },
347 static const int len_months[2][MONSPERYEAR] = {
348 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
349 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
352 static const int len_years[2] = {
353 DAYSPERNYEAR, DAYSPERLYEAR
356 static struct attype {
360 static zic_t gmtoffs[TZ_MAX_TYPES];
361 static char isdsts[TZ_MAX_TYPES];
362 static unsigned char abbrinds[TZ_MAX_TYPES];
363 static bool ttisstds[TZ_MAX_TYPES];
364 static bool ttisgmts[TZ_MAX_TYPES];
365 static char chars[TZ_MAX_CHARS];
366 static zic_t trans[TZ_MAX_LEAPS];
367 static zic_t corr[TZ_MAX_LEAPS];
368 static char roll[TZ_MAX_LEAPS];
371 ** Memory allocation.
374 static _Noreturn void
375 memory_exhausted(const char *msg)
377 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
381 static ATTRIBUTE_PURE size_t
382 size_product(size_t nitems, size_t itemsize)
384 if (SIZE_MAX / itemsize < nitems)
385 memory_exhausted(_("size overflow"));
386 return nitems * itemsize;
391 strdup(char const *str)
393 char *result = malloc(strlen(str) + 1);
394 return result ? strcpy(result, str) : result;
398 static ATTRIBUTE_PURE void *
402 memory_exhausted(strerror(errno));
409 return memcheck(malloc(size));
413 erealloc(void *ptr, size_t size)
415 return memcheck(realloc(ptr, size));
419 ecpyalloc (char const *str)
421 return memcheck(strdup(str));
425 growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
427 if (nitems < *nitems_alloc)
430 int nitems_max = INT_MAX - WORK_AROUND_QTBUG_53071;
431 int amax = nitems_max < SIZE_MAX ? nitems_max : SIZE_MAX;
432 if ((amax - 1) / 3 * 2 < *nitems_alloc)
433 memory_exhausted(_("int overflow"));
434 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
435 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
444 eats(const char *const name, const int num, const char *const rname,
454 eat(const char *const name, const int num)
456 eats(name, num, NULL, -1);
459 static void ATTRIBUTE_FORMAT((printf, 1, 0))
460 verror(const char *const string, va_list args)
463 ** Match the format of "cc" to allow sh users to
464 ** zic ... 2>&1 | error -t "*" -v
468 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
469 vfprintf(stderr, string, args);
470 if (rfilename != NULL)
471 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
472 rfilename, rlinenum);
473 fprintf(stderr, "\n");
476 static void ATTRIBUTE_FORMAT((printf, 1, 2))
477 error(const char *const string, ...)
480 va_start(args, string);
481 verror(string, args);
486 static void ATTRIBUTE_FORMAT((printf, 1, 2))
487 warning(const char *const string, ...)
490 fprintf(stderr, _("warning: "));
491 va_start(args, string);
492 verror(string, args);
498 close_file(FILE *stream, char const *name)
500 char const *e = (ferror(stream) ? _("I/O error")
501 : fclose(stream) != 0 ? strerror(errno) : NULL);
503 fprintf(stderr, "%s: ", progname);
505 fprintf(stderr, "%s: ", name);
506 fprintf(stderr, "%s\n", e);
511 static _Noreturn void
512 usage(FILE *stream, int status)
515 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
516 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
517 "\t[ -L leapseconds ] [ filename ... ]\n\n"
518 "Report bugs to %s.\n"),
519 progname, progname, REPORT_BUGS_TO);
520 if (status == EXIT_SUCCESS)
521 close_file(stream, NULL);
525 static const char * psxrules;
526 static const char * lcltime;
527 static const char * directory;
528 static const char * leapsec;
529 static const char * yitcommand;
532 main(int argc, char **argv)
539 umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
542 setlocale(LC_ALL, "");
544 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
545 #endif /* defined TEXTDOMAINDIR */
546 textdomain(TZ_DOMAIN);
547 #endif /* HAVE_GETTEXT */
549 if (TYPE_BIT(zic_t) < 64) {
550 fprintf(stderr, "%s: %s\n", progname,
551 _("wild compilation-time specification of zic_t"));
554 for (i = 1; i < argc; ++i)
555 if (strcmp(argv[i], "--version") == 0) {
556 printf("zic %s%s\n", PKGVERSION, TZVERSION);
557 close_file(stdout, NULL);
559 } else if (strcmp(argv[i], "--help") == 0) {
560 usage(stdout, EXIT_SUCCESS);
562 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
565 usage(stderr, EXIT_FAILURE);
567 if (directory == NULL)
571 _("%s: More than one -d option specified\n"),
581 _("%s: More than one -l option specified\n"),
587 if (psxrules == NULL)
591 _("%s: More than one -p option specified\n"),
597 if (yitcommand == NULL)
601 _("%s: More than one -y option specified\n"),
611 _("%s: More than one -L option specified\n"),
620 warning(_("-s ignored"));
623 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
624 usage(stderr, EXIT_FAILURE); /* usage message by request */
625 if (directory == NULL)
627 if (yitcommand == NULL)
628 yitcommand = "yearistype";
630 if (optind < argc && leapsec != NULL) {
635 for (i = optind; i < argc; ++i)
640 for (i = 0; i < nzones; i = j) {
642 ** Find the next non-continuation zone entry.
644 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
646 outzone(&zones[i], j - i);
651 for (i = 0; i < nlinks; ++i) {
652 eat(links[i].l_filename, links[i].l_linenum);
653 dolink(links[i].l_from, links[i].l_to);
655 for (j = 0; j < nlinks; ++j)
656 if (strcmp(links[i].l_to,
657 links[j].l_from) == 0)
658 warning(_("link to link"));
660 if (lcltime != NULL) {
661 eat(_("command line"), 1);
662 dolink(lcltime, TZDEFAULT);
664 if (psxrules != NULL) {
665 eat(_("command line"), 1);
666 dolink(psxrules, TZDEFRULES);
668 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
670 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
674 componentcheck(char const *name, char const *component,
675 char const *component_end)
677 enum { component_len_max = 14 };
678 size_t component_len = component_end - component;
679 if (component_len == 0) {
681 error (_("empty file name"));
683 error (_(component == name
684 ? "file name '%s' begins with '/'"
686 ? "file name '%s' contains '//'"
687 : "file name '%s' ends with '/'"),
691 if (0 < component_len && component_len <= 2
692 && component[0] == '.' && component_end[-1] == '.') {
693 error(_("file name '%s' contains '%.*s' component"),
694 name, (int) component_len, component);
698 if (0 < component_len && component[0] == '-')
699 warning(_("file name '%s' component contains leading '-'"),
701 if (component_len_max < component_len)
702 warning(_("file name '%s' contains overlength component"
704 name, component_len_max, component);
710 namecheck(const char *name)
712 register char const *cp;
714 /* Benign characters in a portable file name. */
715 static char const benign[] =
717 "abcdefghijklmnopqrstuvwxyz"
718 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
720 /* Non-control chars in the POSIX portable character set,
721 excluding the benign characters. */
722 static char const printable_and_not_benign[] =
723 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
725 register char const *component = name;
726 for (cp = name; *cp; cp++) {
727 unsigned char c = *cp;
728 if (noise && !strchr(benign, c)) {
729 warning((strchr(printable_and_not_benign, c)
730 ? _("file name '%s' contains byte '%c'")
731 : _("file name '%s' contains byte '\\%o'")),
735 if (!componentcheck(name, component, cp))
740 return componentcheck(name, component, cp);
744 relname(char const *dir, char const *base)
747 return ecpyalloc(base);
749 size_t dir_len = strlen(dir);
750 bool needs_slash = dir_len && dir[dir_len - 1] != '/';
751 char *result = emalloc(dir_len + needs_slash + strlen(base) + 1);
752 result[dir_len] = '/';
753 strcpy(result + dir_len + needs_slash, base);
754 return memcpy(result, dir, dir_len);
759 dolink(char const *fromfield, char const *tofield)
761 register char * fromname;
762 register char * toname;
763 register int fromisdir;
765 fromname = relname(directory, fromfield);
766 toname = relname(directory, tofield);
768 ** We get to be careful here since
769 ** there's a fair chance of root running us.
771 fromisdir = itsdir(fromname);
773 char const *e = strerror(fromisdir < 0 ? errno : EPERM);
774 fprintf(stderr, _("%s: link from %s failed: %s"),
775 progname, fromname, e);
778 if (link(fromname, toname) != 0) {
779 int link_errno = errno;
780 bool retry_if_link_supported = false;
782 if (link_errno == ENOENT || link_errno == ENOTSUP) {
783 if (! mkdirs(toname))
785 retry_if_link_supported = true;
787 if ((link_errno == EEXIST || link_errno == ENOTSUP)
788 && itsdir(toname) == 0
789 && (remove(toname) == 0 || errno == ENOENT))
790 retry_if_link_supported = true;
791 if (retry_if_link_supported && link_errno != ENOTSUP)
792 link_errno = link(fromname, toname) == 0 ? 0 : errno;
793 if (link_errno != 0) {
794 const char *s = fromfield;
798 char *symlinkcontents;
803 while ((s = strchr(s, '/'))
804 && strncmp(fromfield, tofield, ++s - fromfield) == 0);
806 for (s = tofield + (t - fromfield); *s; s++)
807 dotdots += *s == '/';
808 symlinkcontents = emalloc(3 * dotdots + strlen(t) + 1);
809 for (p = symlinkcontents; dotdots-- != 0; p += 3)
812 symlink_result = symlink(symlinkcontents, toname);
813 free(symlinkcontents);
814 if (symlink_result == 0) {
815 if (link_errno != ENOTSUP)
816 warning(_("symbolic link used because hard link failed: %s"),
817 strerror (link_errno));
821 fp = fopen(fromname, "rb");
823 const char *e = strerror(errno);
825 _("%s: Can't read %s: %s\n"),
826 progname, fromname, e);
829 tp = fopen(toname, "wb");
831 const char *e = strerror(errno);
833 _("%s: Can't create %s: %s\n"),
834 progname, toname, e);
837 while ((c = getc(fp)) != EOF)
839 close_file(fp, fromname);
840 close_file(tp, toname);
841 if (link_errno != ENOTSUP)
842 warning(_("copy used because hard link failed: %s"),
843 strerror (link_errno));
851 #define TIME_T_BITS_IN_FILE 64
853 static zic_t const min_time = MINVAL (zic_t, TIME_T_BITS_IN_FILE);
854 static zic_t const max_time = MAXVAL (zic_t, TIME_T_BITS_IN_FILE);
856 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
857 rounded downward to the negation of a power of two that is
858 comfortably outside the error bounds.
860 For the time of the Big Bang, see:
862 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
863 I. Overview of products and scientific results.
864 arXiv:1303.5062 2013-03-20 20:10:01 UTC
865 <http://arxiv.org/pdf/1303.5062v1> [PDF]
867 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
868 gives the value 13.798 plus-or-minus 0.037 billion years.
869 Multiplying this by 1000000000 and then by 31557600 (the number of
870 seconds in an astronomical year) gives a value that is comfortably
871 less than 2**59, so BIG_BANG is - 2**59.
873 BIG_BANG is approximate, and may change in future versions.
874 Please do not rely on its exact value. */
877 #define BIG_BANG (- (1LL << 59))
880 /* If true, work around GNOME bug 730332
881 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>
882 by refusing to output time stamps before BIG_BANG.
883 Such time stamps are physically suspect anyway.
885 The GNOME bug is scheduled to be fixed in GNOME 3.22, and if so
886 this workaround will no longer be needed when GNOME 3.21 and
887 earlier are obsolete, say in the year 2021. */
888 enum { WORK_AROUND_GNOME_BUG_730332 = true };
890 static const zic_t early_time = (WORK_AROUND_GNOME_BUG_730332
892 : MINVAL(zic_t, TIME_T_BITS_IN_FILE));
894 /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
896 itsdir(char const *name)
899 int res = stat(name, &st);
902 return S_ISDIR(st.st_mode) != 0;
904 if (res == 0 || errno == EOVERFLOW) {
905 char *nameslashdot = relname(name, ".");
906 bool dir = stat(nameslashdot, &st) == 0 || errno == EOVERFLOW;
914 ** Associate sets of rules with zones.
918 ** Sort by rule name.
922 rcomp(const void *cp1, const void *cp2)
924 return strcmp(((const struct rule *) cp1)->r_name,
925 ((const struct rule *) cp2)->r_name);
931 register struct zone * zp;
932 register struct rule * rp;
933 register int base, out;
937 qsort(rules, nrules, sizeof *rules, rcomp);
938 for (i = 0; i < nrules - 1; ++i) {
939 if (strcmp(rules[i].r_name,
940 rules[i + 1].r_name) != 0)
942 if (strcmp(rules[i].r_filename,
943 rules[i + 1].r_filename) == 0)
945 eat(rules[i].r_filename, rules[i].r_linenum);
946 warning(_("same rule name in multiple files"));
947 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
948 warning(_("same rule name in multiple files"));
949 for (j = i + 2; j < nrules; ++j) {
950 if (strcmp(rules[i].r_name,
951 rules[j].r_name) != 0)
953 if (strcmp(rules[i].r_filename,
954 rules[j].r_filename) == 0)
956 if (strcmp(rules[i + 1].r_filename,
957 rules[j].r_filename) == 0)
964 for (i = 0; i < nzones; ++i) {
969 for (base = 0; base < nrules; base = out) {
971 for (out = base + 1; out < nrules; ++out)
972 if (strcmp(rp->r_name, rules[out].r_name) != 0)
974 for (i = 0; i < nzones; ++i) {
976 if (strcmp(zp->z_rule, rp->r_name) != 0)
979 zp->z_nrules = out - base;
982 for (i = 0; i < nzones; ++i) {
984 if (zp->z_nrules == 0) {
986 ** Maybe we have a local standard time offset.
988 eat(zp->z_filename, zp->z_linenum);
989 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
992 ** Note, though, that if there's no rule,
993 ** a '%s' in the format is a bad thing.
995 if (zp->z_format_specifier == 's')
996 error("%s", _("%s in ruleless zone"));
1004 infile(const char *name)
1007 register char ** fields;
1009 register const struct lookup * lp;
1010 register int nfields;
1011 register bool wantcont;
1015 if (strcmp(name, "-") == 0) {
1016 name = _("standard input");
1018 } else if ((fp = fopen(name, "r")) == NULL) {
1019 const char *e = strerror(errno);
1021 fprintf(stderr, _("%s: Can't open %s: %s\n"),
1026 for (num = 1; ; ++num) {
1028 if (fgets(buf, sizeof buf, fp) != buf)
1030 cp = strchr(buf, '\n');
1032 error(_("line too long"));
1036 fields = getfields(buf);
1038 while (fields[nfields] != NULL) {
1041 if (strcmp(fields[nfields], "-") == 0)
1042 fields[nfields] = &nada;
1047 } else if (wantcont) {
1048 wantcont = inzcont(fields, nfields);
1050 lp = byword(fields[0], line_codes);
1052 error(_("input line of unknown type"));
1053 else switch ((int) (lp->l_value)) {
1055 inrule(fields, nfields);
1059 wantcont = inzone(fields, nfields);
1062 inlink(fields, nfields);
1066 if (name != leapsec)
1067 warning(_("%s: Leap line in non leap"
1068 " seconds file %s"),
1070 else inleap(fields, nfields);
1073 default: /* "cannot happen" */
1075 _("%s: panic: Invalid l_value %d\n"),
1076 progname, lp->l_value);
1082 close_file(fp, filename);
1084 error(_("expected continuation line not found"));
1088 ** Convert a string of one of the forms
1089 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1090 ** into a number of seconds.
1091 ** A null string maps to zero.
1092 ** Call error with errstring and return zero on errors.
1096 gethms(char const *string, char const *errstring, bool signable)
1102 if (string == NULL || *string == '\0')
1106 else if (*string == '-') {
1110 if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
1112 else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
1114 else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
1116 error("%s", errstring);
1120 mm < 0 || mm >= MINSPERHOUR ||
1121 ss < 0 || ss > SECSPERMIN) {
1122 error("%s", errstring);
1125 if (ZIC_MAX / SECSPERHOUR < hh) {
1126 error(_("time overflow"));
1129 if (noise && (hh > HOURSPERDAY ||
1130 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1131 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1132 return oadd(sign * hh * SECSPERHOUR,
1133 sign * (mm * SECSPERMIN + ss));
1137 inrule(char **fields, int nfields)
1139 static struct rule r;
1141 if (nfields != RULE_FIELDS) {
1142 error(_("wrong number of fields on Rule line"));
1145 if (*fields[RF_NAME] == '\0') {
1146 error(_("nameless rule"));
1149 r.r_filename = filename;
1150 r.r_linenum = linenum;
1151 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1152 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1153 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1154 r.r_name = ecpyalloc(fields[RF_NAME]);
1155 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1156 if (max_abbrvar_len < strlen(r.r_abbrvar))
1157 max_abbrvar_len = strlen(r.r_abbrvar);
1158 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1159 rules[nrules++] = r;
1163 inzone(char **fields, int nfields)
1167 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1168 error(_("wrong number of fields on Zone line"));
1171 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1173 _("\"Zone %s\" line and -l option are mutually exclusive"),
1177 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1179 _("\"Zone %s\" line and -p option are mutually exclusive"),
1183 for (i = 0; i < nzones; ++i)
1184 if (zones[i].z_name != NULL &&
1185 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1187 _("duplicate zone name %s (file \"%s\", line %d)"),
1189 zones[i].z_filename,
1190 zones[i].z_linenum);
1193 return inzsub(fields, nfields, false);
1197 inzcont(char **fields, int nfields)
1199 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1200 error(_("wrong number of fields on Zone continuation line"));
1203 return inzsub(fields, nfields, true);
1207 inzsub(char **fields, int nfields, bool iscont)
1211 static struct zone z;
1212 register int i_gmtoff, i_rule, i_format;
1213 register int i_untilyear, i_untilmonth;
1214 register int i_untilday, i_untiltime;
1215 register bool hasuntil;
1218 i_gmtoff = ZFC_GMTOFF;
1220 i_format = ZFC_FORMAT;
1221 i_untilyear = ZFC_TILYEAR;
1222 i_untilmonth = ZFC_TILMONTH;
1223 i_untilday = ZFC_TILDAY;
1224 i_untiltime = ZFC_TILTIME;
1226 } else if (!namecheck(fields[ZF_NAME]))
1229 i_gmtoff = ZF_GMTOFF;
1231 i_format = ZF_FORMAT;
1232 i_untilyear = ZF_TILYEAR;
1233 i_untilmonth = ZF_TILMONTH;
1234 i_untilday = ZF_TILDAY;
1235 i_untiltime = ZF_TILTIME;
1236 z.z_name = ecpyalloc(fields[ZF_NAME]);
1238 z.z_filename = filename;
1239 z.z_linenum = linenum;
1240 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1241 if ((cp = strchr(fields[i_format], '%')) != 0) {
1242 if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
1243 || strchr(fields[i_format], '/')) {
1244 error(_("invalid abbreviation format"));
1248 z.z_rule = ecpyalloc(fields[i_rule]);
1249 z.z_format = cp1 = ecpyalloc(fields[i_format]);
1250 z.z_format_specifier = cp ? *cp : '\0';
1251 if (z.z_format_specifier == 'z') {
1253 warning(_("format '%s' not handled by pre-2015 versions of zic"),
1255 cp1[cp - fields[i_format]] = 's';
1257 if (max_format_len < strlen(z.z_format))
1258 max_format_len = strlen(z.z_format);
1259 hasuntil = nfields > i_untilyear;
1261 z.z_untilrule.r_filename = filename;
1262 z.z_untilrule.r_linenum = linenum;
1263 rulesub(&z.z_untilrule,
1264 fields[i_untilyear],
1267 (nfields > i_untilmonth) ?
1268 fields[i_untilmonth] : "Jan",
1269 (nfields > i_untilday) ? fields[i_untilday] : "1",
1270 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1271 z.z_untiltime = rpytime(&z.z_untilrule,
1272 z.z_untilrule.r_loyear);
1273 if (iscont && nzones > 0 &&
1274 z.z_untiltime > min_time &&
1275 z.z_untiltime < max_time &&
1276 zones[nzones - 1].z_untiltime > min_time &&
1277 zones[nzones - 1].z_untiltime < max_time &&
1278 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1280 "Zone continuation line end time is not after end time of previous line"
1285 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1286 zones[nzones++] = z;
1288 ** If there was an UNTIL field on this line,
1289 ** there's more information about the zone on the next line.
1295 inleap(char **fields, int nfields)
1297 register const char * cp;
1298 register const struct lookup * lp;
1306 if (nfields != LEAP_FIELDS) {
1307 error(_("wrong number of fields on Leap line"));
1311 cp = fields[LP_YEAR];
1312 if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) {
1316 error(_("invalid leaping year"));
1319 if (!leapseen || leapmaxyear < year)
1321 if (!leapseen || leapminyear > year)
1327 i = len_years[isleap(j)];
1331 i = -len_years[isleap(j)];
1333 dayoff = oadd(dayoff, i);
1335 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1336 error(_("invalid month name"));
1339 month = lp->l_value;
1341 while (j != month) {
1342 i = len_months[isleap(year)][j];
1343 dayoff = oadd(dayoff, i);
1346 cp = fields[LP_DAY];
1347 if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
1348 day <= 0 || day > len_months[isleap(year)][month]) {
1349 error(_("invalid day of month"));
1352 dayoff = oadd(dayoff, day - 1);
1353 if (dayoff < min_time / SECSPERDAY) {
1354 error(_("time too small"));
1357 if (dayoff > max_time / SECSPERDAY) {
1358 error(_("time too large"));
1361 t = dayoff * SECSPERDAY;
1362 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1363 cp = fields[LP_CORR];
1365 register bool positive;
1368 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1371 } else if (strcmp(cp, "--") == 0) {
1374 } else if (strcmp(cp, "+") == 0) {
1377 } else if (strcmp(cp, "++") == 0) {
1381 error(_("illegal CORRECTION field on Leap line"));
1384 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1386 "illegal Rolling/Stationary field on Leap line"
1391 if (t < early_time) {
1392 error(_("leap second precedes Big Bang"));
1395 leapadd(t, positive, lp->l_value, count);
1400 inlink(char **fields, int nfields)
1404 if (nfields != LINK_FIELDS) {
1405 error(_("wrong number of fields on Link line"));
1408 if (*fields[LF_FROM] == '\0') {
1409 error(_("blank FROM field on Link line"));
1412 if (! namecheck(fields[LF_TO]))
1414 l.l_filename = filename;
1415 l.l_linenum = linenum;
1416 l.l_from = ecpyalloc(fields[LF_FROM]);
1417 l.l_to = ecpyalloc(fields[LF_TO]);
1418 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1419 links[nlinks++] = l;
1423 rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
1424 const char *typep, const char *monthp, const char *dayp,
1427 register const struct lookup * lp;
1428 register const char * cp;
1433 if ((lp = byword(monthp, mon_names)) == NULL) {
1434 error(_("invalid month name"));
1437 rp->r_month = lp->l_value;
1438 rp->r_todisstd = false;
1439 rp->r_todisgmt = false;
1440 dp = ecpyalloc(timep);
1442 ep = dp + strlen(dp) - 1;
1443 switch (lowerit(*ep)) {
1444 case 's': /* Standard */
1445 rp->r_todisstd = true;
1446 rp->r_todisgmt = false;
1449 case 'w': /* Wall */
1450 rp->r_todisstd = false;
1451 rp->r_todisgmt = false;
1454 case 'g': /* Greenwich */
1455 case 'u': /* Universal */
1456 case 'z': /* Zulu */
1457 rp->r_todisstd = true;
1458 rp->r_todisgmt = true;
1463 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1469 lp = byword(cp, begin_years);
1470 rp->r_lowasnum = lp == NULL;
1471 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1473 rp->r_loyear = ZIC_MIN;
1476 rp->r_loyear = ZIC_MAX;
1478 default: /* "cannot happen" */
1480 _("%s: panic: Invalid l_value %d\n"),
1481 progname, lp->l_value);
1483 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) {
1484 error(_("invalid starting year"));
1488 lp = byword(cp, end_years);
1489 rp->r_hiwasnum = lp == NULL;
1490 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1492 rp->r_hiyear = ZIC_MIN;
1495 rp->r_hiyear = ZIC_MAX;
1498 rp->r_hiyear = rp->r_loyear;
1500 default: /* "cannot happen" */
1502 _("%s: panic: Invalid l_value %d\n"),
1503 progname, lp->l_value);
1505 } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) {
1506 error(_("invalid ending year"));
1509 if (rp->r_loyear > rp->r_hiyear) {
1510 error(_("starting year greater than ending year"));
1514 rp->r_yrtype = NULL;
1516 if (rp->r_loyear == rp->r_hiyear) {
1517 error(_("typed single year"));
1520 rp->r_yrtype = ecpyalloc(typep);
1524 ** Accept things such as:
1530 dp = ecpyalloc(dayp);
1531 if ((lp = byword(dp, lasts)) != NULL) {
1532 rp->r_dycode = DC_DOWLEQ;
1533 rp->r_wday = lp->l_value;
1534 rp->r_dayofmonth = len_months[1][rp->r_month];
1536 if ((ep = strchr(dp, '<')) != 0)
1537 rp->r_dycode = DC_DOWLEQ;
1538 else if ((ep = strchr(dp, '>')) != 0)
1539 rp->r_dycode = DC_DOWGEQ;
1542 rp->r_dycode = DC_DOM;
1544 if (rp->r_dycode != DC_DOM) {
1547 error(_("invalid day of month"));
1551 if ((lp = byword(dp, wday_names)) == NULL) {
1552 error(_("invalid weekday name"));
1556 rp->r_wday = lp->l_value;
1558 if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
1559 rp->r_dayofmonth <= 0 ||
1560 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1561 error(_("invalid day of month"));
1570 convert(const int_fast32_t val, char *const buf)
1574 unsigned char *const b = (unsigned char *) buf;
1576 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1577 b[i] = val >> shift;
1581 convert64(const zic_t val, char *const buf)
1585 unsigned char *const b = (unsigned char *) buf;
1587 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1588 b[i] = val >> shift;
1592 puttzcode(const int_fast32_t val, FILE *const fp)
1597 fwrite(buf, sizeof buf, 1, fp);
1601 puttzcode64(const zic_t val, FILE *const fp)
1605 convert64(val, buf);
1606 fwrite(buf, sizeof buf, 1, fp);
1610 atcomp(const void *avp, const void *bvp)
1612 const zic_t a = ((const struct attype *) avp)->at;
1613 const zic_t b = ((const struct attype *) bvp)->at;
1615 return (a < b) ? -1 : (a > b);
1621 return INT32_MIN <= x && x <= INT32_MAX;
1625 writezone(const char *const name, const char *const string, char version)
1629 register int leapcnt32, leapi32;
1630 register int timecnt32, timei32;
1633 static const struct tzhead tzh0;
1634 static struct tzhead tzh;
1636 zic_t y2038_boundary = one << 31;
1637 int nats = timecnt + WORK_AROUND_QTBUG_53071;
1638 zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
1639 void *typesptr = ats + nats;
1640 unsigned char *types = typesptr;
1646 qsort(attypes, timecnt, sizeof *attypes, atcomp);
1656 while (fromi < timecnt && attypes[fromi].at < early_time)
1658 for ( ; fromi < timecnt; ++fromi) {
1659 if (toi > 1 && ((attypes[fromi].at +
1660 gmtoffs[attypes[toi - 1].type]) <=
1661 (attypes[toi - 1].at +
1662 gmtoffs[attypes[toi - 2].type]))) {
1663 attypes[toi - 1].type =
1664 attypes[fromi].type;
1668 attypes[toi - 1].type != attypes[fromi].type)
1669 attypes[toi++] = attypes[fromi];
1673 if (noise && timecnt > 1200)
1674 warning(_("pre-2014 clients may mishandle"
1675 " more than 1200 transition times"));
1679 for (i = 0; i < timecnt; ++i) {
1680 ats[i] = attypes[i].at;
1681 types[i] = attypes[i].type;
1684 /* Work around QTBUG-53071 for time stamps less than y2038_boundary - 1,
1685 by inserting a no-op transition at time y2038_boundary - 1.
1686 This works only for timestamps before the boundary, which
1687 should be good enough in practice as QTBUG-53071 should be
1688 long-dead by 2038. */
1689 if (WORK_AROUND_QTBUG_53071 && timecnt != 0
1690 && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<')) {
1691 ats[timecnt] = y2038_boundary - 1;
1692 types[timecnt] = types[timecnt - 1];
1697 ** Correct for leap seconds.
1699 for (i = 0; i < timecnt; ++i) {
1702 if (ats[i] > trans[j] - corr[j]) {
1703 ats[i] = tadd(ats[i], corr[j]);
1708 ** Figure out 32-bit-limited starts and counts.
1710 timecnt32 = timecnt;
1712 leapcnt32 = leapcnt;
1714 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1716 while (timecnt32 > 0 && !is32(ats[timei32])) {
1721 ** Output an INT32_MIN "transition" if appropriate; see below.
1723 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1727 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1729 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1733 fullname = relname(directory, name);
1735 ** Remove old file, if any, to snap links.
1737 if (itsdir(fullname) == 0 && remove(fullname) != 0 && errno != ENOENT) {
1738 const char *e = strerror(errno);
1740 fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1741 progname, fullname, e);
1744 if ((fp = fopen(fullname, "wb")) == NULL) {
1745 if (! mkdirs(fullname))
1747 if ((fp = fopen(fullname, "wb")) == NULL) {
1748 const char *e = strerror(errno);
1750 fprintf(stderr, _("%s: Can't create %s: %s\n"),
1751 progname, fullname, e);
1755 for (pass = 1; pass <= 2; ++pass) {
1756 register int thistimei, thistimecnt;
1757 register int thisleapi, thisleapcnt;
1758 register int thistimelim, thisleaplim;
1759 int writetype[TZ_MAX_TYPES];
1760 int typemap[TZ_MAX_TYPES];
1761 register int thistypecnt;
1762 char thischars[TZ_MAX_CHARS];
1764 int indmap[TZ_MAX_CHARS];
1767 thistimei = timei32;
1768 thistimecnt = timecnt32;
1769 thisleapi = leapi32;
1770 thisleapcnt = leapcnt32;
1773 thistimecnt = timecnt;
1775 thisleapcnt = leapcnt;
1777 thistimelim = thistimei + thistimecnt;
1778 thisleaplim = thisleapi + thisleapcnt;
1779 for (i = 0; i < typecnt; ++i)
1780 writetype[i] = thistimecnt == timecnt;
1781 if (thistimecnt == 0) {
1783 ** No transition times fall in the current
1784 ** (32- or 64-bit) window.
1787 writetype[typecnt - 1] = true;
1789 for (i = thistimei - 1; i < thistimelim; ++i)
1791 writetype[types[i]] = true;
1793 ** For America/Godthab and Antarctica/Palmer
1796 writetype[0] = true;
1798 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1800 ** For some pre-2011 systems: if the last-to-be-written
1801 ** standard (or daylight) type has an offset different from the
1802 ** most recently used offset,
1803 ** append an (unused) copy of the most recently used type
1804 ** (to help get global "altzone" and "timezone" variables
1808 register int mrudst, mrustd, hidst, histd, type;
1810 hidst = histd = mrudst = mrustd = -1;
1811 for (i = thistimei; i < thistimelim; ++i)
1812 if (isdsts[types[i]])
1814 else mrustd = types[i];
1815 for (i = 0; i < typecnt; ++i)
1821 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1822 gmtoffs[hidst] != gmtoffs[mrudst]) {
1823 isdsts[mrudst] = -1;
1824 type = addtype(gmtoffs[mrudst],
1825 &chars[abbrinds[mrudst]],
1830 writetype[type] = true;
1832 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1833 gmtoffs[histd] != gmtoffs[mrustd]) {
1834 isdsts[mrustd] = -1;
1835 type = addtype(gmtoffs[mrustd],
1836 &chars[abbrinds[mrustd]],
1841 writetype[type] = true;
1844 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1846 for (i = 0; i < typecnt; ++i)
1847 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1848 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1851 for (i = 0; i < typecnt; ++i) {
1852 register char * thisabbr;
1856 if (indmap[abbrinds[i]] >= 0)
1858 thisabbr = &chars[abbrinds[i]];
1859 for (j = 0; j < thischarcnt; ++j)
1860 if (strcmp(&thischars[j], thisabbr) == 0)
1862 if (j == thischarcnt) {
1863 strcpy(&thischars[(int) thischarcnt],
1865 thischarcnt += strlen(thisabbr) + 1;
1867 indmap[abbrinds[i]] = j;
1869 #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
1871 strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1872 tzh.tzh_version[0] = version;
1873 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1874 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1875 convert(thisleapcnt, tzh.tzh_leapcnt);
1876 convert(thistimecnt, tzh.tzh_timecnt);
1877 convert(thistypecnt, tzh.tzh_typecnt);
1878 convert(thischarcnt, tzh.tzh_charcnt);
1889 for (i = thistimei; i < thistimelim; ++i)
1892 ** Output an INT32_MIN "transition"
1893 ** if appropriate; see above.
1895 puttzcode(((ats[i] < INT32_MIN) ?
1896 INT32_MIN : ats[i]), fp);
1897 else puttzcode64(ats[i], fp);
1898 for (i = thistimei; i < thistimelim; ++i) {
1901 uc = typemap[types[i]];
1902 fwrite(&uc, sizeof uc, 1, fp);
1904 for (i = 0; i < typecnt; ++i)
1906 puttzcode(gmtoffs[i], fp);
1907 putc(isdsts[i], fp);
1908 putc((unsigned char) indmap[abbrinds[i]], fp);
1910 if (thischarcnt != 0)
1911 fwrite(thischars, sizeof thischars[0],
1913 for (i = thisleapi; i < thisleaplim; ++i) {
1914 register zic_t todo;
1917 if (timecnt == 0 || trans[i] < ats[0]) {
1920 if (++j >= typecnt) {
1926 while (j < timecnt &&
1931 todo = tadd(trans[i], -gmtoffs[j]);
1932 } else todo = trans[i];
1934 puttzcode(todo, fp);
1935 else puttzcode64(todo, fp);
1936 puttzcode(corr[i], fp);
1938 for (i = 0; i < typecnt; ++i)
1940 putc(ttisstds[i], fp);
1941 for (i = 0; i < typecnt; ++i)
1943 putc(ttisgmts[i], fp);
1945 fprintf(fp, "\n%s\n", string);
1946 close_file(fp, fullname);
1952 abbroffset(char *buf, zic_t offset)
1955 int seconds, minutes;
1962 seconds = offset % SECSPERMIN;
1963 offset /= SECSPERMIN;
1964 minutes = offset % MINSPERHOUR;
1965 offset /= MINSPERHOUR;
1966 if (100 <= offset) {
1967 error(_("%%z UTC offset magnitude exceeds 99:59:59"));
1972 *p++ = '0' + offset / 10;
1973 *p++ = '0' + offset % 10;
1974 if (minutes | seconds) {
1975 *p++ = '0' + minutes / 10;
1976 *p++ = '0' + minutes % 10;
1978 *p++ = '0' + seconds / 10;
1979 *p++ = '0' + seconds % 10;
1988 doabbr(char *abbr, struct zone const *zp, char const *letters,
1989 zic_t stdoff, bool doquotes)
1992 register char * slashp;
1993 register size_t len;
1994 char const *format = zp->z_format;
1996 slashp = strchr(format, '/');
1997 if (slashp == NULL) {
1998 char letterbuf[PERCENT_Z_LEN_BOUND + 1];
1999 if (zp->z_format_specifier == 'z')
2000 letters = abbroffset(letterbuf, zp->z_gmtoff + stdoff);
2003 sprintf(abbr, format, letters);
2004 } else if (stdoff != 0) {
2005 strcpy(abbr, slashp + 1);
2007 memcpy(abbr, format, slashp - format);
2008 abbr[slashp - format] = '\0';
2013 for (cp = abbr; is_alpha(*cp); cp++)
2015 if (len > 0 && *cp == '\0')
2017 abbr[len + 2] = '\0';
2018 abbr[len + 1] = '>';
2019 memmove(abbr + 1, abbr, len);
2025 updateminmax(const zic_t x)
2034 stringoffset(char *result, zic_t offset)
2037 register int minutes;
2038 register int seconds;
2039 bool negative = offset < 0;
2046 seconds = offset % SECSPERMIN;
2047 offset /= SECSPERMIN;
2048 minutes = offset % MINSPERHOUR;
2049 offset /= MINSPERHOUR;
2051 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
2055 len += sprintf(result + len, "%d", hours);
2056 if (minutes != 0 || seconds != 0) {
2057 len += sprintf(result + len, ":%02d", minutes);
2059 len += sprintf(result + len, ":%02d", seconds);
2065 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2068 register zic_t tod = rp->r_tod;
2069 register int compat = 0;
2071 if (rp->r_dycode == DC_DOM) {
2072 register int month, total;
2074 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2077 for (month = 0; month < rp->r_month; ++month)
2078 total += len_months[0][month];
2079 /* Omit the "J" in Jan and Feb, as that's shorter. */
2080 if (rp->r_month <= 1)
2081 result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2083 result += sprintf(result, "J%d", total + rp->r_dayofmonth);
2086 register int wday = rp->r_wday;
2087 register int wdayoff;
2089 if (rp->r_dycode == DC_DOWGEQ) {
2090 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2094 tod += wdayoff * SECSPERDAY;
2095 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
2096 } else if (rp->r_dycode == DC_DOWLEQ) {
2097 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2100 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2104 tod += wdayoff * SECSPERDAY;
2105 week = rp->r_dayofmonth / DAYSPERWEEK;
2107 } else return -1; /* "cannot happen" */
2109 wday += DAYSPERWEEK;
2110 result += sprintf(result, "M%d.%d.%d",
2111 rp->r_month + 1, week, wday);
2115 if (rp->r_todisstd && rp->r_stdoff == 0)
2117 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2119 if (! stringoffset(result, tod))
2124 } else if (SECSPERDAY <= tod) {
2133 rule_cmp(struct rule const *a, struct rule const *b)
2139 if (a->r_hiyear != b->r_hiyear)
2140 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2141 if (a->r_month - b->r_month != 0)
2142 return a->r_month - b->r_month;
2143 return a->r_dayofmonth - b->r_dayofmonth;
2146 enum { YEAR_BY_YEAR_ZONE = 1 };
2149 stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
2151 register const struct zone * zp;
2152 register struct rule * rp;
2153 register struct rule * stdrp;
2154 register struct rule * dstrp;
2156 register const char * abbrvar;
2157 register int compat = 0;
2161 struct rule stdr, dstr;
2164 zp = zpfirst + zonecount - 1;
2165 stdrp = dstrp = NULL;
2166 for (i = 0; i < zp->z_nrules; ++i) {
2167 rp = &zp->z_rules[i];
2168 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2170 if (rp->r_yrtype != NULL)
2172 if (rp->r_stdoff == 0) {
2182 if (stdrp == NULL && dstrp == NULL) {
2184 ** There are no rules running through "max".
2185 ** Find the latest std rule in stdabbrrp
2186 ** and latest rule of any type in stdrp.
2188 register struct rule *stdabbrrp = NULL;
2189 for (i = 0; i < zp->z_nrules; ++i) {
2190 rp = &zp->z_rules[i];
2191 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2193 if (rule_cmp(stdrp, rp) < 0)
2197 ** Horrid special case: if year is 2037,
2198 ** presume this is a zone handled on a year-by-year basis;
2199 ** do not try to apply a rule to the zone.
2201 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2202 return YEAR_BY_YEAR_ZONE;
2204 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2205 /* Perpetual DST. */
2206 dstr.r_month = TM_JANUARY;
2207 dstr.r_dycode = DC_DOM;
2208 dstr.r_dayofmonth = 1;
2210 dstr.r_todisstd = dstr.r_todisgmt = false;
2211 dstr.r_stdoff = stdrp->r_stdoff;
2212 dstr.r_abbrvar = stdrp->r_abbrvar;
2213 stdr.r_month = TM_DECEMBER;
2214 stdr.r_dycode = DC_DOM;
2215 stdr.r_dayofmonth = 31;
2216 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2217 stdr.r_todisstd = stdr.r_todisgmt = false;
2220 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2225 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2227 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2228 len = doabbr(result, zp, abbrvar, 0, true);
2229 offsetlen = stringoffset(result + len, -zp->z_gmtoff);
2237 len += doabbr(result + len, zp, dstrp->r_abbrvar, dstrp->r_stdoff, true);
2238 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
2239 offsetlen = stringoffset(result + len,
2240 -(zp->z_gmtoff + dstrp->r_stdoff));
2247 result[len++] = ',';
2248 c = stringrule(result + len, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2255 len += strlen(result + len);
2256 result[len++] = ',';
2257 c = stringrule(result + len, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2268 outzone(const struct zone *zpfirst, int zonecount)
2270 register const struct zone * zp;
2271 register struct rule * rp;
2273 register bool usestart, useuntil;
2274 register zic_t starttime, untiltime;
2275 register zic_t gmtoff;
2276 register zic_t stdoff;
2277 register zic_t year;
2278 register zic_t startoff;
2279 register bool startttisstd;
2280 register bool startttisgmt;
2282 register char * startbuf;
2284 register char * envvar;
2285 register int max_abbr_len;
2286 register int max_envvar_len;
2287 register bool prodstic; /* all rules are min to max */
2288 register int compat;
2289 register bool do_extend;
2290 register char version;
2292 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2293 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2294 startbuf = emalloc(max_abbr_len + 1);
2295 ab = emalloc(max_abbr_len + 1);
2296 envvar = emalloc(max_envvar_len + 1);
2297 INITIALIZE(untiltime);
2298 INITIALIZE(starttime);
2300 ** Now. . .finally. . .generate some useful data!
2305 prodstic = zonecount == 1;
2307 ** Thanks to Earl Chew
2308 ** for noting the need to unconditionally initialize startttisstd.
2310 startttisstd = false;
2311 startttisgmt = false;
2312 min_year = max_year = EPOCH_YEAR;
2314 updateminmax(leapminyear);
2315 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2317 for (i = 0; i < zonecount; ++i) {
2319 if (i < zonecount - 1)
2320 updateminmax(zp->z_untilrule.r_loyear);
2321 for (j = 0; j < zp->z_nrules; ++j) {
2322 rp = &zp->z_rules[j];
2324 updateminmax(rp->r_loyear);
2326 updateminmax(rp->r_hiyear);
2327 if (rp->r_lowasnum || rp->r_hiwasnum)
2332 ** Generate lots of data if a rule can't cover all future times.
2334 compat = stringzone(envvar, zpfirst, zonecount);
2335 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2336 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2340 _("no POSIX environment variable for zone"),
2342 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2343 /* Circa-COMPAT clients, and earlier clients, might
2344 not work for this zone when given dates before
2345 1970 or after 2038. */
2346 warning(_("%s: pre-%d clients may mishandle"
2347 " distant timestamps"),
2348 zpfirst->z_name, compat);
2353 ** Search through a couple of extra years past the obvious
2354 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2355 ** rule applies from 2012 onwards and has transitions in March
2356 ** and September, plus some one-off transitions in November
2357 ** 2013. If zic looked only at the last 400 years, it would
2358 ** set max_year=2413, with the intent that the 400 years 2014
2359 ** through 2413 will be repeated. The last transition listed
2360 ** in the tzfile would be in 2413-09, less than 400 years
2361 ** after the last one-off transition in 2013-11. Two years
2362 ** might be overkill, but with the kind of edge cases
2363 ** available we're not sure that one year would suffice.
2365 enum { years_of_observations = YEARSPERREPEAT + 2 };
2367 if (min_year >= ZIC_MIN + years_of_observations)
2368 min_year -= years_of_observations;
2369 else min_year = ZIC_MIN;
2370 if (max_year <= ZIC_MAX - years_of_observations)
2371 max_year += years_of_observations;
2372 else max_year = ZIC_MAX;
2374 ** Regardless of any of the above,
2375 ** for a "proDSTic" zone which specifies that its rules
2376 ** always have and always will be in effect,
2377 ** we only need one cycle to define the zone.
2381 max_year = min_year + years_of_observations;
2385 ** For the benefit of older systems,
2386 ** generate data from 1900 through 2037.
2388 if (min_year > 1900)
2390 if (max_year < 2037)
2392 for (i = 0; i < zonecount; ++i) {
2394 ** A guess that may well be corrected later.
2398 usestart = i > 0 && (zp - 1)->z_untiltime > early_time;
2399 useuntil = i < (zonecount - 1);
2400 if (useuntil && zp->z_untiltime <= early_time)
2402 gmtoff = zp->z_gmtoff;
2403 eat(zp->z_filename, zp->z_linenum);
2405 startoff = zp->z_gmtoff;
2406 if (zp->z_nrules == 0) {
2407 stdoff = zp->z_stdoff;
2408 doabbr(startbuf, zp, NULL, stdoff, false);
2409 type = addtype(oadd(zp->z_gmtoff, stdoff),
2410 startbuf, stdoff != 0, startttisstd,
2413 addtt(starttime, type);
2415 } else addtt(early_time, type);
2416 } else for (year = min_year; year <= max_year; ++year) {
2417 if (useuntil && year > zp->z_untilrule.r_hiyear)
2420 ** Mark which rules to do in the current year.
2421 ** For those to do, calculate rpytime(rp, year);
2423 for (j = 0; j < zp->z_nrules; ++j) {
2424 rp = &zp->z_rules[j];
2425 eats(zp->z_filename, zp->z_linenum,
2426 rp->r_filename, rp->r_linenum);
2427 rp->r_todo = year >= rp->r_loyear &&
2428 year <= rp->r_hiyear &&
2429 yearistype(year, rp->r_yrtype);
2431 rp->r_temp = rpytime(rp, year);
2435 register zic_t jtime, ktime;
2436 register zic_t offset;
2441 ** Turn untiltime into UT
2442 ** assuming the current gmtoff and
2445 untiltime = zp->z_untiltime;
2446 if (!zp->z_untilrule.r_todisgmt)
2447 untiltime = tadd(untiltime,
2449 if (!zp->z_untilrule.r_todisstd)
2450 untiltime = tadd(untiltime,
2454 ** Find the rule (of those to do, if any)
2455 ** that takes effect earliest in the year.
2458 for (j = 0; j < zp->z_nrules; ++j) {
2459 rp = &zp->z_rules[j];
2462 eats(zp->z_filename, zp->z_linenum,
2463 rp->r_filename, rp->r_linenum);
2464 offset = rp->r_todisgmt ? 0 : gmtoff;
2465 if (!rp->r_todisstd)
2466 offset = oadd(offset, stdoff);
2468 if (jtime == min_time ||
2471 jtime = tadd(jtime, -offset);
2472 if (k < 0 || jtime < ktime) {
2475 } else if (jtime == ktime) {
2476 char const *dup_rules_msg =
2477 _("two rules for same instant");
2478 eats(zp->z_filename, zp->z_linenum,
2479 rp->r_filename, rp->r_linenum);
2480 warning("%s", dup_rules_msg);
2481 rp = &zp->z_rules[k];
2482 eats(zp->z_filename, zp->z_linenum,
2483 rp->r_filename, rp->r_linenum);
2484 error("%s", dup_rules_msg);
2488 break; /* go on to next year */
2489 rp = &zp->z_rules[k];
2491 if (useuntil && ktime >= untiltime)
2493 stdoff = rp->r_stdoff;
2494 if (usestart && ktime == starttime)
2497 if (ktime < starttime) {
2498 startoff = oadd(zp->z_gmtoff,
2500 doabbr(startbuf, zp,
2506 if (*startbuf == '\0' &&
2507 startoff == oadd(zp->z_gmtoff,
2516 eats(zp->z_filename, zp->z_linenum,
2517 rp->r_filename, rp->r_linenum);
2518 doabbr(ab, zp, rp->r_abbrvar,
2519 rp->r_stdoff, false);
2520 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2521 type = addtype(offset, ab, rp->r_stdoff != 0,
2522 rp->r_todisstd, rp->r_todisgmt);
2527 if (*startbuf == '\0' &&
2528 zp->z_format != NULL &&
2529 strchr(zp->z_format, '%') == NULL &&
2530 strchr(zp->z_format, '/') == NULL)
2531 strcpy(startbuf, zp->z_format);
2532 eat(zp->z_filename, zp->z_linenum);
2533 if (*startbuf == '\0')
2534 error(_("can't determine time zone abbreviation to use just after until time"));
2535 else addtt(starttime,
2536 addtype(startoff, startbuf,
2537 startoff != zp->z_gmtoff,
2542 ** Now we may get to set starttime for the next zone line.
2545 startttisstd = zp->z_untilrule.r_todisstd;
2546 startttisgmt = zp->z_untilrule.r_todisgmt;
2547 starttime = zp->z_untiltime;
2549 starttime = tadd(starttime, -stdoff);
2551 starttime = tadd(starttime, -gmtoff);
2556 ** If we're extending the explicitly listed observations
2557 ** for 400 years because we can't fill the POSIX-TZ field,
2558 ** check whether we actually ended up explicitly listing
2559 ** observations through that period. If there aren't any
2560 ** near the end of the 400-year period, add a redundant
2561 ** one at the end of the final year, to make it clear
2562 ** that we are claiming to have definite knowledge of
2563 ** the lack of transitions up to that point.
2566 struct attype *lastat;
2567 xr.r_month = TM_JANUARY;
2568 xr.r_dycode = DC_DOM;
2569 xr.r_dayofmonth = 1;
2571 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2572 if (attypes[i].at > lastat->at)
2573 lastat = &attypes[i];
2574 if (lastat->at < rpytime(&xr, max_year - 1)) {
2576 ** Create new type code for the redundant entry,
2577 ** to prevent it being optimized away.
2579 if (typecnt >= TZ_MAX_TYPES) {
2580 error(_("too many local time types"));
2583 gmtoffs[typecnt] = gmtoffs[lastat->type];
2584 isdsts[typecnt] = isdsts[lastat->type];
2585 ttisstds[typecnt] = ttisstds[lastat->type];
2586 ttisgmts[typecnt] = ttisgmts[lastat->type];
2587 abbrinds[typecnt] = abbrinds[lastat->type];
2589 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2592 writezone(zpfirst->z_name, envvar, version);
2599 addtt(zic_t starttime, int type)
2601 if (starttime <= early_time
2602 || (timecnt == 1 && attypes[0].at < early_time)) {
2603 gmtoffs[0] = gmtoffs[type];
2604 isdsts[0] = isdsts[type];
2605 ttisstds[0] = ttisstds[type];
2606 ttisgmts[0] = ttisgmts[type];
2607 if (abbrinds[type] != 0)
2608 strcpy(chars, &chars[abbrinds[type]]);
2610 charcnt = strlen(chars) + 1;
2615 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2616 attypes[timecnt].at = starttime;
2617 attypes[timecnt].type = type;
2622 addtype(zic_t gmtoff, char const *abbr, bool isdst, bool ttisstd, bool ttisgmt)
2627 ** See if there's already an entry for this zone type.
2628 ** If so, just return its index.
2630 for (i = 0; i < typecnt; ++i) {
2631 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2632 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2633 ttisstd == ttisstds[i] &&
2634 ttisgmt == ttisgmts[i])
2638 ** There isn't one; add a new one, unless there are already too
2641 if (typecnt >= TZ_MAX_TYPES) {
2642 error(_("too many local time types"));
2645 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2646 error(_("UT offset out of range"));
2649 gmtoffs[i] = gmtoff;
2651 ttisstds[i] = ttisstd;
2652 ttisgmts[i] = ttisgmt;
2654 for (j = 0; j < charcnt; ++j)
2655 if (strcmp(&chars[j], abbr) == 0)
2665 leapadd(zic_t t, bool positive, int rolling, int count)
2669 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2670 error(_("too many leap seconds"));
2673 for (i = 0; i < leapcnt; ++i)
2674 if (t <= trans[i]) {
2675 if (t == trans[i]) {
2676 error(_("repeated leap second moment"));
2682 for (j = leapcnt; j > i; --j) {
2683 trans[j] = trans[j - 1];
2684 corr[j] = corr[j - 1];
2685 roll[j] = roll[j - 1];
2688 corr[i] = positive ? 1 : -count;
2691 } while (positive && --count != 0);
2698 register zic_t last = 0;
2701 ** propagate leap seconds forward
2703 for (i = 0; i < leapcnt; ++i) {
2704 trans[i] = tadd(trans[i], last);
2705 last = corr[i] += last;
2710 yearistype(int year, const char *type)
2715 if (type == NULL || *type == '\0')
2717 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
2718 sprintf(buf, "%s %d %s", yitcommand, year, type);
2719 result = system(buf);
2720 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2726 error(_("Wild result from command execution"));
2727 fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2728 progname, buf, result);
2733 /* Is A a space character in the C locale? */
2740 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2745 /* Is A an alphabetic character in the C locale? */
2752 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2753 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2754 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2755 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2756 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2757 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2758 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2759 case 'v': case 'w': case 'x': case 'y': case 'z':
2764 /* If A is an uppercase character in the C locale, return its lowercase
2765 counterpart. Otherwise, return A. */
2771 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2772 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2773 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2774 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2775 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2776 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2777 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2778 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2779 case 'Y': return 'y'; case 'Z': return 'z';
2783 /* case-insensitive equality */
2784 static ATTRIBUTE_PURE bool
2785 ciequal(register const char *ap, register const char *bp)
2787 while (lowerit(*ap) == lowerit(*bp++))
2793 static ATTRIBUTE_PURE bool
2794 itsabbr(register const char *abbr, register const char *word)
2796 if (lowerit(*abbr) != lowerit(*word))
2799 while (*++abbr != '\0')
2803 } while (lowerit(*word++) != lowerit(*abbr));
2807 static ATTRIBUTE_PURE const struct lookup *
2808 byword(const char *word, const struct lookup *table)
2810 register const struct lookup * foundlp;
2811 register const struct lookup * lp;
2813 if (word == NULL || table == NULL)
2816 ** Look for exact match.
2818 for (lp = table; lp->l_word != NULL; ++lp)
2819 if (ciequal(word, lp->l_word))
2822 ** Look for inexact match.
2825 for (lp = table; lp->l_word != NULL; ++lp)
2826 if (itsabbr(word, lp->l_word)) {
2827 if (foundlp == NULL)
2829 else return NULL; /* multiple inexact matches */
2835 getfields(register char *cp)
2838 register char ** array;
2843 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
2846 while (is_space(*cp))
2848 if (*cp == '\0' || *cp == '#')
2850 array[nsubs++] = dp = cp;
2852 if ((*dp = *cp++) != '"')
2854 else while ((*dp = *cp++) != '"')
2859 "Odd number of quotation marks"
2863 } while (*cp && *cp != '#' && !is_space(*cp));
2868 array[nsubs] = NULL;
2872 static _Noreturn void
2875 error(_("time overflow"));
2879 static ATTRIBUTE_PURE zic_t
2880 oadd(zic_t t1, zic_t t2)
2882 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2)
2887 static ATTRIBUTE_PURE zic_t
2888 tadd(zic_t t1, zic_t t2)
2891 if (t2 < min_time - t1) {
2897 if (max_time - t1 < t2) {
2907 ** Given a rule, and a year, compute the date (in seconds since January 1,
2908 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
2912 rpytime(const struct rule *rp, zic_t wantedy)
2915 register zic_t dayoff; /* with a nod to Margaret O. */
2916 register zic_t t, y;
2918 if (wantedy == ZIC_MIN)
2920 if (wantedy == ZIC_MAX)
2925 while (wantedy != y) {
2927 i = len_years[isleap(y)];
2931 i = -len_years[isleap(y)];
2933 dayoff = oadd(dayoff, i);
2935 while (m != rp->r_month) {
2936 i = len_months[isleap(y)][m];
2937 dayoff = oadd(dayoff, i);
2940 i = rp->r_dayofmonth;
2941 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2942 if (rp->r_dycode == DC_DOWLEQ)
2945 error(_("use of 2/29 in non leap-year"));
2950 dayoff = oadd(dayoff, i);
2951 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2952 register zic_t wday;
2954 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2957 ** Don't trust mod of negative numbers.
2960 wday = (wday + dayoff) % LDAYSPERWEEK;
2962 wday -= ((-dayoff) % LDAYSPERWEEK);
2964 wday += LDAYSPERWEEK;
2966 while (wday != rp->r_wday)
2967 if (rp->r_dycode == DC_DOWGEQ) {
2968 dayoff = oadd(dayoff, 1);
2969 if (++wday >= LDAYSPERWEEK)
2973 dayoff = oadd(dayoff, -1);
2975 wday = LDAYSPERWEEK - 1;
2978 if (i < 0 || i >= len_months[isleap(y)][m]) {
2980 warning(_("rule goes past start/end of month; \
2981 will not work with pre-2004 versions of zic"));
2984 if (dayoff < min_time / SECSPERDAY)
2986 if (dayoff > max_time / SECSPERDAY)
2988 t = (zic_t) dayoff * SECSPERDAY;
2989 return tadd(t, rp->r_tod);
2993 newabbr(const char *string)
2997 if (strcmp(string, GRANDPARENTED) != 0) {
2998 register const char * cp;
3003 while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9')
3004 || *cp == '-' || *cp == '+')
3006 if (noise && cp - string < 3)
3007 mp = _("time zone abbreviation has fewer than 3 characters");
3008 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
3009 mp = _("time zone abbreviation has too many characters");
3011 mp = _("time zone abbreviation differs from POSIX standard");
3013 warning("%s (%s)", mp, string);
3015 i = strlen(string) + 1;
3016 if (charcnt + i > TZ_MAX_CHARS) {
3017 error(_("too many, or too long, time zone abbreviations"));
3020 strcpy(&chars[charcnt], string);
3025 mkdirs(char *argname)
3027 register char * name;
3030 if (argname == NULL || *argname == '\0')
3032 cp = name = ecpyalloc(argname);
3033 while ((cp = strchr(cp + 1, '/')) != 0) {
3035 #ifdef HAVE_DOS_FILE_NAMES
3037 ** DOS drive specifier?
3039 if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0') {
3045 ** Try to create it. It's OK if creation fails because
3046 ** the directory already exists, perhaps because some
3047 ** other process just created it.
3049 if (mkdir(name, MKDIR_UMASK) != 0) {
3051 if (itsdir(name) <= 0) {
3052 char const *e = strerror(err);
3053 warning(_("%s: Can't create directory"