zic.c revision 1.3 1 /* $NetBSD: zic.c,v 1.3 1996/01/08 22:51:01 jtc Exp $ */
2
3 #ifndef lint
4 #ifndef NOID
5 static char elsieid[] = "@(#)zic.c 7.57";
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 #define TIME_T_SIGNED (((time_t) -1) < 0)
591 #define TIME_T_BIT (sizeof (time_t) * CHAR_BIT)
592
593 /*
594 ** The tz file format currently allows at most 32-bit quantities.
595 ** This restriction should be removed before signed 32-bit values
596 ** wrap around in 2038, but unfortunately this will require a
597 ** change to the tz file format.
598 */
599
600 #define MAX_BITS_IN_FILE 32
601 #define TIME_T_BITS_IN_FILE ((TIME_T_BIT < MAX_BITS_IN_FILE) ? \
602 TIME_T_BIT : MAX_BITS_IN_FILE)
603
604 static void
605 setboundaries P((void))
606 {
607 if (TIME_T_SIGNED) {
608 min_time = ~ (time_t) 0;
609 min_time <<= TIME_T_BITS_IN_FILE - 1;
610 max_time = ~ (time_t) 0 - min_time;
611 if (sflag)
612 min_time = 0;
613 } else {
614 min_time = 0;
615 max_time = 2 - sflag;
616 max_time <<= TIME_T_BITS_IN_FILE - 1;
617 --max_time;
618 }
619 min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
620 max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
621 }
622
623 static int
624 itsdir(name)
625 const char * const name;
626 {
627 register char * myname;
628 register int accres;
629
630 myname = ecpyalloc(name);
631 myname = ecatalloc(myname, "/.");
632 accres = access(myname, F_OK);
633 ifree(myname);
634 return accres == 0;
635 }
636
637 /*
638 ** Associate sets of rules with zones.
639 */
640
641 /*
642 ** Sort by rule name.
643 */
644
645 static int
646 rcomp(cp1, cp2)
647 const void * cp1;
648 const void * cp2;
649 {
650 return strcmp(((const struct rule *) cp1)->r_name,
651 ((const struct rule *) cp2)->r_name);
652 }
653
654 static void
655 associate P((void))
656 {
657 register struct zone * zp;
658 register struct rule * rp;
659 register int base, out;
660 register int i;
661
662 if (nrules != 0)
663 (void) qsort((void *) rules, (size_t) nrules,
664 (size_t) sizeof *rules, rcomp);
665 for (i = 0; i < nzones; ++i) {
666 zp = &zones[i];
667 zp->z_rules = NULL;
668 zp->z_nrules = 0;
669 }
670 for (base = 0; base < nrules; base = out) {
671 rp = &rules[base];
672 for (out = base + 1; out < nrules; ++out)
673 if (strcmp(rp->r_name, rules[out].r_name) != 0)
674 break;
675 for (i = 0; i < nzones; ++i) {
676 zp = &zones[i];
677 if (strcmp(zp->z_rule, rp->r_name) != 0)
678 continue;
679 zp->z_rules = rp;
680 zp->z_nrules = out - base;
681 }
682 }
683 for (i = 0; i < nzones; ++i) {
684 zp = &zones[i];
685 if (zp->z_nrules == 0) {
686 /*
687 ** Maybe we have a local standard time offset.
688 */
689 eat(zp->z_filename, zp->z_linenum);
690 zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
691 /*
692 ** Note, though, that if there's no rule,
693 ** a '%s' in the format is a bad thing.
694 */
695 if (strchr(zp->z_format, '%') != 0)
696 error("%s in ruleless zone");
697 }
698 }
699 if (errors)
700 (void) exit(EXIT_FAILURE);
701 }
702
703 static void
704 infile(name)
705 const char * name;
706 {
707 register FILE * fp;
708 register char ** fields;
709 register char * cp;
710 register const struct lookup * lp;
711 register int nfields;
712 register int wantcont;
713 register int num;
714 char buf[BUFSIZ];
715
716 if (strcmp(name, "-") == 0) {
717 name = "standard input";
718 fp = stdin;
719 } else if ((fp = fopen(name, "r")) == NULL) {
720 (void) fprintf(stderr, "%s: Can't open ", progname);
721 (void) perror(name);
722 (void) exit(EXIT_FAILURE);
723 }
724 wantcont = FALSE;
725 for (num = 1; ; ++num) {
726 eat(name, num);
727 if (fgets(buf, (int) sizeof buf, fp) != buf)
728 break;
729 cp = strchr(buf, '\n');
730 if (cp == NULL) {
731 error("line too long");
732 (void) exit(EXIT_FAILURE);
733 }
734 *cp = '\0';
735 fields = getfields(buf);
736 nfields = 0;
737 while (fields[nfields] != NULL) {
738 static char nada;
739
740 if (strcmp(fields[nfields], "-") == 0)
741 fields[nfields] = &nada;
742 ++nfields;
743 }
744 if (nfields == 0) {
745 /* nothing to do */
746 } else if (wantcont) {
747 wantcont = inzcont(fields, nfields);
748 } else {
749 lp = byword(fields[0], line_codes);
750 if (lp == NULL)
751 error("input line of unknown type");
752 else switch ((int) (lp->l_value)) {
753 case LC_RULE:
754 inrule(fields, nfields);
755 wantcont = FALSE;
756 break;
757 case LC_ZONE:
758 wantcont = inzone(fields, nfields);
759 break;
760 case LC_LINK:
761 inlink(fields, nfields);
762 wantcont = FALSE;
763 break;
764 case LC_LEAP:
765 if (name != leapsec)
766 (void) fprintf(stderr,
767 "%s: Leap line in non leap seconds file %s\n",
768 progname, name);
769 else inleap(fields, nfields);
770 wantcont = FALSE;
771 break;
772 default: /* "cannot happen" */
773 (void) fprintf(stderr,
774 "%s: panic: Invalid l_value %d\n",
775 progname, lp->l_value);
776 (void) exit(EXIT_FAILURE);
777 }
778 }
779 ifree((char *) fields);
780 }
781 if (ferror(fp)) {
782 (void) fprintf(stderr, "%s: Error reading ", progname);
783 (void) perror(filename);
784 (void) exit(EXIT_FAILURE);
785 }
786 if (fp != stdin && fclose(fp)) {
787 (void) fprintf(stderr, "%s: Error closing ", progname);
788 (void) perror(filename);
789 (void) exit(EXIT_FAILURE);
790 }
791 if (wantcont)
792 error("expected continuation line not found");
793 }
794
795 /*
796 ** Convert a string of one of the forms
797 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
798 ** into a number of seconds.
799 ** A null string maps to zero.
800 ** Call error with errstring and return zero on errors.
801 */
802
803 static long
804 gethms(string, errstring, signable)
805 const char * string;
806 const char * const errstring;
807 const int signable;
808 {
809 int hh, mm, ss, sign;
810
811 if (string == NULL || *string == '\0')
812 return 0;
813 if (!signable)
814 sign = 1;
815 else if (*string == '-') {
816 sign = -1;
817 ++string;
818 } else sign = 1;
819 if (sscanf(string, scheck(string, "%d"), &hh) == 1)
820 mm = ss = 0;
821 else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
822 ss = 0;
823 else if (sscanf(string, scheck(string, "%d:%d:%d"),
824 &hh, &mm, &ss) != 3) {
825 error(errstring);
826 return 0;
827 }
828 if (hh < 0 || hh >= HOURSPERDAY ||
829 mm < 0 || mm >= MINSPERHOUR ||
830 ss < 0 || ss > SECSPERMIN) {
831 error(errstring);
832 return 0;
833 }
834 return eitol(sign) *
835 (eitol(hh * MINSPERHOUR + mm) *
836 eitol(SECSPERMIN) + eitol(ss));
837 }
838
839 static void
840 inrule(fields, nfields)
841 register char ** const fields;
842 const int nfields;
843 {
844 static struct rule r;
845
846 if (nfields != RULE_FIELDS) {
847 error("wrong number of fields on Rule line");
848 return;
849 }
850 if (*fields[RF_NAME] == '\0') {
851 error("nameless rule");
852 return;
853 }
854 r.r_filename = filename;
855 r.r_linenum = linenum;
856 r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
857 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
858 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
859 r.r_name = ecpyalloc(fields[RF_NAME]);
860 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
861 rules = (struct rule *) (void *) erealloc((char *) rules,
862 (int) ((nrules + 1) * sizeof *rules));
863 rules[nrules++] = r;
864 }
865
866 static int
867 inzone(fields, nfields)
868 register char ** const fields;
869 const int nfields;
870 {
871 register int i;
872 static char * buf;
873
874 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
875 error("wrong number of fields on Zone line");
876 return FALSE;
877 }
878 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
879 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
880 (void) sprintf(buf,
881 "\"Zone %s\" line and -l option are mutually exclusive",
882 TZDEFAULT);
883 error(buf);
884 return FALSE;
885 }
886 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
887 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
888 (void) sprintf(buf,
889 "\"Zone %s\" line and -p option are mutually exclusive",
890 TZDEFRULES);
891 error(buf);
892 return FALSE;
893 }
894 for (i = 0; i < nzones; ++i)
895 if (zones[i].z_name != NULL &&
896 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
897 buf = erealloc(buf, (int) (132 +
898 strlen(fields[ZF_NAME]) +
899 strlen(zones[i].z_filename)));
900 (void) sprintf(buf,
901 "duplicate zone name %s (file \"%s\", line %d)",
902 fields[ZF_NAME],
903 zones[i].z_filename,
904 zones[i].z_linenum);
905 error(buf);
906 return FALSE;
907 }
908 return inzsub(fields, nfields, FALSE);
909 }
910
911 static int
912 inzcont(fields, nfields)
913 register char ** const fields;
914 const int nfields;
915 {
916 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
917 error("wrong number of fields on Zone continuation line");
918 return FALSE;
919 }
920 return inzsub(fields, nfields, TRUE);
921 }
922
923 static int
924 inzsub(fields, nfields, iscont)
925 register char ** const fields;
926 const int nfields;
927 const int iscont;
928 {
929 register char * cp;
930 static struct zone z;
931 register int i_gmtoff, i_rule, i_format;
932 register int i_untilyear, i_untilmonth;
933 register int i_untilday, i_untiltime;
934 register int hasuntil;
935
936 if (iscont) {
937 i_gmtoff = ZFC_GMTOFF;
938 i_rule = ZFC_RULE;
939 i_format = ZFC_FORMAT;
940 i_untilyear = ZFC_TILYEAR;
941 i_untilmonth = ZFC_TILMONTH;
942 i_untilday = ZFC_TILDAY;
943 i_untiltime = ZFC_TILTIME;
944 z.z_name = NULL;
945 } else {
946 i_gmtoff = ZF_GMTOFF;
947 i_rule = ZF_RULE;
948 i_format = ZF_FORMAT;
949 i_untilyear = ZF_TILYEAR;
950 i_untilmonth = ZF_TILMONTH;
951 i_untilday = ZF_TILDAY;
952 i_untiltime = ZF_TILTIME;
953 z.z_name = ecpyalloc(fields[ZF_NAME]);
954 }
955 z.z_filename = filename;
956 z.z_linenum = linenum;
957 z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
958 if ((cp = strchr(fields[i_format], '%')) != 0) {
959 if (*++cp != 's' || strchr(cp, '%') != 0) {
960 error("invalid abbreviation format");
961 return FALSE;
962 }
963 }
964 z.z_rule = ecpyalloc(fields[i_rule]);
965 z.z_format = ecpyalloc(fields[i_format]);
966 hasuntil = nfields > i_untilyear;
967 if (hasuntil) {
968 z.z_untilrule.r_filename = filename;
969 z.z_untilrule.r_linenum = linenum;
970 rulesub(&z.z_untilrule,
971 fields[i_untilyear],
972 "only",
973 "",
974 (nfields > i_untilmonth) ?
975 fields[i_untilmonth] : "Jan",
976 (nfields > i_untilday) ? fields[i_untilday] : "1",
977 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
978 z.z_untiltime = rpytime(&z.z_untilrule,
979 z.z_untilrule.r_loyear);
980 if (iscont && nzones > 0 &&
981 z.z_untiltime > min_time &&
982 z.z_untiltime < max_time &&
983 zones[nzones - 1].z_untiltime > min_time &&
984 zones[nzones - 1].z_untiltime < max_time &&
985 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
986 error("Zone continuation line end time is not \
987 after end time of previous line");
988 return FALSE;
989 }
990 }
991 zones = (struct zone *) (void *) erealloc((char *) zones,
992 (int) ((nzones + 1) * sizeof *zones));
993 zones[nzones++] = z;
994 /*
995 ** If there was an UNTIL field on this line,
996 ** there's more information about the zone on the next line.
997 */
998 return hasuntil;
999 }
1000
1001 static void
1002 inleap(fields, nfields)
1003 register char ** const fields;
1004 const int nfields;
1005 {
1006 register const char * cp;
1007 register const struct lookup * lp;
1008 register int i, j;
1009 int year, month, day;
1010 long dayoff, tod;
1011 time_t t;
1012
1013 if (nfields != LEAP_FIELDS) {
1014 error("wrong number of fields on Leap line");
1015 return;
1016 }
1017 dayoff = 0;
1018 cp = fields[LP_YEAR];
1019 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1020 /*
1021 * Leapin' Lizards!
1022 */
1023 error("invalid leaping year");
1024 return;
1025 }
1026 j = EPOCH_YEAR;
1027 while (j != year) {
1028 if (year > j) {
1029 i = len_years[isleap(j)];
1030 ++j;
1031 } else {
1032 --j;
1033 i = -len_years[isleap(j)];
1034 }
1035 dayoff = oadd(dayoff, eitol(i));
1036 }
1037 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1038 error("invalid month name");
1039 return;
1040 }
1041 month = lp->l_value;
1042 j = TM_JANUARY;
1043 while (j != month) {
1044 i = len_months[isleap(year)][j];
1045 dayoff = oadd(dayoff, eitol(i));
1046 ++j;
1047 }
1048 cp = fields[LP_DAY];
1049 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1050 day <= 0 || day > len_months[isleap(year)][month]) {
1051 error("invalid day of month");
1052 return;
1053 }
1054 dayoff = oadd(dayoff, eitol(day - 1));
1055 if (dayoff < 0 && !TIME_T_SIGNED) {
1056 error("time before zero");
1057 return;
1058 }
1059 t = (time_t) dayoff * SECSPERDAY;
1060 /*
1061 ** Cheap overflow check.
1062 */
1063 if (t / SECSPERDAY != dayoff) {
1064 error("time overflow");
1065 return;
1066 }
1067 tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
1068 cp = fields[LP_CORR];
1069 {
1070 register int positive;
1071 int count;
1072
1073 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1074 positive = FALSE;
1075 count = 1;
1076 } else if (strcmp(cp, "--") == 0) {
1077 positive = FALSE;
1078 count = 2;
1079 } else if (strcmp(cp, "+") == 0) {
1080 positive = TRUE;
1081 count = 1;
1082 } else if (strcmp(cp, "++") == 0) {
1083 positive = TRUE;
1084 count = 2;
1085 } else {
1086 error("illegal CORRECTION field on Leap line");
1087 return;
1088 }
1089 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1090 error("illegal Rolling/Stationary field on Leap line");
1091 return;
1092 }
1093 leapadd(tadd(t, tod), positive, lp->l_value, count);
1094 }
1095 }
1096
1097 static void
1098 inlink(fields, nfields)
1099 register char ** const fields;
1100 const int nfields;
1101 {
1102 struct link l;
1103
1104 if (nfields != LINK_FIELDS) {
1105 error("wrong number of fields on Link line");
1106 return;
1107 }
1108 if (*fields[LF_FROM] == '\0') {
1109 error("blank FROM field on Link line");
1110 return;
1111 }
1112 if (*fields[LF_TO] == '\0') {
1113 error("blank TO field on Link line");
1114 return;
1115 }
1116 l.l_filename = filename;
1117 l.l_linenum = linenum;
1118 l.l_from = ecpyalloc(fields[LF_FROM]);
1119 l.l_to = ecpyalloc(fields[LF_TO]);
1120 links = (struct link *) (void *) erealloc((char *) links,
1121 (int) ((nlinks + 1) * sizeof *links));
1122 links[nlinks++] = l;
1123 }
1124
1125 static void
1126 rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
1127 register struct rule * const rp;
1128 const char * const loyearp;
1129 const char * const hiyearp;
1130 const char * const typep;
1131 const char * const monthp;
1132 const char * const dayp;
1133 const char * const timep;
1134 {
1135 register const struct lookup * lp;
1136 register const char * cp;
1137 register char * dp;
1138 register char * ep;
1139
1140 if ((lp = byword(monthp, mon_names)) == NULL) {
1141 error("invalid month name");
1142 return;
1143 }
1144 rp->r_month = lp->l_value;
1145 rp->r_todisstd = FALSE;
1146 rp->r_todisgmt = FALSE;
1147 dp = ecpyalloc(timep);
1148 if (*dp != '\0') {
1149 ep = dp + strlen(dp) - 1;
1150 switch (lowerit(*ep)) {
1151 case 's': /* Standard */
1152 rp->r_todisstd = TRUE;
1153 rp->r_todisgmt = FALSE;
1154 *ep = '\0';
1155 break;
1156 case 'w': /* Wall */
1157 rp->r_todisstd = FALSE;
1158 rp->r_todisgmt = FALSE;
1159 *ep = '\0';
1160 case 'g': /* Greenwich */
1161 case 'u': /* Universal */
1162 case 'z': /* Zulu */
1163 rp->r_todisstd = TRUE;
1164 rp->r_todisgmt = TRUE;
1165 *ep = '\0';
1166 break;
1167 }
1168 }
1169 rp->r_tod = gethms(dp, "invalid time of day", FALSE);
1170 ifree(dp);
1171 /*
1172 ** Year work.
1173 */
1174 cp = loyearp;
1175 lp = byword(cp, begin_years);
1176 if (lp != NULL) switch ((int) lp->l_value) {
1177 case YR_MINIMUM:
1178 rp->r_loyear = INT_MIN;
1179 break;
1180 case YR_MAXIMUM:
1181 rp->r_loyear = INT_MAX;
1182 break;
1183 default: /* "cannot happen" */
1184 (void) fprintf(stderr,
1185 "%s: panic: Invalid l_value %d\n",
1186 progname, lp->l_value);
1187 (void) exit(EXIT_FAILURE);
1188 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1189 error("invalid starting year");
1190 return;
1191 }
1192 cp = hiyearp;
1193 if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
1194 case YR_MINIMUM:
1195 rp->r_hiyear = INT_MIN;
1196 break;
1197 case YR_MAXIMUM:
1198 rp->r_hiyear = INT_MAX;
1199 break;
1200 case YR_ONLY:
1201 rp->r_hiyear = rp->r_loyear;
1202 break;
1203 default: /* "cannot happen" */
1204 (void) fprintf(stderr,
1205 "%s: panic: Invalid l_value %d\n",
1206 progname, lp->l_value);
1207 (void) exit(EXIT_FAILURE);
1208 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1209 error("invalid ending year");
1210 return;
1211 }
1212 if (rp->r_loyear > rp->r_hiyear) {
1213 error("starting year greater than ending year");
1214 return;
1215 }
1216 if (*typep == '\0')
1217 rp->r_yrtype = NULL;
1218 else {
1219 if (rp->r_loyear == rp->r_hiyear) {
1220 error("typed single year");
1221 return;
1222 }
1223 rp->r_yrtype = ecpyalloc(typep);
1224 }
1225 /*
1226 ** Day work.
1227 ** Accept things such as:
1228 ** 1
1229 ** last-Sunday
1230 ** Sun<=20
1231 ** Sun>=7
1232 */
1233 dp = ecpyalloc(dayp);
1234 if ((lp = byword(dp, lasts)) != NULL) {
1235 rp->r_dycode = DC_DOWLEQ;
1236 rp->r_wday = lp->l_value;
1237 rp->r_dayofmonth = len_months[1][rp->r_month];
1238 } else {
1239 if ((ep = strchr(dp, '<')) != 0)
1240 rp->r_dycode = DC_DOWLEQ;
1241 else if ((ep = strchr(dp, '>')) != 0)
1242 rp->r_dycode = DC_DOWGEQ;
1243 else {
1244 ep = dp;
1245 rp->r_dycode = DC_DOM;
1246 }
1247 if (rp->r_dycode != DC_DOM) {
1248 *ep++ = 0;
1249 if (*ep++ != '=') {
1250 error("invalid day of month");
1251 ifree(dp);
1252 return;
1253 }
1254 if ((lp = byword(dp, wday_names)) == NULL) {
1255 error("invalid weekday name");
1256 ifree(dp);
1257 return;
1258 }
1259 rp->r_wday = lp->l_value;
1260 }
1261 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1262 rp->r_dayofmonth <= 0 ||
1263 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1264 error("invalid day of month");
1265 ifree(dp);
1266 return;
1267 }
1268 }
1269 ifree(dp);
1270 }
1271
1272 static void
1273 convert(val, buf)
1274 const long val;
1275 char * const buf;
1276 {
1277 register int i;
1278 register long shift;
1279
1280 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1281 buf[i] = val >> shift;
1282 }
1283
1284 static void
1285 puttzcode(val, fp)
1286 const long val;
1287 FILE * const fp;
1288 {
1289 char buf[4];
1290
1291 convert(val, buf);
1292 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1293 }
1294
1295 static void
1296 writezone(name)
1297 const char * const name;
1298 {
1299 register FILE * fp;
1300 register int i, j;
1301 static char * fullname;
1302 static struct tzhead tzh;
1303
1304 fullname = erealloc(fullname,
1305 (int) (strlen(directory) + 1 + strlen(name) + 1));
1306 (void) sprintf(fullname, "%s/%s", directory, name);
1307 if ((fp = fopen(fullname, "wb")) == NULL) {
1308 if (mkdirs(fullname) != 0)
1309 (void) exit(EXIT_FAILURE);
1310 if ((fp = fopen(fullname, "wb")) == NULL) {
1311 (void) fprintf(stderr, "%s: Can't create ", progname);
1312 (void) perror(fullname);
1313 (void) exit(EXIT_FAILURE);
1314 }
1315 }
1316 convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1317 convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1318 convert(eitol(leapcnt), tzh.tzh_leapcnt);
1319 convert(eitol(timecnt), tzh.tzh_timecnt);
1320 convert(eitol(typecnt), tzh.tzh_typecnt);
1321 convert(eitol(charcnt), tzh.tzh_charcnt);
1322 #define DO(field) (void) fwrite((void *) tzh.field, \
1323 (size_t) sizeof tzh.field, (size_t) 1, fp)
1324 DO(tzh_reserved);
1325 DO(tzh_ttisgmtcnt);
1326 DO(tzh_ttisstdcnt);
1327 DO(tzh_leapcnt);
1328 DO(tzh_timecnt);
1329 DO(tzh_typecnt);
1330 DO(tzh_charcnt);
1331 #undef DO
1332 for (i = 0; i < timecnt; ++i) {
1333 j = leapcnt;
1334 while (--j >= 0)
1335 if (ats[i] >= trans[j]) {
1336 ats[i] = tadd(ats[i], corr[j]);
1337 break;
1338 }
1339 puttzcode((long) ats[i], fp);
1340 }
1341 if (timecnt > 0)
1342 (void) fwrite((void *) types, (size_t) sizeof types[0],
1343 (size_t) timecnt, fp);
1344 for (i = 0; i < typecnt; ++i) {
1345 puttzcode((long) gmtoffs[i], fp);
1346 (void) putc(isdsts[i], fp);
1347 (void) putc(abbrinds[i], fp);
1348 }
1349 if (charcnt != 0)
1350 (void) fwrite((void *) chars, (size_t) sizeof chars[0],
1351 (size_t) charcnt, fp);
1352 for (i = 0; i < leapcnt; ++i) {
1353 if (roll[i]) {
1354 if (timecnt == 0 || trans[i] < ats[0]) {
1355 j = 0;
1356 while (isdsts[j])
1357 if (++j >= typecnt) {
1358 j = 0;
1359 break;
1360 }
1361 } else {
1362 j = 1;
1363 while (j < timecnt && trans[i] >= ats[j])
1364 ++j;
1365 j = types[j - 1];
1366 }
1367 puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
1368 } else puttzcode((long) trans[i], fp);
1369 puttzcode((long) corr[i], fp);
1370 }
1371 for (i = 0; i < typecnt; ++i)
1372 (void) putc(ttisstds[i], fp);
1373 for (i = 0; i < typecnt; ++i)
1374 (void) putc(ttisgmts[i], fp);
1375 if (ferror(fp) || fclose(fp)) {
1376 (void) fprintf(stderr, "%s: Write error on ", progname);
1377 (void) perror(fullname);
1378 (void) exit(EXIT_FAILURE);
1379 }
1380 }
1381
1382 static void
1383 doabbr(abbr, format, letters, isdst)
1384 char * const abbr;
1385 const char * const format;
1386 const char * const letters;
1387 const int isdst;
1388 {
1389 if (strchr(format, '/') == NULL) {
1390 if (letters == NULL)
1391 (void) strcpy(abbr, format);
1392 else (void) sprintf(abbr, format, letters);
1393 } else if (isdst)
1394 (void) strcpy(abbr, strchr(format, '/') + 1);
1395 else {
1396 (void) strcpy(abbr, format);
1397 *strchr(abbr, '/') = '\0';
1398 }
1399 }
1400
1401 static void
1402 outzone(zpfirst, zonecount)
1403 const struct zone * const zpfirst;
1404 const int zonecount;
1405 {
1406 register const struct zone * zp;
1407 register struct rule * rp;
1408 register int i, j;
1409 register int usestart, useuntil;
1410 register time_t starttime, untiltime;
1411 register long gmtoff;
1412 register long stdoff;
1413 register int year;
1414 register long startoff;
1415 register int startisdst;
1416 register int startttisstd;
1417 register int startttisgmt;
1418 register int type;
1419 char startbuf[BUFSIZ];
1420
1421 INITIALIZE(untiltime);
1422 INITIALIZE(starttime);
1423 INITIALIZE(startoff);
1424 /*
1425 ** Now. . .finally. . .generate some useful data!
1426 */
1427 timecnt = 0;
1428 typecnt = 0;
1429 charcnt = 0;
1430 /*
1431 ** A guess that may well be corrected later.
1432 */
1433 stdoff = 0;
1434 /*
1435 ** Thanks to Earl Chew (earl (at) dnd.icp.nec.com.au)
1436 ** for noting the need to unconditionally initialize startttisstd.
1437 */
1438 startttisstd = FALSE;
1439 startttisgmt = FALSE;
1440 for (i = 0; i < zonecount; ++i) {
1441 zp = &zpfirst[i];
1442 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1443 useuntil = i < (zonecount - 1);
1444 if (useuntil && zp->z_untiltime <= min_time)
1445 continue;
1446 gmtoff = zp->z_gmtoff;
1447 eat(zp->z_filename, zp->z_linenum);
1448 startisdst = -1;
1449 if (zp->z_nrules == 0) {
1450 stdoff = zp->z_stdoff;
1451 doabbr(startbuf, zp->z_format,
1452 (char *) NULL, stdoff != 0);
1453 type = addtype(oadd(zp->z_gmtoff, stdoff),
1454 startbuf, stdoff != 0, startttisstd,
1455 startttisgmt);
1456 if (usestart)
1457 addtt(starttime, type);
1458 else if (stdoff != 0)
1459 addtt(min_time, type);
1460 } else for (year = min_year; year <= max_year; ++year) {
1461 if (useuntil && year > zp->z_untilrule.r_hiyear)
1462 break;
1463 /*
1464 ** Mark which rules to do in the current year.
1465 ** For those to do, calculate rpytime(rp, year);
1466 */
1467 for (j = 0; j < zp->z_nrules; ++j) {
1468 rp = &zp->z_rules[j];
1469 eats(zp->z_filename, zp->z_linenum,
1470 rp->r_filename, rp->r_linenum);
1471 rp->r_todo = year >= rp->r_loyear &&
1472 year <= rp->r_hiyear &&
1473 yearistype(year, rp->r_yrtype);
1474 if (rp->r_todo)
1475 rp->r_temp = rpytime(rp, year);
1476 }
1477 for ( ; ; ) {
1478 register int k;
1479 register time_t jtime, ktime;
1480 register long offset;
1481 char buf[BUFSIZ];
1482
1483 INITIALIZE(ktime);
1484 if (useuntil) {
1485 /*
1486 ** Turn untiltime into GMT
1487 ** assuming the current gmtoff and
1488 ** stdoff values.
1489 */
1490 untiltime = zp->z_untiltime;
1491 if (!zp->z_untilrule.r_todisgmt)
1492 untiltime = tadd(untiltime,
1493 -gmtoff);
1494 if (!zp->z_untilrule.r_todisstd)
1495 untiltime = tadd(untiltime,
1496 -stdoff);
1497 }
1498 /*
1499 ** Find the rule (of those to do, if any)
1500 ** that takes effect earliest in the year.
1501 */
1502 k = -1;
1503 for (j = 0; j < zp->z_nrules; ++j) {
1504 rp = &zp->z_rules[j];
1505 if (!rp->r_todo)
1506 continue;
1507 eats(zp->z_filename, zp->z_linenum,
1508 rp->r_filename, rp->r_linenum);
1509 offset = rp->r_todisgmt ? 0 : gmtoff;
1510 if (!rp->r_todisstd)
1511 offset = oadd(offset, stdoff);
1512 jtime = rp->r_temp;
1513 if (jtime == min_time ||
1514 jtime == max_time)
1515 continue;
1516 jtime = tadd(jtime, -offset);
1517 if (k < 0 || jtime < ktime) {
1518 k = j;
1519 ktime = jtime;
1520 }
1521 }
1522 if (k < 0)
1523 break; /* go on to next year */
1524 rp = &zp->z_rules[k];
1525 rp->r_todo = FALSE;
1526 if (useuntil && ktime >= untiltime)
1527 break;
1528 if (usestart) {
1529 if (ktime < starttime) {
1530 stdoff = rp->r_stdoff;
1531 startoff = oadd(zp->z_gmtoff,
1532 rp->r_stdoff);
1533 doabbr(startbuf, zp->z_format,
1534 rp->r_abbrvar,
1535 rp->r_stdoff != 0);
1536 startisdst = rp->r_stdoff != 0;
1537 continue;
1538 }
1539 usestart = FALSE;
1540 if (ktime != starttime) {
1541 if (startisdst < 0 &&
1542 zp->z_gmtoff !=
1543 (zp - 1)->z_gmtoff) {
1544 type = (timecnt == 0) ? 0 :
1545 types[timecnt - 1];
1546 startoff = oadd(gmtoffs[type],
1547 -(zp - 1)->z_gmtoff);
1548 startisdst = startoff != 0;
1549 startoff = oadd(startoff,
1550 zp->z_gmtoff);
1551 (void) strcpy(startbuf,
1552 &chars[abbrinds[type]]);
1553 }
1554 if (startisdst >= 0)
1555 addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd,
1556 startttisgmt));
1557 }
1558 }
1559 eats(zp->z_filename, zp->z_linenum,
1560 rp->r_filename, rp->r_linenum);
1561 doabbr(buf, zp->z_format, rp->r_abbrvar,
1562 rp->r_stdoff != 0);
1563 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1564 type = addtype(offset, buf, rp->r_stdoff != 0,
1565 rp->r_todisstd, rp->r_todisgmt);
1566 addtt(ktime, type);
1567 stdoff = rp->r_stdoff;
1568 }
1569 }
1570 /*
1571 ** Now we may get to set starttime for the next zone line.
1572 */
1573 if (useuntil) {
1574 starttime = tadd(zp->z_untiltime, -gmtoff);
1575 startttisstd = zp->z_untilrule.r_todisstd;
1576 startttisgmt = zp->z_untilrule.r_todisgmt;
1577 if (!startttisstd)
1578 starttime = tadd(starttime, -stdoff);
1579 }
1580 }
1581 writezone(zpfirst->z_name);
1582 }
1583
1584 static void
1585 addtt(starttime, type)
1586 const time_t starttime;
1587 const int type;
1588 {
1589 if (timecnt != 0 && type == types[timecnt - 1])
1590 return; /* easy enough! */
1591 if (timecnt == 0 && type == 0 && isdsts[0] == 0)
1592 return; /* handled by default rule */
1593 if (timecnt >= TZ_MAX_TIMES) {
1594 error("too many transitions?!");
1595 (void) exit(EXIT_FAILURE);
1596 }
1597 ats[timecnt] = starttime;
1598 types[timecnt] = type;
1599 ++timecnt;
1600 }
1601
1602 static int
1603 addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
1604 const long gmtoff;
1605 const char * const abbr;
1606 const int isdst;
1607 const int ttisstd;
1608 const int ttisgmt;
1609 {
1610 register int i, j;
1611
1612 /*
1613 ** See if there's already an entry for this zone type.
1614 ** If so, just return its index.
1615 */
1616 for (i = 0; i < typecnt; ++i) {
1617 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1618 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1619 ttisstd == ttisstds[i] &&
1620 ttisgmt == ttisgmts[i])
1621 return i;
1622 }
1623 /*
1624 ** There isn't one; add a new one, unless there are already too
1625 ** many.
1626 */
1627 if (typecnt >= TZ_MAX_TYPES) {
1628 error("too many local time types");
1629 (void) exit(EXIT_FAILURE);
1630 }
1631 gmtoffs[i] = gmtoff;
1632 isdsts[i] = isdst;
1633 ttisstds[i] = ttisstd;
1634 ttisgmts[i] = ttisgmt;
1635
1636 for (j = 0; j < charcnt; ++j)
1637 if (strcmp(&chars[j], abbr) == 0)
1638 break;
1639 if (j == charcnt)
1640 newabbr(abbr);
1641 abbrinds[i] = j;
1642 ++typecnt;
1643 return i;
1644 }
1645
1646 static void
1647 leapadd(t, positive, rolling, count)
1648 const time_t t;
1649 const int positive;
1650 const int rolling;
1651 int count;
1652 {
1653 register int i, j;
1654
1655 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1656 error("too many leap seconds");
1657 (void) exit(EXIT_FAILURE);
1658 }
1659 for (i = 0; i < leapcnt; ++i)
1660 if (t <= trans[i]) {
1661 if (t == trans[i]) {
1662 error("repeated leap second moment");
1663 (void) exit(EXIT_FAILURE);
1664 }
1665 break;
1666 }
1667 do {
1668 for (j = leapcnt; j > i; --j) {
1669 trans[j] = trans[j - 1];
1670 corr[j] = corr[j - 1];
1671 roll[j] = roll[j - 1];
1672 }
1673 trans[i] = t;
1674 corr[i] = positive ? 1L : eitol(-count);
1675 roll[i] = rolling;
1676 ++leapcnt;
1677 } while (positive && --count != 0);
1678 }
1679
1680 static void
1681 adjleap P((void))
1682 {
1683 register int i;
1684 register long last = 0;
1685
1686 /*
1687 ** propagate leap seconds forward
1688 */
1689 for (i = 0; i < leapcnt; ++i) {
1690 trans[i] = tadd(trans[i], last);
1691 last = corr[i] += last;
1692 }
1693 }
1694
1695 static int
1696 yearistype(year, type)
1697 const int year;
1698 const char * const type;
1699 {
1700 static char * buf;
1701 int result;
1702
1703 if (type == NULL || *type == '\0')
1704 return TRUE;
1705 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
1706 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1707 result = system(buf);
1708 if (result == 0)
1709 return TRUE;
1710 if (result == (1 << 8))
1711 return FALSE;
1712 error("Wild result from command execution");
1713 (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
1714 progname, buf, result);
1715 for ( ; ; )
1716 (void) exit(EXIT_FAILURE);
1717 }
1718
1719 static int
1720 lowerit(a)
1721 int a;
1722 {
1723 a = (unsigned char) a;
1724 return (isascii(a) && isupper(a)) ? tolower(a) : a;
1725 }
1726
1727 static int
1728 ciequal(ap, bp) /* case-insensitive equality */
1729 register const char * ap;
1730 register const char * bp;
1731 {
1732 while (lowerit(*ap) == lowerit(*bp++))
1733 if (*ap++ == '\0')
1734 return TRUE;
1735 return FALSE;
1736 }
1737
1738 static int
1739 itsabbr(abbr, word)
1740 register const char * abbr;
1741 register const char * word;
1742 {
1743 if (lowerit(*abbr) != lowerit(*word))
1744 return FALSE;
1745 ++word;
1746 while (*++abbr != '\0')
1747 do {
1748 if (*word == '\0')
1749 return FALSE;
1750 } while (lowerit(*word++) != lowerit(*abbr));
1751 return TRUE;
1752 }
1753
1754 static const struct lookup *
1755 byword(word, table)
1756 register const char * const word;
1757 register const struct lookup * const table;
1758 {
1759 register const struct lookup * foundlp;
1760 register const struct lookup * lp;
1761
1762 if (word == NULL || table == NULL)
1763 return NULL;
1764 /*
1765 ** Look for exact match.
1766 */
1767 for (lp = table; lp->l_word != NULL; ++lp)
1768 if (ciequal(word, lp->l_word))
1769 return lp;
1770 /*
1771 ** Look for inexact match.
1772 */
1773 foundlp = NULL;
1774 for (lp = table; lp->l_word != NULL; ++lp)
1775 if (itsabbr(word, lp->l_word))
1776 if (foundlp == NULL)
1777 foundlp = lp;
1778 else return NULL; /* multiple inexact matches */
1779 return foundlp;
1780 }
1781
1782 static char **
1783 getfields(cp)
1784 register char * cp;
1785 {
1786 register char * dp;
1787 register char ** array;
1788 register int nsubs;
1789
1790 if (cp == NULL)
1791 return NULL;
1792 array = (char **) (void *)
1793 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
1794 nsubs = 0;
1795 for ( ; ; ) {
1796 while (isascii(*cp) && isspace((unsigned char) *cp))
1797 ++cp;
1798 if (*cp == '\0' || *cp == '#')
1799 break;
1800 array[nsubs++] = dp = cp;
1801 do {
1802 if ((*dp = *cp++) != '"')
1803 ++dp;
1804 else while ((*dp = *cp++) != '"')
1805 if (*dp != '\0')
1806 ++dp;
1807 else error("Odd number of quotation marks");
1808 } while (*cp != '\0' && *cp != '#' &&
1809 (!isascii(*cp) || !isspace((unsigned char) *cp)));
1810 if (isascii(*cp) && isspace((unsigned char) *cp))
1811 ++cp;
1812 *dp = '\0';
1813 }
1814 array[nsubs] = NULL;
1815 return array;
1816 }
1817
1818 static long
1819 oadd(t1, t2)
1820 const long t1;
1821 const long t2;
1822 {
1823 register long t;
1824
1825 t = t1 + t2;
1826 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1827 error("time overflow");
1828 (void) exit(EXIT_FAILURE);
1829 }
1830 return t;
1831 }
1832
1833 static time_t
1834 tadd(t1, t2)
1835 const time_t t1;
1836 const long t2;
1837 {
1838 register time_t t;
1839
1840 if (t1 == max_time && t2 > 0)
1841 return max_time;
1842 if (t1 == min_time && t2 < 0)
1843 return min_time;
1844 t = t1 + t2;
1845 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1846 error("time overflow");
1847 (void) exit(EXIT_FAILURE);
1848 }
1849 return t;
1850 }
1851
1852 /*
1853 ** Given a rule, and a year, compute the date - in seconds since January 1,
1854 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1855 */
1856
1857 static time_t
1858 rpytime(rp, wantedy)
1859 register const struct rule * const rp;
1860 register const int wantedy;
1861 {
1862 register int y, m, i;
1863 register long dayoff; /* with a nod to Margaret O. */
1864 register time_t t;
1865
1866 if (wantedy == INT_MIN)
1867 return min_time;
1868 if (wantedy == INT_MAX)
1869 return max_time;
1870 dayoff = 0;
1871 m = TM_JANUARY;
1872 y = EPOCH_YEAR;
1873 while (wantedy != y) {
1874 if (wantedy > y) {
1875 i = len_years[isleap(y)];
1876 ++y;
1877 } else {
1878 --y;
1879 i = -len_years[isleap(y)];
1880 }
1881 dayoff = oadd(dayoff, eitol(i));
1882 }
1883 while (m != rp->r_month) {
1884 i = len_months[isleap(y)][m];
1885 dayoff = oadd(dayoff, eitol(i));
1886 ++m;
1887 }
1888 i = rp->r_dayofmonth;
1889 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1890 if (rp->r_dycode == DC_DOWLEQ)
1891 --i;
1892 else {
1893 error("use of 2/29 in non leap-year");
1894 (void) exit(EXIT_FAILURE);
1895 }
1896 }
1897 --i;
1898 dayoff = oadd(dayoff, eitol(i));
1899 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1900 register long wday;
1901
1902 #define LDAYSPERWEEK ((long) DAYSPERWEEK)
1903 wday = eitol(EPOCH_WDAY);
1904 /*
1905 ** Don't trust mod of negative numbers.
1906 */
1907 if (dayoff >= 0)
1908 wday = (wday + dayoff) % LDAYSPERWEEK;
1909 else {
1910 wday -= ((-dayoff) % LDAYSPERWEEK);
1911 if (wday < 0)
1912 wday += LDAYSPERWEEK;
1913 }
1914 while (wday != eitol(rp->r_wday))
1915 if (rp->r_dycode == DC_DOWGEQ) {
1916 dayoff = oadd(dayoff, (long) 1);
1917 if (++wday >= LDAYSPERWEEK)
1918 wday = 0;
1919 ++i;
1920 } else {
1921 dayoff = oadd(dayoff, (long) -1);
1922 if (--wday < 0)
1923 wday = LDAYSPERWEEK - 1;
1924 --i;
1925 }
1926 if (i < 0 || i >= len_months[isleap(y)][m]) {
1927 error("no day in month matches rule");
1928 (void) exit(EXIT_FAILURE);
1929 }
1930 }
1931 if (dayoff < 0 && !TIME_T_SIGNED)
1932 return min_time;
1933 t = (time_t) dayoff * SECSPERDAY;
1934 /*
1935 ** Cheap overflow check.
1936 */
1937 if (t / SECSPERDAY != dayoff)
1938 return (dayoff > 0) ? max_time : min_time;
1939 return tadd(t, rp->r_tod);
1940 }
1941
1942 static void
1943 newabbr(string)
1944 const char * const string;
1945 {
1946 register int i;
1947
1948 i = strlen(string) + 1;
1949 if (charcnt + i > TZ_MAX_CHARS) {
1950 error("too many, or too long, time zone abbreviations");
1951 (void) exit(EXIT_FAILURE);
1952 }
1953 (void) strcpy(&chars[charcnt], string);
1954 charcnt += eitol(i);
1955 }
1956
1957 static int
1958 mkdirs(argname)
1959 char * const argname;
1960 {
1961 register char * name;
1962 register char * cp;
1963
1964 if (argname == NULL || *argname == '\0')
1965 return 0;
1966 cp = name = ecpyalloc(argname);
1967 while ((cp = strchr(cp + 1, '/')) != 0) {
1968 *cp = '\0';
1969 #ifndef unix
1970 /*
1971 ** DOS drive specifier?
1972 */
1973 if (isalpha((unsigned char) name[0]) &&
1974 name[1] == ':' && name[2] != '\0') {
1975 *cp = '/';
1976 continue;
1977 }
1978 #endif /* !defined unix */
1979 if (!itsdir(name)) {
1980 /*
1981 ** It doesn't seem to exist, so we try to create it.
1982 */
1983 if (mkdir(name, 0755) != 0) {
1984 (void) fprintf(stderr,
1985 "%s: Can't create directory ",
1986 progname);
1987 (void) perror(name);
1988 ifree(name);
1989 return -1;
1990 }
1991 }
1992 *cp = '/';
1993 }
1994 ifree(name);
1995 return 0;
1996 }
1997
1998 static long
1999 eitol(i)
2000 const int i;
2001 {
2002 long l;
2003
2004 l = i;
2005 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
2006 (void) fprintf(stderr,
2007 "%s: %d did not sign extend correctly\n",
2008 progname, i);
2009 (void) exit(EXIT_FAILURE);
2010 }
2011 return l;
2012 }
2013
2014 /*
2015 ** UNIX was a registered trademark of UNIX System Laboratories in 1993.
2016 */
2017