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