|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)zic.c 1.3 (Berkeley) 10/22/87";
3: #endif
4:
5: #include "stdio.h"
6: #include "ctype.h"
7: #include "sys/types.h"
8: #include "sys/stat.h"
9: #include "sys/file.h"
10: #include "strings.h"
11: #include "time.h"
12: #include "tzfile.h"
13:
14: #ifndef BUFSIZ
15: #define BUFSIZ 1024
16: #endif
17:
18: #ifndef TRUE
19: #define TRUE 1
20: #define FALSE 0
21: #endif
22:
23: extern char * icpyalloc();
24: extern char * imalloc();
25: extern char * irealloc();
26: extern char * optarg;
27: extern int optind;
28: extern char * scheck();
29:
30: static addtt();
31: static addtype();
32: static associate();
33: static int charcnt;
34: static ciequal();
35: static long eitol();
36: static int errors;
37: static char * filename;
38: static char ** getfields();
39: static long gethms();
40: static infile();
41: static inlink();
42: static inrule();
43: static inzcont();
44: static inzone();
45: static inzsub();
46: static int linenum;
47: static lowerit();
48: static time_t max_time;
49: static int max_year;
50: static time_t min_time;
51: static int min_year;
52: static mkdirs();
53: static newabbr();
54: static int noise;
55: static nondunlink();
56: static long oadd();
57: static outzone();
58: static char * progname;
59: static char * rfilename;
60: static int rlinenum;
61: static time_t rpytime();
62: static rulesub();
63: static setboundaries();
64: static time_t tadd();
65: static int timecnt;
66: static int tt_signed;
67: static int typecnt;
68: static yearistype();
69:
70: /*
71: ** Line codes.
72: */
73:
74: #define LC_RULE 0
75: #define LC_ZONE 1
76: #define LC_LINK 2
77:
78: /*
79: ** Which fields are which on a Zone line.
80: */
81:
82: #define ZF_NAME 1
83: #define ZF_GMTOFF 2
84: #define ZF_RULE 3
85: #define ZF_FORMAT 4
86: #define ZF_UNTILYEAR 5
87: #define ZF_UNTILMONTH 6
88: #define ZF_UNTILDAY 7
89: #define ZF_UNTILTIME 8
90: #define ZONE_MINFIELDS 5
91: #define ZONE_MAXFIELDS 9
92:
93: /*
94: ** Which fields are which on a Zone continuation line.
95: */
96:
97: #define ZFC_GMTOFF 0
98: #define ZFC_RULE 1
99: #define ZFC_FORMAT 2
100: #define ZFC_UNTILYEAR 3
101: #define ZFC_UNTILMONTH 4
102: #define ZFC_UNTILDAY 5
103: #define ZFC_UNTILTIME 6
104: #define ZONEC_MINFIELDS 3
105: #define ZONEC_MAXFIELDS 7
106:
107: /*
108: ** Which files are which on a Rule line.
109: */
110:
111: #define RF_NAME 1
112: #define RF_LOYEAR 2
113: #define RF_HIYEAR 3
114: #define RF_COMMAND 4
115: #define RF_MONTH 5
116: #define RF_DAY 6
117: #define RF_TOD 7
118: #define RF_STDOFF 8
119: #define RF_ABBRVAR 9
120: #define RULE_FIELDS 10
121:
122: /*
123: ** Which fields are which on a Link line.
124: */
125:
126: #define LF_FROM 1
127: #define LF_TO 2
128: #define LINK_FIELDS 3
129:
130: struct rule {
131: char * r_filename;
132: int r_linenum;
133: char * r_name;
134:
135: int r_loyear; /* for example, 1986 */
136: int r_hiyear; /* for example, 1986 */
137: char * r_yrtype;
138:
139: int r_month; /* 0..11 */
140:
141: int r_dycode; /* see below */
142: int r_dayofmonth;
143: int r_wday;
144:
145: long r_tod; /* time from midnight */
146: int r_todisstd; /* above is standard time if TRUE */
147: /* above is wall clock time if FALSE */
148: long r_stdoff; /* offset from standard time */
149: char * r_abbrvar; /* variable part of time zone abbreviation */
150:
151: int r_todo; /* a rule to do (used in outzone) */
152: time_t r_temp; /* used in outzone */
153: };
154:
155: /*
156: ** r_dycode r_dayofmonth r_wday
157: */
158: #define DC_DOM 0 /* 1..31 */ /* unused */
159: #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
160: #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
161:
162: /*
163: ** Year synonyms.
164: */
165:
166: #define YR_MINIMUM 0
167: #define YR_MAXIMUM 1
168: #define YR_ONLY 2
169:
170: static struct rule * rules;
171: static int nrules; /* number of rules */
172:
173: struct zone {
174: char * z_filename;
175: int z_linenum;
176:
177: char * z_name;
178: long z_gmtoff;
179: char * z_rule;
180: char * z_format;
181:
182: long z_stdoff;
183:
184: struct rule * z_rules;
185: int z_nrules;
186:
187: struct rule z_untilrule;
188: time_t z_untiltime;
189: };
190:
191: static struct zone * zones;
192: static int nzones; /* number of zones */
193:
194: struct link {
195: char * l_filename;
196: int l_linenum;
197: char * l_from;
198: char * l_to;
199: };
200:
201: static struct link * links;
202: static int nlinks;
203:
204: struct lookup {
205: char * l_word;
206: int l_value;
207: };
208:
209: static struct lookup * byword();
210:
211: static struct lookup line_codes[] = {
212: "Rule", LC_RULE,
213: "Zone", LC_ZONE,
214: "Link", LC_LINK,
215: NULL, 0
216: };
217:
218: static struct lookup mon_names[] = {
219: "January", TM_JANUARY,
220: "February", TM_FEBRUARY,
221: "March", TM_MARCH,
222: "April", TM_APRIL,
223: "May", TM_MAY,
224: "June", TM_JUNE,
225: "July", TM_JULY,
226: "August", TM_AUGUST,
227: "September", TM_SEPTEMBER,
228: "October", TM_OCTOBER,
229: "November", TM_NOVEMBER,
230: "December", TM_DECEMBER,
231: NULL, 0
232: };
233:
234: static struct lookup wday_names[] = {
235: "Sunday", TM_SUNDAY,
236: "Monday", TM_MONDAY,
237: "Tuesday", TM_TUESDAY,
238: "Wednesday", TM_WEDNESDAY,
239: "Thursday", TM_THURSDAY,
240: "Friday", TM_FRIDAY,
241: "Saturday", TM_SATURDAY,
242: NULL, 0
243: };
244:
245: static struct lookup lasts[] = {
246: "last-Sunday", TM_SUNDAY,
247: "last-Monday", TM_MONDAY,
248: "last-Tuesday", TM_TUESDAY,
249: "last-Wednesday", TM_WEDNESDAY,
250: "last-Thursday", TM_THURSDAY,
251: "last-Friday", TM_FRIDAY,
252: "last-Saturday", TM_SATURDAY,
253: NULL, 0
254: };
255:
256: static struct lookup begin_years[] = {
257: "minimum", YR_MINIMUM,
258: "maximum", YR_MAXIMUM,
259: NULL, 0
260: };
261:
262: static struct lookup end_years[] = {
263: "minimum", YR_MINIMUM,
264: "maximum", YR_MAXIMUM,
265: "only", YR_ONLY,
266: NULL, 0
267: };
268:
269: static int len_months[2][MONS_PER_YEAR] = {
270: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
271: 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
272: };
273:
274: static int len_years[2] = {
275: DAYS_PER_NYEAR, DAYS_PER_LYEAR
276: };
277:
278: static time_t ats[TZ_MAX_TIMES];
279: static unsigned char types[TZ_MAX_TIMES];
280: static long gmtoffs[TZ_MAX_TYPES];
281: static char isdsts[TZ_MAX_TYPES];
282: static char abbrinds[TZ_MAX_TYPES];
283: static char chars[TZ_MAX_CHARS];
284:
285: /*
286: ** Memory allocation.
287: */
288:
289: static char *
290: memcheck(ptr)
291: char * ptr;
292: {
293: if (ptr == NULL) {
294: perror(progname);
295: exit(1);
296: }
297: return ptr;
298: }
299:
300: #define emalloc(size) memcheck(imalloc(size))
301: #define erealloc(ptr, size) memcheck(irealloc(ptr, size))
302: #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
303:
304: /*
305: ** Error handling.
306: */
307:
308: static
309: eats(name, num, rname, rnum)
310: char * name;
311: char * rname;
312: {
313: filename = name;
314: linenum = num;
315: rfilename = rname;
316: rlinenum = rnum;
317: }
318:
319: static
320: eat(name, num)
321: char * name;
322: {
323: eats(name, num, (char *) NULL, -1);
324: }
325:
326: static
327: error(string)
328: char * string;
329: {
330: /*
331: ** Match the format of "cc" to allow sh users to
332: ** zic ... 2>&1 | error -t "*" -v
333: ** on BSD systems.
334: */
335: (void) fprintf(stderr, "\"%s\", line %d: %s",
336: filename, linenum, string);
337: if (rfilename != NULL)
338: (void) fprintf(stderr, " (rule from \"%s\", line %d)",
339: rfilename, rlinenum);
340: (void) fprintf(stderr, "\n");
341: ++errors;
342: }
343:
344: static
345: usage()
346: {
347: (void) fprintf(stderr,
348: "%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n",
349: progname, progname);
350: exit(1);
351: }
352:
353: static char * lcltime = NULL;
354: static char * directory = NULL;
355:
356: main(argc, argv)
357: int argc;
358: char * argv[];
359: {
360: register int i, j;
361: register int c;
362:
363: #ifdef unix
364: umask(umask(022) | 022);
365: #endif
366: progname = argv[0];
367: while ((c = getopt(argc, argv, "d:l:v")) != EOF)
368: switch (c) {
369: default:
370: usage();
371: case 'd':
372: if (directory == NULL)
373: directory = optarg;
374: else {
375: (void) fprintf(stderr,
376: "%s: More than one -d option specified\n",
377: progname);
378: exit(1);
379: }
380: break;
381: case 'l':
382: if (lcltime == NULL)
383: lcltime = optarg;
384: else {
385: (void) fprintf(stderr,
386: "%s: More than one -l option specified\n",
387: progname);
388: exit(1);
389: }
390: break;
391: case 'v':
392: noise = TRUE;
393: break;
394: }
395: if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
396: usage(); /* usage message by request */
397: if (directory == NULL)
398: directory = TZDIR;
399:
400: setboundaries();
401:
402: zones = (struct zone *) emalloc(0);
403: rules = (struct rule *) emalloc(0);
404: links = (struct link *) emalloc(0);
405: for (i = optind; i < argc; ++i)
406: infile(argv[i]);
407: if (errors)
408: exit(1);
409: associate();
410: for (i = 0; i < nzones; i = j) {
411: /*
412: * Find the next non-continuation zone entry.
413: */
414: for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
415: ;
416: outzone(&zones[i], j - i);
417: }
418: /*
419: ** We'll take the easy way out on this last part.
420: */
421: if (chdir(directory) != 0) {
422: (void) fprintf(stderr, "%s: Can't chdir to ", progname);
423: perror(directory);
424: exit(1);
425: }
426: for (i = 0; i < nlinks; ++i) {
427: nondunlink(links[i].l_to);
428: if (link(links[i].l_from, links[i].l_to) != 0) {
429: (void) fprintf(stderr, "%s: Can't link %s to ",
430: progname, links[i].l_from);
431: perror(links[i].l_to);
432: exit(1);
433: }
434: }
435: if (lcltime != NULL) {
436: nondunlink(TZDEFAULT);
437: if (link(lcltime, TZDEFAULT) != 0) {
438: (void) fprintf(stderr, "%s: Can't link %s to ",
439: progname, lcltime);
440: perror(TZDEFAULT);
441: exit(1);
442: }
443: }
444: exit((errors == 0) ? 0 : 1);
445: }
446:
447: static
448: setboundaries()
449: {
450: register time_t bit;
451:
452: for (bit = 1; bit > 0; bit <<= 1)
453: ;
454: if (bit == 0) { /* time_t is an unsigned type */
455: tt_signed = FALSE;
456: min_time = 0;
457: max_time = ~(time_t) 0;
458: } else {
459: tt_signed = TRUE;
460: min_time = bit;
461: max_time = bit;
462: ++max_time;
463: max_time = -max_time;
464: }
465: min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
466: max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
467: }
468:
469: /*
470: ** We get to be careful here since there's a fair chance of root running us.
471: */
472:
473: static
474: nondunlink(name)
475: char * name;
476: {
477: struct stat s;
478:
479: if (stat(name, &s) != 0)
480: return;
481: if ((s.st_mode & S_IFMT) == S_IFDIR)
482: return;
483: (void) unlink(name);
484: }
485:
486: /*
487: ** Associate sets of rules with zones.
488: */
489:
490: /*
491: ** Sort by rule name.
492: */
493:
494: static
495: rcomp(cp1, cp2)
496: char * cp1;
497: char * cp2;
498: {
499: return strcmp(((struct rule *) cp1)->r_name,
500: ((struct rule *) cp2)->r_name);
501: }
502:
503: static
504: associate()
505: {
506: register struct zone * zp;
507: register struct rule * rp;
508: register int base, out;
509: register int i;
510:
511: if (nrules != 0)
512: (void) qsort((char *) rules, nrules, sizeof *rules, rcomp);
513: for (i = 0; i < nzones; ++i) {
514: zp = &zones[i];
515: zp->z_rules = NULL;
516: zp->z_nrules = 0;
517: }
518: for (base = 0; base < nrules; base = out) {
519: rp = &rules[base];
520: for (out = base + 1; out < nrules; ++out)
521: if (strcmp(rp->r_name, rules[out].r_name) != 0)
522: break;
523: for (i = 0; i < nzones; ++i) {
524: zp = &zones[i];
525: if (strcmp(zp->z_rule, rp->r_name) != 0)
526: continue;
527: zp->z_rules = rp;
528: zp->z_nrules = out - base;
529: }
530: }
531: for (i = 0; i < nzones; ++i) {
532: zp = &zones[i];
533: if (zp->z_nrules == 0) {
534: /*
535: ** Maybe we have a local standard time offset.
536: */
537: eat(zp->z_filename, zp->z_linenum);
538: zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
539: /*
540: ** Note, though, that if there's no rule,
541: ** a '%s' in the format is a bad thing.
542: */
543: if (index(zp->z_format, '%') != 0)
544: error("%s in ruleless zone");
545: }
546: }
547: if (errors)
548: exit(1);
549: }
550:
551: static
552: infile(name)
553: char * name;
554: {
555: register FILE * fp;
556: register char ** fields;
557: register char * cp;
558: register struct lookup * lp;
559: register int nfields;
560: register int wantcont;
561: register int num;
562: char buf[BUFSIZ];
563:
564: if (strcmp(name, "-") == 0) {
565: name = "standard input";
566: fp = stdin;
567: } else if ((fp = fopen(name, "r")) == NULL) {
568: (void) fprintf(stderr, "%s: Can't open ", progname);
569: perror(name);
570: exit(1);
571: }
572: wantcont = FALSE;
573: for (num = 1; ; ++num) {
574: eat(name, num);
575: if (fgets(buf, sizeof buf, fp) != buf)
576: break;
577: cp = index(buf, '\n');
578: if (cp == NULL) {
579: error("line too long");
580: exit(1);
581: }
582: *cp = '\0';
583: fields = getfields(buf);
584: nfields = 0;
585: while (fields[nfields] != NULL) {
586: if (ciequal(fields[nfields], "-"))
587: fields[nfields] = "";
588: ++nfields;
589: }
590: if (nfields == 0) {
591: /* nothing to do */
592: } else if (wantcont) {
593: wantcont = inzcont(fields, nfields);
594: } else {
595: lp = byword(fields[0], line_codes);
596: if (lp == NULL)
597: error("input line of unknown type");
598: else switch ((int) (lp->l_value)) {
599: case LC_RULE:
600: inrule(fields, nfields);
601: wantcont = FALSE;
602: break;
603: case LC_ZONE:
604: wantcont = inzone(fields, nfields);
605: break;
606: case LC_LINK:
607: inlink(fields, nfields);
608: wantcont = FALSE;
609: break;
610: default: /* "cannot happen" */
611: (void) fprintf(stderr,
612: "%s: panic: Invalid l_value %d\n",
613: progname, lp->l_value);
614: exit(1);
615: }
616: }
617: free((char *) fields);
618: }
619: if (ferror(fp)) {
620: (void) fprintf(stderr, "%s: Error reading ", progname);
621: perror(filename);
622: exit(1);
623: }
624: if (fp != stdin && fclose(fp)) {
625: (void) fprintf(stderr, "%s: Error closing ", progname);
626: perror(filename);
627: exit(1);
628: }
629: if (wantcont)
630: error("expected continuation line not found");
631: }
632:
633: /*
634: ** Convert a string of one of the forms
635: ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
636: ** into a number of seconds.
637: ** A null string maps to zero.
638: ** Call error with errstring and return zero on errors.
639: */
640:
641: static long
642: gethms(string, errstring, signable)
643: char * string;
644: char * errstring;
645: {
646: int hh, mm, ss, sign;
647:
648: if (string == NULL || *string == '\0')
649: return 0;
650: if (!signable)
651: sign = 1;
652: else if (*string == '-') {
653: sign = -1;
654: ++string;
655: } else sign = 1;
656: if (sscanf(string, scheck(string, "%d"), &hh) == 1)
657: mm = ss = 0;
658: else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
659: ss = 0;
660: else if (sscanf(string, scheck(string, "%d:%d:%d"),
661: &hh, &mm, &ss) != 3) {
662: error(errstring);
663: return 0;
664: }
665: if (hh < 0 || hh >= HOURS_PER_DAY ||
666: mm < 0 || mm >= MINS_PER_HOUR ||
667: ss < 0 || ss >= SECS_PER_MIN) {
668: error(errstring);
669: return 0;
670: }
671: return eitol(sign) *
672: (eitol(hh * MINS_PER_HOUR + mm) *
673: eitol(SECS_PER_MIN) + eitol(ss));
674: }
675:
676: static
677: inrule(fields, nfields)
678: register char ** fields;
679: {
680: static struct rule r;
681:
682: if (nfields != RULE_FIELDS) {
683: error("wrong number of fields on Rule line");
684: return;
685: }
686: if (*fields[RF_NAME] == '\0') {
687: error("nameless rule");
688: return;
689: }
690: r.r_filename = filename;
691: r.r_linenum = linenum;
692: r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
693: rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
694: fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
695: r.r_name = ecpyalloc(fields[RF_NAME]);
696: r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
697: rules = (struct rule *) erealloc((char *) rules,
698: (nrules + 1) * sizeof *rules);
699: rules[nrules++] = r;
700: }
701:
702: static
703: inzone(fields, nfields)
704: register char ** fields;
705: {
706: register int i;
707: char buf[132];
708:
709: if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
710: error("wrong number of fields on Zone line");
711: return FALSE;
712: }
713: if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
714: (void) sprintf(buf,
715: "\"Zone %s\" line and -l option are mutually exclusive",
716: TZDEFAULT);
717: error(buf);
718: return FALSE;
719: }
720: for (i = 0; i < nzones; ++i)
721: if (zones[i].z_name != NULL &&
722: strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
723: (void) sprintf(buf,
724: "duplicate zone name %s (file \"%s\", line %d)",
725: fields[ZF_NAME],
726: zones[i].z_filename,
727: zones[i].z_linenum);
728: error(buf);
729: return FALSE;
730: }
731: return inzsub(fields, nfields, FALSE);
732: }
733:
734: static
735: inzcont(fields, nfields)
736: register char ** fields;
737: {
738: if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
739: error("wrong number of fields on Zone continuation line");
740: return FALSE;
741: }
742: return inzsub(fields, nfields, TRUE);
743: }
744:
745: static
746: inzsub(fields, nfields, iscont)
747: register char ** fields;
748: {
749: register char * cp;
750: static struct zone z;
751: register int i_gmtoff, i_rule, i_format;
752: register int i_untilyear, i_untilmonth;
753: register int i_untilday, i_untiltime;
754: register int hasuntil;
755:
756: if (iscont) {
757: i_gmtoff = ZFC_GMTOFF;
758: i_rule = ZFC_RULE;
759: i_format = ZFC_FORMAT;
760: i_untilyear = ZFC_UNTILYEAR;
761: i_untilmonth = ZFC_UNTILMONTH;
762: i_untilday = ZFC_UNTILDAY;
763: i_untiltime = ZFC_UNTILTIME;
764: z.z_name = NULL;
765: } else {
766: i_gmtoff = ZF_GMTOFF;
767: i_rule = ZF_RULE;
768: i_format = ZF_FORMAT;
769: i_untilyear = ZF_UNTILYEAR;
770: i_untilmonth = ZF_UNTILMONTH;
771: i_untilday = ZF_UNTILDAY;
772: i_untiltime = ZF_UNTILTIME;
773: z.z_name = ecpyalloc(fields[ZF_NAME]);
774: }
775: z.z_filename = filename;
776: z.z_linenum = linenum;
777: z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
778: if ((cp = index(fields[i_format], '%')) != 0) {
779: if (*++cp != 's' || index(cp, '%') != 0) {
780: error("invalid abbreviation format");
781: return FALSE;
782: }
783: }
784: z.z_rule = ecpyalloc(fields[i_rule]);
785: z.z_format = ecpyalloc(fields[i_format]);
786: hasuntil = nfields > i_untilyear;
787: if (hasuntil) {
788: z.z_untilrule.r_filename = filename;
789: z.z_untilrule.r_linenum = linenum;
790: rulesub(&z.z_untilrule,
791: fields[i_untilyear],
792: "only",
793: "",
794: (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
795: (nfields > i_untilday) ? fields[i_untilday] : "1",
796: (nfields > i_untiltime) ? fields[i_untiltime] : "0");
797: z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
798: if (iscont && nzones > 0 && z.z_untiltime < max_time &&
799: z.z_untiltime > min_time &&
800: zones[nzones - 1].z_untiltime >= z.z_untiltime) {
801: error("Zone continuation line end time is not after end time of previous line");
802: return FALSE;
803: }
804: }
805: zones = (struct zone *) erealloc((char *) zones,
806: (nzones + 1) * sizeof *zones);
807: zones[nzones++] = z;
808: /*
809: ** If there was an UNTIL field on this line,
810: ** there's more information about the zone on the next line.
811: */
812: return hasuntil;
813: }
814:
815: static
816: inlink(fields, nfields)
817: register char ** fields;
818: {
819: struct link l;
820:
821: if (nfields != LINK_FIELDS) {
822: error("wrong number of fields on Link line");
823: return;
824: }
825: if (*fields[LF_FROM] == '\0') {
826: error("blank FROM field on Link line");
827: return;
828: }
829: if (*fields[LF_TO] == '\0') {
830: error("blank TO field on Link line");
831: return;
832: }
833: l.l_filename = filename;
834: l.l_linenum = linenum;
835: l.l_from = ecpyalloc(fields[LF_FROM]);
836: l.l_to = ecpyalloc(fields[LF_TO]);
837: links = (struct link *) erealloc((char *) links,
838: (nlinks + 1) * sizeof *links);
839: links[nlinks++] = l;
840: }
841:
842: static
843: rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
844: register struct rule * rp;
845: char * loyearp;
846: char * hiyearp;
847: char * typep;
848: char * monthp;
849: char * dayp;
850: char * timep;
851: {
852: register struct lookup * lp;
853: register char * cp;
854:
855: if ((lp = byword(monthp, mon_names)) == NULL) {
856: error("invalid month name");
857: return;
858: }
859: rp->r_month = lp->l_value;
860: rp->r_todisstd = FALSE;
861: cp = timep;
862: if (*cp != '\0') {
863: cp += strlen(cp) - 1;
864: switch (lowerit(*cp)) {
865: case 's':
866: rp->r_todisstd = TRUE;
867: *cp = '\0';
868: break;
869: case 'w':
870: rp->r_todisstd = FALSE;
871: *cp = '\0';
872: break;
873: }
874: }
875: rp->r_tod = gethms(timep, "invalid time of day", FALSE);
876: /*
877: ** Year work.
878: */
879: cp = loyearp;
880: if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
881: case YR_MINIMUM:
882: rp->r_loyear = min_year;
883: break;
884: case YR_MAXIMUM:
885: rp->r_loyear = max_year;
886: break;
887: default: /* "cannot happen" */
888: (void) fprintf(stderr,
889: "%s: panic: Invalid l_value %d\n",
890: progname, lp->l_value);
891: exit(1);
892: } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
893: rp->r_loyear < min_year || rp->r_loyear > max_year) {
894: if (noise)
895: error("invalid starting year");
896: if (rp->r_loyear > max_year)
897: return;
898: }
899: cp = hiyearp;
900: if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
901: case YR_MINIMUM:
902: rp->r_hiyear = min_year;
903: break;
904: case YR_MAXIMUM:
905: rp->r_hiyear = max_year;
906: break;
907: case YR_ONLY:
908: rp->r_hiyear = rp->r_loyear;
909: break;
910: default: /* "cannot happen" */
911: (void) fprintf(stderr,
912: "%s: panic: Invalid l_value %d\n",
913: progname, lp->l_value);
914: exit(1);
915: } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
916: rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
917: if (noise)
918: error("invalid ending year");
919: if (rp->r_hiyear < min_year)
920: return;
921: }
922: if (rp->r_hiyear < min_year)
923: return;
924: if (rp->r_loyear < min_year)
925: rp->r_loyear = min_year;
926: if (rp->r_hiyear > max_year)
927: rp->r_hiyear = max_year;
928: if (rp->r_loyear > rp->r_hiyear) {
929: error("starting year greater than ending year");
930: return;
931: }
932: if (*typep == '\0')
933: rp->r_yrtype = NULL;
934: else {
935: if (rp->r_loyear == rp->r_hiyear) {
936: error("typed single year");
937: return;
938: }
939: rp->r_yrtype = ecpyalloc(typep);
940: }
941: /*
942: ** Day work.
943: ** Accept things such as:
944: ** 1
945: ** last-Sunday
946: ** Sun<=20
947: ** Sun>=7
948: */
949: if ((lp = byword(dayp, lasts)) != NULL) {
950: rp->r_dycode = DC_DOWLEQ;
951: rp->r_wday = lp->l_value;
952: rp->r_dayofmonth = len_months[1][rp->r_month];
953: } else {
954: if ((cp = index(dayp, '<')) != 0)
955: rp->r_dycode = DC_DOWLEQ;
956: else if ((cp = index(dayp, '>')) != 0)
957: rp->r_dycode = DC_DOWGEQ;
958: else {
959: cp = dayp;
960: rp->r_dycode = DC_DOM;
961: }
962: if (rp->r_dycode != DC_DOM) {
963: *cp++ = 0;
964: if (*cp++ != '=') {
965: error("invalid day of month");
966: return;
967: }
968: if ((lp = byword(dayp, wday_names)) == NULL) {
969: error("invalid weekday name");
970: return;
971: }
972: rp->r_wday = lp->l_value;
973: }
974: if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
975: rp->r_dayofmonth <= 0 ||
976: (rp->r_dayofmonth > len_months[1][rp->r_month])) {
977: error("invalid day of month");
978: return;
979: }
980: }
981: }
982:
983: static
984: puttzcode(val, fp)
985: long val;
986: FILE * fp;
987: {
988: register int c;
989: register int shift;
990:
991: for (shift = 24; shift >= 0; shift -= 8) {
992: c = val >> shift;
993: (void) putc(c, fp);
994: }
995: }
996:
997: static
998: writezone(name)
999: char * name;
1000: {
1001: register FILE * fp;
1002: register int i;
1003: char fullname[BUFSIZ];
1004:
1005: if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
1006: (void) fprintf(stderr,
1007: "%s: File name %s/%s too long\n", progname,
1008: directory, name);
1009: exit(1);
1010: }
1011: (void) sprintf(fullname, "%s/%s", directory, name);
1012: if ((fp = fopen(fullname, "w")) == NULL) {
1013: if (mkdirs(fullname) != 0)
1014: exit(1);
1015: if ((fp = fopen(fullname, "w")) == NULL) {
1016: (void) fprintf(stderr, "%s: Can't create ", progname);
1017: perror(fullname);
1018: exit(1);
1019: }
1020: }
1021: (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0);
1022: puttzcode(eitol(timecnt), fp);
1023: puttzcode(eitol(typecnt), fp);
1024: puttzcode(eitol(charcnt), fp);
1025: for (i = 0; i < timecnt; ++i)
1026: puttzcode((long) ats[i], fp);
1027: if (timecnt > 0)
1028: (void) fwrite((char *) types, sizeof types[0],
1029: (int) timecnt, fp);
1030: for (i = 0; i < typecnt; ++i) {
1031: puttzcode((long) gmtoffs[i], fp);
1032: (void) putc(isdsts[i], fp);
1033: (void) putc(abbrinds[i], fp);
1034: }
1035: if (charcnt != 0)
1036: (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp);
1037: if (ferror(fp) || fclose(fp)) {
1038: (void) fprintf(stderr, "%s: Write error on ", progname);
1039: perror(fullname);
1040: exit(1);
1041: }
1042: }
1043:
1044: static
1045: outzone(zpfirst, zonecount)
1046: struct zone * zpfirst;
1047: {
1048: register struct zone * zp;
1049: register struct rule * rp;
1050: register int i, j;
1051: register int usestart, useuntil;
1052: register time_t starttime, untiltime;
1053: register long gmtoff;
1054: register long stdoff;
1055: register int year;
1056: register long startoff;
1057: register int startisdst;
1058: register int type;
1059: char startbuf[BUFSIZ];
1060:
1061: /*
1062: ** Now. . .finally. . .generate some useful data!
1063: */
1064: timecnt = 0;
1065: typecnt = 0;
1066: charcnt = 0;
1067: /*
1068: ** Two guesses. . .the second may well be corrected later.
1069: */
1070: gmtoff = zpfirst->z_gmtoff;
1071: stdoff = 0;
1072: for (i = 0; i < zonecount; ++i) {
1073: usestart = i > 0;
1074: useuntil = i < (zonecount - 1);
1075: zp = &zpfirst[i];
1076: eat(zp->z_filename, zp->z_linenum);
1077: startisdst = -1;
1078: if (zp->z_nrules == 0) {
1079: type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
1080: zp->z_format, zp->z_stdoff != 0);
1081: if (usestart)
1082: addtt(starttime, type);
1083: gmtoff = zp->z_gmtoff;
1084: stdoff = zp->z_stdoff;
1085: } else for (year = min_year; year <= max_year; ++year) {
1086: if (useuntil && year > zp->z_untilrule.r_hiyear)
1087: break;
1088: /*
1089: ** Mark which rules to do in the current year.
1090: ** For those to do, calculate rpytime(rp, year);
1091: */
1092: for (j = 0; j < zp->z_nrules; ++j) {
1093: rp = &zp->z_rules[j];
1094: eats(zp->z_filename, zp->z_linenum,
1095: rp->r_filename, rp->r_linenum);
1096: rp->r_todo = year >= rp->r_loyear &&
1097: year <= rp->r_hiyear &&
1098: yearistype(year, rp->r_yrtype);
1099: if (rp->r_todo)
1100: rp->r_temp = rpytime(rp, year);
1101: }
1102: for ( ; ; ) {
1103: register int k;
1104: register time_t jtime, ktime;
1105: register long offset;
1106: char buf[BUFSIZ];
1107:
1108: if (useuntil) {
1109: /*
1110: ** Turn untiltime into GMT
1111: ** assuming the current gmtoff and
1112: ** stdoff values.
1113: */
1114: offset = gmtoff;
1115: if (!zp->z_untilrule.r_todisstd)
1116: offset = oadd(offset, stdoff);
1117: untiltime = tadd(zp->z_untiltime,
1118: -offset);
1119: }
1120: /*
1121: ** Find the rule (of those to do, if any)
1122: ** that takes effect earliest in the year.
1123: */
1124: k = -1;
1125: for (j = 0; j < zp->z_nrules; ++j) {
1126: rp = &zp->z_rules[j];
1127: if (!rp->r_todo)
1128: continue;
1129: eats(zp->z_filename, zp->z_linenum,
1130: rp->r_filename, rp->r_linenum);
1131: offset = gmtoff;
1132: if (!rp->r_todisstd)
1133: offset = oadd(offset, stdoff);
1134: jtime = rp->r_temp;
1135: if (jtime == min_time ||
1136: jtime == max_time)
1137: continue;
1138: jtime = tadd(jtime, -offset);
1139: if (k < 0 || jtime < ktime) {
1140: k = j;
1141: ktime = jtime;
1142: }
1143: }
1144: if (k < 0)
1145: break; /* go on to next year */
1146: rp = &zp->z_rules[k];
1147: rp->r_todo = FALSE;
1148: if (useuntil && ktime >= untiltime)
1149: break;
1150: if (usestart) {
1151: if (ktime < starttime) {
1152: stdoff = rp->r_stdoff;
1153: startoff = oadd(zp->z_gmtoff,
1154: rp->r_stdoff);
1155: (void) sprintf(startbuf,
1156: zp->z_format,
1157: rp->r_abbrvar);
1158: startisdst =
1159: rp->r_stdoff != 0;
1160: continue;
1161: }
1162: if (ktime != starttime &&
1163: startisdst >= 0)
1164: addtt(starttime, addtype(startoff, startbuf, startisdst));
1165: usestart = FALSE;
1166: }
1167: eats(zp->z_filename, zp->z_linenum,
1168: rp->r_filename, rp->r_linenum);
1169: (void) sprintf(buf, zp->z_format,
1170: rp->r_abbrvar);
1171: offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1172: type = addtype(offset, buf, rp->r_stdoff != 0);
1173: if (timecnt != 0 || rp->r_stdoff != 0)
1174: addtt(ktime, type);
1175: gmtoff = zp->z_gmtoff;
1176: stdoff = rp->r_stdoff;
1177: }
1178: }
1179: /*
1180: ** Now we may get to set starttime for the next zone line.
1181: */
1182: if (useuntil)
1183: starttime = tadd(zp->z_untiltime,
1184: -gmtoffs[types[timecnt - 1]]);
1185: }
1186: writezone(zpfirst->z_name);
1187: }
1188:
1189: static
1190: addtt(starttime, type)
1191: time_t starttime;
1192: {
1193: if (timecnt != 0 && type == types[timecnt - 1])
1194: return; /* easy enough! */
1195: if (timecnt >= TZ_MAX_TIMES) {
1196: error("too many transitions?!");
1197: exit(1);
1198: }
1199: ats[timecnt] = starttime;
1200: types[timecnt] = type;
1201: ++timecnt;
1202: }
1203:
1204: static
1205: addtype(gmtoff, abbr, isdst)
1206: long gmtoff;
1207: char * abbr;
1208: {
1209: register int i, j;
1210:
1211: /*
1212: ** See if there's already an entry for this zone type.
1213: ** If so, just return its index.
1214: */
1215: for (i = 0; i < typecnt; ++i) {
1216: if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1217: strcmp(abbr, &chars[abbrinds[i]]) == 0)
1218: return i;
1219: }
1220: /*
1221: ** There isn't one; add a new one, unless there are already too
1222: ** many.
1223: */
1224: if (typecnt >= TZ_MAX_TYPES) {
1225: error("too many local time types");
1226: exit(1);
1227: }
1228: gmtoffs[i] = gmtoff;
1229: isdsts[i] = isdst;
1230:
1231: for (j = 0; j < charcnt; ++j)
1232: if (strcmp(&chars[j], abbr) == 0)
1233: break;
1234: if (j == charcnt)
1235: newabbr(abbr);
1236: abbrinds[i] = j;
1237: ++typecnt;
1238: return i;
1239: }
1240:
1241: static
1242: yearistype(year, type)
1243: char * type;
1244: {
1245: char buf[BUFSIZ];
1246: int result;
1247:
1248: if (type == NULL || *type == '\0')
1249: return TRUE;
1250: if (strcmp(type, "uspres") == 0)
1251: return (year % 4) == 0;
1252: if (strcmp(type, "nonpres") == 0)
1253: return (year % 4) != 0;
1254: (void) sprintf(buf, "yearistype %d %s", year, type);
1255: result = system(buf);
1256: if (result == 0)
1257: return TRUE;
1258: if (result == 1 << 8)
1259: return FALSE;
1260: error("Wild result from command execution");
1261: (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
1262: progname, buf, result);
1263: for ( ; ; )
1264: exit(1);
1265: }
1266:
1267: static
1268: lowerit(a)
1269: {
1270: return (isascii(a) && isupper(a)) ? tolower(a) : a;
1271: }
1272:
1273: static
1274: ciequal(ap, bp) /* case-insensitive equality */
1275: register char * ap;
1276: register char * bp;
1277: {
1278: while (lowerit(*ap) == lowerit(*bp++))
1279: if (*ap++ == '\0')
1280: return TRUE;
1281: return FALSE;
1282: }
1283:
1284: static
1285: isabbr(abbr, word)
1286: register char * abbr;
1287: register char * word;
1288: {
1289: if (lowerit(*abbr) != lowerit(*word))
1290: return FALSE;
1291: ++word;
1292: while (*++abbr != '\0')
1293: do if (*word == '\0')
1294: return FALSE;
1295: while (lowerit(*word++) != lowerit(*abbr));
1296: return TRUE;
1297: }
1298:
1299: static struct lookup *
1300: byword(word, table)
1301: register char * word;
1302: register struct lookup * table;
1303: {
1304: register struct lookup * foundlp;
1305: register struct lookup * lp;
1306:
1307: if (word == NULL || table == NULL)
1308: return NULL;
1309: /*
1310: ** Look for exact match.
1311: */
1312: for (lp = table; lp->l_word != NULL; ++lp)
1313: if (ciequal(word, lp->l_word))
1314: return lp;
1315: /*
1316: ** Look for inexact match.
1317: */
1318: foundlp = NULL;
1319: for (lp = table; lp->l_word != NULL; ++lp)
1320: if (isabbr(word, lp->l_word))
1321: if (foundlp == NULL)
1322: foundlp = lp;
1323: else return NULL; /* multiple inexact matches */
1324: return foundlp;
1325: }
1326:
1327: static char **
1328: getfields(cp)
1329: register char * cp;
1330: {
1331: register char * dp;
1332: register char ** array;
1333: register int nsubs;
1334:
1335: if (cp == NULL)
1336: return NULL;
1337: array = (char **) emalloc((strlen(cp) + 1) * sizeof *array);
1338: nsubs = 0;
1339: for ( ; ; ) {
1340: while (isascii(*cp) && isspace(*cp))
1341: ++cp;
1342: if (*cp == '\0' || *cp == '#')
1343: break;
1344: array[nsubs++] = dp = cp;
1345: do {
1346: if ((*dp = *cp++) != '"')
1347: ++dp;
1348: else while ((*dp = *cp++) != '"')
1349: if (*dp != '\0')
1350: ++dp;
1351: else error("Odd number of quotation marks");
1352: } while (*cp != '\0' && *cp != '#' &&
1353: (!isascii(*cp) || !isspace(*cp)));
1354: if (isascii(*cp) && isspace(*cp))
1355: ++cp;
1356: *dp = '\0';
1357: }
1358: array[nsubs] = NULL;
1359: return array;
1360: }
1361:
1362: static long
1363: oadd(t1, t2)
1364: long t1;
1365: long t2;
1366: {
1367: register long t;
1368:
1369: t = t1 + t2;
1370: if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1371: error("time overflow");
1372: exit(1);
1373: }
1374: return t;
1375: }
1376:
1377: static time_t
1378: tadd(t1, t2)
1379: time_t t1;
1380: long t2;
1381: {
1382: register time_t t;
1383:
1384: if (t1 == max_time && t2 > 0)
1385: return max_time;
1386: if (t1 == min_time && t2 < 0)
1387: return min_time;
1388: t = t1 + t2;
1389: if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
1390: error("time overflow");
1391: exit(1);
1392: }
1393: return t;
1394: }
1395:
1396: /*
1397: ** Given a rule, and a year, compute the date - in seconds since January 1,
1398: ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1399: */
1400:
1401: static time_t
1402: rpytime(rp, wantedy)
1403: register struct rule * rp;
1404: register int wantedy;
1405: {
1406: register int y, m, i;
1407: register long dayoff; /* with a nod to Margaret O. */
1408: register time_t t;
1409:
1410: dayoff = 0;
1411: m = TM_JANUARY;
1412: y = EPOCH_YEAR;
1413: while (wantedy != y) {
1414: if (wantedy > y) {
1415: i = len_years[isleap(y)];
1416: ++y;
1417: } else {
1418: --y;
1419: i = -len_years[isleap(y)];
1420: }
1421: dayoff = oadd(dayoff, eitol(i));
1422: }
1423: while (m != rp->r_month) {
1424: i = len_months[isleap(y)][m];
1425: dayoff = oadd(dayoff, eitol(i));
1426: ++m;
1427: }
1428: i = rp->r_dayofmonth;
1429: if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1430: if (rp->r_dycode == DC_DOWLEQ)
1431: --i;
1432: else {
1433: error("use of 2/29 in non leap-year");
1434: exit(1);
1435: }
1436: }
1437: --i;
1438: dayoff = oadd(dayoff, eitol(i));
1439: if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1440: register long wday;
1441:
1442: #define LDAYS_PER_WEEK ((long) DAYS_PER_WEEK)
1443: wday = eitol(EPOCH_WDAY);
1444: /*
1445: ** Don't trust mod of negative numbers.
1446: */
1447: if (dayoff >= 0)
1448: wday = (wday + dayoff) % LDAYS_PER_WEEK;
1449: else {
1450: wday -= ((-dayoff) % LDAYS_PER_WEEK);
1451: if (wday < 0)
1452: wday += LDAYS_PER_WEEK;
1453: }
1454: while (wday != eitol(rp->r_wday))
1455: if (rp->r_dycode == DC_DOWGEQ) {
1456: dayoff = oadd(dayoff, (long) 1);
1457: if (++wday >= LDAYS_PER_WEEK)
1458: wday = 0;
1459: ++i;
1460: } else {
1461: dayoff = oadd(dayoff, (long) -1);
1462: if (--wday < 0)
1463: wday = LDAYS_PER_WEEK;
1464: --i;
1465: }
1466: if (i < 0 || i >= len_months[isleap(y)][m]) {
1467: error("no day in month matches rule");
1468: exit(1);
1469: }
1470: }
1471: if (dayoff < 0 && !tt_signed) {
1472: if (wantedy == rp->r_loyear)
1473: return min_time;
1474: error("time before zero");
1475: exit(1);
1476: }
1477: t = (time_t) dayoff * SECS_PER_DAY;
1478: /*
1479: ** Cheap overflow check.
1480: */
1481: if (t / SECS_PER_DAY != dayoff) {
1482: if (wantedy == rp->r_hiyear)
1483: return max_time;
1484: if (wantedy == rp->r_loyear)
1485: return min_time;
1486: error("time overflow");
1487: exit(1);
1488: }
1489: return tadd(t, rp->r_tod);
1490: }
1491:
1492: static
1493: newabbr(string)
1494: char * string;
1495: {
1496: register int i;
1497:
1498: i = strlen(string) + 1;
1499: if (charcnt + i >= TZ_MAX_CHARS) {
1500: error("too many, or too long, time zone abbreviations");
1501: exit(1);
1502: }
1503: (void) strcpy(&chars[charcnt], string);
1504: charcnt += eitol(i);
1505: }
1506:
1507: static
1508: mkdirs(name)
1509: char * name;
1510: {
1511: register char * cp;
1512:
1513: if ((cp = name) == NULL || *cp == '\0')
1514: return 0;
1515: while ((cp = index(cp + 1,'/')) != 0) {
1516: *cp = '\0';
1517: if (access(name,F_OK) && mkdir(name,0755)) {
1518: perror(name);
1519: return -1;
1520: }
1521: *cp = '/';
1522: }
1523: return 0;
1524: }
1525:
1526: static long
1527: eitol(i)
1528: {
1529: long l;
1530:
1531: l = i;
1532: if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
1533: (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
1534: progname, i);
1535: exit(1);
1536: }
1537: return l;
1538: }
1539:
1540: /*
1541: ** UNIX is a registered trademark of AT&T.
1542: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.