7 static char elsieid[] = "@(#)zic.c 7.1";
8 #endif /* !defined NOID */
9 #endif /* !defined lint */
15 const char * r_filename;
19 int r_loyear; /* for example, 1986 */
20 int r_hiyear; /* for example, 1986 */
21 const char * r_yrtype;
23 int r_month; /* 0..11 */
25 int r_dycode; /* see below */
29 long r_tod; /* time from midnight */
30 int r_todisstd; /* above is standard time if TRUE */
31 /* or wall clock time if FALSE */
32 long r_stdoff; /* offset from standard time */
33 const char * r_abbrvar; /* variable part of abbreviation */
35 int r_todo; /* a rule to do (used in outzone) */
36 time_t r_temp; /* used in outzone */
40 ** r_dycode r_dayofmonth r_wday
43 #define DC_DOM 0 /* 1..31 */ /* unused */
44 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
45 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
48 const char * z_filename;
54 const char * z_format;
58 struct rule * z_rules;
61 struct rule z_untilrule;
65 extern int emkdir P((const char * name, int mode));
66 extern int getopt P((int argc, char * argv[], const char * options));
67 extern char * icatalloc P((char * old, const char * new));
68 extern char * icpyalloc P((const char * string));
69 extern void ifree P((char * p));
70 extern char * imalloc P((int n));
71 extern char * irealloc P((char * old, int n));
72 extern int link P((const char * fromname, const char * toname));
75 extern char * scheck P((const char * string, const char * format));
77 static void addtt P((time_t starttime, int type));
78 static int addtype P((long gmtoff, const char * abbr, int isdst,
80 static void addleap P((time_t t, int positive, int rolling));
81 static void adjleap P((void));
82 static void associate P((void));
83 static int ciequal P((const char * ap, const char * bp));
84 static void convert P((long val, char * buf));
85 static void dolink P((const char * fromfile, const char * tofile));
86 static void eat P((const char * name, int num));
87 static void eats P((const char * name, int num,
88 const char * rname, int rnum));
89 static long eitol P((int i));
90 static void error P((const char * message));
91 static char ** getfields P((char * buf));
92 static long gethms P((const char * string, const char * errstrng,
94 static void infile P((const char * filename));
95 static void inleap P((char ** fields, int nfields));
96 static void inlink P((char ** fields, int nfields));
97 static void inrule P((char ** fields, int nfields));
98 static int inzcont P((char ** fields, int nfields));
99 static int inzone P((char ** fields, int nfields));
100 static int inzsub P((char ** fields, int nfields, int iscont));
101 static int itsabbr P((const char * abbr, const char * word));
102 static int itsdir P((const char * name));
103 static int lowerit P((int c));
104 static char * memcheck P((char * tocheck));
105 static int mkdirs P((char * filename));
106 static void newabbr P((const char * abbr));
107 static long oadd P((long t1, long t2));
108 static void outzone P((const struct zone * zp, int ntzones));
109 static void puttzcode P((long code, FILE * fp));
110 static int rcomp P((const genericptr_t leftp, const genericptr_t rightp));
111 static time_t rpytime P((const struct rule * rp, int wantedy));
112 static void rulesub P((struct rule * rp,
113 char * loyearp, char * hiyearp,
114 char * typep, char * monthp,
115 char * dayp, char * timep));
116 static void setboundaries P((void));
117 static time_t tadd P((time_t t1, long t2));
118 static void usage P((void));
119 static void writezone P((const char * name));
120 static int yearistype P((int year, const char * type));
124 static const char * filename;
127 static time_t max_time;
129 static time_t min_time;
132 static const char * rfilename;
134 static const char * progname;
137 static int tt_signed;
149 ** Which fields are which on a Zone line.
157 #define ZF_TILMONTH 6
160 #define ZONE_MINFIELDS 5
161 #define ZONE_MAXFIELDS 9
164 ** Which fields are which on a Zone continuation line.
170 #define ZFC_TILYEAR 3
171 #define ZFC_TILMONTH 4
173 #define ZFC_TILTIME 6
174 #define ZONEC_MINFIELDS 3
175 #define ZONEC_MAXFIELDS 7
178 ** Which files are which on a Rule line.
190 #define RULE_FIELDS 10
193 ** Which fields are which on a Link line.
198 #define LINK_FIELDS 3
201 ** Which fields are which on a Leap line.
210 #define LEAP_FIELDS 7
220 static struct rule * rules;
221 static int nrules; /* number of rules */
223 static struct zone * zones;
224 static int nzones; /* number of zones */
227 const char * l_filename;
233 static struct link * links;
241 static struct lookup const * byword P((const char * string,
242 const struct lookup * lp));
244 static struct lookup const line_codes[] = {
252 static struct lookup const mon_names[] = {
253 "January", TM_JANUARY,
254 "February", TM_FEBRUARY,
261 "September", TM_SEPTEMBER,
262 "October", TM_OCTOBER,
263 "November", TM_NOVEMBER,
264 "December", TM_DECEMBER,
268 static struct lookup const wday_names[] = {
271 "Tuesday", TM_TUESDAY,
272 "Wednesday", TM_WEDNESDAY,
273 "Thursday", TM_THURSDAY,
275 "Saturday", TM_SATURDAY,
279 static struct lookup const lasts[] = {
280 "last-Sunday", TM_SUNDAY,
281 "last-Monday", TM_MONDAY,
282 "last-Tuesday", TM_TUESDAY,
283 "last-Wednesday", TM_WEDNESDAY,
284 "last-Thursday", TM_THURSDAY,
285 "last-Friday", TM_FRIDAY,
286 "last-Saturday", TM_SATURDAY,
290 static struct lookup const begin_years[] = {
291 "minimum", YR_MINIMUM,
292 "maximum", YR_MAXIMUM,
296 static struct lookup const end_years[] = {
297 "minimum", YR_MINIMUM,
298 "maximum", YR_MAXIMUM,
303 static struct lookup const leap_types[] = {
309 static const int len_months[2][MONSPERYEAR] = {
310 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
311 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
314 static const int len_years[2] = {
315 DAYSPERNYEAR, DAYSPERLYEAR
318 static time_t ats[TZ_MAX_TIMES];
319 static unsigned char types[TZ_MAX_TIMES];
320 static long gmtoffs[TZ_MAX_TYPES];
321 static char isdsts[TZ_MAX_TYPES];
322 static char abbrinds[TZ_MAX_TYPES];
323 static char ttisstds[TZ_MAX_TYPES];
324 static char chars[TZ_MAX_CHARS];
325 static time_t trans[TZ_MAX_LEAPS];
326 static long corr[TZ_MAX_LEAPS];
327 static char roll[TZ_MAX_LEAPS];
330 ** Memory allocation.
338 (void) perror(progname);
339 (void) exit(EXIT_FAILURE);
344 #define emalloc(size) memcheck(imalloc(size))
345 #define erealloc(ptr, size) memcheck(irealloc(ptr, size))
346 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
347 #define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp))
354 eats(name, num, rname, rnum)
355 const char * const name;
357 const char * const rname;
368 const char * const name;
371 eats(name, num, (char *) NULL, -1);
376 const char * const string;
379 ** Match the format of "cc" to allow sh users to
380 ** zic ... 2>&1 | error -t "*" -v
383 (void) fprintf(stderr, "\"%s\", line %d: %s",
384 filename, linenum, string);
385 if (rfilename != NULL)
386 (void) fprintf(stderr, " (rule from \"%s\", line %d)",
387 rfilename, rlinenum);
388 (void) fprintf(stderr, "\n");
395 (void) fprintf(stderr,
396 "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\
397 \t[ -L leapseconds ] [ filename ... ]\n",
399 (void) exit(EXIT_FAILURE);
402 static const char * psxrules;
403 static const char * lcltime;
404 static const char * directory;
405 static const char * leapsec;
406 static int sflag = FALSE;
417 (void) umask(umask(022) | 022);
418 #endif /* defined unix */
420 while ((c = getopt(argc, argv, "d:l:p:L:vs")) != EOF)
425 if (directory == NULL)
428 (void) fprintf(stderr,
429 "%s: More than one -d option specified\n",
431 (void) exit(EXIT_FAILURE);
438 (void) fprintf(stderr,
439 "%s: More than one -l option specified\n",
441 (void) exit(EXIT_FAILURE);
445 if (psxrules == NULL)
448 (void) fprintf(stderr,
449 "%s: More than one -p option specified\n",
451 (void) exit(EXIT_FAILURE);
458 (void) fprintf(stderr,
459 "%s: More than one -L option specified\n",
461 (void) exit(EXIT_FAILURE);
471 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
472 usage(); /* usage message by request */
473 if (directory == NULL)
478 if (optind < argc && leapsec != NULL) {
483 zones = (struct zone *) emalloc(0);
484 rules = (struct rule *) emalloc(0);
485 links = (struct link *) emalloc(0);
486 for (i = optind; i < argc; ++i)
489 (void) exit(EXIT_FAILURE);
491 for (i = 0; i < nzones; i = j) {
493 ** Find the next non-continuation zone entry.
495 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
497 outzone(&zones[i], j - i);
502 for (i = 0; i < nlinks; ++i)
503 dolink(links[i].l_from, links[i].l_to);
505 dolink(lcltime, TZDEFAULT);
506 if (psxrules != NULL)
507 dolink(psxrules, TZDEFRULES);
508 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
512 dolink(fromfile, tofile)
513 const char * const fromfile;
514 const char * const tofile;
516 register char * fromname;
517 register char * toname;
519 fromname = ecpyalloc(directory);
520 fromname = ecatalloc(fromname, "/");
521 fromname = ecatalloc(fromname, fromfile);
522 toname = ecpyalloc(directory);
523 toname = ecatalloc(toname, "/");
524 toname = ecatalloc(toname, tofile);
526 ** We get to be careful here since
527 ** there's a fair chance of root running us.
530 (void) remove(toname);
531 if (link(fromname, toname) != 0) {
532 (void) fprintf(stderr, "%s: Can't link from %s to ",
534 (void) perror(toname);
535 (void) exit(EXIT_FAILURE);
546 for (bit = 1; bit > 0; bit <<= 1)
548 if (bit == 0) { /* time_t is an unsigned type */
551 max_time = ~(time_t) 0;
559 max_time = -max_time;
563 min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
564 max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
569 const char * const name;
571 register char * myname;
574 myname = ecpyalloc(name);
575 myname = ecatalloc(myname, "/.");
576 accres = access(myname, 0);
582 ** Associate sets of rules with zones.
586 ** Sort by rule name.
591 const genericptr_t cp1;
592 const genericptr_t cp2;
594 return strcmp(((struct rule *) cp1)->r_name,
595 ((struct rule *) cp2)->r_name);
601 register struct zone * zp;
602 register struct rule * rp;
603 register int base, out;
607 (void) qsort((genericptr_t) rules,
608 (qsort_size_t) nrules,
609 (qsort_size_t) sizeof *rules, rcomp);
610 for (i = 0; i < nzones; ++i) {
615 for (base = 0; base < nrules; base = out) {
617 for (out = base + 1; out < nrules; ++out)
618 if (strcmp(rp->r_name, rules[out].r_name) != 0)
620 for (i = 0; i < nzones; ++i) {
622 if (strcmp(zp->z_rule, rp->r_name) != 0)
625 zp->z_nrules = out - base;
628 for (i = 0; i < nzones; ++i) {
630 if (zp->z_nrules == 0) {
632 ** Maybe we have a local standard time offset.
634 eat(zp->z_filename, zp->z_linenum);
635 zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
637 ** Note, though, that if there's no rule,
638 ** a '%s' in the format is a bad thing.
640 if (strchr(zp->z_format, '%') != 0)
641 error("%s in ruleless zone");
645 (void) exit(EXIT_FAILURE);
653 register char ** fields;
655 register const struct lookup * lp;
656 register int nfields;
657 register int wantcont;
661 if (strcmp(name, "-") == 0) {
662 name = "standard input";
664 } else if ((fp = fopen(name, "r")) == NULL) {
665 (void) fprintf(stderr, "%s: Can't open ", progname);
667 (void) exit(EXIT_FAILURE);
670 for (num = 1; ; ++num) {
672 if (fgets(buf, (int) sizeof buf, fp) != buf)
674 cp = strchr(buf, '\n');
676 error("line too long");
677 (void) exit(EXIT_FAILURE);
680 fields = getfields(buf);
682 while (fields[nfields] != NULL) {
683 if (ciequal(fields[nfields], "-"))
684 fields[nfields] = "";
689 } else if (wantcont) {
690 wantcont = inzcont(fields, nfields);
692 lp = byword(fields[0], line_codes);
694 error("input line of unknown type");
695 else switch ((int) (lp->l_value)) {
697 inrule(fields, nfields);
701 wantcont = inzone(fields, nfields);
704 inlink(fields, nfields);
709 (void) fprintf(stderr,
710 "%s: Leap line in non leap seconds file %s\n",
712 else inleap(fields, nfields);
715 default: /* "cannot happen" */
716 (void) fprintf(stderr,
717 "%s: panic: Invalid l_value %d\n",
718 progname, lp->l_value);
719 (void) exit(EXIT_FAILURE);
722 ifree((char *) fields);
725 (void) fprintf(stderr, "%s: Error reading ", progname);
726 (void) perror(filename);
727 (void) exit(EXIT_FAILURE);
729 if (fp != stdin && fclose(fp)) {
730 (void) fprintf(stderr, "%s: Error closing ", progname);
731 (void) perror(filename);
732 (void) exit(EXIT_FAILURE);
735 error("expected continuation line not found");
739 ** Convert a string of one of the forms
740 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
741 ** into a number of seconds.
742 ** A null string maps to zero.
743 ** Call error with errstring and return zero on errors.
747 gethms(string, errstring, signable)
749 const char * const errstring;
752 int hh, mm, ss, sign;
754 if (string == NULL || *string == '\0')
758 else if (*string == '-') {
762 if (sscanf(string, scheck(string, "%d"), &hh) == 1)
764 else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
766 else if (sscanf(string, scheck(string, "%d:%d:%d"),
767 &hh, &mm, &ss) != 3) {
771 if (hh < 0 || hh >= HOURSPERDAY ||
772 mm < 0 || mm >= MINSPERHOUR ||
773 ss < 0 || ss > SECSPERMIN) {
778 (eitol(hh * MINSPERHOUR + mm) *
779 eitol(SECSPERMIN) + eitol(ss));
783 inrule(fields, nfields)
784 register char ** const fields;
787 static struct rule r;
789 if (nfields != RULE_FIELDS) {
790 error("wrong number of fields on Rule line");
793 if (*fields[RF_NAME] == '\0') {
794 error("nameless rule");
797 r.r_filename = filename;
798 r.r_linenum = linenum;
799 r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
800 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
801 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
802 r.r_name = ecpyalloc(fields[RF_NAME]);
803 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
804 rules = (struct rule *) erealloc((char *) rules,
805 (int) ((nrules + 1) * sizeof *rules));
810 inzone(fields, nfields)
811 register char ** const fields;
817 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
818 error("wrong number of fields on Zone line");
821 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
823 "\"Zone %s\" line and -l option are mutually exclusive",
828 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
830 "\"Zone %s\" line and -p option are mutually exclusive",
835 for (i = 0; i < nzones; ++i)
836 if (zones[i].z_name != NULL &&
837 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
839 "duplicate zone name %s (file \"%s\", line %d)",
846 return inzsub(fields, nfields, FALSE);
850 inzcont(fields, nfields)
851 register char ** const fields;
854 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
855 error("wrong number of fields on Zone continuation line");
858 return inzsub(fields, nfields, TRUE);
862 inzsub(fields, nfields, iscont)
863 register char ** const fields;
868 static struct zone z;
869 register int i_gmtoff, i_rule, i_format;
870 register int i_untilyear, i_untilmonth;
871 register int i_untilday, i_untiltime;
872 register int hasuntil;
875 i_gmtoff = ZFC_GMTOFF;
877 i_format = ZFC_FORMAT;
878 i_untilyear = ZFC_TILYEAR;
879 i_untilmonth = ZFC_TILMONTH;
880 i_untilday = ZFC_TILDAY;
881 i_untiltime = ZFC_TILTIME;
884 i_gmtoff = ZF_GMTOFF;
886 i_format = ZF_FORMAT;
887 i_untilyear = ZF_TILYEAR;
888 i_untilmonth = ZF_TILMONTH;
889 i_untilday = ZF_TILDAY;
890 i_untiltime = ZF_TILTIME;
891 z.z_name = ecpyalloc(fields[ZF_NAME]);
893 z.z_filename = filename;
894 z.z_linenum = linenum;
895 z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
896 if ((cp = strchr(fields[i_format], '%')) != 0) {
897 if (*++cp != 's' || strchr(cp, '%') != 0) {
898 error("invalid abbreviation format");
902 z.z_rule = ecpyalloc(fields[i_rule]);
903 z.z_format = ecpyalloc(fields[i_format]);
904 hasuntil = nfields > i_untilyear;
906 z.z_untilrule.r_filename = filename;
907 z.z_untilrule.r_linenum = linenum;
908 rulesub(&z.z_untilrule,
912 (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
913 (nfields > i_untilday) ? fields[i_untilday] : "1",
914 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
915 z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
916 if (iscont && nzones > 0 && z.z_untiltime < max_time &&
917 z.z_untiltime > min_time &&
918 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
919 error("Zone continuation line end time is not after end time of previous line");
923 zones = (struct zone *) erealloc((char *) zones,
924 (int) ((nzones + 1) * sizeof *zones));
927 ** If there was an UNTIL field on this line,
928 ** there's more information about the zone on the next line.
934 inleap(fields, nfields)
935 register char ** const fields;
938 register const char * cp;
939 register const struct lookup * lp;
941 int year, month, day;
945 if (nfields != LEAP_FIELDS) {
946 error("wrong number of fields on Leap line");
950 cp = fields[LP_YEAR];
951 if (sscanf(cp, scheck(cp, "%d"), &year) != 1 ||
952 year < min_year || year > max_year) {
956 error("invalid leaping year");
962 i = len_years[isleap(j)];
966 i = -len_years[isleap(j)];
968 dayoff = oadd(dayoff, eitol(i));
970 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
971 error("invalid month name");
977 i = len_months[isleap(year)][j];
978 dayoff = oadd(dayoff, eitol(i));
982 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
983 day <= 0 || day > len_months[isleap(year)][month]) {
984 error("invalid day of month");
987 dayoff = oadd(dayoff, eitol(day - 1));
988 if (dayoff < 0 && !tt_signed) {
989 error("time before zero");
992 t = (time_t) dayoff * SECSPERDAY;
994 ** Cheap overflow check.
996 if (t / SECSPERDAY != dayoff) {
997 error("time overflow");
1000 tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
1001 cp = fields[LP_CORR];
1002 if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) {
1003 /* infile() turned "-" into "" */
1004 error("illegal CORRECTION field on Leap line");
1007 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1008 error("illegal Rolling/Stationary field on Leap line");
1011 addleap(tadd(t, tod), *cp == '+', lp->l_value);
1015 inlink(fields, nfields)
1016 register char ** const fields;
1021 if (nfields != LINK_FIELDS) {
1022 error("wrong number of fields on Link line");
1025 if (*fields[LF_FROM] == '\0') {
1026 error("blank FROM field on Link line");
1029 if (*fields[LF_TO] == '\0') {
1030 error("blank TO field on Link line");
1033 l.l_filename = filename;
1034 l.l_linenum = linenum;
1035 l.l_from = ecpyalloc(fields[LF_FROM]);
1036 l.l_to = ecpyalloc(fields[LF_TO]);
1037 links = (struct link *) erealloc((char *) links,
1038 (int) ((nlinks + 1) * sizeof *links));
1039 links[nlinks++] = l;
1043 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1044 register struct rule * const rp;
1045 char * const loyearp;
1046 char * const hiyearp;
1048 char * const monthp;
1052 register struct lookup const * lp;
1055 if ((lp = byword(monthp, mon_names)) == NULL) {
1056 error("invalid month name");
1059 rp->r_month = lp->l_value;
1060 rp->r_todisstd = FALSE;
1063 cp += strlen(cp) - 1;
1064 switch (lowerit(*cp)) {
1066 rp->r_todisstd = TRUE;
1070 rp->r_todisstd = FALSE;
1075 rp->r_tod = gethms(timep, "invalid time of day", FALSE);
1080 if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
1082 rp->r_loyear = min_year;
1085 rp->r_loyear = max_year;
1087 default: /* "cannot happen" */
1088 (void) fprintf(stderr,
1089 "%s: panic: Invalid l_value %d\n",
1090 progname, lp->l_value);
1091 (void) exit(EXIT_FAILURE);
1092 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
1093 rp->r_loyear < min_year || rp->r_loyear > max_year) {
1095 error("invalid starting year");
1096 if (rp->r_loyear > max_year)
1100 if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
1102 rp->r_hiyear = min_year;
1105 rp->r_hiyear = max_year;
1108 rp->r_hiyear = rp->r_loyear;
1110 default: /* "cannot happen" */
1111 (void) fprintf(stderr,
1112 "%s: panic: Invalid l_value %d\n",
1113 progname, lp->l_value);
1114 (void) exit(EXIT_FAILURE);
1115 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
1116 rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
1118 error("invalid ending year");
1119 if (rp->r_hiyear < min_year)
1122 if (rp->r_hiyear < min_year)
1124 if (rp->r_loyear < min_year)
1125 rp->r_loyear = min_year;
1126 if (rp->r_hiyear > max_year)
1127 rp->r_hiyear = max_year;
1128 if (rp->r_loyear > rp->r_hiyear) {
1129 error("starting year greater than ending year");
1133 rp->r_yrtype = NULL;
1135 if (rp->r_loyear == rp->r_hiyear) {
1136 error("typed single year");
1139 rp->r_yrtype = ecpyalloc(typep);
1143 ** Accept things such as:
1149 if ((lp = byword(dayp, lasts)) != NULL) {
1150 rp->r_dycode = DC_DOWLEQ;
1151 rp->r_wday = lp->l_value;
1152 rp->r_dayofmonth = len_months[1][rp->r_month];
1154 if ((cp = strchr(dayp, '<')) != 0)
1155 rp->r_dycode = DC_DOWLEQ;
1156 else if ((cp = strchr(dayp, '>')) != 0)
1157 rp->r_dycode = DC_DOWGEQ;
1160 rp->r_dycode = DC_DOM;
1162 if (rp->r_dycode != DC_DOM) {
1165 error("invalid day of month");
1168 if ((lp = byword(dayp, wday_names)) == NULL) {
1169 error("invalid weekday name");
1172 rp->r_wday = lp->l_value;
1174 if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
1175 rp->r_dayofmonth <= 0 ||
1176 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1177 error("invalid day of month");
1189 register long shift;
1191 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1192 buf[i] = val >> shift;
1203 (void) fwrite((genericptr_t) buf,
1204 (fwrite_size_t) sizeof buf,
1205 (fwrite_size_t) 1, fp);
1210 const char * const name;
1214 char fullname[BUFSIZ];
1215 static struct tzhead tzh;
1217 if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
1218 (void) fprintf(stderr,
1219 "%s: File name %s/%s too long\n", progname,
1221 (void) exit(EXIT_FAILURE);
1223 (void) sprintf(fullname, "%s/%s", directory, name);
1224 if ((fp = fopen(fullname, "wb")) == NULL) {
1225 if (mkdirs(fullname) != 0)
1226 (void) exit(EXIT_FAILURE);
1227 if ((fp = fopen(fullname, "wb")) == NULL) {
1228 (void) fprintf(stderr, "%s: Can't create ", progname);
1229 (void) perror(fullname);
1230 (void) exit(EXIT_FAILURE);
1233 convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1234 convert(eitol(leapcnt), tzh.tzh_leapcnt);
1235 convert(eitol(timecnt), tzh.tzh_timecnt);
1236 convert(eitol(typecnt), tzh.tzh_typecnt);
1237 convert(eitol(charcnt), tzh.tzh_charcnt);
1238 (void) fwrite((genericptr_t) &tzh,
1239 (fwrite_size_t) sizeof tzh,
1240 (fwrite_size_t) 1, fp);
1241 for (i = 0; i < timecnt; ++i) {
1244 if (ats[i] >= trans[j]) {
1245 ats[i] = tadd(ats[i], corr[j]);
1248 puttzcode((long) ats[i], fp);
1251 (void) fwrite((genericptr_t) types,
1252 (fwrite_size_t) sizeof types[0],
1253 (fwrite_size_t) timecnt, fp);
1254 for (i = 0; i < typecnt; ++i) {
1255 puttzcode((long) gmtoffs[i], fp);
1256 (void) putc(isdsts[i], fp);
1257 (void) putc(abbrinds[i], fp);
1260 (void) fwrite((genericptr_t) chars,
1261 (fwrite_size_t) sizeof chars[0],
1262 (fwrite_size_t) charcnt, fp);
1263 for (i = 0; i < leapcnt; ++i) {
1265 if (timecnt == 0 || trans[i] < ats[0]) {
1268 if (++j >= typecnt) {
1274 while (j < timecnt && trans[i] >= ats[j])
1278 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
1279 } else puttzcode((long) trans[i], fp);
1280 puttzcode((long) corr[i], fp);
1282 for (i = 0; i < typecnt; ++i)
1283 (void) putc(ttisstds[i], fp);
1284 if (ferror(fp) || fclose(fp)) {
1285 (void) fprintf(stderr, "%s: Write error on ", progname);
1286 (void) perror(fullname);
1287 (void) exit(EXIT_FAILURE);
1292 outzone(zpfirst, zonecount)
1293 const struct zone * const zpfirst;
1294 const int zonecount;
1296 register const struct zone * zp;
1297 register struct rule * rp;
1299 register int usestart, useuntil;
1300 register time_t starttime, untiltime;
1301 register long gmtoff;
1302 register long stdoff;
1304 register long startoff;
1305 register int startisdst;
1306 register int startttisstd;
1308 char startbuf[BUFSIZ];
1311 ** Now. . .finally. . .generate some useful data!
1317 ** Two guesses. . .the second may well be corrected later.
1319 gmtoff = zpfirst->z_gmtoff;
1323 startttisstd = FALSE;
1324 #endif /* defined lint */
1325 for (i = 0; i < zonecount; ++i) {
1327 useuntil = i < (zonecount - 1);
1329 eat(zp->z_filename, zp->z_linenum);
1331 if (zp->z_nrules == 0) {
1332 type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
1333 zp->z_format, zp->z_stdoff != 0,
1336 addtt(starttime, type);
1337 gmtoff = zp->z_gmtoff;
1338 stdoff = zp->z_stdoff;
1339 } else for (year = min_year; year <= max_year; ++year) {
1340 if (useuntil && year > zp->z_untilrule.r_hiyear)
1343 ** Mark which rules to do in the current year.
1344 ** For those to do, calculate rpytime(rp, year);
1346 for (j = 0; j < zp->z_nrules; ++j) {
1347 rp = &zp->z_rules[j];
1348 eats(zp->z_filename, zp->z_linenum,
1349 rp->r_filename, rp->r_linenum);
1350 rp->r_todo = year >= rp->r_loyear &&
1351 year <= rp->r_hiyear &&
1352 yearistype(year, rp->r_yrtype);
1354 rp->r_temp = rpytime(rp, year);
1358 register time_t jtime, ktime;
1359 register long offset;
1364 ** Turn untiltime into GMT
1365 ** assuming the current gmtoff and
1369 if (!zp->z_untilrule.r_todisstd)
1370 offset = oadd(offset, stdoff);
1371 untiltime = tadd(zp->z_untiltime,
1375 ** Find the rule (of those to do, if any)
1376 ** that takes effect earliest in the year.
1381 #endif /* defined lint */
1382 for (j = 0; j < zp->z_nrules; ++j) {
1383 rp = &zp->z_rules[j];
1386 eats(zp->z_filename, zp->z_linenum,
1387 rp->r_filename, rp->r_linenum);
1389 if (!rp->r_todisstd)
1390 offset = oadd(offset, stdoff);
1392 if (jtime == min_time ||
1395 jtime = tadd(jtime, -offset);
1396 if (k < 0 || jtime < ktime) {
1402 break; /* go on to next year */
1403 rp = &zp->z_rules[k];
1405 if (useuntil && ktime >= untiltime)
1408 if (ktime < starttime) {
1409 stdoff = rp->r_stdoff;
1410 startoff = oadd(zp->z_gmtoff,
1412 (void) sprintf(startbuf,
1419 if (ktime != starttime &&
1421 addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
1424 eats(zp->z_filename, zp->z_linenum,
1425 rp->r_filename, rp->r_linenum);
1426 (void) sprintf(buf, zp->z_format,
1428 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1429 type = addtype(offset, buf, rp->r_stdoff != 0,
1431 if (timecnt != 0 || rp->r_stdoff != 0)
1433 gmtoff = zp->z_gmtoff;
1434 stdoff = rp->r_stdoff;
1438 ** Now we may get to set starttime for the next zone line.
1441 starttime = tadd(zp->z_untiltime,
1442 -gmtoffs[types[timecnt - 1]]);
1443 startttisstd = zp->z_untilrule.r_todisstd;
1446 writezone(zpfirst->z_name);
1450 addtt(starttime, type)
1451 const time_t starttime;
1454 if (timecnt != 0 && type == types[timecnt - 1])
1455 return; /* easy enough! */
1456 if (timecnt >= TZ_MAX_TIMES) {
1457 error("too many transitions?!");
1458 (void) exit(EXIT_FAILURE);
1460 ats[timecnt] = starttime;
1461 types[timecnt] = type;
1466 addtype(gmtoff, abbr, isdst, ttisstd)
1468 const char * const abbr;
1475 ** See if there's already an entry for this zone type.
1476 ** If so, just return its index.
1478 for (i = 0; i < typecnt; ++i) {
1479 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1480 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1481 ttisstd == ttisstds[i])
1485 ** There isn't one; add a new one, unless there are already too
1488 if (typecnt >= TZ_MAX_TYPES) {
1489 error("too many local time types");
1490 (void) exit(EXIT_FAILURE);
1492 gmtoffs[i] = gmtoff;
1494 ttisstds[i] = ttisstd;
1496 for (j = 0; j < charcnt; ++j)
1497 if (strcmp(&chars[j], abbr) == 0)
1507 addleap(t, positive, rolling)
1514 if (leapcnt >= TZ_MAX_LEAPS) {
1515 error("too many leap seconds");
1516 (void) exit(EXIT_FAILURE);
1518 for (i = 0; i < leapcnt; ++i)
1519 if (t <= trans[i]) {
1520 if (t == trans[i]) {
1521 error("repeated leap second moment");
1522 (void) exit(EXIT_FAILURE);
1526 for (j = leapcnt; j > i; --j) {
1527 trans[j] = trans[j-1];
1528 corr[j] = corr[j-1];
1529 roll[j] = roll[j-1];
1532 corr[i] = (positive ? 1L : -1L);
1541 register long last = 0;
1544 ** propagate leap seconds forward
1546 for (i = 0; i < leapcnt; ++i) {
1547 trans[i] = tadd(trans[i], last);
1548 last = corr[i] += last;
1553 yearistype(year, type)
1555 const char * const type;
1560 if (type == NULL || *type == '\0')
1562 if (strcmp(type, "uspres") == 0)
1563 return (year % 4) == 0;
1564 if (strcmp(type, "nonpres") == 0)
1565 return (year % 4) != 0;
1566 (void) sprintf(buf, "yearistype %d %s", year, type);
1567 result = system(buf);
1570 if (result == (1 << 8))
1572 error("Wild result from command execution");
1573 (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
1574 progname, buf, result);
1576 (void) exit(EXIT_FAILURE);
1583 return (isascii(a) && isupper(a)) ? tolower(a) : a;
1587 ciequal(ap, bp) /* case-insensitive equality */
1588 register const char * ap;
1589 register const char * bp;
1591 while (lowerit(*ap) == lowerit(*bp++))
1599 register const char * abbr;
1600 register const char * word;
1602 if (lowerit(*abbr) != lowerit(*word))
1605 while (*++abbr != '\0')
1606 do if (*word == '\0')
1608 while (lowerit(*word++) != lowerit(*abbr));
1612 static const struct lookup *
1614 register const char * const word;
1615 register const struct lookup * const table;
1617 register const struct lookup * foundlp;
1618 register const struct lookup * lp;
1620 if (word == NULL || table == NULL)
1623 ** Look for exact match.
1625 for (lp = table; lp->l_word != NULL; ++lp)
1626 if (ciequal(word, lp->l_word))
1629 ** Look for inexact match.
1632 for (lp = table; lp->l_word != NULL; ++lp)
1633 if (itsabbr(word, lp->l_word))
1634 if (foundlp == NULL)
1636 else return NULL; /* multiple inexact matches */
1645 register char ** array;
1650 array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
1653 while (isascii(*cp) && isspace(*cp))
1655 if (*cp == '\0' || *cp == '#')
1657 array[nsubs++] = dp = cp;
1659 if ((*dp = *cp++) != '"')
1661 else while ((*dp = *cp++) != '"')
1664 else error("Odd number of quotation marks");
1665 } while (*cp != '\0' && *cp != '#' &&
1666 (!isascii(*cp) || !isspace(*cp)));
1667 if (isascii(*cp) && isspace(*cp))
1671 array[nsubs] = NULL;
1683 if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1684 error("time overflow");
1685 (void) exit(EXIT_FAILURE);
1697 if (t1 == max_time && t2 > 0)
1699 if (t1 == min_time && t2 < 0)
1702 if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1703 error("time overflow");
1704 (void) exit(EXIT_FAILURE);
1710 ** Given a rule, and a year, compute the date - in seconds since January 1,
1711 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1715 rpytime(rp, wantedy)
1716 register const struct rule * const rp;
1717 register const int wantedy;
1719 register int y, m, i;
1720 register long dayoff; /* with a nod to Margaret O. */
1726 while (wantedy != y) {
1728 i = len_years[isleap(y)];
1732 i = -len_years[isleap(y)];
1734 dayoff = oadd(dayoff, eitol(i));
1736 while (m != rp->r_month) {
1737 i = len_months[isleap(y)][m];
1738 dayoff = oadd(dayoff, eitol(i));
1741 i = rp->r_dayofmonth;
1742 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1743 if (rp->r_dycode == DC_DOWLEQ)
1746 error("use of 2/29 in non leap-year");
1747 (void) exit(EXIT_FAILURE);
1751 dayoff = oadd(dayoff, eitol(i));
1752 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1755 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
1756 wday = eitol(EPOCH_WDAY);
1758 ** Don't trust mod of negative numbers.
1761 wday = (wday + dayoff) % LDAYSPERWEEK;
1763 wday -= ((-dayoff) % LDAYSPERWEEK);
1765 wday += LDAYSPERWEEK;
1767 while (wday != eitol(rp->r_wday))
1768 if (rp->r_dycode == DC_DOWGEQ) {
1769 dayoff = oadd(dayoff, (long) 1);
1770 if (++wday >= LDAYSPERWEEK)
1774 dayoff = oadd(dayoff, (long) -1);
1776 wday = LDAYSPERWEEK;
1779 if (i < 0 || i >= len_months[isleap(y)][m]) {
1780 error("no day in month matches rule");
1781 (void) exit(EXIT_FAILURE);
1784 if (dayoff < 0 && !tt_signed) {
1785 if (wantedy == rp->r_loyear)
1787 error("time before zero");
1788 (void) exit(EXIT_FAILURE);
1790 t = (time_t) dayoff * SECSPERDAY;
1792 ** Cheap overflow check.
1794 if (t / SECSPERDAY != dayoff) {
1795 if (wantedy == rp->r_hiyear)
1797 if (wantedy == rp->r_loyear)
1799 error("time overflow");
1800 (void) exit(EXIT_FAILURE);
1802 return tadd(t, rp->r_tod);
1807 const char * const string;
1811 i = strlen(string) + 1;
1812 if (charcnt + i >= TZ_MAX_CHARS) {
1813 error("too many, or too long, time zone abbreviations");
1814 (void) exit(EXIT_FAILURE);
1816 (void) strcpy(&chars[charcnt], string);
1817 charcnt += eitol(i);
1826 if ((cp = name) == NULL || *cp == '\0')
1828 while ((cp = strchr(cp + 1, '/')) != 0) {
1832 ** MS-DOS drive specifier?
1834 if (strlen(name) == 2 && isascii(name[0]) &&
1835 isalpha(name[0]) && name[1] == ':') {
1839 #endif /* !defined unix */
1840 if (!itsdir(name)) {
1842 ** It doesn't seem to exist, so we try to create it.
1844 if (emkdir(name, 0755) != 0) {
1845 (void) fprintf(stderr,
1846 "%s: Can't create directory ",
1848 (void) perror(name);
1864 if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
1865 (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
1867 (void) exit(EXIT_FAILURE);
1873 ** UNIX is a registered trademark of AT&T.