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