2 ** This file is in the public domain, so clarified as of
3 ** 2006-07-17 by Arthur David Olson.
6 static const char elsieid[] = "@(#)zic.c 8.19";
9 static const char rcsid[] =
17 #include <sys/stat.h> /* for umask manifest constants */
18 #include <sys/types.h>
21 #define ZIC_VERSION '2'
23 typedef int_fast64_t zic_t;
25 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
26 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
27 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
29 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
32 ** On some ancient hosts, predicates like `isspace(C)' are defined
33 ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
34 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
35 ** Neither the C Standard nor POSIX require that `isascii' exist.
36 ** For portability, we check both ancient and modern requirements.
37 ** If isascii is not defined, the isascii check succeeds trivially.
44 #define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
45 #define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
47 #define end(cp) (strchr((cp), '\0'))
50 const char * r_filename;
54 int r_loyear; /* for example, 1986 */
55 int r_hiyear; /* for example, 1986 */
56 const char * r_yrtype;
60 int r_month; /* 0..11 */
62 int r_dycode; /* see below */
66 long r_tod; /* time from midnight */
67 int r_todisstd; /* above is standard time if TRUE */
68 /* or wall clock time if FALSE */
69 int r_todisgmt; /* above is GMT if TRUE */
70 /* or local time if FALSE */
71 long r_stdoff; /* offset from standard time */
72 const char * r_abbrvar; /* variable part of abbreviation */
74 int r_todo; /* a rule to do (used in outzone) */
75 zic_t r_temp; /* used in outzone */
79 ** r_dycode r_dayofmonth r_wday
82 #define DC_DOM 0 /* 1..31 */ /* unused */
83 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
84 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
87 const char * z_filename;
93 const char * z_format;
97 struct rule * z_rules;
100 struct rule z_untilrule;
104 static void addtt(zic_t starttime, int type);
105 static int addtype(long gmtoff, const char * abbr, int isdst,
106 int ttisstd, int ttisgmt);
107 static void leapadd(zic_t t, int positive, int rolling, int count);
108 static void adjleap(void);
109 static void associate(void);
110 static int ciequal(const char * ap, const char * bp);
111 static void convert(long val, char * buf);
112 static void convert64(zic_t val, char * buf);
113 static void dolink(const char * fromfield, const char * tofield);
114 static void doabbr(char * abbr, const char * format,
115 const char * letters, int isdst, int doquotes);
116 static void eat(const char * name, int num);
117 static void eats(const char * name, int num,
118 const char * rname, int rnum);
119 static long eitol(int i);
120 static void error(const char * message);
121 static char ** getfields(char * buf);
122 static long gethms(const char * string, const char * errstrng,
124 static void infile(const char * filename);
125 static void inleap(char ** fields, int nfields);
126 static void inlink(char ** fields, int nfields);
127 static void inrule(char ** fields, int nfields);
128 static int inzcont(char ** fields, int nfields);
129 static int inzone(char ** fields, int nfields);
130 static int inzsub(char ** fields, int nfields, int iscont);
131 static int is32(zic_t x);
132 static int itsabbr(const char * abbr, const char * word);
133 static int itsdir(const char * name);
134 static int lowerit(int c);
135 static char * memcheck(char * tocheck);
136 static int mkdirs(char * filename);
137 static void newabbr(const char * abbr);
138 static long oadd(long t1, long t2);
139 static void outzone(const struct zone * zp, int ntzones);
140 static void puttzcode(long code, FILE * fp);
141 static void puttzcode64(zic_t code, FILE * fp);
142 static int rcomp(const void * leftp, const void * rightp);
143 static zic_t rpytime(const struct rule * rp, int wantedy);
144 static void rulesub(struct rule * rp,
145 const char * loyearp, const char * hiyearp,
146 const char * typep, const char * monthp,
147 const char * dayp, const char * timep);
148 static int stringoffset(char * result, long offset);
149 static int stringrule(char * result, const struct rule * rp,
150 long dstoff, long gmtoff);
151 static void stringzone(char * result,
152 const struct zone * zp, int ntzones);
153 static void setboundaries(void);
154 static void setgroup(gid_t *flag, const char *name);
155 static void setuser(uid_t *flag, const char *name);
156 static zic_t tadd(zic_t t1, long t2);
157 static void usage(FILE *stream, int status);
158 static void writezone(const char * name, const char * string);
159 static int yearistype(int year, const char * type);
163 static const char * filename;
166 static int leapminyear;
167 static int leapmaxyear;
169 static int max_abbrvar_len;
170 static int max_format_len;
171 static zic_t max_time;
173 static zic_t min_time;
175 static zic_t min_time;
177 static const char * rfilename;
192 ** Which fields are which on a Zone line.
200 #define ZF_TILMONTH 6
203 #define ZONE_MINFIELDS 5
204 #define ZONE_MAXFIELDS 9
207 ** Which fields are which on a Zone continuation line.
213 #define ZFC_TILYEAR 3
214 #define ZFC_TILMONTH 4
216 #define ZFC_TILTIME 6
217 #define ZONEC_MINFIELDS 3
218 #define ZONEC_MAXFIELDS 7
221 ** Which files are which on a Rule line.
233 #define RULE_FIELDS 10
236 ** Which fields are which on a Link line.
241 #define LINK_FIELDS 3
244 ** Which fields are which on a Leap line.
253 #define LEAP_FIELDS 7
263 static struct rule * rules;
264 static int nrules; /* number of rules */
266 static struct zone * zones;
267 static int nzones; /* number of zones */
270 const char * l_filename;
276 static struct link * links;
284 static struct lookup const * byword(const char * string,
285 const struct lookup * lp);
287 static struct lookup const line_codes[] = {
295 static struct lookup const mon_names[] = {
296 { "January", TM_JANUARY },
297 { "February", TM_FEBRUARY },
298 { "March", TM_MARCH },
299 { "April", TM_APRIL },
303 { "August", TM_AUGUST },
304 { "September", TM_SEPTEMBER },
305 { "October", TM_OCTOBER },
306 { "November", TM_NOVEMBER },
307 { "December", TM_DECEMBER },
311 static struct lookup const wday_names[] = {
312 { "Sunday", TM_SUNDAY },
313 { "Monday", TM_MONDAY },
314 { "Tuesday", TM_TUESDAY },
315 { "Wednesday", TM_WEDNESDAY },
316 { "Thursday", TM_THURSDAY },
317 { "Friday", TM_FRIDAY },
318 { "Saturday", TM_SATURDAY },
322 static struct lookup const lasts[] = {
323 { "last-Sunday", TM_SUNDAY },
324 { "last-Monday", TM_MONDAY },
325 { "last-Tuesday", TM_TUESDAY },
326 { "last-Wednesday", TM_WEDNESDAY },
327 { "last-Thursday", TM_THURSDAY },
328 { "last-Friday", TM_FRIDAY },
329 { "last-Saturday", TM_SATURDAY },
333 static struct lookup const begin_years[] = {
334 { "minimum", YR_MINIMUM },
335 { "maximum", YR_MAXIMUM },
339 static struct lookup const end_years[] = {
340 { "minimum", YR_MINIMUM },
341 { "maximum", YR_MAXIMUM },
346 static struct lookup const leap_types[] = {
348 { "Stationary", FALSE },
352 static const int len_months[2][MONSPERYEAR] = {
353 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
354 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
357 static const int len_years[2] = {
358 DAYSPERNYEAR, DAYSPERLYEAR
361 static struct attype {
364 } attypes[TZ_MAX_TIMES];
365 static long gmtoffs[TZ_MAX_TYPES];
366 static char isdsts[TZ_MAX_TYPES];
367 static unsigned char abbrinds[TZ_MAX_TYPES];
368 static char ttisstds[TZ_MAX_TYPES];
369 static char ttisgmts[TZ_MAX_TYPES];
370 static char chars[TZ_MAX_CHARS];
371 static zic_t trans[TZ_MAX_LEAPS];
372 static long corr[TZ_MAX_LEAPS];
373 static char roll[TZ_MAX_LEAPS];
376 ** Memory allocation.
384 errx(EXIT_FAILURE, _("memory exhausted"));
388 #define emalloc(size) memcheck(imalloc(size))
389 #define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
390 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
391 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
398 eats(name, num, rname, rnum)
399 const char * const name;
401 const char * const rname;
412 const char * const name;
415 eats(name, num, (char *) NULL, -1);
420 const char * const string;
423 ** Match the format of "cc" to allow sh users to
424 ** zic ... 2>&1 | error -t "*" -v
427 (void) fprintf(stderr, _("\"%s\", line %d: %s"),
428 filename, linenum, string);
429 if (rfilename != NULL)
430 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
431 rfilename, rlinenum);
432 (void) fprintf(stderr, "\n");
438 const char * const string;
442 cp = ecpyalloc(_("warning: "));
443 cp = ecatalloc(cp, string);
450 usage(FILE *stream, int status)
452 (void) fprintf(stream, _("usage is zic \
453 [ --version ] [--help] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
454 \t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
456 Report bugs to tz@elsie.nci.nih.gov.\n"));
460 static const char * psxrules;
461 static const char * lcltime;
462 static const char * directory;
463 static const char * leapsec;
464 static const char * yitcommand;
466 static uid_t uflag = (uid_t)-1;
467 static gid_t gflag = (gid_t)-1;
468 static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH
481 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
482 #endif /* defined unix */
484 (void) setlocale(LC_ALL, "");
486 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
487 #endif /* defined TEXTDOMAINDIR */
488 (void) textdomain(TZ_DOMAIN);
489 #endif /* HAVE_GETTEXT */
490 if (TYPE_BIT(zic_t) < 64) {
491 (void) fprintf(stderr, "zic: %s\n",
492 _("wild compilation-time specification of zic_t"));
495 for (i = 1; i < argc; ++i)
496 if (strcmp(argv[i], "--version") == 0) {
497 errx(EXIT_SUCCESS, "%s", elsieid);
498 } else if (strcmp(argv[i], "--help") == 0) {
499 usage(stdout, EXIT_SUCCESS);
501 while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
504 usage(stderr, EXIT_FAILURE);
509 if (directory == NULL)
513 _("more than one -d option specified"));
516 setgroup(&gflag, optarg);
523 _("more than one -l option specified"));
527 void *set = setmode(optarg);
530 _("invalid file mode"));
531 mflag = getmode(set, mflag);
536 if (psxrules == NULL)
540 _("more than one -p option specified"));
543 setuser(&uflag, optarg);
546 if (yitcommand == NULL)
550 _("more than one -y option specified"));
557 _("more than one -L option specified"));
563 (void) printf("zic: -s ignored\n");
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;
657 while ((s = strchr(s+1, '/')) != NULL)
659 ecatalloc(symlinkcontents,
662 ecatalloc(symlinkcontents,
665 symlink(symlinkcontents,
668 warning(_("hard link failed, symbolic link used"));
669 ifree(symlinkcontents);
671 #endif /* HAVE_SYMLINK */
673 err(EXIT_FAILURE, _("can't link from %s to %s"),
681 #define TIME_T_BITS_IN_FILE 64
689 for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
691 max_time = -(min_time + 1);
696 const char * const name;
698 register char * myname;
701 myname = ecpyalloc(name);
702 myname = ecatalloc(myname, "/.");
703 accres = access(myname, F_OK);
709 ** Associate sets of rules with zones.
713 ** Sort by rule name.
721 return strcmp(((const struct rule *) cp1)->r_name,
722 ((const struct rule *) cp2)->r_name);
728 register struct zone * zp;
729 register struct rule * rp;
730 register int base, out;
734 (void) qsort((void *) rules, (size_t) nrules,
735 (size_t) sizeof *rules, rcomp);
736 for (i = 0; i < nrules - 1; ++i) {
737 if (strcmp(rules[i].r_name,
738 rules[i + 1].r_name) != 0)
740 if (strcmp(rules[i].r_filename,
741 rules[i + 1].r_filename) == 0)
743 eat(rules[i].r_filename, rules[i].r_linenum);
744 warning(_("same rule name in multiple files"));
745 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
746 warning(_("same rule name in multiple files"));
747 for (j = i + 2; j < nrules; ++j) {
748 if (strcmp(rules[i].r_name,
749 rules[j].r_name) != 0)
751 if (strcmp(rules[i].r_filename,
752 rules[j].r_filename) == 0)
754 if (strcmp(rules[i + 1].r_filename,
755 rules[j].r_filename) == 0)
762 for (i = 0; i < nzones; ++i) {
767 for (base = 0; base < nrules; base = out) {
769 for (out = base + 1; out < nrules; ++out)
770 if (strcmp(rp->r_name, rules[out].r_name) != 0)
772 for (i = 0; i < nzones; ++i) {
774 if (strcmp(zp->z_rule, rp->r_name) != 0)
777 zp->z_nrules = out - base;
780 for (i = 0; i < nzones; ++i) {
782 if (zp->z_nrules == 0) {
784 ** Maybe we have a local standard time offset.
786 eat(zp->z_filename, zp->z_linenum);
787 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
790 ** Note, though, that if there's no rule,
791 ** a '%s' in the format is a bad thing.
793 if (strchr(zp->z_format, '%') != 0)
794 error(_("%s in ruleless zone"));
806 register char ** fields;
808 register const struct lookup * lp;
809 register int nfields;
810 register int wantcont;
814 if (strcmp(name, "-") == 0) {
815 name = _("standard input");
817 } else if ((fp = fopen(name, "r")) == NULL)
818 err(EXIT_FAILURE, _("can't open %s"), name);
820 for (num = 1; ; ++num) {
822 if (fgets(buf, (int) sizeof buf, fp) != buf)
824 cp = strchr(buf, '\n');
826 error(_("line too long"));
830 fields = getfields(buf);
832 while (fields[nfields] != NULL) {
835 if (strcmp(fields[nfields], "-") == 0)
836 fields[nfields] = &nada;
841 } else if (wantcont) {
842 wantcont = inzcont(fields, nfields);
844 lp = byword(fields[0], line_codes);
846 error(_("input line of unknown type"));
847 else switch ((int) (lp->l_value)) {
849 inrule(fields, nfields);
853 wantcont = inzone(fields, nfields);
856 inlink(fields, nfields);
862 _("leap line in non leap seconds file %s"), name);
863 else inleap(fields, nfields);
866 default: /* "cannot happen" */
868 _("panic: invalid l_value %d"), lp->l_value);
871 ifree((char *) fields);
874 errx(EXIT_FAILURE, _("error reading %s"), filename);
875 if (fp != stdin && fclose(fp))
876 err(EXIT_FAILURE, _("error closing %s"), filename);
878 error(_("expected continuation line not found"));
882 ** Convert a string of one of the forms
883 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
884 ** into a number of seconds.
885 ** A null string maps to zero.
886 ** Call error with errstring and return zero on errors.
890 gethms(string, errstring, signable)
892 const char * const errstring;
898 if (string == NULL || *string == '\0')
902 else if (*string == '-') {
906 if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
908 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
910 else if (sscanf(string, scheck(string, "%ld:%d:%d"),
911 &hh, &mm, &ss) != 3) {
916 mm < 0 || mm >= MINSPERHOUR ||
917 ss < 0 || ss > SECSPERMIN) {
921 if (LONG_MAX / SECSPERHOUR < hh) {
922 error(_("time overflow"));
925 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
926 warning(_("24:00 not handled by pre-1998 versions of zic"));
927 if (noise && (hh > HOURSPERDAY ||
928 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
929 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
930 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
931 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
935 inrule(fields, nfields)
936 register char ** const fields;
939 static struct rule r;
941 if (nfields != RULE_FIELDS) {
942 error(_("wrong number of fields on Rule line"));
945 if (*fields[RF_NAME] == '\0') {
946 error(_("nameless rule"));
949 r.r_filename = filename;
950 r.r_linenum = linenum;
951 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
952 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
953 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
954 r.r_name = ecpyalloc(fields[RF_NAME]);
955 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
956 if (max_abbrvar_len < strlen(r.r_abbrvar))
957 max_abbrvar_len = strlen(r.r_abbrvar);
958 rules = (struct rule *) (void *) erealloc((char *) rules,
959 (int) ((nrules + 1) * sizeof *rules));
964 inzone(fields, nfields)
965 register char ** const fields;
971 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
972 error(_("wrong number of fields on Zone line"));
975 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
976 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
978 _("\"Zone %s\" line and -l option are mutually exclusive"),
983 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
984 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
986 _("\"Zone %s\" line and -p option are mutually exclusive"),
991 for (i = 0; i < nzones; ++i)
992 if (zones[i].z_name != NULL &&
993 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
994 buf = erealloc(buf, (int) (132 +
995 strlen(fields[ZF_NAME]) +
996 strlen(zones[i].z_filename)));
998 _("duplicate zone name %s (file \"%s\", line %d)"),
1000 zones[i].z_filename,
1001 zones[i].z_linenum);
1005 return inzsub(fields, nfields, FALSE);
1009 inzcont(fields, nfields)
1010 register char ** const fields;
1013 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1014 error(_("wrong number of fields on Zone continuation line"));
1017 return inzsub(fields, nfields, TRUE);
1021 inzsub(fields, nfields, iscont)
1022 register char ** const fields;
1027 static struct zone z;
1028 register int i_gmtoff, i_rule, i_format;
1029 register int i_untilyear, i_untilmonth;
1030 register int i_untilday, i_untiltime;
1031 register int hasuntil;
1034 i_gmtoff = ZFC_GMTOFF;
1036 i_format = ZFC_FORMAT;
1037 i_untilyear = ZFC_TILYEAR;
1038 i_untilmonth = ZFC_TILMONTH;
1039 i_untilday = ZFC_TILDAY;
1040 i_untiltime = ZFC_TILTIME;
1043 i_gmtoff = ZF_GMTOFF;
1045 i_format = ZF_FORMAT;
1046 i_untilyear = ZF_TILYEAR;
1047 i_untilmonth = ZF_TILMONTH;
1048 i_untilday = ZF_TILDAY;
1049 i_untiltime = ZF_TILTIME;
1050 z.z_name = ecpyalloc(fields[ZF_NAME]);
1052 z.z_filename = filename;
1053 z.z_linenum = linenum;
1054 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
1055 if ((cp = strchr(fields[i_format], '%')) != 0) {
1056 if (*++cp != 's' || strchr(cp, '%') != 0) {
1057 error(_("invalid abbreviation format"));
1061 z.z_rule = ecpyalloc(fields[i_rule]);
1062 z.z_format = ecpyalloc(fields[i_format]);
1063 if (max_format_len < strlen(z.z_format))
1064 max_format_len = strlen(z.z_format);
1065 hasuntil = nfields > i_untilyear;
1067 z.z_untilrule.r_filename = filename;
1068 z.z_untilrule.r_linenum = linenum;
1069 rulesub(&z.z_untilrule,
1070 fields[i_untilyear],
1073 (nfields > i_untilmonth) ?
1074 fields[i_untilmonth] : "Jan",
1075 (nfields > i_untilday) ? fields[i_untilday] : "1",
1076 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1077 z.z_untiltime = rpytime(&z.z_untilrule,
1078 z.z_untilrule.r_loyear);
1079 if (iscont && nzones > 0 &&
1080 z.z_untiltime > min_time &&
1081 z.z_untiltime < max_time &&
1082 zones[nzones - 1].z_untiltime > min_time &&
1083 zones[nzones - 1].z_untiltime < max_time &&
1084 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1086 "Zone continuation line end time is not after end time of previous line"
1091 zones = (struct zone *) (void *) erealloc((char *) zones,
1092 (int) ((nzones + 1) * sizeof *zones));
1093 zones[nzones++] = z;
1095 ** If there was an UNTIL field on this line,
1096 ** there's more information about the zone on the next line.
1102 inleap(fields, nfields)
1103 register char ** const fields;
1106 register const char * cp;
1107 register const struct lookup * lp;
1109 int year, month, day;
1113 if (nfields != LEAP_FIELDS) {
1114 error(_("wrong number of fields on Leap line"));
1118 cp = fields[LP_YEAR];
1119 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1123 error(_("invalid leaping year"));
1126 if (!leapseen || leapmaxyear < year)
1128 if (!leapseen || leapminyear > year)
1134 i = len_years[isleap(j)];
1138 i = -len_years[isleap(j)];
1140 dayoff = oadd(dayoff, eitol(i));
1142 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1143 error(_("invalid month name"));
1146 month = lp->l_value;
1148 while (j != month) {
1149 i = len_months[isleap(year)][j];
1150 dayoff = oadd(dayoff, eitol(i));
1153 cp = fields[LP_DAY];
1154 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1155 day <= 0 || day > len_months[isleap(year)][month]) {
1156 error(_("invalid day of month"));
1159 dayoff = oadd(dayoff, eitol(day - 1));
1160 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1161 error(_("time before zero"));
1164 if (dayoff < min_time / SECSPERDAY) {
1165 error(_("time too small"));
1168 if (dayoff > max_time / SECSPERDAY) {
1169 error(_("time too large"));
1172 t = (zic_t) dayoff * SECSPERDAY;
1173 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1174 cp = fields[LP_CORR];
1176 register int positive;
1179 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1182 } else if (strcmp(cp, "--") == 0) {
1185 } else if (strcmp(cp, "+") == 0) {
1188 } else if (strcmp(cp, "++") == 0) {
1192 error(_("illegal CORRECTION field on Leap line"));
1195 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1197 "illegal Rolling/Stationary field on Leap line"
1201 leapadd(tadd(t, tod), positive, lp->l_value, count);
1206 inlink(fields, nfields)
1207 register char ** const fields;
1212 if (nfields != LINK_FIELDS) {
1213 error(_("wrong number of fields on Link line"));
1216 if (*fields[LF_FROM] == '\0') {
1217 error(_("blank FROM field on Link line"));
1220 if (*fields[LF_TO] == '\0') {
1221 error(_("blank TO field on Link line"));
1224 l.l_filename = filename;
1225 l.l_linenum = linenum;
1226 l.l_from = ecpyalloc(fields[LF_FROM]);
1227 l.l_to = ecpyalloc(fields[LF_TO]);
1228 links = (struct link *) (void *) erealloc((char *) links,
1229 (int) ((nlinks + 1) * sizeof *links));
1230 links[nlinks++] = l;
1234 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1235 register struct rule * const rp;
1236 const char * const loyearp;
1237 const char * const hiyearp;
1238 const char * const typep;
1239 const char * const monthp;
1240 const char * const dayp;
1241 const char * const timep;
1243 register const struct lookup * lp;
1244 register const char * cp;
1248 if ((lp = byword(monthp, mon_names)) == NULL) {
1249 error(_("invalid month name"));
1252 rp->r_month = lp->l_value;
1253 rp->r_todisstd = FALSE;
1254 rp->r_todisgmt = FALSE;
1255 dp = ecpyalloc(timep);
1257 ep = dp + strlen(dp) - 1;
1258 switch (lowerit(*ep)) {
1259 case 's': /* Standard */
1260 rp->r_todisstd = TRUE;
1261 rp->r_todisgmt = FALSE;
1264 case 'w': /* Wall */
1265 rp->r_todisstd = FALSE;
1266 rp->r_todisgmt = FALSE;
1269 case 'g': /* Greenwich */
1270 case 'u': /* Universal */
1271 case 'z': /* Zulu */
1272 rp->r_todisstd = TRUE;
1273 rp->r_todisgmt = TRUE;
1278 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1284 lp = byword(cp, begin_years);
1285 rp->r_lowasnum = lp == NULL;
1286 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1288 rp->r_loyear = INT_MIN;
1291 rp->r_loyear = INT_MAX;
1293 default: /* "cannot happen" */
1295 _("panic: invalid l_value %d"), lp->l_value);
1296 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1297 error(_("invalid starting year"));
1301 lp = byword(cp, end_years);
1302 rp->r_hiwasnum = lp == NULL;
1303 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1305 rp->r_hiyear = INT_MIN;
1308 rp->r_hiyear = INT_MAX;
1311 rp->r_hiyear = rp->r_loyear;
1313 default: /* "cannot happen" */
1315 _("panic: invalid l_value %d"), lp->l_value);
1316 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1317 error(_("invalid ending year"));
1320 if (rp->r_loyear > rp->r_hiyear) {
1321 error(_("starting year greater than ending year"));
1325 rp->r_yrtype = NULL;
1327 if (rp->r_loyear == rp->r_hiyear) {
1328 error(_("typed single year"));
1331 rp->r_yrtype = ecpyalloc(typep);
1335 ** Accept things such as:
1341 dp = ecpyalloc(dayp);
1342 if ((lp = byword(dp, lasts)) != NULL) {
1343 rp->r_dycode = DC_DOWLEQ;
1344 rp->r_wday = lp->l_value;
1345 rp->r_dayofmonth = len_months[1][rp->r_month];
1347 if ((ep = strchr(dp, '<')) != 0)
1348 rp->r_dycode = DC_DOWLEQ;
1349 else if ((ep = strchr(dp, '>')) != 0)
1350 rp->r_dycode = DC_DOWGEQ;
1353 rp->r_dycode = DC_DOM;
1355 if (rp->r_dycode != DC_DOM) {
1358 error(_("invalid day of month"));
1362 if ((lp = byword(dp, wday_names)) == NULL) {
1363 error(_("invalid weekday name"));
1367 rp->r_wday = lp->l_value;
1369 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1370 rp->r_dayofmonth <= 0 ||
1371 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1372 error(_("invalid day of month"));
1388 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1389 buf[i] = val >> shift;
1400 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1401 buf[i] = val >> shift;
1412 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1416 puttzcode64(val, fp)
1422 convert64(val, buf);
1423 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1431 const zic_t a = ((const struct attype *) avp)->at;
1432 const zic_t b = ((const struct attype *) bvp)->at;
1434 return (a < b) ? -1 : (a > b);
1441 return INT32_MIN <= x && x <= INT32_MAX;
1445 writezone(name, string)
1446 const char * const name;
1447 const char * const string;
1451 register int leapcnt32, leapi32;
1452 register int timecnt32, timei32;
1454 static char * fullname;
1455 static const struct tzhead tzh0;
1456 static struct tzhead tzh;
1457 zic_t ats[TZ_MAX_TIMES];
1458 unsigned char types[TZ_MAX_TIMES];
1464 (void) qsort((void *) attypes, (size_t) timecnt,
1465 (size_t) sizeof *attypes, atcomp);
1475 while (fromi < timecnt && attypes[fromi].at < min_time)
1478 while (fromi < timecnt && attypes[fromi].type == 0)
1479 ++fromi; /* handled by default rule */
1480 for ( ; fromi < timecnt; ++fromi) {
1481 if (toi != 0 && ((attypes[fromi].at +
1482 gmtoffs[attypes[toi - 1].type]) <=
1483 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1484 : attypes[toi - 2].type]))) {
1485 attypes[toi - 1].type =
1486 attypes[fromi].type;
1490 attypes[toi - 1].type != attypes[fromi].type)
1491 attypes[toi++] = attypes[fromi];
1498 for (i = 0; i < timecnt; ++i) {
1499 ats[i] = attypes[i].at;
1500 types[i] = attypes[i].type;
1503 ** Correct for leap seconds.
1505 for (i = 0; i < timecnt; ++i) {
1508 if (ats[i] > trans[j] - corr[j]) {
1509 ats[i] = tadd(ats[i], corr[j]);
1514 ** Figure out 32-bit-limited starts and counts.
1516 timecnt32 = timecnt;
1518 leapcnt32 = leapcnt;
1520 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1522 while (timecnt32 > 0 && !is32(ats[timei32])) {
1526 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1528 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1532 fullname = erealloc(fullname,
1533 (int) (strlen(directory) + 1 + strlen(name) + 1));
1534 (void) sprintf(fullname, "%s/%s", directory, name);
1537 * Remove old file, if any, to snap links.
1539 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
1540 err(EXIT_FAILURE, _("can't remove %s"), fullname);
1542 if ((fp = fopen(fullname, "wb")) == NULL) {
1543 if (mkdirs(fullname) != 0)
1545 if ((fp = fopen(fullname, "wb")) == NULL)
1546 err(EXIT_FAILURE, _("can't create %s"), fullname);
1548 for (pass = 1; pass <= 2; ++pass) {
1549 register int thistimei, thistimecnt;
1550 register int thisleapi, thisleapcnt;
1551 register int thistimelim, thisleaplim;
1552 int writetype[TZ_MAX_TIMES];
1553 int typemap[TZ_MAX_TYPES];
1554 register int thistypecnt;
1555 char thischars[TZ_MAX_CHARS];
1557 int indmap[TZ_MAX_CHARS];
1560 thistimei = timei32;
1561 thistimecnt = timecnt32;
1562 thisleapi = leapi32;
1563 thisleapcnt = leapcnt32;
1566 thistimecnt = timecnt;
1568 thisleapcnt = leapcnt;
1570 thistimelim = thistimei + thistimecnt;
1571 thisleaplim = thisleapi + thisleapcnt;
1572 for (i = 0; i < typecnt; ++i)
1573 writetype[i] = thistimecnt == timecnt;
1574 if (thistimecnt == 0) {
1576 ** No transition times fall in the current
1577 ** (32- or 64-bit) window.
1580 writetype[typecnt - 1] = TRUE;
1582 for (i = thistimei - 1; i < thistimelim; ++i)
1584 writetype[types[i]] = TRUE;
1586 ** For America/Godthab and Antarctica/Palmer
1589 writetype[0] = TRUE;
1592 for (i = 0; i < typecnt; ++i)
1593 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1594 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1597 for (i = 0; i < typecnt; ++i) {
1598 register char * thisabbr;
1602 if (indmap[abbrinds[i]] >= 0)
1604 thisabbr = &chars[abbrinds[i]];
1605 for (j = 0; j < thischarcnt; ++j)
1606 if (strcmp(&thischars[j], thisabbr) == 0)
1608 if (j == thischarcnt) {
1609 (void) strcpy(&thischars[(int) thischarcnt],
1611 thischarcnt += strlen(thisabbr) + 1;
1613 indmap[abbrinds[i]] = j;
1615 #define DO(field) (void) fwrite((void *) tzh.field, \
1616 (size_t) sizeof tzh.field, (size_t) 1, fp)
1618 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1619 tzh.tzh_version[0] = ZIC_VERSION;
1620 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
1621 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
1622 convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
1623 convert(eitol(thistimecnt), tzh.tzh_timecnt);
1624 convert(eitol(thistypecnt), tzh.tzh_typecnt);
1625 convert(eitol(thischarcnt), tzh.tzh_charcnt);
1636 for (i = thistimei; i < thistimelim; ++i)
1638 puttzcode((long) ats[i], fp);
1639 else puttzcode64(ats[i], fp);
1640 for (i = thistimei; i < thistimelim; ++i) {
1643 uc = typemap[types[i]];
1644 (void) fwrite((void *) &uc,
1649 for (i = 0; i < typecnt; ++i)
1651 puttzcode(gmtoffs[i], fp);
1652 (void) putc(isdsts[i], fp);
1653 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1655 if (thischarcnt != 0)
1656 (void) fwrite((void *) thischars,
1657 (size_t) sizeof thischars[0],
1658 (size_t) thischarcnt, fp);
1659 for (i = thisleapi; i < thisleaplim; ++i) {
1660 register zic_t todo;
1663 if (timecnt == 0 || trans[i] < ats[0]) {
1666 if (++j >= typecnt) {
1672 while (j < timecnt &&
1677 todo = tadd(trans[i], -gmtoffs[j]);
1678 } else todo = trans[i];
1680 puttzcode((long) todo, fp);
1681 else puttzcode64(todo, fp);
1682 puttzcode(corr[i], fp);
1684 for (i = 0; i < typecnt; ++i)
1686 (void) putc(ttisstds[i], fp);
1687 for (i = 0; i < typecnt; ++i)
1689 (void) putc(ttisgmts[i], fp);
1691 (void) fprintf(fp, "\n%s\n", string);
1692 if (ferror(fp) || fclose(fp))
1693 errx(EXIT_FAILURE, _("error writing %s"), fullname);
1694 if (chmod(fullname, mflag) < 0)
1695 err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
1696 fullname, (unsigned)mflag);
1697 if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
1698 && chown(fullname, uflag, gflag) < 0)
1699 err(EXIT_FAILURE, _("cannot change ownership of %s"),
1704 doabbr(abbr, format, letters, isdst, doquotes)
1706 const char * const format;
1707 const char * const letters;
1712 register char * slashp;
1715 slashp = strchr(format, '/');
1716 if (slashp == NULL) {
1717 if (letters == NULL)
1718 (void) strcpy(abbr, format);
1719 else (void) sprintf(abbr, format, letters);
1721 (void) strcpy(abbr, slashp + 1);
1723 if (slashp > format)
1724 (void) strncpy(abbr, format,
1725 (unsigned) (slashp - format));
1726 abbr[slashp - format] = '\0';
1730 for (cp = abbr; *cp != '\0'; ++cp)
1731 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1732 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1735 if (len > 0 && *cp == '\0')
1737 abbr[len + 2] = '\0';
1738 abbr[len + 1] = '>';
1739 for ( ; len > 0; --len)
1740 abbr[len] = abbr[len - 1];
1755 stringoffset(result, offset)
1760 register int minutes;
1761 register int seconds;
1765 (void) strcpy(result, "-");
1768 seconds = offset % SECSPERMIN;
1769 offset /= SECSPERMIN;
1770 minutes = offset % MINSPERHOUR;
1771 offset /= MINSPERHOUR;
1773 if (hours >= HOURSPERDAY) {
1777 (void) sprintf(end(result), "%d", hours);
1778 if (minutes != 0 || seconds != 0) {
1779 (void) sprintf(end(result), ":%02d", minutes);
1781 (void) sprintf(end(result), ":%02d", seconds);
1787 stringrule(result, rp, dstoff, gmtoff)
1789 const struct rule * const rp;
1795 result = end(result);
1796 if (rp->r_dycode == DC_DOM) {
1797 register int month, total;
1799 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1802 for (month = 0; month < rp->r_month; ++month)
1803 total += len_months[0][month];
1804 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
1808 if (rp->r_dycode == DC_DOWGEQ) {
1809 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1810 if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
1812 } else if (rp->r_dycode == DC_DOWLEQ) {
1813 if (rp->r_dayofmonth == len_months[1][rp->r_month])
1816 week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
1817 if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
1820 } else return -1; /* "cannot happen" */
1821 (void) sprintf(result, "M%d.%d.%d",
1822 rp->r_month + 1, week, rp->r_wday);
1827 if (rp->r_todisstd && rp->r_stdoff == 0)
1833 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1834 (void) strcat(result, "/");
1835 if (stringoffset(end(result), tod) != 0)
1842 stringzone(result, zpfirst, zonecount)
1844 const struct zone * const zpfirst;
1845 const int zonecount;
1847 register const struct zone * zp;
1848 register struct rule * rp;
1849 register struct rule * stdrp;
1850 register struct rule * dstrp;
1852 register const char * abbrvar;
1855 zp = zpfirst + zonecount - 1;
1856 stdrp = dstrp = NULL;
1857 for (i = 0; i < zp->z_nrules; ++i) {
1858 rp = &zp->z_rules[i];
1859 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
1861 if (rp->r_yrtype != NULL)
1863 if (rp->r_stdoff == 0) {
1873 if (stdrp == NULL && dstrp == NULL) {
1875 ** There are no rules running through "max".
1876 ** Let's find the latest rule.
1878 for (i = 0; i < zp->z_nrules; ++i) {
1879 rp = &zp->z_rules[i];
1880 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
1881 (rp->r_hiyear == stdrp->r_hiyear &&
1882 rp->r_month > stdrp->r_month))
1885 if (stdrp != NULL && stdrp->r_stdoff != 0)
1886 return; /* We end up in DST (a POSIX no-no). */
1888 ** Horrid special case: if year is 2037,
1889 ** presume this is a zone handled on a year-by-year basis;
1890 ** do not try to apply a rule to the zone.
1892 if (stdrp != NULL && stdrp->r_hiyear == 2037)
1895 if (stdrp == NULL && zp->z_nrules != 0)
1897 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
1898 doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
1899 if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
1905 doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
1906 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
1907 if (stringoffset(end(result),
1908 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
1912 (void) strcat(result, ",");
1913 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1917 (void) strcat(result, ",");
1918 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
1925 outzone(zpfirst, zonecount)
1926 const struct zone * const zpfirst;
1927 const int zonecount;
1929 register const struct zone * zp;
1930 register struct rule * rp;
1932 register int usestart, useuntil;
1933 register zic_t starttime, untiltime;
1934 register long gmtoff;
1935 register long stdoff;
1937 register long startoff;
1938 register int startttisstd;
1939 register int startttisgmt;
1941 register char * startbuf;
1943 register char * envvar;
1944 register int max_abbr_len;
1945 register int max_envvar_len;
1947 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
1948 max_envvar_len = 2 * max_abbr_len + 5 * 9;
1949 startbuf = emalloc(max_abbr_len + 1);
1950 ab = emalloc(max_abbr_len + 1);
1951 envvar = emalloc(max_envvar_len + 1);
1952 INITIALIZE(untiltime);
1953 INITIALIZE(starttime);
1955 ** Now. . .finally. . .generate some useful data!
1961 ** Thanks to Earl Chew
1962 ** for noting the need to unconditionally initialize startttisstd.
1964 startttisstd = FALSE;
1965 startttisgmt = FALSE;
1966 min_year = max_year = EPOCH_YEAR;
1968 updateminmax(leapminyear);
1969 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
1971 for (i = 0; i < zonecount; ++i) {
1973 if (i < zonecount - 1)
1974 updateminmax(zp->z_untilrule.r_loyear);
1975 for (j = 0; j < zp->z_nrules; ++j) {
1976 rp = &zp->z_rules[j];
1978 updateminmax(rp->r_loyear);
1980 updateminmax(rp->r_hiyear);
1984 ** Generate lots of data if a rule can't cover all future times.
1986 stringzone(envvar, zpfirst, zonecount);
1987 if (noise && envvar[0] == '\0') {
1990 wp = ecpyalloc(_("no POSIX environment variable for zone"));
1991 wp = ecatalloc(wp, " ");
1992 wp = ecatalloc(wp, zpfirst->z_name);
1996 if (envvar[0] == '\0') {
1997 if (min_year >= INT_MIN + YEARSPERREPEAT)
1998 min_year -= YEARSPERREPEAT;
1999 else min_year = INT_MIN;
2000 if (max_year <= INT_MAX - YEARSPERREPEAT)
2001 max_year += YEARSPERREPEAT;
2002 else max_year = INT_MAX;
2005 ** For the benefit of older systems,
2006 ** generate data from 1900 through 2037.
2008 if (min_year > 1900)
2010 if (max_year < 2037)
2012 for (i = 0; i < zonecount; ++i) {
2014 ** A guess that may well be corrected later.
2018 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2019 useuntil = i < (zonecount - 1);
2020 if (useuntil && zp->z_untiltime <= min_time)
2022 gmtoff = zp->z_gmtoff;
2023 eat(zp->z_filename, zp->z_linenum);
2025 startoff = zp->z_gmtoff;
2026 if (zp->z_nrules == 0) {
2027 stdoff = zp->z_stdoff;
2028 doabbr(startbuf, zp->z_format,
2029 (char *) NULL, stdoff != 0, FALSE);
2030 type = addtype(oadd(zp->z_gmtoff, stdoff),
2031 startbuf, stdoff != 0, startttisstd,
2034 addtt(starttime, type);
2036 } else if (stdoff != 0)
2037 addtt(min_time, type);
2038 } else for (year = min_year; year <= max_year; ++year) {
2039 if (useuntil && year > zp->z_untilrule.r_hiyear)
2042 ** Mark which rules to do in the current year.
2043 ** For those to do, calculate rpytime(rp, year);
2045 for (j = 0; j < zp->z_nrules; ++j) {
2046 rp = &zp->z_rules[j];
2047 eats(zp->z_filename, zp->z_linenum,
2048 rp->r_filename, rp->r_linenum);
2049 rp->r_todo = year >= rp->r_loyear &&
2050 year <= rp->r_hiyear &&
2051 yearistype(year, rp->r_yrtype);
2053 rp->r_temp = rpytime(rp, year);
2057 register zic_t jtime, ktime;
2058 register long offset;
2063 ** Turn untiltime into UTC
2064 ** assuming the current gmtoff and
2067 untiltime = zp->z_untiltime;
2068 if (!zp->z_untilrule.r_todisgmt)
2069 untiltime = tadd(untiltime,
2071 if (!zp->z_untilrule.r_todisstd)
2072 untiltime = tadd(untiltime,
2076 ** Find the rule (of those to do, if any)
2077 ** that takes effect earliest in the year.
2080 for (j = 0; j < zp->z_nrules; ++j) {
2081 rp = &zp->z_rules[j];
2084 eats(zp->z_filename, zp->z_linenum,
2085 rp->r_filename, rp->r_linenum);
2086 offset = rp->r_todisgmt ? 0 : gmtoff;
2087 if (!rp->r_todisstd)
2088 offset = oadd(offset, stdoff);
2090 if (jtime == min_time ||
2093 jtime = tadd(jtime, -offset);
2094 if (k < 0 || jtime < ktime) {
2100 break; /* go on to next year */
2101 rp = &zp->z_rules[k];
2103 if (useuntil && ktime >= untiltime)
2105 stdoff = rp->r_stdoff;
2106 if (usestart && ktime == starttime)
2109 if (ktime < starttime) {
2110 startoff = oadd(zp->z_gmtoff,
2112 doabbr(startbuf, zp->z_format,
2118 if (*startbuf == '\0' &&
2119 startoff == oadd(zp->z_gmtoff,
2129 eats(zp->z_filename, zp->z_linenum,
2130 rp->r_filename, rp->r_linenum);
2131 doabbr(ab, zp->z_format, rp->r_abbrvar,
2132 rp->r_stdoff != 0, FALSE);
2133 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2134 type = addtype(offset, ab, rp->r_stdoff != 0,
2135 rp->r_todisstd, rp->r_todisgmt);
2140 if (*startbuf == '\0' &&
2141 zp->z_format != NULL &&
2142 strchr(zp->z_format, '%') == NULL &&
2143 strchr(zp->z_format, '/') == NULL)
2144 (void) strcpy(startbuf, zp->z_format);
2145 eat(zp->z_filename, zp->z_linenum);
2146 if (*startbuf == '\0')
2147 error(_("can't determine time zone abbreviation to use just after until time"));
2148 else addtt(starttime,
2149 addtype(startoff, startbuf,
2150 startoff != zp->z_gmtoff,
2155 ** Now we may get to set starttime for the next zone line.
2158 startttisstd = zp->z_untilrule.r_todisstd;
2159 startttisgmt = zp->z_untilrule.r_todisgmt;
2160 starttime = zp->z_untiltime;
2162 starttime = tadd(starttime, -stdoff);
2164 starttime = tadd(starttime, -gmtoff);
2167 writezone(zpfirst->z_name, envvar);
2174 addtt(starttime, type)
2175 const zic_t starttime;
2178 if (starttime <= min_time ||
2179 (timecnt == 1 && attypes[0].at < min_time)) {
2180 gmtoffs[0] = gmtoffs[type];
2181 isdsts[0] = isdsts[type];
2182 ttisstds[0] = ttisstds[type];
2183 ttisgmts[0] = ttisgmts[type];
2184 if (abbrinds[type] != 0)
2185 (void) strcpy(chars, &chars[abbrinds[type]]);
2187 charcnt = strlen(chars) + 1;
2192 if (timecnt >= TZ_MAX_TIMES) {
2193 error(_("too many transitions?!"));
2196 attypes[timecnt].at = starttime;
2197 attypes[timecnt].type = type;
2202 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
2204 const char * const abbr;
2211 if (isdst != TRUE && isdst != FALSE) {
2212 error(_("internal error - addtype called with bad isdst"));
2215 if (ttisstd != TRUE && ttisstd != FALSE) {
2216 error(_("internal error - addtype called with bad ttisstd"));
2219 if (ttisgmt != TRUE && ttisgmt != FALSE) {
2220 error(_("internal error - addtype called with bad ttisgmt"));
2224 ** See if there's already an entry for this zone type.
2225 ** If so, just return its index.
2227 for (i = 0; i < typecnt; ++i) {
2228 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2229 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2230 ttisstd == ttisstds[i] &&
2231 ttisgmt == ttisgmts[i])
2235 ** There isn't one; add a new one, unless there are already too
2238 if (typecnt >= TZ_MAX_TYPES) {
2239 error(_("too many local time types"));
2242 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2243 error(_("UTC offset out of range"));
2246 gmtoffs[i] = gmtoff;
2248 ttisstds[i] = ttisstd;
2249 ttisgmts[i] = ttisgmt;
2251 for (j = 0; j < charcnt; ++j)
2252 if (strcmp(&chars[j], abbr) == 0)
2262 leapadd(t, positive, rolling, count)
2270 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2271 error(_("too many leap seconds"));
2274 for (i = 0; i < leapcnt; ++i)
2275 if (t <= trans[i]) {
2276 if (t == trans[i]) {
2277 error(_("repeated leap second moment"));
2283 for (j = leapcnt; j > i; --j) {
2284 trans[j] = trans[j - 1];
2285 corr[j] = corr[j - 1];
2286 roll[j] = roll[j - 1];
2289 corr[i] = positive ? 1L : eitol(-count);
2292 } while (positive && --count != 0);
2299 register long last = 0;
2302 ** propagate leap seconds forward
2304 for (i = 0; i < leapcnt; ++i) {
2305 trans[i] = tadd(trans[i], last);
2306 last = corr[i] += last;
2311 yearistype(year, type)
2313 const char * const type;
2318 if (type == NULL || *type == '\0')
2320 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
2321 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
2322 result = system(buf);
2323 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2329 error(_("wild result from command execution"));
2330 warnx(_("command was '%s', result was %d"), buf, result);
2339 a = (unsigned char) a;
2340 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2344 ciequal(ap, bp) /* case-insensitive equality */
2345 register const char * ap;
2346 register const char * bp;
2348 while (lowerit(*ap) == lowerit(*bp++))
2356 register const char * abbr;
2357 register const char * word;
2359 if (lowerit(*abbr) != lowerit(*word))
2362 while (*++abbr != '\0')
2366 } while (lowerit(*word++) != lowerit(*abbr));
2370 static const struct lookup *
2372 register const char * const word;
2373 register const struct lookup * const table;
2375 register const struct lookup * foundlp;
2376 register const struct lookup * lp;
2378 if (word == NULL || table == NULL)
2381 ** Look for exact match.
2383 for (lp = table; lp->l_word != NULL; ++lp)
2384 if (ciequal(word, lp->l_word))
2387 ** Look for inexact match.
2390 for (lp = table; lp->l_word != NULL; ++lp)
2391 if (itsabbr(word, lp->l_word)) {
2392 if (foundlp == NULL)
2394 else return NULL; /* multiple inexact matches */
2404 register char ** array;
2409 array = (char **) (void *)
2410 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
2413 while (isascii((unsigned char) *cp) &&
2414 isspace((unsigned char) *cp))
2416 if (*cp == '\0' || *cp == '#')
2418 array[nsubs++] = dp = cp;
2420 if ((*dp = *cp++) != '"')
2422 else while ((*dp = *cp++) != '"')
2426 error(_("odd number of quotation marks"));
2429 } while (*cp != '\0' && *cp != '#' &&
2430 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2431 if (isascii(*cp) && isspace((unsigned char) *cp))
2435 array[nsubs] = NULL;
2447 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2448 error(_("time overflow"));
2461 if (t1 == max_time && t2 > 0)
2463 if (t1 == min_time && t2 < 0)
2466 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
2467 error(_("time overflow"));
2474 ** Given a rule, and a year, compute the date - in seconds since January 1,
2475 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2479 rpytime(rp, wantedy)
2480 register const struct rule * const rp;
2481 register const int wantedy;
2483 register int y, m, i;
2484 register long dayoff; /* with a nod to Margaret O. */
2487 if (wantedy == INT_MIN)
2489 if (wantedy == INT_MAX)
2494 while (wantedy != y) {
2496 i = len_years[isleap(y)];
2500 i = -len_years[isleap(y)];
2502 dayoff = oadd(dayoff, eitol(i));
2504 while (m != rp->r_month) {
2505 i = len_months[isleap(y)][m];
2506 dayoff = oadd(dayoff, eitol(i));
2509 i = rp->r_dayofmonth;
2510 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2511 if (rp->r_dycode == DC_DOWLEQ)
2514 error(_("use of 2/29 in non leap-year"));
2519 dayoff = oadd(dayoff, eitol(i));
2520 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2523 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
2524 wday = eitol(EPOCH_WDAY);
2526 ** Don't trust mod of negative numbers.
2529 wday = (wday + dayoff) % LDAYSPERWEEK;
2531 wday -= ((-dayoff) % LDAYSPERWEEK);
2533 wday += LDAYSPERWEEK;
2535 while (wday != eitol(rp->r_wday))
2536 if (rp->r_dycode == DC_DOWGEQ) {
2537 dayoff = oadd(dayoff, (long) 1);
2538 if (++wday >= LDAYSPERWEEK)
2542 dayoff = oadd(dayoff, (long) -1);
2544 wday = LDAYSPERWEEK - 1;
2547 if (i < 0 || i >= len_months[isleap(y)][m]) {
2549 warning(_("rule goes past start/end of month--\
2550 will not work with pre-2004 versions of zic"));
2553 if (dayoff < min_time / SECSPERDAY)
2555 if (dayoff > max_time / SECSPERDAY)
2557 t = (zic_t) dayoff * SECSPERDAY;
2558 return tadd(t, rp->r_tod);
2563 const char * const string;
2567 if (strcmp(string, GRANDPARENTED) != 0) {
2568 register const char * cp;
2572 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2573 ** optionally followed by a + or - and a number from 1 to 14.
2577 while (isascii((unsigned char) *cp) &&
2578 isalpha((unsigned char) *cp))
2580 if (cp - string == 0)
2581 wp = _("time zone abbreviation lacks alphabetic at start");
2582 if (noise && cp - string > 3)
2583 wp = _("time zone abbreviation has more than 3 alphabetics");
2584 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2585 wp = _("time zone abbreviation has too many alphabetics");
2586 if (wp == NULL && (*cp == '+' || *cp == '-')) {
2588 if (isascii((unsigned char) *cp) &&
2589 isdigit((unsigned char) *cp))
2591 *cp >= '0' && *cp <= '4')
2595 wp = _("time zone abbreviation differs from POSIX standard");
2598 wp = ecatalloc(wp, " (");
2599 wp = ecatalloc(wp, string);
2600 wp = ecatalloc(wp, ")");
2605 i = strlen(string) + 1;
2606 if (charcnt + i > TZ_MAX_CHARS) {
2607 error(_("too many, or too long, time zone abbreviations"));
2610 (void) strcpy(&chars[charcnt], string);
2611 charcnt += eitol(i);
2618 register char * name;
2621 if (argname == NULL || *argname == '\0' || Dflag)
2623 cp = name = ecpyalloc(argname);
2624 while ((cp = strchr(cp + 1, '/')) != 0) {
2628 ** DOS drive specifier?
2630 if (isalpha((unsigned char) name[0]) &&
2631 name[1] == ':' && name[2] == '\0') {
2635 #endif /* !defined unix */
2636 if (!itsdir(name)) {
2638 ** It doesn't seem to exist, so we try to create it.
2639 ** Creation may fail because of the directory being
2640 ** created by some other multiprocessor, so we get
2641 ** to do extra checking.
2643 if (mkdir(name, MKDIR_UMASK) != 0
2644 && (errno != EEXIST || !itsdir(name))) {
2645 warn(_("can't create directory %s"), name);
2663 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2664 errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
2672 setgroup(flag, name)
2678 if (*flag != (gid_t)-1)
2679 errx(EXIT_FAILURE, _("multiple -g flags specified"));
2681 gr = getgrnam(name);
2686 ul = strtoul(name, &ep, 10);
2687 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2691 errx(EXIT_FAILURE, _("group `%s' not found"), name);
2703 if (*flag != (gid_t)-1)
2704 errx(EXIT_FAILURE, _("multiple -u flags specified"));
2706 pw = getpwnam(name);
2711 ul = strtoul(name, &ep, 10);
2712 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2716 errx(EXIT_FAILURE, _("user `%s' not found"), name);
2722 ** UNIX was a registered trademark of The Open Group in 2003.