2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
11 #define ZIC_VERSION '2'
13 typedef int_fast64_t zic_t;
15 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
16 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
17 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
23 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
25 #define MKDIR_UMASK 0755
29 ** On some ancient hosts, predicates like `isspace(C)' are defined
30 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
31 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
32 ** Neither the C Standard nor Posix require that `isascii' exist.
33 ** For portability, we check both ancient and modern requirements.
34 ** If isascii is not defined, the isascii check succeeds trivially.
41 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
42 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
44 #define end(cp) (strchr((cp), '\0'))
47 const char * r_filename;
51 int r_loyear; /* for example, 1986 */
52 int r_hiyear; /* for example, 1986 */
53 const char * r_yrtype;
57 int r_month; /* 0..11 */
59 int r_dycode; /* see below */
63 long r_tod; /* time from midnight */
64 int r_todisstd; /* above is standard time if TRUE */
65 /* or wall clock time if FALSE */
66 int r_todisgmt; /* above is GMT if TRUE */
67 /* or local time if FALSE */
68 long r_stdoff; /* offset from standard time */
69 const char * r_abbrvar; /* variable part of abbreviation */
71 int r_todo; /* a rule to do (used in outzone) */
72 zic_t r_temp; /* used in outzone */
76 ** r_dycode r_dayofmonth r_wday
79 #define DC_DOM 0 /* 1..31 */ /* unused */
80 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
81 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
84 const char * z_filename;
90 const char * z_format;
94 struct rule * z_rules;
97 struct rule z_untilrule;
101 extern int getopt(int argc, char * const argv[],
102 const char * options);
103 extern int link(const char * fromname, const char * toname);
104 extern char * optarg;
107 static void addtt(zic_t starttime, int type);
108 static int addtype(long gmtoff, const char * abbr, int isdst,
109 int ttisstd, int ttisgmt);
110 static void leapadd(zic_t t, int positive, int rolling, int count);
111 static void adjleap(void);
112 static void associate(void);
113 static int ciequal(const char * ap, const char * bp);
114 static void convert(long val, char * buf);
115 static void convert64(zic_t val, char * buf);
116 static void dolink(const char * fromfield, const char * tofield);
117 static void doabbr(char * abbr, const char * format,
118 const char * letters, int isdst, int doquotes);
119 static void eat(const char * name, int num);
120 static void eats(const char * name, int num,
121 const char * rname, int rnum);
122 static long eitol(int i);
123 static void error(const char * message);
124 static char ** getfields(char * buf);
125 static long gethms(const char * string, const char * errstrng,
127 static void infile(const char * filename);
128 static void inleap(char ** fields, int nfields);
129 static void inlink(char ** fields, int nfields);
130 static void inrule(char ** fields, int nfields);
131 static int inzcont(char ** fields, int nfields);
132 static int inzone(char ** fields, int nfields);
133 static int inzsub(char ** fields, int nfields, int iscont);
134 static int is32(zic_t x);
135 static int itsabbr(const char * abbr, const char * word);
136 static int itsdir(const char * name);
137 static int lowerit(int c);
138 static char * memcheck(char * tocheck);
139 static int mkdirs(char * filename);
140 static void newabbr(const char * abbr);
141 static long oadd(long t1, long t2);
142 static void outzone(const struct zone * zp, int ntzones);
143 static void puttzcode(long code, FILE * fp);
144 static void puttzcode64(zic_t code, FILE * fp);
145 static int rcomp(const void * leftp, const void * rightp);
146 static zic_t rpytime(const struct rule * rp, int wantedy);
147 static void rulesub(struct rule * rp,
148 const char * loyearp, const char * hiyearp,
149 const char * typep, const char * monthp,
150 const char * dayp, const char * timep);
151 static int stringoffset(char * result, long offset);
152 static int stringrule(char * result, const struct rule * rp,
153 long dstoff, long gmtoff);
154 static void stringzone(char * result,
155 const struct zone * zp, int ntzones);
156 static void setboundaries(void);
157 static zic_t tadd(zic_t t1, long t2);
158 static void usage(FILE *stream, int status);
159 static void writezone(const char * name, const char * string);
160 static int yearistype(int year, const char * type);
164 static const char * filename;
167 static int leapminyear;
168 static int leapmaxyear;
170 static int max_abbrvar_len;
171 static int max_format_len;
172 static zic_t max_time;
174 static zic_t min_time;
177 static const char * rfilename;
179 static const char * progname;
193 ** Which fields are which on a Zone line.
201 #define ZF_TILMONTH 6
204 #define ZONE_MINFIELDS 5
205 #define ZONE_MAXFIELDS 9
208 ** Which fields are which on a Zone continuation line.
214 #define ZFC_TILYEAR 3
215 #define ZFC_TILMONTH 4
217 #define ZFC_TILTIME 6
218 #define ZONEC_MINFIELDS 3
219 #define ZONEC_MAXFIELDS 7
222 ** Which files are which on a Rule line.
234 #define RULE_FIELDS 10
237 ** Which fields are which on a Link line.
242 #define LINK_FIELDS 3
245 ** Which fields are which on a Leap line.
254 #define LEAP_FIELDS 7
264 static struct rule * rules;
265 static int nrules; /* number of rules */
267 static struct zone * zones;
268 static int nzones; /* number of zones */
271 const char * l_filename;
277 static struct link * links;
285 static struct lookup const * byword(const char * string,
286 const struct lookup * lp);
288 static struct lookup const line_codes[] = {
296 static struct lookup const mon_names[] = {
297 { "January", TM_JANUARY },
298 { "February", TM_FEBRUARY },
299 { "March", TM_MARCH },
300 { "April", TM_APRIL },
304 { "August", TM_AUGUST },
305 { "September", TM_SEPTEMBER },
306 { "October", TM_OCTOBER },
307 { "November", TM_NOVEMBER },
308 { "December", TM_DECEMBER },
312 static struct lookup const wday_names[] = {
313 { "Sunday", TM_SUNDAY },
314 { "Monday", TM_MONDAY },
315 { "Tuesday", TM_TUESDAY },
316 { "Wednesday", TM_WEDNESDAY },
317 { "Thursday", TM_THURSDAY },
318 { "Friday", TM_FRIDAY },
319 { "Saturday", TM_SATURDAY },
323 static struct lookup const lasts[] = {
324 { "last-Sunday", TM_SUNDAY },
325 { "last-Monday", TM_MONDAY },
326 { "last-Tuesday", TM_TUESDAY },
327 { "last-Wednesday", TM_WEDNESDAY },
328 { "last-Thursday", TM_THURSDAY },
329 { "last-Friday", TM_FRIDAY },
330 { "last-Saturday", TM_SATURDAY },
334 static struct lookup const begin_years[] = {
335 { "minimum", YR_MINIMUM },
336 { "maximum", YR_MAXIMUM },
340 static struct lookup const end_years[] = {
341 { "minimum", YR_MINIMUM },
342 { "maximum", YR_MAXIMUM },
347 static struct lookup const leap_types[] = {
349 { "Stationary", FALSE },
353 static const int len_months[2][MONSPERYEAR] = {
354 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
355 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
358 static const int len_years[2] = {
359 DAYSPERNYEAR, DAYSPERLYEAR
362 static struct attype {
365 } attypes[TZ_MAX_TIMES];
366 static long gmtoffs[TZ_MAX_TYPES];
367 static char isdsts[TZ_MAX_TYPES];
368 static unsigned char abbrinds[TZ_MAX_TYPES];
369 static char ttisstds[TZ_MAX_TYPES];
370 static char ttisgmts[TZ_MAX_TYPES];
371 static char chars[TZ_MAX_CHARS];
372 static zic_t trans[TZ_MAX_LEAPS];
373 static long corr[TZ_MAX_LEAPS];
374 static char roll[TZ_MAX_LEAPS];
377 ** Memory allocation.
385 const char *e = strerror(errno);
387 (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
394 #define emalloc(size) memcheck(imalloc(size))
395 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
396 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
397 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
404 eats(name, num, rname, rnum)
405 const char * const name;
407 const char * const rname;
418 const char * const name;
421 eats(name, num, (char *) NULL, -1);
426 const char * const string;
429 ** Match the format of "cc" to allow sh users to
430 ** zic ... 2>&1 | error -t "*" -v
433 (void) fprintf(stderr, _("\"%s\", line %d: %s"),
434 filename, linenum, string);
435 if (rfilename != NULL)
436 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
437 rfilename, rlinenum);
438 (void) fprintf(stderr, "\n");
444 const char * const string;
448 cp = ecpyalloc(_("warning: "));
449 cp = ecatalloc(cp, string);
456 usage(FILE *stream, int status)
458 (void) fprintf(stream, _("%s: usage is %s \
459 [ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
460 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
462 Report bugs to tz@elsie.nci.nih.gov.\n"),
467 static const char * psxrules;
468 static const char * lcltime;
469 static const char * directory;
470 static const char * leapsec;
471 static const char * yitcommand;
483 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
484 #endif /* defined unix */
486 (void) setlocale(LC_ALL, "");
488 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
489 #endif /* defined TEXTDOMAINDIR */
490 (void) textdomain(TZ_DOMAIN);
491 #endif /* HAVE_GETTEXT */
493 if (TYPE_BIT(zic_t) < 64) {
494 (void) fprintf(stderr, "%s: %s\n", progname,
495 _("wild compilation-time specification of zic_t"));
498 for (i = 1; i < argc; ++i)
499 if (strcmp(argv[i], "--version") == 0) {
500 (void) printf("%s\n", TZVERSION);
502 } else if (strcmp(argv[i], "--help") == 0) {
503 usage(stdout, EXIT_SUCCESS);
505 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
508 usage(stderr, EXIT_FAILURE);
510 if (directory == NULL)
513 (void) fprintf(stderr,
514 _("%s: More than one -d option specified\n"),
523 (void) fprintf(stderr,
524 _("%s: More than one -l option specified\n"),
530 if (psxrules == NULL)
533 (void) fprintf(stderr,
534 _("%s: More than one -p option specified\n"),
540 if (yitcommand == NULL)
543 (void) fprintf(stderr,
544 _("%s: More than one -y option specified\n"),
553 (void) fprintf(stderr,
554 _("%s: More than one -L option specified\n"),
563 (void) printf("%s: -s ignored\n", progname);
566 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
567 usage(stderr, EXIT_FAILURE); /* usage message by request */
568 if (directory == NULL)
570 if (yitcommand == NULL)
571 yitcommand = "yearistype";
575 if (optind < argc && leapsec != NULL) {
580 for (i = optind; i < argc; ++i)
585 for (i = 0; i < nzones; i = j) {
587 ** Find the next non-continuation zone entry.
589 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
591 outzone(&zones[i], j - i);
596 for (i = 0; i < nlinks; ++i) {
597 eat(links[i].l_filename, links[i].l_linenum);
598 dolink(links[i].l_from, links[i].l_to);
600 for (j = 0; j < nlinks; ++j)
601 if (strcmp(links[i].l_to,
602 links[j].l_from) == 0)
603 warning(_("link to link"));
605 if (lcltime != NULL) {
606 eat("command line", 1);
607 dolink(lcltime, TZDEFAULT);
609 if (psxrules != NULL) {
610 eat("command line", 1);
611 dolink(psxrules, TZDEFRULES);
613 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
617 dolink(fromfield, tofield)
618 const char * const fromfield;
619 const char * const tofield;
621 register char * fromname;
622 register char * toname;
624 if (fromfield[0] == '/')
625 fromname = ecpyalloc(fromfield);
627 fromname = ecpyalloc(directory);
628 fromname = ecatalloc(fromname, "/");
629 fromname = ecatalloc(fromname, fromfield);
631 if (tofield[0] == '/')
632 toname = ecpyalloc(tofield);
634 toname = ecpyalloc(directory);
635 toname = ecatalloc(toname, "/");
636 toname = ecatalloc(toname, tofield);
639 ** We get to be careful here since
640 ** there's a fair chance of root running us.
643 (void) remove(toname);
644 if (link(fromname, toname) != 0) {
647 if (mkdirs(toname) != 0)
650 result = link(fromname, toname);
653 access(fromname, F_OK) == 0 &&
655 const char *s = tofield;
656 register char * symlinkcontents = NULL;
658 while ((s = strchr(s+1, '/')) != NULL)
660 ecatalloc(symlinkcontents,
663 ecatalloc(symlinkcontents,
665 result = symlink(symlinkcontents,
668 warning(_("hard link failed, symbolic link used"));
669 ifree(symlinkcontents);
671 #endif /* HAVE_SYMLINK */
673 const char *e = strerror(errno);
675 (void) fprintf(stderr,
676 _("%s: Can't link from %s to %s: %s\n"),
677 progname, fromname, toname, e);
685 #define TIME_T_BITS_IN_FILE 64
693 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
695 max_time = -(min_time + 1);
700 const char * const name;
702 register char * myname;
705 myname = ecpyalloc(name);
706 myname = ecatalloc(myname, "/.");
707 accres = access(myname, F_OK);
713 ** Associate sets of rules with zones.
717 ** Sort by rule name.
725 return strcmp(((const struct rule *) cp1)->r_name,
726 ((const struct rule *) cp2)->r_name);
732 register struct zone * zp;
733 register struct rule * rp;
734 register int base, out;
738 (void) qsort((void *) rules, (size_t) nrules,
739 (size_t) sizeof *rules, rcomp);
740 for (i = 0; i < nrules - 1; ++i) {
741 if (strcmp(rules[i].r_name,
742 rules[i + 1].r_name) != 0)
744 if (strcmp(rules[i].r_filename,
745 rules[i + 1].r_filename) == 0)
747 eat(rules[i].r_filename, rules[i].r_linenum);
748 warning(_("same rule name in multiple files"));
749 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
750 warning(_("same rule name in multiple files"));
751 for (j = i + 2; j < nrules; ++j) {
752 if (strcmp(rules[i].r_name,
753 rules[j].r_name) != 0)
755 if (strcmp(rules[i].r_filename,
756 rules[j].r_filename) == 0)
758 if (strcmp(rules[i + 1].r_filename,
759 rules[j].r_filename) == 0)
766 for (i = 0; i < nzones; ++i) {
771 for (base = 0; base < nrules; base = out) {
773 for (out = base + 1; out < nrules; ++out)
774 if (strcmp(rp->r_name, rules[out].r_name) != 0)
776 for (i = 0; i < nzones; ++i) {
778 if (strcmp(zp->z_rule, rp->r_name) != 0)
781 zp->z_nrules = out - base;
784 for (i = 0; i < nzones; ++i) {
786 if (zp->z_nrules == 0) {
788 ** Maybe we have a local standard time offset.
790 eat(zp->z_filename, zp->z_linenum);
791 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
794 ** Note, though, that if there's no rule,
795 ** a '%s' in the format is a bad thing.
797 if (strchr(zp->z_format, '%') != 0)
798 error(_("%s in ruleless zone"));
810 register char ** fields;
812 register const struct lookup * lp;
813 register int nfields;
814 register int wantcont;
818 if (strcmp(name, "-") == 0) {
819 name = _("standard input");
821 } else if ((fp = fopen(name, "r")) == NULL) {
822 const char *e = strerror(errno);
824 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
829 for (num = 1; ; ++num) {
831 if (fgets(buf, (int) sizeof buf, fp) != buf)
833 cp = strchr(buf, '\n');
835 error(_("line too long"));
839 fields = getfields(buf);
841 while (fields[nfields] != NULL) {
844 if (strcmp(fields[nfields], "-") == 0)
845 fields[nfields] = &nada;
850 } else if (wantcont) {
851 wantcont = inzcont(fields, nfields);
853 lp = byword(fields[0], line_codes);
855 error(_("input line of unknown type"));
856 else switch ((int) (lp->l_value)) {
858 inrule(fields, nfields);
862 wantcont = inzone(fields, nfields);
865 inlink(fields, nfields);
870 (void) fprintf(stderr,
871 _("%s: Leap line in non leap seconds file %s\n"),
873 else inleap(fields, nfields);
876 default: /* "cannot happen" */
877 (void) fprintf(stderr,
878 _("%s: panic: Invalid l_value %d\n"),
879 progname, lp->l_value);
883 ifree((char *) fields);
886 (void) fprintf(stderr, _("%s: Error reading %s\n"),
890 if (fp != stdin && fclose(fp)) {
891 const char *e = strerror(errno);
893 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
894 progname, filename, e);
898 error(_("expected continuation line not found"));
902 ** Convert a string of one of the forms
903 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
904 ** into a number of seconds.
905 ** A null string maps to zero.
906 ** Call error with errstring and return zero on errors.
910 gethms(string, errstring, signable)
912 const char * const errstring;
918 if (string == NULL || *string == '\0')
922 else if (*string == '-') {
926 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
928 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
930 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
931 &hh, &mm, &ss) != 3) {
936 mm < 0 || mm >= MINSPERHOUR ||
937 ss < 0 || ss > SECSPERMIN) {
941 if (LONG_MAX / SECSPERHOUR < hh) {
942 error(_("time overflow"));
945 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
946 warning(_("24:00 not handled by pre-1998 versions of zic"));
947 if (noise && (hh > HOURSPERDAY ||
948 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
949 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
950 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
951 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
955 inrule(fields, nfields)
956 register char ** const fields;
959 static struct rule r;
961 if (nfields != RULE_FIELDS) {
962 error(_("wrong number of fields on Rule line"));
965 if (*fields[RF_NAME] == '\0') {
966 error(_("nameless rule"));
969 r.r_filename = filename;
970 r.r_linenum = linenum;
971 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
972 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
973 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
974 r.r_name = ecpyalloc(fields[RF_NAME]);
975 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
976 if (max_abbrvar_len < strlen(r.r_abbrvar))
977 max_abbrvar_len = strlen(r.r_abbrvar);
978 rules = (struct rule *) (void *) erealloc((char *) rules,
979 (int) ((nrules + 1) * sizeof *rules));
984 inzone(fields, nfields)
985 register char ** const fields;
991 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
992 error(_("wrong number of fields on Zone line"));
995 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
996 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
998 _("\"Zone %s\" line and -l option are mutually exclusive"),
1003 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1004 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
1006 _("\"Zone %s\" line and -p option are mutually exclusive"),
1011 for (i = 0; i < nzones; ++i)
1012 if (zones[i].z_name != NULL &&
1013 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1014 buf = erealloc(buf, (int) (132 +
1015 strlen(fields[ZF_NAME]) +
1016 strlen(zones[i].z_filename)));
1018 _("duplicate zone name %s (file \"%s\", line %d)"),
1020 zones[i].z_filename,
1021 zones[i].z_linenum);
1025 return inzsub(fields, nfields, FALSE);
1029 inzcont(fields, nfields)
1030 register char ** const fields;
1033 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1034 error(_("wrong number of fields on Zone continuation line"));
1037 return inzsub(fields, nfields, TRUE);
1041 inzsub(fields, nfields, iscont)
1042 register char ** const fields;
1047 static struct zone z;
1048 register int i_gmtoff, i_rule, i_format;
1049 register int i_untilyear, i_untilmonth;
1050 register int i_untilday, i_untiltime;
1051 register int hasuntil;
1054 i_gmtoff = ZFC_GMTOFF;
1056 i_format = ZFC_FORMAT;
1057 i_untilyear = ZFC_TILYEAR;
1058 i_untilmonth = ZFC_TILMONTH;
1059 i_untilday = ZFC_TILDAY;
1060 i_untiltime = ZFC_TILTIME;
1063 i_gmtoff = ZF_GMTOFF;
1065 i_format = ZF_FORMAT;
1066 i_untilyear = ZF_TILYEAR;
1067 i_untilmonth = ZF_TILMONTH;
1068 i_untilday = ZF_TILDAY;
1069 i_untiltime = ZF_TILTIME;
1070 z.z_name = ecpyalloc(fields[ZF_NAME]);
1072 z.z_filename = filename;
1073 z.z_linenum = linenum;
1074 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1075 if ((cp = strchr(fields[i_format], '%')) != 0) {
1076 if (*++cp != 's' || strchr(cp, '%') != 0) {
1077 error(_("invalid abbreviation format"));
1081 z.z_rule = ecpyalloc(fields[i_rule]);
1082 z.z_format = ecpyalloc(fields[i_format]);
1083 if (max_format_len < strlen(z.z_format))
1084 max_format_len = strlen(z.z_format);
1085 hasuntil = nfields > i_untilyear;
1087 z.z_untilrule.r_filename = filename;
1088 z.z_untilrule.r_linenum = linenum;
1089 rulesub(&z.z_untilrule,
1090 fields[i_untilyear],
1093 (nfields > i_untilmonth) ?
1094 fields[i_untilmonth] : "Jan",
1095 (nfields > i_untilday) ? fields[i_untilday] : "1",
1096 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1097 z.z_untiltime = rpytime(&z.z_untilrule,
1098 z.z_untilrule.r_loyear);
1099 if (iscont && nzones > 0 &&
1100 z.z_untiltime > min_time &&
1101 z.z_untiltime < max_time &&
1102 zones[nzones - 1].z_untiltime > min_time &&
1103 zones[nzones - 1].z_untiltime < max_time &&
1104 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1106 "Zone continuation line end time is not after end time of previous line"
1111 zones = (struct zone *) (void *) erealloc((char *) zones,
1112 (int) ((nzones + 1) * sizeof *zones));
1113 zones[nzones++] = z;
1115 ** If there was an UNTIL field on this line,
1116 ** there's more information about the zone on the next line.
1122 inleap(fields, nfields)
1123 register char ** const fields;
1126 register const char * cp;
1127 register const struct lookup * lp;
1129 int year, month, day;
1133 if (nfields != LEAP_FIELDS) {
1134 error(_("wrong number of fields on Leap line"));
1138 cp = fields[LP_YEAR];
1139 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1143 error(_("invalid leaping year"));
1146 if (!leapseen || leapmaxyear < year)
1148 if (!leapseen || leapminyear > year)
1154 i = len_years[isleap(j)];
1158 i = -len_years[isleap(j)];
1160 dayoff = oadd(dayoff, eitol(i));
1162 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1163 error(_("invalid month name"));
1166 month = lp->l_value;
1168 while (j != month) {
1169 i = len_months[isleap(year)][j];
1170 dayoff = oadd(dayoff, eitol(i));
1173 cp = fields[LP_DAY];
1174 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1175 day <= 0 || day > len_months[isleap(year)][month]) {
1176 error(_("invalid day of month"));
1179 dayoff = oadd(dayoff, eitol(day - 1));
1180 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1181 error(_("time before zero"));
1184 if (dayoff < min_time / SECSPERDAY) {
1185 error(_("time too small"));
1188 if (dayoff > max_time / SECSPERDAY) {
1189 error(_("time too large"));
1192 t = (zic_t) dayoff * SECSPERDAY;
1193 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1194 cp = fields[LP_CORR];
1196 register int positive;
1199 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1202 } else if (strcmp(cp, "--") == 0) {
1205 } else if (strcmp(cp, "+") == 0) {
1208 } else if (strcmp(cp, "++") == 0) {
1212 error(_("illegal CORRECTION field on Leap line"));
1215 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1217 "illegal Rolling/Stationary field on Leap line"
1221 leapadd(tadd(t, tod), positive, lp->l_value, count);
1226 inlink(fields, nfields)
1227 register char ** const fields;
1232 if (nfields != LINK_FIELDS) {
1233 error(_("wrong number of fields on Link line"));
1236 if (*fields[LF_FROM] == '\0') {
1237 error(_("blank FROM field on Link line"));
1240 if (*fields[LF_TO] == '\0') {
1241 error(_("blank TO field on Link line"));
1244 l.l_filename = filename;
1245 l.l_linenum = linenum;
1246 l.l_from = ecpyalloc(fields[LF_FROM]);
1247 l.l_to = ecpyalloc(fields[LF_TO]);
1248 links = (struct link *) (void *) erealloc((char *) links,
1249 (int) ((nlinks + 1) * sizeof *links));
1250 links[nlinks++] = l;
1254 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1255 register struct rule * const rp;
1256 const char * const loyearp;
1257 const char * const hiyearp;
1258 const char * const typep;
1259 const char * const monthp;
1260 const char * const dayp;
1261 const char * const timep;
1263 register const struct lookup * lp;
1264 register const char * cp;
1268 if ((lp = byword(monthp, mon_names)) == NULL) {
1269 error(_("invalid month name"));
1272 rp->r_month = lp->l_value;
1273 rp->r_todisstd = FALSE;
1274 rp->r_todisgmt = FALSE;
1275 dp = ecpyalloc(timep);
1277 ep = dp + strlen(dp) - 1;
1278 switch (lowerit(*ep)) {
1279 case 's': /* Standard */
1280 rp->r_todisstd = TRUE;
1281 rp->r_todisgmt = FALSE;
1284 case 'w': /* Wall */
1285 rp->r_todisstd = FALSE;
1286 rp->r_todisgmt = FALSE;
1289 case 'g': /* Greenwich */
1290 case 'u': /* Universal */
1291 case 'z': /* Zulu */
1292 rp->r_todisstd = TRUE;
1293 rp->r_todisgmt = TRUE;
1298 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1304 lp = byword(cp, begin_years);
1305 rp->r_lowasnum = lp == NULL;
1306 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1308 rp->r_loyear = INT_MIN;
1311 rp->r_loyear = INT_MAX;
1313 default: /* "cannot happen" */
1314 (void) fprintf(stderr,
1315 _("%s: panic: Invalid l_value %d\n"),
1316 progname, lp->l_value);
1318 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1319 error(_("invalid starting year"));
1323 lp = byword(cp, end_years);
1324 rp->r_hiwasnum = lp == NULL;
1325 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1327 rp->r_hiyear = INT_MIN;
1330 rp->r_hiyear = INT_MAX;
1333 rp->r_hiyear = rp->r_loyear;
1335 default: /* "cannot happen" */
1336 (void) fprintf(stderr,
1337 _("%s: panic: Invalid l_value %d\n"),
1338 progname, lp->l_value);
1340 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1341 error(_("invalid ending year"));
1344 if (rp->r_loyear > rp->r_hiyear) {
1345 error(_("starting year greater than ending year"));
1349 rp->r_yrtype = NULL;
1351 if (rp->r_loyear == rp->r_hiyear) {
1352 error(_("typed single year"));
1355 rp->r_yrtype = ecpyalloc(typep);
1359 ** Accept things such as:
1365 dp = ecpyalloc(dayp);
1366 if ((lp = byword(dp, lasts)) != NULL) {
1367 rp->r_dycode = DC_DOWLEQ;
1368 rp->r_wday = lp->l_value;
1369 rp->r_dayofmonth = len_months[1][rp->r_month];
1371 if ((ep = strchr(dp, '<')) != 0)
1372 rp->r_dycode = DC_DOWLEQ;
1373 else if ((ep = strchr(dp, '>')) != 0)
1374 rp->r_dycode = DC_DOWGEQ;
1377 rp->r_dycode = DC_DOM;
1379 if (rp->r_dycode != DC_DOM) {
1382 error(_("invalid day of month"));
1386 if ((lp = byword(dp, wday_names)) == NULL) {
1387 error(_("invalid weekday name"));
1391 rp->r_wday = lp->l_value;
1393 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1394 rp->r_dayofmonth <= 0 ||
1395 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1396 error(_("invalid day of month"));
1412 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1413 buf[i] = val >> shift;
1424 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1425 buf[i] = val >> shift;
1436 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1440 puttzcode64(val, fp)
1446 convert64(val, buf);
1447 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1455 const zic_t a = ((const struct attype *) avp)->at;
1456 const zic_t b = ((const struct attype *) bvp)->at;
1458 return (a < b) ? -1 : (a > b);
1465 return INT32_MIN <= x && x <= INT32_MAX;
1469 writezone(name, string)
1470 const char * const name;
1471 const char * const string;
1475 register int leapcnt32, leapi32;
1476 register int timecnt32, timei32;
1478 static char * fullname;
1479 static const struct tzhead tzh0;
1480 static struct tzhead tzh;
1481 zic_t ats[TZ_MAX_TIMES];
1482 unsigned char types[TZ_MAX_TIMES];
1488 (void) qsort((void *) attypes, (size_t) timecnt,
1489 (size_t) sizeof *attypes, atcomp);
1499 while (fromi < timecnt && attypes[fromi].at < min_time)
1502 while (fromi < timecnt && attypes[fromi].type == 0)
1503 ++fromi; /* handled by default rule */
1504 for ( ; fromi < timecnt; ++fromi) {
1505 if (toi != 0 && ((attypes[fromi].at +
1506 gmtoffs[attypes[toi - 1].type]) <=
1507 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1508 : attypes[toi - 2].type]))) {
1509 attypes[toi - 1].type =
1510 attypes[fromi].type;
1514 attypes[toi - 1].type != attypes[fromi].type)
1515 attypes[toi++] = attypes[fromi];
1522 for (i = 0; i < timecnt; ++i) {
1523 ats[i] = attypes[i].at;
1524 types[i] = attypes[i].type;
1527 ** Correct for leap seconds.
1529 for (i = 0; i < timecnt; ++i) {
1532 if (ats[i] > trans[j] - corr[j]) {
1533 ats[i] = tadd(ats[i], corr[j]);
1538 ** Figure out 32-bit-limited starts and counts.
1540 timecnt32 = timecnt;
1542 leapcnt32 = leapcnt;
1544 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1546 while (timecnt32 > 0 && !is32(ats[timei32])) {
1550 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1552 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1556 fullname = erealloc(fullname,
1557 (int) (strlen(directory) + 1 + strlen(name) + 1));
1558 (void) sprintf(fullname, "%s/%s", directory, name);
1560 ** Remove old file, if any, to snap links.
1562 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1563 const char *e = strerror(errno);
1565 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1566 progname, fullname, e);
1569 if ((fp = fopen(fullname, "wb")) == NULL) {
1570 if (mkdirs(fullname) != 0)
1572 if ((fp = fopen(fullname, "wb")) == NULL) {
1573 const char *e = strerror(errno);
1575 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1576 progname, fullname, e);
1580 for (pass = 1; pass <= 2; ++pass) {
1581 register int thistimei, thistimecnt;
1582 register int thisleapi, thisleapcnt;
1583 register int thistimelim, thisleaplim;
1584 int writetype[TZ_MAX_TIMES];
1585 int typemap[TZ_MAX_TYPES];
1586 register int thistypecnt;
1587 char thischars[TZ_MAX_CHARS];
1589 int indmap[TZ_MAX_CHARS];
1592 thistimei = timei32;
1593 thistimecnt = timecnt32;
1594 thisleapi = leapi32;
1595 thisleapcnt = leapcnt32;
1598 thistimecnt = timecnt;
1600 thisleapcnt = leapcnt;
1602 thistimelim = thistimei + thistimecnt;
1603 thisleaplim = thisleapi + thisleapcnt;
1604 for (i = 0; i < typecnt; ++i)
1605 writetype[i] = thistimecnt == timecnt;
1606 if (thistimecnt == 0) {
1608 ** No transition times fall in the current
1609 ** (32- or 64-bit) window.
1612 writetype[typecnt - 1] = TRUE;
1614 for (i = thistimei - 1; i < thistimelim; ++i)
1616 writetype[types[i]] = TRUE;
1618 ** For America/Godthab and Antarctica/Palmer
1621 writetype[0] = TRUE;
1623 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1625 ** For some pre-2011 systems: if the last-to-be-written
1626 ** standard (or daylight) type has an offset different from the
1627 ** most recently used offset,
1628 ** append an (unused) copy of the most recently used type
1629 ** (to help get global "altzone" and "timezone" variables
1633 register int mrudst, mrustd, hidst, histd, type;
1635 hidst = histd = mrudst = mrustd = -1;
1636 for (i = thistimei; i < thistimelim; ++i)
1637 if (isdsts[types[i]])
1639 else mrustd = types[i];
1640 for (i = 0; i < typecnt; ++i)
1646 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1647 gmtoffs[hidst] != gmtoffs[mrudst]) {
1648 isdsts[mrudst] = -1;
1649 type = addtype(gmtoffs[mrudst],
1650 &chars[abbrinds[mrudst]],
1654 isdsts[mrudst] = TRUE;
1655 writetype[type] = TRUE;
1657 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1658 gmtoffs[histd] != gmtoffs[mrustd]) {
1659 isdsts[mrustd] = -1;
1660 type = addtype(gmtoffs[mrustd],
1661 &chars[abbrinds[mrustd]],
1665 isdsts[mrustd] = FALSE;
1666 writetype[type] = TRUE;
1669 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1671 for (i = 0; i < typecnt; ++i)
1672 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1673 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1676 for (i = 0; i < typecnt; ++i) {
1677 register char * thisabbr;
1681 if (indmap[abbrinds[i]] >= 0)
1683 thisabbr = &chars[abbrinds[i]];
1684 for (j = 0; j < thischarcnt; ++j)
1685 if (strcmp(&thischars[j], thisabbr) == 0)
1687 if (j == thischarcnt) {
1688 (void) strcpy(&thischars[(int) thischarcnt],
1690 thischarcnt += strlen(thisabbr) + 1;
1692 indmap[abbrinds[i]] = j;
1694 #define DO(field) (void) fwrite((void *) tzh.field, \
1695 (size_t) sizeof tzh.field, (size_t) 1, fp)
1697 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1698 tzh.tzh_version[0] = ZIC_VERSION;
1699 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1700 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1701 convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1702 convert(eitol(thistimecnt), tzh.tzh_timecnt);
1703 convert(eitol(thistypecnt), tzh.tzh_typecnt);
1704 convert(eitol(thischarcnt), tzh.tzh_charcnt);
1715 for (i = thistimei; i < thistimelim; ++i)
1717 puttzcode((long) ats[i], fp);
1718 else puttzcode64(ats[i], fp);
1719 for (i = thistimei; i < thistimelim; ++i) {
1722 uc = typemap[types[i]];
1723 (void) fwrite((void *) &uc,
1728 for (i = 0; i < typecnt; ++i)
1730 puttzcode(gmtoffs[i], fp);
1731 (void) putc(isdsts[i], fp);
1732 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1734 if (thischarcnt != 0)
1735 (void) fwrite((void *) thischars,
1736 (size_t) sizeof thischars[0],
1737 (size_t) thischarcnt, fp);
1738 for (i = thisleapi; i < thisleaplim; ++i) {
1739 register zic_t todo;
1742 if (timecnt == 0 || trans[i] < ats[0]) {
1745 if (++j >= typecnt) {
1751 while (j < timecnt &&
1756 todo = tadd(trans[i], -gmtoffs[j]);
1757 } else todo = trans[i];
1759 puttzcode((long) todo, fp);
1760 else puttzcode64(todo, fp);
1761 puttzcode(corr[i], fp);
1763 for (i = 0; i < typecnt; ++i)
1765 (void) putc(ttisstds[i], fp);
1766 for (i = 0; i < typecnt; ++i)
1768 (void) putc(ttisgmts[i], fp);
1770 (void) fprintf(fp, "\n%s\n", string);
1771 if (ferror(fp) || fclose(fp)) {
1772 (void) fprintf(stderr, _("%s: Error writing %s\n"),
1773 progname, fullname);
1779 doabbr(abbr, format, letters, isdst, doquotes)
1781 const char * const format;
1782 const char * const letters;
1787 register char * slashp;
1790 slashp = strchr(format, '/');
1791 if (slashp == NULL) {
1792 if (letters == NULL)
1793 (void) strcpy(abbr, format);
1794 else (void) sprintf(abbr, format, letters);
1796 (void) strcpy(abbr, slashp + 1);
1798 if (slashp > format)
1799 (void) strncpy(abbr, format,
1800 (unsigned) (slashp - format));
1801 abbr[slashp - format] = '\0';
1805 for (cp = abbr; *cp != '\0'; ++cp)
1806 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1807 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1810 if (len > 0 && *cp == '\0')
1812 abbr[len + 2] = '\0';
1813 abbr[len + 1] = '>';
1814 for ( ; len > 0; --len)
1815 abbr[len] = abbr[len - 1];
1830 stringoffset(result, offset)
1835 register int minutes;
1836 register int seconds;
1840 (void) strcpy(result, "-");
1843 seconds = offset % SECSPERMIN;
1844 offset /= SECSPERMIN;
1845 minutes = offset % MINSPERHOUR;
1846 offset /= MINSPERHOUR;
1848 if (hours >= HOURSPERDAY) {
1852 (void) sprintf(end(result), "%d", hours);
1853 if (minutes != 0 || seconds != 0) {
1854 (void) sprintf(end(result), ":%02d", minutes);
1856 (void) sprintf(end(result), ":%02d", seconds);
1862 stringrule(result, rp, dstoff, gmtoff)
1864 const struct rule * const rp;
1870 result = end(result);
1871 if (rp->r_dycode == DC_DOM) {
1872 register int month, total;
1874 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1877 for (month = 0; month < rp->r_month; ++month)
1878 total += len_months[0][month];
1879 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1883 if (rp->r_dycode == DC_DOWGEQ) {
1884 if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
1886 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1887 } else if (rp->r_dycode == DC_DOWLEQ) {
1888 if (rp->r_dayofmonth == len_months[1][rp->r_month])
1891 if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
1893 week = rp->r_dayofmonth / DAYSPERWEEK;
1895 } else return -1; /* "cannot happen" */
1896 (void) sprintf(result, "M%d.%d.%d",
1897 rp->r_month + 1, week, rp->r_wday);
1902 if (rp->r_todisstd && rp->r_stdoff == 0)
1908 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1909 (void) strcat(result, "/");
1910 if (stringoffset(end(result), tod) != 0)
1917 stringzone(result, zpfirst, zonecount)
1919 const struct zone * const zpfirst;
1920 const int zonecount;
1922 register const struct zone * zp;
1923 register struct rule * rp;
1924 register struct rule * stdrp;
1925 register struct rule * dstrp;
1927 register const char * abbrvar;
1930 zp = zpfirst + zonecount - 1;
1931 stdrp = dstrp = NULL;
1932 for (i = 0; i < zp->z_nrules; ++i) {
1933 rp = &zp->z_rules[i];
1934 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1936 if (rp->r_yrtype != NULL)
1938 if (rp->r_stdoff == 0) {
1948 if (stdrp == NULL && dstrp == NULL) {
1950 ** There are no rules running through "max".
1951 ** Let's find the latest rule.
1953 for (i = 0; i < zp->z_nrules; ++i) {
1954 rp = &zp->z_rules[i];
1955 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1956 (rp->r_hiyear == stdrp->r_hiyear &&
1957 rp->r_month > stdrp->r_month))
1960 if (stdrp != NULL && stdrp->r_stdoff != 0)
1961 return; /* We end up in DST (a POSIX no-no). */
1963 ** Horrid special case: if year is 2037,
1964 ** presume this is a zone handled on a year-by-year basis;
1965 ** do not try to apply a rule to the zone.
1967 if (stdrp != NULL && stdrp->r_hiyear == 2037)
1970 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
1972 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1973 doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
1974 if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1980 doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
1981 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
1982 if (stringoffset(end(result),
1983 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1987 (void) strcat(result, ",");
1988 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1992 (void) strcat(result, ",");
1993 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
2000 outzone(zpfirst, zonecount)
2001 const struct zone * const zpfirst;
2002 const int zonecount;
2004 register const struct zone * zp;
2005 register struct rule * rp;
2007 register int usestart, useuntil;
2008 register zic_t starttime, untiltime;
2009 register long gmtoff;
2010 register long stdoff;
2012 register long startoff;
2013 register int startttisstd;
2014 register int startttisgmt;
2016 register char * startbuf;
2018 register char * envvar;
2019 register int max_abbr_len;
2020 register int max_envvar_len;
2021 register int prodstic; /* all rules are min to max */
2023 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2024 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2025 startbuf = emalloc(max_abbr_len + 1);
2026 ab = emalloc(max_abbr_len + 1);
2027 envvar = emalloc(max_envvar_len + 1);
2028 INITIALIZE(untiltime);
2029 INITIALIZE(starttime);
2031 ** Now. . .finally. . .generate some useful data!
2036 prodstic = zonecount == 1;
2038 ** Thanks to Earl Chew
2039 ** for noting the need to unconditionally initialize startttisstd.
2041 startttisstd = FALSE;
2042 startttisgmt = FALSE;
2043 min_year = max_year = EPOCH_YEAR;
2045 updateminmax(leapminyear);
2046 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
2048 for (i = 0; i < zonecount; ++i) {
2050 if (i < zonecount - 1)
2051 updateminmax(zp->z_untilrule.r_loyear);
2052 for (j = 0; j < zp->z_nrules; ++j) {
2053 rp = &zp->z_rules[j];
2055 updateminmax(rp->r_loyear);
2057 updateminmax(rp->r_hiyear);
2058 if (rp->r_lowasnum || rp->r_hiwasnum)
2063 ** Generate lots of data if a rule can't cover all future times.
2065 stringzone(envvar, zpfirst, zonecount);
2066 if (noise && envvar[0] == '\0') {
2069 wp = ecpyalloc(_("no POSIX environment variable for zone"));
2070 wp = ecatalloc(wp, " ");
2071 wp = ecatalloc(wp, zpfirst->z_name);
2075 if (envvar[0] == '\0') {
2076 if (min_year >= INT_MIN + YEARSPERREPEAT)
2077 min_year -= YEARSPERREPEAT;
2078 else min_year = INT_MIN;
2079 if (max_year <= INT_MAX - YEARSPERREPEAT)
2080 max_year += YEARSPERREPEAT;
2081 else max_year = INT_MAX;
2083 ** Regardless of any of the above,
2084 ** for a "proDSTic" zone which specifies that its rules
2085 ** always have and always will be in effect,
2086 ** we only need one cycle to define the zone.
2090 max_year = min_year + YEARSPERREPEAT;
2094 ** For the benefit of older systems,
2095 ** generate data from 1900 through 2037.
2097 if (min_year > 1900)
2099 if (max_year < 2037)
2101 for (i = 0; i < zonecount; ++i) {
2103 ** A guess that may well be corrected later.
2107 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2108 useuntil = i < (zonecount - 1);
2109 if (useuntil && zp->z_untiltime <= min_time)
2111 gmtoff = zp->z_gmtoff;
2112 eat(zp->z_filename, zp->z_linenum);
2114 startoff = zp->z_gmtoff;
2115 if (zp->z_nrules == 0) {
2116 stdoff = zp->z_stdoff;
2117 doabbr(startbuf, zp->z_format,
2118 (char *) NULL, stdoff != 0, FALSE);
2119 type = addtype(oadd(zp->z_gmtoff, stdoff),
2120 startbuf, stdoff != 0, startttisstd,
2123 addtt(starttime, type);
2125 } else if (stdoff != 0)
2126 addtt(min_time, type);
2127 } else for (year = min_year; year <= max_year; ++year) {
2128 if (useuntil && year > zp->z_untilrule.r_hiyear)
2131 ** Mark which rules to do in the current year.
2132 ** For those to do, calculate rpytime(rp, year);
2134 for (j = 0; j < zp->z_nrules; ++j) {
2135 rp = &zp->z_rules[j];
2136 eats(zp->z_filename, zp->z_linenum,
2137 rp->r_filename, rp->r_linenum);
2138 rp->r_todo = year >= rp->r_loyear &&
2139 year <= rp->r_hiyear &&
2140 yearistype(year, rp->r_yrtype);
2142 rp->r_temp = rpytime(rp, year);
2146 register zic_t jtime, ktime;
2147 register long offset;
2152 ** Turn untiltime into UTC
2153 ** assuming the current gmtoff and
2156 untiltime = zp->z_untiltime;
2157 if (!zp->z_untilrule.r_todisgmt)
2158 untiltime = tadd(untiltime,
2160 if (!zp->z_untilrule.r_todisstd)
2161 untiltime = tadd(untiltime,
2165 ** Find the rule (of those to do, if any)
2166 ** that takes effect earliest in the year.
2169 for (j = 0; j < zp->z_nrules; ++j) {
2170 rp = &zp->z_rules[j];
2173 eats(zp->z_filename, zp->z_linenum,
2174 rp->r_filename, rp->r_linenum);
2175 offset = rp->r_todisgmt ? 0 : gmtoff;
2176 if (!rp->r_todisstd)
2177 offset = oadd(offset, stdoff);
2179 if (jtime == min_time ||
2182 jtime = tadd(jtime, -offset);
2183 if (k < 0 || jtime < ktime) {
2189 break; /* go on to next year */
2190 rp = &zp->z_rules[k];
2192 if (useuntil && ktime >= untiltime)
2194 stdoff = rp->r_stdoff;
2195 if (usestart && ktime == starttime)
2198 if (ktime < starttime) {
2199 startoff = oadd(zp->z_gmtoff,
2201 doabbr(startbuf, zp->z_format,
2207 if (*startbuf == '\0' &&
2208 startoff == oadd(zp->z_gmtoff,
2218 eats(zp->z_filename, zp->z_linenum,
2219 rp->r_filename, rp->r_linenum);
2220 doabbr(ab, zp->z_format, rp->r_abbrvar,
2221 rp->r_stdoff != 0, FALSE);
2222 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2223 type = addtype(offset, ab, rp->r_stdoff != 0,
2224 rp->r_todisstd, rp->r_todisgmt);
2229 if (*startbuf == '\0' &&
2230 zp->z_format != NULL &&
2231 strchr(zp->z_format, '%') == NULL &&
2232 strchr(zp->z_format, '/') == NULL)
2233 (void) strcpy(startbuf, zp->z_format);
2234 eat(zp->z_filename, zp->z_linenum);
2235 if (*startbuf == '\0')
2236 error(_("can't determine time zone abbreviation to use just after until time"));
2237 else addtt(starttime,
2238 addtype(startoff, startbuf,
2239 startoff != zp->z_gmtoff,
2244 ** Now we may get to set starttime for the next zone line.
2247 startttisstd = zp->z_untilrule.r_todisstd;
2248 startttisgmt = zp->z_untilrule.r_todisgmt;
2249 starttime = zp->z_untiltime;
2251 starttime = tadd(starttime, -stdoff);
2253 starttime = tadd(starttime, -gmtoff);
2256 writezone(zpfirst->z_name, envvar);
2263 addtt(starttime, type)
2264 const zic_t starttime;
2267 if (starttime <= min_time ||
2268 (timecnt == 1 && attypes[0].at < min_time)) {
2269 gmtoffs[0] = gmtoffs[type];
2270 isdsts[0] = isdsts[type];
2271 ttisstds[0] = ttisstds[type];
2272 ttisgmts[0] = ttisgmts[type];
2273 if (abbrinds[type] != 0)
2274 (void) strcpy(chars, &chars[abbrinds[type]]);
2276 charcnt = strlen(chars) + 1;
2281 if (timecnt >= TZ_MAX_TIMES) {
2282 error(_("too many transitions?!"));
2285 attypes[timecnt].at = starttime;
2286 attypes[timecnt].type = type;
2291 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2293 const char * const abbr;
2300 if (isdst != TRUE && isdst != FALSE) {
2301 error(_("internal error - addtype called with bad isdst"));
2304 if (ttisstd != TRUE && ttisstd != FALSE) {
2305 error(_("internal error - addtype called with bad ttisstd"));
2308 if (ttisgmt != TRUE && ttisgmt != FALSE) {
2309 error(_("internal error - addtype called with bad ttisgmt"));
2313 ** See if there's already an entry for this zone type.
2314 ** If so, just return its index.
2316 for (i = 0; i < typecnt; ++i) {
2317 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2318 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2319 ttisstd == ttisstds[i] &&
2320 ttisgmt == ttisgmts[i])
2324 ** There isn't one; add a new one, unless there are already too
2327 if (typecnt >= TZ_MAX_TYPES) {
2328 error(_("too many local time types"));
2331 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2332 error(_("UTC offset out of range"));
2335 gmtoffs[i] = gmtoff;
2337 ttisstds[i] = ttisstd;
2338 ttisgmts[i] = ttisgmt;
2340 for (j = 0; j < charcnt; ++j)
2341 if (strcmp(&chars[j], abbr) == 0)
2351 leapadd(t, positive, rolling, count)
2359 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2360 error(_("too many leap seconds"));
2363 for (i = 0; i < leapcnt; ++i)
2364 if (t <= trans[i]) {
2365 if (t == trans[i]) {
2366 error(_("repeated leap second moment"));
2372 for (j = leapcnt; j > i; --j) {
2373 trans[j] = trans[j - 1];
2374 corr[j] = corr[j - 1];
2375 roll[j] = roll[j - 1];
2378 corr[i] = positive ? 1L : eitol(-count);
2381 } while (positive && --count != 0);
2388 register long last = 0;
2391 ** propagate leap seconds forward
2393 for (i = 0; i < leapcnt; ++i) {
2394 trans[i] = tadd(trans[i], last);
2395 last = corr[i] += last;
2400 yearistype(year, type)
2402 const char * const type;
2407 if (type == NULL || *type == '\0')
2409 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
2410 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
2411 result = system(buf);
2412 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2418 error(_("Wild result from command execution"));
2419 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2420 progname, buf, result);
2429 a = (unsigned char) a;
2430 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2434 ciequal(ap, bp) /* case-insensitive equality */
2435 register const char * ap;
2436 register const char * bp;
2438 while (lowerit(*ap) == lowerit(*bp++))
2446 register const char * abbr;
2447 register const char * word;
2449 if (lowerit(*abbr) != lowerit(*word))
2452 while (*++abbr != '\0')
2456 } while (lowerit(*word++) != lowerit(*abbr));
2460 static const struct lookup *
2462 register const char * const word;
2463 register const struct lookup * const table;
2465 register const struct lookup * foundlp;
2466 register const struct lookup * lp;
2468 if (word == NULL || table == NULL)
2471 ** Look for exact match.
2473 for (lp = table; lp->l_word != NULL; ++lp)
2474 if (ciequal(word, lp->l_word))
2477 ** Look for inexact match.
2480 for (lp = table; lp->l_word != NULL; ++lp)
2481 if (itsabbr(word, lp->l_word)) {
2482 if (foundlp == NULL)
2484 else return NULL; /* multiple inexact matches */
2494 register char ** array;
2499 array = (char **) (void *)
2500 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
2503 while (isascii((unsigned char) *cp) &&
2504 isspace((unsigned char) *cp))
2506 if (*cp == '\0' || *cp == '#')
2508 array[nsubs++] = dp = cp;
2510 if ((*dp = *cp++) != '"')
2512 else while ((*dp = *cp++) != '"')
2517 "Odd number of quotation marks"
2521 } while (*cp != '\0' && *cp != '#' &&
2522 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2523 if (isascii(*cp) && isspace((unsigned char) *cp))
2527 array[nsubs] = NULL;
2539 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2540 error(_("time overflow"));
2553 if (t1 == max_time && t2 > 0)
2555 if (t1 == min_time && t2 < 0)
2558 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2559 error(_("time overflow"));
2566 ** Given a rule, and a year, compute the date - in seconds since January 1,
2567 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2571 rpytime(rp, wantedy)
2572 register const struct rule * const rp;
2573 register const int wantedy;
2575 register int y, m, i;
2576 register long dayoff; /* with a nod to Margaret O. */
2579 if (wantedy == INT_MIN)
2581 if (wantedy == INT_MAX)
2586 while (wantedy != y) {
2588 i = len_years[isleap(y)];
2592 i = -len_years[isleap(y)];
2594 dayoff = oadd(dayoff, eitol(i));
2596 while (m != rp->r_month) {
2597 i = len_months[isleap(y)][m];
2598 dayoff = oadd(dayoff, eitol(i));
2601 i = rp->r_dayofmonth;
2602 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2603 if (rp->r_dycode == DC_DOWLEQ)
2606 error(_("use of 2/29 in non leap-year"));
2611 dayoff = oadd(dayoff, eitol(i));
2612 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2615 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
2616 wday = eitol(EPOCH_WDAY);
2618 ** Don't trust mod of negative numbers.
2621 wday = (wday + dayoff) % LDAYSPERWEEK;
2623 wday -= ((-dayoff) % LDAYSPERWEEK);
2625 wday += LDAYSPERWEEK;
2627 while (wday != eitol(rp->r_wday))
2628 if (rp->r_dycode == DC_DOWGEQ) {
2629 dayoff = oadd(dayoff, (long) 1);
2630 if (++wday >= LDAYSPERWEEK)
2634 dayoff = oadd(dayoff, (long) -1);
2636 wday = LDAYSPERWEEK - 1;
2639 if (i < 0 || i >= len_months[isleap(y)][m]) {
2641 warning(_("rule goes past start/end of month--\
2642 will not work with pre-2004 versions of zic"));
2645 if (dayoff < min_time / SECSPERDAY)
2647 if (dayoff > max_time / SECSPERDAY)
2649 t = (zic_t) dayoff * SECSPERDAY;
2650 return tadd(t, rp->r_tod);
2655 const char * const string;
2659 if (strcmp(string, GRANDPARENTED) != 0) {
2660 register const char * cp;
2664 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2665 ** optionally followed by a + or - and a number from 1 to 14.
2669 while (isascii((unsigned char) *cp) &&
2670 isalpha((unsigned char) *cp))
2672 if (cp - string == 0)
2673 wp = _("time zone abbreviation lacks alphabetic at start");
2674 if (noise && cp - string > 3)
2675 wp = _("time zone abbreviation has more than 3 alphabetics");
2676 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2677 wp = _("time zone abbreviation has too many alphabetics");
2678 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2680 if (isascii((unsigned char) *cp) &&
2681 isdigit((unsigned char) *cp))
2683 *cp >= '0' && *cp <= '4')
2687 wp = _("time zone abbreviation differs from POSIX standard");
2690 wp = ecatalloc(wp, " (");
2691 wp = ecatalloc(wp, string);
2692 wp = ecatalloc(wp, ")");
2697 i = strlen(string) + 1;
2698 if (charcnt + i > TZ_MAX_CHARS) {
2699 error(_("too many, or too long, time zone abbreviations"));
2702 (void) strcpy(&chars[charcnt], string);
2703 charcnt += eitol(i);
2710 register char * name;
2713 if (argname == NULL || *argname == '\0')
2715 cp = name = ecpyalloc(argname);
2716 while ((cp = strchr(cp + 1, '/')) != 0) {
2720 ** DOS drive specifier?
2722 if (isalpha((unsigned char) name[0]) &&
2723 name[1] == ':' && name[2] == '\0') {
2727 #endif /* !defined unix */
2728 if (!itsdir(name)) {
2730 ** It doesn't seem to exist, so we try to create it.
2731 ** Creation may fail because of the directory being
2732 ** created by some other multiprocessor, so we get
2733 ** to do extra checking.
2735 if (mkdir(name, MKDIR_UMASK) != 0) {
2736 const char *e = strerror(errno);
2738 if (errno != EEXIST || !itsdir(name)) {
2739 (void) fprintf(stderr,
2740 _("%s: Can't create directory %s: %s\n"),
2760 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2761 (void) fprintf(stderr,
2762 _("%s: %d did not sign extend correctly\n"),
2770 ** UNIX was a registered trademark of The Open Group in 2003.