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