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