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