zic.c revision 1.51 1 /* $NetBSD: zic.c,v 1.51 2014/10/07 21:51:03 christos Exp $ */
2 /*
3 ** This file is in the public domain, so clarified as of
4 ** 2006-07-17 by Arthur David Olson.
5 */
6
7 #if HAVE_NBTOOL_CONFIG_H
8 #include "nbtool_config.h"
9 #endif
10
11 #include <sys/cdefs.h>
12 #ifndef lint
13 __RCSID("$NetBSD: zic.c,v 1.51 2014/10/07 21:51:03 christos Exp $");
14 #endif /* !defined lint */
15
16 #include "version.h"
17 #include "private.h"
18 #include "locale.h"
19 #include "tzfile.h"
20
21 #include <stdarg.h>
22 #include <unistd.h>
23
24 #define ZIC_VERSION_PRE_2013 '2'
25 #define ZIC_VERSION '3'
26
27 typedef int_fast64_t zic_t;
28 #define ZIC_MIN INT_FAST64_MIN
29 #define ZIC_MAX INT_FAST64_MAX
30 #define SCNdZIC SCNdFAST64
31
32 #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
33 #define ZIC_MAX_ABBR_LEN_WO_WARN 6
34 #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
35
36 #if HAVE_SYS_STAT_H
37 #include <sys/stat.h>
38 #endif
39 #ifdef S_IRUSR
40 #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
41 #else
42 #define MKDIR_UMASK 0755
43 #endif
44
45 #define end(cp) (strchr((cp), '\0'))
46
47 struct rule {
48 const char * r_filename;
49 int r_linenum;
50 const char * r_name;
51
52 zic_t r_loyear; /* for example, 1986 */
53 zic_t r_hiyear; /* for example, 1986 */
54 const char * r_yrtype;
55 bool r_lowasnum;
56 bool r_hiwasnum;
57
58 int r_month; /* 0..11 */
59
60 int r_dycode; /* see below */
61 int r_dayofmonth;
62 int r_wday;
63
64 zic_t r_tod; /* time from midnight */
65 bool r_todisstd; /* above is standard time if 1 */
66 /* or wall clock time if 0 */
67 bool r_todisgmt; /* above is GMT if 1 */
68 /* or local time if 0 */
69 zic_t r_stdoff; /* offset from standard time */
70 const char * r_abbrvar; /* variable part of abbreviation */
71
72 int r_todo; /* a rule to do (used in outzone) */
73 zic_t r_temp; /* used in outzone */
74 };
75
76 /*
77 ** r_dycode r_dayofmonth r_wday
78 */
79
80 #define DC_DOM 0 /* 1..31 */ /* unused */
81 #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
82 #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
83
84 struct zone {
85 const char * z_filename;
86 int z_linenum;
87
88 const char * z_name;
89 zic_t z_gmtoff;
90 const char * z_rule;
91 const char * z_format;
92
93 zic_t z_stdoff;
94
95 struct rule * z_rules;
96 int z_nrules;
97
98 struct rule z_untilrule;
99 zic_t z_untiltime;
100 };
101
102 extern int getopt(int argc, char * const argv[],
103 const char * options);
104 extern int link(const char * fromname, const char * toname);
105 extern char * optarg;
106 extern int optind;
107
108 #if ! HAVE_LINK
109 # define link(from, to) (-1)
110 #endif
111 #if ! HAVE_SYMLINK
112 # define symlink(from, to) (-1)
113 #endif
114
115 static void addtt(zic_t starttime, int type);
116 static int addtype(zic_t, char * const, bool, bool, bool);
117 static void leapadd(zic_t, bool, int, int);
118 static void adjleap(void);
119 static void associate(void);
120 static void dolink(const char * fromfield, const char * tofield);
121 static char ** getfields(char * buf);
122 static zic_t gethms(const char * string, const char * errstring,
123 bool);
124 static void infile(const char * filename);
125 static void inleap(char ** fields, int nfields);
126 static void inlink(char ** fields, int nfields);
127 static void inrule(char ** fields, int nfields);
128 static bool inzcont(char ** fields, int nfields);
129 static bool inzone(char ** fields, int nfields);
130 static bool inzsub(char ** fields, int nfields, int iscont);
131 static int itsdir(const char * name);
132 static bool is_alpha(char a);
133 static char lowerit(char);
134 static bool mkdirs(char * filename);
135 static void newabbr(const char * abbr);
136 static zic_t oadd(zic_t t1, zic_t t2);
137 static void outzone(const struct zone * zp, int ntzones);
138 static int rcomp(const void * leftp, const void * rightp);
139 static zic_t rpytime(const struct rule * rp, zic_t wantedy);
140 static void rulesub(struct rule * rp,
141 const char * loyearp, const char * hiyearp,
142 const char * typep, const char * monthp,
143 const char * dayp, const char * timep);
144 static zic_t tadd(zic_t t1, zic_t t2);
145 static bool yearistype(int year, const char * type);
146 static int atcomp(const void *avp, const void *bvp);
147 static void updateminmax(zic_t x);
148
149 static int charcnt;
150 static bool errors;
151 static bool warnings;
152 static const char * filename;
153 static int leapcnt;
154 static bool leapseen;
155 static zic_t leapminyear;
156 static zic_t leapmaxyear;
157 static int linenum;
158 static size_t max_abbrvar_len;
159 static size_t max_format_len;
160 static zic_t max_year;
161 static zic_t min_year;
162 static bool noise;
163 static const char * rfilename;
164 static int rlinenum;
165 static const char * progname;
166 static int timecnt;
167 static int timecnt_alloc;
168 static int typecnt;
169
170 /*
171 ** Line codes.
172 */
173
174 #define LC_RULE 0
175 #define LC_ZONE 1
176 #define LC_LINK 2
177 #define LC_LEAP 3
178
179 /*
180 ** Which fields are which on a Zone line.
181 */
182
183 #define ZF_NAME 1
184 #define ZF_GMTOFF 2
185 #define ZF_RULE 3
186 #define ZF_FORMAT 4
187 #define ZF_TILYEAR 5
188 #define ZF_TILMONTH 6
189 #define ZF_TILDAY 7
190 #define ZF_TILTIME 8
191 #define ZONE_MINFIELDS 5
192 #define ZONE_MAXFIELDS 9
193
194 /*
195 ** Which fields are which on a Zone continuation line.
196 */
197
198 #define ZFC_GMTOFF 0
199 #define ZFC_RULE 1
200 #define ZFC_FORMAT 2
201 #define ZFC_TILYEAR 3
202 #define ZFC_TILMONTH 4
203 #define ZFC_TILDAY 5
204 #define ZFC_TILTIME 6
205 #define ZONEC_MINFIELDS 3
206 #define ZONEC_MAXFIELDS 7
207
208 /*
209 ** Which files are which on a Rule line.
210 */
211
212 #define RF_NAME 1
213 #define RF_LOYEAR 2
214 #define RF_HIYEAR 3
215 #define RF_COMMAND 4
216 #define RF_MONTH 5
217 #define RF_DAY 6
218 #define RF_TOD 7
219 #define RF_STDOFF 8
220 #define RF_ABBRVAR 9
221 #define RULE_FIELDS 10
222
223 /*
224 ** Which fields are which on a Link line.
225 */
226
227 #define LF_FROM 1
228 #define LF_TO 2
229 #define LINK_FIELDS 3
230
231 /*
232 ** Which fields are which on a Leap line.
233 */
234
235 #define LP_YEAR 1
236 #define LP_MONTH 2
237 #define LP_DAY 3
238 #define LP_TIME 4
239 #define LP_CORR 5
240 #define LP_ROLL 6
241 #define LEAP_FIELDS 7
242
243 /*
244 ** Year synonyms.
245 */
246
247 #define YR_MINIMUM 0
248 #define YR_MAXIMUM 1
249 #define YR_ONLY 2
250
251 static struct rule * rules;
252 static int nrules; /* number of rules */
253 static int nrules_alloc;
254
255 static struct zone * zones;
256 static int nzones; /* number of zones */
257 static int nzones_alloc;
258
259 struct link {
260 const char * l_filename;
261 int l_linenum;
262 const char * l_from;
263 const char * l_to;
264 };
265
266 static struct link * links;
267 static int nlinks;
268 static int nlinks_alloc;
269
270 struct lookup {
271 const char * l_word;
272 const int l_value;
273 };
274
275 static struct lookup const * byword(const char * string,
276 const struct lookup * lp);
277
278 static struct lookup const line_codes[] = {
279 { "Rule", LC_RULE },
280 { "Zone", LC_ZONE },
281 { "Link", LC_LINK },
282 { "Leap", LC_LEAP },
283 { NULL, 0}
284 };
285
286 static struct lookup const mon_names[] = {
287 { "January", TM_JANUARY },
288 { "February", TM_FEBRUARY },
289 { "March", TM_MARCH },
290 { "April", TM_APRIL },
291 { "May", TM_MAY },
292 { "June", TM_JUNE },
293 { "July", TM_JULY },
294 { "August", TM_AUGUST },
295 { "September", TM_SEPTEMBER },
296 { "October", TM_OCTOBER },
297 { "November", TM_NOVEMBER },
298 { "December", TM_DECEMBER },
299 { NULL, 0 }
300 };
301
302 static struct lookup const wday_names[] = {
303 { "Sunday", TM_SUNDAY },
304 { "Monday", TM_MONDAY },
305 { "Tuesday", TM_TUESDAY },
306 { "Wednesday", TM_WEDNESDAY },
307 { "Thursday", TM_THURSDAY },
308 { "Friday", TM_FRIDAY },
309 { "Saturday", TM_SATURDAY },
310 { NULL, 0 }
311 };
312
313 static struct lookup const lasts[] = {
314 { "last-Sunday", TM_SUNDAY },
315 { "last-Monday", TM_MONDAY },
316 { "last-Tuesday", TM_TUESDAY },
317 { "last-Wednesday", TM_WEDNESDAY },
318 { "last-Thursday", TM_THURSDAY },
319 { "last-Friday", TM_FRIDAY },
320 { "last-Saturday", TM_SATURDAY },
321 { NULL, 0 }
322 };
323
324 static struct lookup const begin_years[] = {
325 { "minimum", YR_MINIMUM },
326 { "maximum", YR_MAXIMUM },
327 { NULL, 0 }
328 };
329
330 static struct lookup const end_years[] = {
331 { "minimum", YR_MINIMUM },
332 { "maximum", YR_MAXIMUM },
333 { "only", YR_ONLY },
334 { NULL, 0 }
335 };
336
337 static struct lookup const leap_types[] = {
338 { "Rolling", true },
339 { "Stationary", false },
340 { NULL, 0 }
341 };
342
343 static const int len_months[2][MONSPERYEAR] = {
344 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
345 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
346 };
347
348 static const int len_years[2] = {
349 DAYSPERNYEAR, DAYSPERLYEAR
350 };
351
352 static struct attype {
353 zic_t at;
354 unsigned char type;
355 } * attypes;
356 static zic_t gmtoffs[TZ_MAX_TYPES];
357 static char isdsts[TZ_MAX_TYPES];
358 static unsigned char abbrinds[TZ_MAX_TYPES];
359 static bool ttisstds[TZ_MAX_TYPES];
360 static bool ttisgmts[TZ_MAX_TYPES];
361 static char chars[TZ_MAX_CHARS];
362 static zic_t trans[TZ_MAX_LEAPS];
363 static zic_t corr[TZ_MAX_LEAPS];
364 static char roll[TZ_MAX_LEAPS];
365
366 /*
367 ** Memory allocation.
368 */
369
370 static _Noreturn void
371 memory_exhausted(const char *msg)
372 {
373 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
374 exit(EXIT_FAILURE);
375 }
376
377 static ATTRIBUTE_PURE size_t
378 size_product(size_t nitems, size_t itemsize)
379 {
380 if (SIZE_MAX / itemsize < nitems)
381 memory_exhausted(_("size overflow"));
382 return nitems * itemsize;
383 }
384
385 static ATTRIBUTE_PURE void *
386 memcheck(void *const ptr)
387 {
388 if (ptr == NULL)
389 memory_exhausted(strerror(errno));
390 return ptr;
391 }
392
393 #define emalloc(size) memcheck(malloc(size))
394 #define erealloc(ptr, size) memcheck(realloc((ptr), (size)))
395 #define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
396 #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
397
398 static void *
399 growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
400 {
401 if (nitems < *nitems_alloc)
402 return ptr;
403 else {
404 int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX;
405 if ((amax - 1) / 3 * 2 < *nitems_alloc)
406 memory_exhausted(_("int overflow"));
407 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
408 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
409 }
410 }
411
412 /*
413 ** Error handling.
414 */
415
416 static void
417 eats(const char *const name, const int num, const char *const rname,
418 const int rnum)
419 {
420 filename = name;
421 linenum = num;
422 rfilename = rname;
423 rlinenum = rnum;
424 }
425
426 static void
427 eat(const char *const name, const int num)
428 {
429 eats(name, num, NULL, -1);
430 }
431
432 static void ATTRIBUTE_FORMAT((printf, 1, 0))
433 verror(const char *const string, va_list args)
434 {
435 /*
436 ** Match the format of "cc" to allow sh users to
437 ** zic ... 2>&1 | error -t "*" -v
438 ** on BSD systems.
439 */
440 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
441 vfprintf(stderr, string, args);
442 if (rfilename != NULL)
443 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
444 rfilename, rlinenum);
445 fprintf(stderr, "\n");
446 }
447
448 static void ATTRIBUTE_FORMAT((printf, 1, 2))
449 error(const char *const string, ...)
450 {
451 va_list args;
452 va_start(args, string);
453 verror(string, args);
454 va_end(args);
455 errors = true;
456 }
457
458 static void ATTRIBUTE_FORMAT((printf, 1, 2))
459 warning(const char *const string, ...)
460 {
461 va_list args;
462 fprintf(stderr, _("warning: "));
463 va_start(args, string);
464 verror(string, args);
465 va_end(args);
466 warnings = true;
467 }
468
469 static void
470 close_file(FILE *stream, char const *name)
471 {
472 char const *e = (ferror(stream) ? _("I/O error")
473 : fclose(stream) != 0 ? strerror(errno) : NULL);
474 if (e) {
475 fprintf(stderr, "%s: ", progname);
476 if (name)
477 fprintf(stderr, "%s: ", name);
478 fprintf(stderr, "%s\n", e);
479 exit(EXIT_FAILURE);
480 }
481 }
482
483 static _Noreturn void
484 usage(FILE *stream, int status)
485 {
486 fprintf(stream,
487 _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
488 "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
489 "\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\n"
490 "Report bugs to %s.\n"),
491 progname, progname, REPORT_BUGS_TO);
492 if (status == EXIT_SUCCESS)
493 close_file(stream, NULL);
494 exit(status);
495 }
496
497 static const char * psxrules;
498 static const char * lcltime;
499 static const char * directory;
500 static const char * leapsec;
501 static const char * yitcommand;
502
503 int
504 main(int argc, char *argv[])
505 {
506 int i;
507 int j;
508 int c;
509
510 #ifdef S_IWGRP
511 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
512 #endif
513 #if HAVE_GETTEXT - 0
514 (void) setlocale(LC_MESSAGES, "");
515 #ifdef TZ_DOMAINDIR
516 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
517 #endif /* defined TEXTDOMAINDIR */
518 (void) textdomain(TZ_DOMAIN);
519 #endif /* HAVE_GETTEXT */
520 progname = argv[0];
521 if (TYPE_BIT(zic_t) < 64) {
522 (void) fprintf(stderr, "%s: %s\n", progname,
523 _("wild compilation-time specification of zic_t"));
524 return EXIT_FAILURE;
525 }
526 for (i = 1; i < argc; ++i)
527 if (strcmp(argv[i], "--version") == 0) {
528 (void) printf("zic %s%s\n", PKGVERSION, TZVERSION);
529 close_file(stdout, NULL);
530 return EXIT_SUCCESS;
531 } else if (strcmp(argv[i], "--help") == 0) {
532 usage(stdout, EXIT_SUCCESS);
533 }
534 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
535 switch (c) {
536 default:
537 usage(stderr, EXIT_FAILURE);
538 case 'd':
539 if (directory == NULL)
540 directory = optarg;
541 else {
542 fprintf(stderr,
543 _("%s: More than one -d option specified\n"),
544 progname);
545 return EXIT_FAILURE;
546 }
547 break;
548 case 'l':
549 if (lcltime == NULL)
550 lcltime = optarg;
551 else {
552 fprintf(stderr,
553 _("%s: More than one -l option specified\n"),
554 progname);
555 return EXIT_FAILURE;
556 }
557 break;
558 case 'p':
559 if (psxrules == NULL)
560 psxrules = optarg;
561 else {
562 fprintf(stderr,
563 _("%s: More than one -p option specified\n"),
564 progname);
565 return EXIT_FAILURE;
566 }
567 break;
568 case 'y':
569 if (yitcommand == NULL)
570 yitcommand = optarg;
571 else {
572 fprintf(stderr,
573 _("%s: More than one -y option specified\n"),
574 progname);
575 return EXIT_FAILURE;
576 }
577 break;
578 case 'L':
579 if (leapsec == NULL)
580 leapsec = optarg;
581 else {
582 fprintf(stderr,
583 _("%s: More than one -L option specified\n"),
584 progname);
585 return EXIT_FAILURE;
586 }
587 break;
588 case 'v':
589 noise = true;
590 break;
591 case 's':
592 warning(_("-s ignored\n"));
593 break;
594 }
595 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
596 usage(stderr, EXIT_FAILURE); /* usage message by request */
597 if (directory == NULL)
598 directory = TZDIR;
599 if (yitcommand == NULL)
600 yitcommand = "yearistype";
601
602 if (optind < argc && leapsec != NULL) {
603 infile(leapsec);
604 adjleap();
605 }
606
607 for (i = optind; i < argc; ++i)
608 infile(argv[i]);
609 if (errors)
610 return EXIT_FAILURE;
611 associate();
612 for (i = 0; i < nzones; i = j) {
613 /*
614 ** Find the next non-continuation zone entry.
615 */
616 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
617 continue;
618 outzone(&zones[i], j - i);
619 }
620 /*
621 ** Make links.
622 */
623 for (i = 0; i < nlinks; ++i) {
624 eat(links[i].l_filename, links[i].l_linenum);
625 dolink(links[i].l_from, links[i].l_to);
626 if (noise)
627 for (j = 0; j < nlinks; ++j)
628 if (strcmp(links[i].l_to,
629 links[j].l_from) == 0)
630 warning(_("link to link"));
631 }
632 if (lcltime != NULL) {
633 eat(_("command line"), 1);
634 dolink(lcltime, TZDEFAULT);
635 }
636 if (psxrules != NULL) {
637 eat(_("command line"), 1);
638 dolink(psxrules, TZDEFRULES);
639 }
640 if (warnings && (ferror(stderr) || fclose(stderr) != 0))
641 return EXIT_FAILURE;
642 return errors ? EXIT_FAILURE : EXIT_SUCCESS;
643 }
644
645 static void
646 componentcheck(char const *name, char const *component,
647 char const *component_end)
648 {
649 enum { component_len_max = 14 };
650 size_t component_len = component_end - component;
651 if (0 < component_len && component_len <= 2
652 && component[0] == '.' && component_end[-1] == '.') {
653 fprintf(stderr, _("%s: file name '%s' contains"
654 " '%.*s' component"),
655 progname, name, (int) component_len, component);
656 exit(EXIT_FAILURE);
657 }
658 if (!noise)
659 return;
660 if (0 < component_len && component[0] == '-')
661 warning(_("file name '%s' component contains leading '-'"),
662 name);
663 if (component_len_max < component_len)
664 warning(_("file name '%s' contains overlength component"
665 " '%.*s...'"),
666 name, component_len_max, component);
667 }
668
669 static void
670 namecheck(const char *name)
671 {
672 char const *cp;
673
674 /* Benign characters in a portable file name. */
675 static char const benign[] =
676 "-/_"
677 "abcdefghijklmnopqrstuvwxyz"
678 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
679
680 /* Non-control chars in the POSIX portable character set,
681 excluding the benign characters. */
682 static char const printable_and_not_benign[] =
683 " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
684
685 char const *component = name;
686 for (cp = name; *cp; cp++) {
687 unsigned char c = *cp;
688 if (noise && !strchr(benign, c)) {
689 warning((strchr(printable_and_not_benign, c)
690 ? _("file name '%s' contains byte '%c'")
691 : _("file name '%s' contains byte '\\%o'")),
692 name, c);
693 return;
694 }
695 if (c == '/') {
696 componentcheck(name, component, cp);
697 component = cp + 1;
698 }
699 }
700 componentcheck(name, component, cp);
701 }
702
703 static void
704 dolink(const char *const fromfield, const char *const tofield)
705 {
706 char * fromname;
707 char * toname;
708 int fromisdir;
709
710 namecheck(tofield);
711 if (fromfield[0] == '/')
712 fromname = ecpyalloc(fromfield);
713 else {
714 fromname = ecpyalloc(directory);
715 fromname = ecatalloc(fromname, "/");
716 fromname = ecatalloc(fromname, fromfield);
717 }
718 if (tofield[0] == '/')
719 toname = ecpyalloc(tofield);
720 else {
721 toname = ecpyalloc(directory);
722 toname = ecatalloc(toname, "/");
723 toname = ecatalloc(toname, tofield);
724 }
725 /*
726 ** We get to be careful here since
727 ** there's a fair chance of root running us.
728 */
729 fromisdir = itsdir(fromname);
730 if (fromisdir) {
731 char const *e = strerror(fromisdir < 0 ? errno : EPERM);
732 fprintf(stderr, _("%s: link from %s failed: %s"),
733 progname, fromname, e);
734 exit(EXIT_FAILURE);
735 }
736 if (itsdir(toname) <= 0)
737 remove(toname);
738 if (link(fromname, toname) != 0) {
739 int result;
740
741 if (! mkdirs(toname))
742 exit(EXIT_FAILURE);
743
744 result = link(fromname, toname);
745 if (result != 0) {
746 const char *s = fromfield;
747 const char *t;
748 char * symlinkcontents = NULL;
749
750 do
751 t = s;
752 while ((s = strchr(s, '/'))
753 && ! strncmp (fromfield, tofield,
754 ++s - fromfield));
755
756 for (s = tofield + (t - fromfield);
757 (s = strchr(s, '/'));
758 s++)
759 symlinkcontents =
760 ecatalloc(symlinkcontents,
761 "../");
762 symlinkcontents = ecatalloc(symlinkcontents, t);
763 result = symlink(symlinkcontents, toname);
764 if (result == 0)
765 warning(_("hard link failed, symbolic link used"));
766 free(symlinkcontents);
767 }
768 if (result != 0) {
769 FILE *fp, *tp;
770 int c;
771 fp = fopen(fromname, "rb");
772 if (!fp) {
773 const char *e = strerror(errno);
774 fprintf(stderr,
775 _("%s: Can't read %s: %s\n"),
776 progname, fromname, e);
777 exit(EXIT_FAILURE);
778 }
779 tp = fopen(toname, "wb");
780 if (!tp) {
781 const char *e = strerror(errno);
782 fprintf(stderr,
783 _("%s: Can't create %s: %s\n"),
784 progname, toname, e);
785 exit(EXIT_FAILURE);
786 }
787 while ((c = getc(fp)) != EOF)
788 putc(c, tp);
789 close_file(fp, fromname);
790 close_file(tp, toname);
791 warning(_("link failed, copy used"));
792 }
793 }
794 free(fromname);
795 free(toname);
796 }
797
798 #define TIME_T_BITS_IN_FILE 64
799
800 static const zic_t min_time = (zic_t) -1 << (TIME_T_BITS_IN_FILE - 1);
801 static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1));
802
803 /* Estimated time of the Big Bang, in seconds since the POSIX epoch.
804 rounded downward to the negation of a power of two that is
805 comfortably outside the error bounds.
806
807 zic does not output time stamps before this, partly because they
808 are physically suspect, and partly because GNOME mishandles them; see
809 GNOME bug 730332 <https://bugzilla.gnome.org/show_bug.cgi?id=730332>.
810
811 For the time of the Big Bang, see:
812
813 Ade PAR, Aghanim N, Armitage-Caplan C et al. Planck 2013 results.
814 I. Overview of products and scientific results.
815 arXiv:1303.5062 2013-03-20 20:10:01 UTC
816 <http://arxiv.org/pdf/1303.5062v1> [PDF]
817
818 Page 36, Table 9, row Age/Gyr, column Planck+WP+highL+BAO 68% limits
819 gives the value 13.798 plus-or-minus 0.037 billion years.
820 Multiplying this by 1000000000 and then by 31557600 (the number of
821 seconds in an astronomical year) gives a value that is comfortably
822 less than 2**59, so BIG_BANG is - 2**59.
823
824 BIG_BANG is approximate, and may change in future versions.
825 Please do not rely on its exact value. */
826
827 #ifndef BIG_BANG
828 #define BIG_BANG (- (1LL << 59))
829 #endif
830
831 static const zic_t big_bang_time = BIG_BANG;
832
833 /* Return 1 if NAME is a directory, 0 if it's something else, -1 if trouble. */
834 static int
835 itsdir(const char *const name)
836 {
837 struct stat st;
838 int res = stat(name, &st);
839 if (res != 0)
840 return res;
841 #ifdef S_ISDIR
842 return S_ISDIR(st.st_mode) != 0;
843 #else
844 {
845 char *nameslashdot = ecatalloc(ecpyalloc(name), "/.");
846 res = stat(nameslashdot, &st);
847 free(nameslashdot);
848 return res == 0;
849 }
850 #endif
851 }
852
853 /*
854 ** Associate sets of rules with zones.
855 */
856
857 /*
858 ** Sort by rule name.
859 */
860
861 static int
862 rcomp(const void *cp1, const void *cp2)
863 {
864 return strcmp(((const struct rule *) cp1)->r_name,
865 ((const struct rule *) cp2)->r_name);
866 }
867
868 static void
869 associate(void)
870 {
871 struct zone * zp;
872 struct rule * rp;
873 int base, out;
874 int i, j;
875
876 if (nrules != 0) {
877 (void) qsort(rules, (size_t)nrules, sizeof *rules, rcomp);
878 for (i = 0; i < nrules - 1; ++i) {
879 if (strcmp(rules[i].r_name,
880 rules[i + 1].r_name) != 0)
881 continue;
882 if (strcmp(rules[i].r_filename,
883 rules[i + 1].r_filename) == 0)
884 continue;
885 eat(rules[i].r_filename, rules[i].r_linenum);
886 warning(_("same rule name in multiple files"));
887 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
888 warning(_("same rule name in multiple files"));
889 for (j = i + 2; j < nrules; ++j) {
890 if (strcmp(rules[i].r_name,
891 rules[j].r_name) != 0)
892 break;
893 if (strcmp(rules[i].r_filename,
894 rules[j].r_filename) == 0)
895 continue;
896 if (strcmp(rules[i + 1].r_filename,
897 rules[j].r_filename) == 0)
898 continue;
899 break;
900 }
901 i = j - 1;
902 }
903 }
904 for (i = 0; i < nzones; ++i) {
905 zp = &zones[i];
906 zp->z_rules = NULL;
907 zp->z_nrules = 0;
908 }
909 for (base = 0; base < nrules; base = out) {
910 rp = &rules[base];
911 for (out = base + 1; out < nrules; ++out)
912 if (strcmp(rp->r_name, rules[out].r_name) != 0)
913 break;
914 for (i = 0; i < nzones; ++i) {
915 zp = &zones[i];
916 if (strcmp(zp->z_rule, rp->r_name) != 0)
917 continue;
918 zp->z_rules = rp;
919 zp->z_nrules = out - base;
920 }
921 }
922 for (i = 0; i < nzones; ++i) {
923 zp = &zones[i];
924 if (zp->z_nrules == 0) {
925 /*
926 ** Maybe we have a local standard time offset.
927 */
928 eat(zp->z_filename, zp->z_linenum);
929 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
930 true);
931 /*
932 ** Note, though, that if there's no rule,
933 ** a '%s' in the format is a bad thing.
934 */
935 if (strchr(zp->z_format, '%') != 0)
936 error("%s", _("%s in ruleless zone"));
937 }
938 }
939 if (errors)
940 exit(EXIT_FAILURE);
941 }
942
943 static void
944 infile(const char *name)
945 {
946 FILE * fp;
947 char ** fields;
948 char * cp;
949 const struct lookup * lp;
950 int nfields;
951 bool wantcont;
952 int num;
953 char buf[BUFSIZ];
954
955 if (strcmp(name, "-") == 0) {
956 name = _("standard input");
957 fp = stdin;
958 } else if ((fp = fopen(name, "r")) == NULL) {
959 const char *e = strerror(errno);
960
961 fprintf(stderr, _("%s: Can't open %s: %s\n"),
962 progname, name, e);
963 exit(EXIT_FAILURE);
964 }
965 wantcont = false;
966 for (num = 1; ; ++num) {
967 eat(name, num);
968 if (fgets(buf, (int) sizeof buf, fp) != buf)
969 break;
970 cp = strchr(buf, '\n');
971 if (cp == NULL) {
972 error(_("line too long"));
973 exit(EXIT_FAILURE);
974 }
975 *cp = '\0';
976 fields = getfields(buf);
977 nfields = 0;
978 while (fields[nfields] != NULL) {
979 static char nada;
980
981 if (strcmp(fields[nfields], "-") == 0)
982 fields[nfields] = &nada;
983 ++nfields;
984 }
985 if (nfields == 0) {
986 /* nothing to do */
987 } else if (wantcont) {
988 wantcont = inzcont(fields, nfields);
989 } else {
990 lp = byword(fields[0], line_codes);
991 if (lp == NULL)
992 error(_("input line of unknown type"));
993 else switch ((int) (lp->l_value)) {
994 case LC_RULE:
995 inrule(fields, nfields);
996 wantcont = false;
997 break;
998 case LC_ZONE:
999 wantcont = inzone(fields, nfields);
1000 break;
1001 case LC_LINK:
1002 inlink(fields, nfields);
1003 wantcont = false;
1004 break;
1005 case LC_LEAP:
1006 if (name != leapsec)
1007 warning(
1008 _("%s: Leap line in non leap seconds file %s\n"),
1009 progname, name);
1010 else inleap(fields, nfields);
1011 wantcont = false;
1012 break;
1013 default: /* "cannot happen" */
1014 fprintf(stderr,
1015 _("%s: panic: Invalid l_value %d\n"),
1016 progname, lp->l_value);
1017 exit(EXIT_FAILURE);
1018 }
1019 }
1020 free(fields);
1021 }
1022 close_file(fp, filename);
1023 if (wantcont)
1024 error(_("expected continuation line not found"));
1025 }
1026
1027 /*
1028 ** Convert a string of one of the forms
1029 ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1030 ** into a number of seconds.
1031 ** A null string maps to zero.
1032 ** Call error with errstring and return zero on errors.
1033 */
1034
1035 static zic_t
1036 gethms(char const *string, char const *errstring, bool signable)
1037 {
1038 zic_t hh;
1039 int mm, ss, sign;
1040
1041 if (string == NULL || *string == '\0')
1042 return 0;
1043 if (!signable)
1044 sign = 1;
1045 else if (*string == '-') {
1046 sign = -1;
1047 ++string;
1048 } else sign = 1;
1049 if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1)
1050 mm = ss = 0;
1051 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2)
1052 ss = 0;
1053 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"),
1054 &hh, &mm, &ss) != 3) {
1055 error("%s", errstring);
1056 return 0;
1057 }
1058 if (hh < 0 ||
1059 mm < 0 || mm >= MINSPERHOUR ||
1060 ss < 0 || ss > SECSPERMIN) {
1061 error("%s", errstring);
1062 return 0;
1063 }
1064 if (ZIC_MAX / SECSPERHOUR < hh) {
1065 error(_("time overflow"));
1066 return 0;
1067 }
1068 if (noise && (hh > HOURSPERDAY ||
1069 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1070 warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
1071 return oadd(sign * hh * SECSPERHOUR,
1072 sign * (mm * SECSPERMIN + ss));
1073 }
1074
1075 static void
1076 inrule(char **const fields, const int nfields)
1077 {
1078 static struct rule r;
1079
1080 if (nfields != RULE_FIELDS) {
1081 error(_("wrong number of fields on Rule line"));
1082 return;
1083 }
1084 if (*fields[RF_NAME] == '\0') {
1085 error(_("nameless rule"));
1086 return;
1087 }
1088 r.r_filename = filename;
1089 r.r_linenum = linenum;
1090 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
1091 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1092 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1093 r.r_name = ecpyalloc(fields[RF_NAME]);
1094 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1095 if (max_abbrvar_len < strlen(r.r_abbrvar))
1096 max_abbrvar_len = strlen(r.r_abbrvar);
1097 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
1098 rules[nrules++] = r;
1099 }
1100
1101 static bool
1102 inzone(char **const fields, const int nfields)
1103 {
1104 int i;
1105
1106 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1107 error(_("wrong number of fields on Zone line"));
1108 return false;
1109 }
1110 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
1111 error(
1112 _("\"Zone %s\" line and -l option are mutually exclusive"),
1113 TZDEFAULT);
1114 return false;
1115 }
1116 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
1117 error(
1118 _("\"Zone %s\" line and -p option are mutually exclusive"),
1119 TZDEFRULES);
1120 return false;
1121 }
1122 for (i = 0; i < nzones; ++i)
1123 if (zones[i].z_name != NULL &&
1124 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
1125 error(
1126 _("duplicate zone name %s (file \"%s\", line %d)"),
1127 fields[ZF_NAME],
1128 zones[i].z_filename,
1129 zones[i].z_linenum);
1130 return false;
1131 }
1132 return inzsub(fields, nfields, false);
1133 }
1134
1135 static bool
1136 inzcont(char **const fields, const int nfields)
1137 {
1138 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1139 error(_("wrong number of fields on Zone continuation line"));
1140 return false;
1141 }
1142 return inzsub(fields, nfields, true);
1143 }
1144
1145 static bool
1146 inzsub(char **const fields, const int nfields, const int iscont)
1147 {
1148 char * cp;
1149 static struct zone z;
1150 int i_gmtoff, i_rule, i_format;
1151 int i_untilyear, i_untilmonth;
1152 int i_untilday, i_untiltime;
1153 bool hasuntil;
1154
1155 if (iscont) {
1156 i_gmtoff = ZFC_GMTOFF;
1157 i_rule = ZFC_RULE;
1158 i_format = ZFC_FORMAT;
1159 i_untilyear = ZFC_TILYEAR;
1160 i_untilmonth = ZFC_TILMONTH;
1161 i_untilday = ZFC_TILDAY;
1162 i_untiltime = ZFC_TILTIME;
1163 z.z_name = NULL;
1164 } else {
1165 i_gmtoff = ZF_GMTOFF;
1166 i_rule = ZF_RULE;
1167 i_format = ZF_FORMAT;
1168 i_untilyear = ZF_TILYEAR;
1169 i_untilmonth = ZF_TILMONTH;
1170 i_untilday = ZF_TILDAY;
1171 i_untiltime = ZF_TILTIME;
1172 z.z_name = ecpyalloc(fields[ZF_NAME]);
1173 }
1174 z.z_filename = filename;
1175 z.z_linenum = linenum;
1176 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
1177 if ((cp = strchr(fields[i_format], '%')) != 0) {
1178 if (*++cp != 's' || strchr(cp, '%') != 0) {
1179 error(_("invalid abbreviation format"));
1180 return false;
1181 }
1182 }
1183 z.z_rule = ecpyalloc(fields[i_rule]);
1184 z.z_format = ecpyalloc(fields[i_format]);
1185 if (max_format_len < strlen(z.z_format))
1186 max_format_len = strlen(z.z_format);
1187 hasuntil = nfields > i_untilyear;
1188 if (hasuntil) {
1189 z.z_untilrule.r_filename = filename;
1190 z.z_untilrule.r_linenum = linenum;
1191 rulesub(&z.z_untilrule,
1192 fields[i_untilyear],
1193 "only",
1194 "",
1195 (nfields > i_untilmonth) ?
1196 fields[i_untilmonth] : "Jan",
1197 (nfields > i_untilday) ? fields[i_untilday] : "1",
1198 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1199 z.z_untiltime = rpytime(&z.z_untilrule,
1200 z.z_untilrule.r_loyear);
1201 if (iscont && nzones > 0 &&
1202 z.z_untiltime > min_time &&
1203 z.z_untiltime < max_time &&
1204 zones[nzones - 1].z_untiltime > min_time &&
1205 zones[nzones - 1].z_untiltime < max_time &&
1206 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1207 error(_(
1208 "Zone continuation line end time is not after end time of previous line"
1209 ));
1210 return false;
1211 }
1212 }
1213 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
1214 zones[nzones++] = z;
1215 /*
1216 ** If there was an UNTIL field on this line,
1217 ** there's more information about the zone on the next line.
1218 */
1219 return hasuntil;
1220 }
1221
1222 static void
1223 inleap(char **const fields, const int nfields)
1224 {
1225 const char * cp;
1226 const struct lookup * lp;
1227 int i, j;
1228 zic_t year;
1229 int month, day;
1230 zic_t dayoff, tod;
1231 zic_t t;
1232
1233 if (nfields != LEAP_FIELDS) {
1234 error(_("wrong number of fields on Leap line"));
1235 return;
1236 }
1237 dayoff = 0;
1238 cp = fields[LP_YEAR];
1239 if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) {
1240 /*
1241 ** Leapin' Lizards!
1242 */
1243 error(_("invalid leaping year"));
1244 return;
1245 }
1246 if (!leapseen || leapmaxyear < year)
1247 leapmaxyear = year;
1248 if (!leapseen || leapminyear > year)
1249 leapminyear = year;
1250 leapseen = true;
1251 j = EPOCH_YEAR;
1252 while (j != year) {
1253 if (year > j) {
1254 i = len_years[isleap(j)];
1255 ++j;
1256 } else {
1257 --j;
1258 i = -len_years[isleap(j)];
1259 }
1260 dayoff = oadd(dayoff, i);
1261 }
1262 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1263 error(_("invalid month name"));
1264 return;
1265 }
1266 month = lp->l_value;
1267 j = TM_JANUARY;
1268 while (j != month) {
1269 i = len_months[isleap(year)][j];
1270 dayoff = oadd(dayoff, i);
1271 ++j;
1272 }
1273 cp = fields[LP_DAY];
1274 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1275 day <= 0 || day > len_months[isleap(year)][month]) {
1276 error(_("invalid day of month"));
1277 return;
1278 }
1279 dayoff = oadd(dayoff, day - 1);
1280 if (dayoff < min_time / SECSPERDAY) {
1281 error(_("time too small"));
1282 return;
1283 }
1284 if (dayoff > max_time / SECSPERDAY) {
1285 error(_("time too large"));
1286 return;
1287 }
1288 t = dayoff * SECSPERDAY;
1289 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
1290 cp = fields[LP_CORR];
1291 {
1292 bool positive;
1293 int count;
1294
1295 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1296 positive = false;
1297 count = 1;
1298 } else if (strcmp(cp, "--") == 0) {
1299 positive = false;
1300 count = 2;
1301 } else if (strcmp(cp, "+") == 0) {
1302 positive = true;
1303 count = 1;
1304 } else if (strcmp(cp, "++") == 0) {
1305 positive = true;
1306 count = 2;
1307 } else {
1308 error(_("illegal CORRECTION field on Leap line"));
1309 return;
1310 }
1311 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1312 error(_(
1313 "illegal Rolling/Stationary field on Leap line"
1314 ));
1315 return;
1316 }
1317 t = tadd(t, tod);
1318 if (t < big_bang_time) {
1319 error(_("leap second precedes Big Bang"));
1320 return;
1321 }
1322 leapadd(t, positive, lp->l_value, count);
1323 }
1324 }
1325
1326 static void
1327 inlink(char **const fields, const int nfields)
1328 {
1329 struct link l;
1330
1331 if (nfields != LINK_FIELDS) {
1332 error(_("wrong number of fields on Link line"));
1333 return;
1334 }
1335 if (*fields[LF_FROM] == '\0') {
1336 error(_("blank FROM field on Link line"));
1337 return;
1338 }
1339 if (*fields[LF_TO] == '\0') {
1340 error(_("blank TO field on Link line"));
1341 return;
1342 }
1343 l.l_filename = filename;
1344 l.l_linenum = linenum;
1345 l.l_from = ecpyalloc(fields[LF_FROM]);
1346 l.l_to = ecpyalloc(fields[LF_TO]);
1347 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
1348 links[nlinks++] = l;
1349 }
1350
1351 static void
1352 rulesub(struct rule *const rp, const char *const loyearp,
1353 const char *const hiyearp, const char *const typep,
1354 const char *const monthp, const char *const dayp, const char *const timep)
1355 {
1356 const struct lookup * lp;
1357 const char * cp;
1358 char * dp;
1359 char * ep;
1360
1361 if ((lp = byword(monthp, mon_names)) == NULL) {
1362 error(_("invalid month name"));
1363 return;
1364 }
1365 rp->r_month = lp->l_value;
1366 rp->r_todisstd = false;
1367 rp->r_todisgmt = false;
1368 dp = ecpyalloc(timep);
1369 if (*dp != '\0') {
1370 ep = dp + strlen(dp) - 1;
1371 switch (lowerit(*ep)) {
1372 case 's': /* Standard */
1373 rp->r_todisstd = true;
1374 rp->r_todisgmt = false;
1375 *ep = '\0';
1376 break;
1377 case 'w': /* Wall */
1378 rp->r_todisstd = false;
1379 rp->r_todisgmt = false;
1380 *ep = '\0';
1381 break;
1382 case 'g': /* Greenwich */
1383 case 'u': /* Universal */
1384 case 'z': /* Zulu */
1385 rp->r_todisstd = true;
1386 rp->r_todisgmt = true;
1387 *ep = '\0';
1388 break;
1389 }
1390 }
1391 rp->r_tod = gethms(dp, _("invalid time of day"), false);
1392 free(dp);
1393 /*
1394 ** Year work.
1395 */
1396 cp = loyearp;
1397 lp = byword(cp, begin_years);
1398 rp->r_lowasnum = lp == NULL;
1399 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1400 case YR_MINIMUM:
1401 rp->r_loyear = ZIC_MIN;
1402 break;
1403 case YR_MAXIMUM:
1404 rp->r_loyear = ZIC_MAX;
1405 break;
1406 default: /* "cannot happen" */
1407 fprintf(stderr,
1408 _("%s: panic: Invalid l_value %d\n"),
1409 progname, lp->l_value);
1410 exit(EXIT_FAILURE);
1411 } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_loyear) != 1) {
1412 error(_("invalid starting year"));
1413 return;
1414 }
1415 cp = hiyearp;
1416 lp = byword(cp, end_years);
1417 rp->r_hiwasnum = lp == NULL;
1418 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1419 case YR_MINIMUM:
1420 rp->r_hiyear = ZIC_MIN;
1421 break;
1422 case YR_MAXIMUM:
1423 rp->r_hiyear = ZIC_MAX;
1424 break;
1425 case YR_ONLY:
1426 rp->r_hiyear = rp->r_loyear;
1427 break;
1428 default: /* "cannot happen" */
1429 fprintf(stderr,
1430 _("%s: panic: Invalid l_value %d\n"),
1431 progname, lp->l_value);
1432 exit(EXIT_FAILURE);
1433 } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_hiyear) != 1) {
1434 error(_("invalid ending year"));
1435 return;
1436 }
1437 if (rp->r_loyear > rp->r_hiyear) {
1438 error(_("starting year greater than ending year"));
1439 return;
1440 }
1441 if (*typep == '\0')
1442 rp->r_yrtype = NULL;
1443 else {
1444 if (rp->r_loyear == rp->r_hiyear) {
1445 error(_("typed single year"));
1446 return;
1447 }
1448 rp->r_yrtype = ecpyalloc(typep);
1449 }
1450 /*
1451 ** Day work.
1452 ** Accept things such as:
1453 ** 1
1454 ** last-Sunday
1455 ** Sun<=20
1456 ** Sun>=7
1457 */
1458 dp = ecpyalloc(dayp);
1459 if ((lp = byword(dp, lasts)) != NULL) {
1460 rp->r_dycode = DC_DOWLEQ;
1461 rp->r_wday = lp->l_value;
1462 rp->r_dayofmonth = len_months[1][rp->r_month];
1463 } else {
1464 if ((ep = strchr(dp, '<')) != 0)
1465 rp->r_dycode = DC_DOWLEQ;
1466 else if ((ep = strchr(dp, '>')) != 0)
1467 rp->r_dycode = DC_DOWGEQ;
1468 else {
1469 ep = dp;
1470 rp->r_dycode = DC_DOM;
1471 }
1472 if (rp->r_dycode != DC_DOM) {
1473 *ep++ = 0;
1474 if (*ep++ != '=') {
1475 error(_("invalid day of month"));
1476 free(dp);
1477 return;
1478 }
1479 if ((lp = byword(dp, wday_names)) == NULL) {
1480 error(_("invalid weekday name"));
1481 free(dp);
1482 return;
1483 }
1484 rp->r_wday = lp->l_value;
1485 }
1486 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1487 rp->r_dayofmonth <= 0 ||
1488 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1489 error(_("invalid day of month"));
1490 free(dp);
1491 return;
1492 }
1493 }
1494 free(dp);
1495 }
1496
1497 static void
1498 convert(const zic_t val, char *const buf)
1499 {
1500 int i;
1501 int shift;
1502 unsigned char *const b = (unsigned char *) buf;
1503
1504 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1505 b[i] = val >> shift;
1506 }
1507
1508 static void
1509 convert64(const zic_t val, char *const buf)
1510 {
1511 int i;
1512 int shift;
1513 unsigned char *const b = (unsigned char *) buf;
1514
1515 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
1516 b[i] = val >> shift;
1517 }
1518
1519 static void
1520 puttzcode(const zic_t val, FILE *const fp)
1521 {
1522 char buf[4];
1523
1524 convert(val, buf);
1525 (void) fwrite(buf, sizeof buf, (size_t) 1, fp);
1526 }
1527
1528 static void
1529 puttzcode64(const zic_t val, FILE *const fp)
1530 {
1531 char buf[8];
1532
1533 convert64(val, buf);
1534 (void) fwrite(buf, sizeof buf, (size_t) 1, fp);
1535 }
1536
1537 static int
1538 atcomp(const void *avp, const void *bvp)
1539 {
1540 const zic_t a = ((const struct attype *) avp)->at;
1541 const zic_t b = ((const struct attype *) bvp)->at;
1542
1543 return (a < b) ? -1 : (a > b);
1544 }
1545
1546 static bool
1547 is32(const zic_t x)
1548 {
1549 return INT32_MIN <= x && x <= INT32_MAX;
1550 }
1551
1552 static void
1553 writezone(const char *const name, const char *const string, char version)
1554 {
1555 FILE * fp;
1556 int i, j;
1557 int leapcnt32, leapi32;
1558 int timecnt32, timei32;
1559 int pass;
1560 static char * fullname;
1561 static const struct tzhead tzh0;
1562 static struct tzhead tzh;
1563 zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
1564 void *typesptr = ats + timecnt;
1565 unsigned char *types = typesptr;
1566
1567 namecheck(name);
1568 /*
1569 ** Sort.
1570 */
1571 if (timecnt > 1)
1572 (void) qsort(attypes, (size_t) timecnt, sizeof *attypes,
1573 atcomp);
1574 /*
1575 ** Optimize.
1576 */
1577 {
1578 int fromi;
1579 int toi;
1580
1581 toi = 0;
1582 fromi = 0;
1583 while (fromi < timecnt && attypes[fromi].at < big_bang_time)
1584 ++fromi;
1585 for ( ; fromi < timecnt; ++fromi) {
1586 if (toi > 1 && ((attypes[fromi].at +
1587 gmtoffs[attypes[toi - 1].type]) <=
1588 (attypes[toi - 1].at +
1589 gmtoffs[attypes[toi - 2].type]))) {
1590 attypes[toi - 1].type =
1591 attypes[fromi].type;
1592 continue;
1593 }
1594 if (toi == 0 ||
1595 attypes[toi - 1].type != attypes[fromi].type)
1596 attypes[toi++] = attypes[fromi];
1597 }
1598 timecnt = toi;
1599 }
1600 if (noise && timecnt > 1200)
1601 warning(_("pre-2014 clients may mishandle"
1602 " more than 1200 transition times"));
1603 /*
1604 ** Transfer.
1605 */
1606 for (i = 0; i < timecnt; ++i) {
1607 ats[i] = attypes[i].at;
1608 types[i] = attypes[i].type;
1609 }
1610 /*
1611 ** Correct for leap seconds.
1612 */
1613 for (i = 0; i < timecnt; ++i) {
1614 j = leapcnt;
1615 while (--j >= 0)
1616 if (ats[i] > trans[j] - corr[j]) {
1617 ats[i] = tadd(ats[i], corr[j]);
1618 break;
1619 }
1620 }
1621 /*
1622 ** Figure out 32-bit-limited starts and counts.
1623 */
1624 timecnt32 = timecnt;
1625 timei32 = 0;
1626 leapcnt32 = leapcnt;
1627 leapi32 = 0;
1628 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1629 --timecnt32;
1630 while (timecnt32 > 0 && !is32(ats[timei32])) {
1631 --timecnt32;
1632 ++timei32;
1633 }
1634 /*
1635 ** Output an INT32_MIN "transition" if appropriate; see below.
1636 */
1637 if (timei32 > 0 && ats[timei32] > INT32_MIN) {
1638 --timei32;
1639 ++timecnt32;
1640 }
1641 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1642 --leapcnt32;
1643 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1644 --leapcnt32;
1645 ++leapi32;
1646 }
1647 fullname = erealloc(fullname,
1648 strlen(directory) + 1 + strlen(name) + 1);
1649 (void) sprintf(fullname, "%s/%s", directory, name); /* XXX: sprintf is safe */
1650 /*
1651 ** Remove old file, if any, to snap links.
1652 */
1653 if (itsdir(fullname) <= 0 && remove(fullname) != 0 && errno != ENOENT) {
1654 const char *e = strerror(errno);
1655
1656 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1657 progname, fullname, e);
1658 exit(EXIT_FAILURE);
1659 }
1660 if ((fp = fopen(fullname, "wb")) == NULL) {
1661 if (! mkdirs(fullname))
1662 exit(EXIT_FAILURE);
1663 if ((fp = fopen(fullname, "wb")) == NULL) {
1664 const char *e = strerror(errno);
1665
1666 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1667 progname, fullname, e);
1668 exit(EXIT_FAILURE);
1669 }
1670 }
1671 for (pass = 1; pass <= 2; ++pass) {
1672 int thistimei, thistimecnt;
1673 int thisleapi, thisleapcnt;
1674 int thistimelim, thisleaplim;
1675 int writetype[TZ_MAX_TYPES];
1676 int typemap[TZ_MAX_TYPES];
1677 int thistypecnt;
1678 char thischars[TZ_MAX_CHARS];
1679 char thischarcnt;
1680 int indmap[TZ_MAX_CHARS];
1681
1682 if (pass == 1) {
1683 thistimei = timei32;
1684 thistimecnt = timecnt32;
1685 thisleapi = leapi32;
1686 thisleapcnt = leapcnt32;
1687 } else {
1688 thistimei = 0;
1689 thistimecnt = timecnt;
1690 thisleapi = 0;
1691 thisleapcnt = leapcnt;
1692 }
1693 thistimelim = thistimei + thistimecnt;
1694 thisleaplim = thisleapi + thisleapcnt;
1695 for (i = 0; i < typecnt; ++i)
1696 writetype[i] = thistimecnt == timecnt;
1697 if (thistimecnt == 0) {
1698 /*
1699 ** No transition times fall in the current
1700 ** (32- or 64-bit) window.
1701 */
1702 if (typecnt != 0)
1703 writetype[typecnt - 1] = true;
1704 } else {
1705 for (i = thistimei - 1; i < thistimelim; ++i)
1706 if (i >= 0)
1707 writetype[types[i]] = true;
1708 /*
1709 ** For America/Godthab and Antarctica/Palmer
1710 */
1711 if (thistimei == 0)
1712 writetype[0] = true;
1713 }
1714 #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1715 /*
1716 ** For some pre-2011 systems: if the last-to-be-written
1717 ** standard (or daylight) type has an offset different from the
1718 ** most recently used offset,
1719 ** append an (unused) copy of the most recently used type
1720 ** (to help get global "altzone" and "timezone" variables
1721 ** set correctly).
1722 */
1723 {
1724 int mrudst, mrustd, hidst, histd, type;
1725
1726 hidst = histd = mrudst = mrustd = -1;
1727 for (i = thistimei; i < thistimelim; ++i) {
1728 if (i < 0)
1729 continue;
1730 if (isdsts[types[i]])
1731 mrudst = types[i];
1732 else mrustd = types[i];
1733 }
1734 for (i = 0; i < typecnt; ++i)
1735 if (writetype[i]) {
1736 if (isdsts[i])
1737 hidst = i;
1738 else histd = i;
1739 }
1740 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1741 gmtoffs[hidst] != gmtoffs[mrudst]) {
1742 isdsts[mrudst] = -1;
1743 type = addtype(gmtoffs[mrudst],
1744 &chars[abbrinds[mrudst]],
1745 true,
1746 ttisstds[mrudst],
1747 ttisgmts[mrudst]);
1748 isdsts[mrudst] = 1;
1749 writetype[type] = true;
1750 }
1751 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1752 gmtoffs[histd] != gmtoffs[mrustd]) {
1753 isdsts[mrustd] = -1;
1754 type = addtype(gmtoffs[mrustd],
1755 &chars[abbrinds[mrustd]],
1756 false,
1757 ttisstds[mrustd],
1758 ttisgmts[mrustd]);
1759 isdsts[mrustd] = 0;
1760 writetype[type] = true;
1761 }
1762 }
1763 #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
1764 thistypecnt = 0;
1765 for (i = 0; i < typecnt; ++i)
1766 typemap[i] = writetype[i] ? thistypecnt++ : -1;
1767 for (i = 0; i < (int)(sizeof indmap / sizeof indmap[0]); ++i)
1768 indmap[i] = -1;
1769 thischarcnt = 0;
1770 for (i = 0; i < typecnt; ++i) {
1771 char * thisabbr;
1772
1773 if (!writetype[i])
1774 continue;
1775 if (indmap[abbrinds[i]] >= 0)
1776 continue;
1777 thisabbr = &chars[abbrinds[i]];
1778 for (j = 0; j < thischarcnt; ++j)
1779 if (strcmp(&thischars[j], thisabbr) == 0)
1780 break;
1781 if (j == thischarcnt) {
1782 (void) strcpy(&thischars[(int) thischarcnt],
1783 thisabbr);
1784 thischarcnt += strlen(thisabbr) + 1;
1785 }
1786 indmap[abbrinds[i]] = j;
1787 }
1788 #define DO(field) (void) fwrite(tzh.field, \
1789 sizeof tzh.field, (size_t) 1, fp)
1790 tzh = tzh0;
1791 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1792 tzh.tzh_version[0] = version;
1793 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1794 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1795 convert(thisleapcnt, tzh.tzh_leapcnt);
1796 convert(thistimecnt, tzh.tzh_timecnt);
1797 convert(thistypecnt, tzh.tzh_typecnt);
1798 convert(thischarcnt, tzh.tzh_charcnt);
1799 DO(tzh_magic);
1800 DO(tzh_version);
1801 DO(tzh_reserved);
1802 DO(tzh_ttisgmtcnt);
1803 DO(tzh_ttisstdcnt);
1804 DO(tzh_leapcnt);
1805 DO(tzh_timecnt);
1806 DO(tzh_typecnt);
1807 DO(tzh_charcnt);
1808 #undef DO
1809 for (i = thistimei; i < thistimelim; ++i)
1810 if (pass == 1)
1811 /*
1812 ** Output an INT32_MIN "transition"
1813 ** if appropriate; see above.
1814 */
1815 puttzcode(((ats[i] < INT32_MIN) ?
1816 INT32_MIN : ats[i]), fp);
1817 else puttzcode64(ats[i], fp);
1818 for (i = thistimei; i < thistimelim; ++i) {
1819 unsigned char uc;
1820
1821 uc = typemap[types[i]];
1822 (void) fwrite(&uc, sizeof uc, (size_t) 1, fp);
1823 }
1824 for (i = 0; i < typecnt; ++i)
1825 if (writetype[i]) {
1826 puttzcode(gmtoffs[i], fp);
1827 (void) putc(isdsts[i], fp);
1828 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1829 }
1830 if (thischarcnt != 0)
1831 (void) fwrite(thischars, sizeof thischars[0],
1832 (size_t) thischarcnt, fp);
1833 for (i = thisleapi; i < thisleaplim; ++i) {
1834 zic_t todo;
1835
1836 if (roll[i]) {
1837 if (timecnt == 0 || trans[i] < ats[0]) {
1838 j = 0;
1839 while (isdsts[j])
1840 if (++j >= typecnt) {
1841 j = 0;
1842 break;
1843 }
1844 } else {
1845 j = 1;
1846 while (j < timecnt &&
1847 trans[i] >= ats[j])
1848 ++j;
1849 j = types[j - 1];
1850 }
1851 todo = tadd(trans[i], -gmtoffs[j]);
1852 } else todo = trans[i];
1853 if (pass == 1)
1854 puttzcode(todo, fp);
1855 else puttzcode64(todo, fp);
1856 puttzcode(corr[i], fp);
1857 }
1858 for (i = 0; i < typecnt; ++i)
1859 if (writetype[i])
1860 (void) putc(ttisstds[i], fp);
1861 for (i = 0; i < typecnt; ++i)
1862 if (writetype[i])
1863 (void) putc(ttisgmts[i], fp);
1864 }
1865 (void) fprintf(fp, "\n%s\n", string);
1866 close_file(fp, fullname);
1867 free(ats);
1868 }
1869
1870 static void
1871 doabbr(char *const abbr, const int abbrlen, const char *const format,
1872 const char *const letters, bool isdst, bool doquotes)
1873 {
1874 char * cp;
1875 char * slashp;
1876 int len;
1877
1878 slashp = strchr(format, '/');
1879 if (slashp == NULL) {
1880 if (letters == NULL)
1881 (void) strlcpy(abbr, format, abbrlen);
1882 else (void) snprintf(abbr, abbrlen, format, letters);
1883 } else if (isdst) {
1884 (void) strlcpy(abbr, slashp + 1, abbrlen);
1885 } else {
1886 (void) memcpy(abbr, format, slashp - format);
1887 abbr[slashp - format] = '\0';
1888 }
1889 if (!doquotes)
1890 return;
1891 for (cp = abbr; is_alpha(*cp); cp++)
1892 continue;
1893 len = strlen(abbr);
1894 if (len > 0 && *cp == '\0')
1895 return;
1896 abbr[len + 2] = '\0';
1897 abbr[len + 1] = '>';
1898 for ( ; len > 0; --len)
1899 abbr[len] = abbr[len - 1];
1900 abbr[0] = '<';
1901 }
1902
1903 static void
1904 updateminmax(const zic_t x)
1905 {
1906 if (min_year > x)
1907 min_year = x;
1908 if (max_year < x)
1909 max_year = x;
1910 }
1911
1912 static bool
1913 stringoffset(char *result, zic_t offset)
1914 {
1915 int hours;
1916 int minutes;
1917 int seconds;
1918
1919 result[0] = '\0';
1920 if (offset < 0) {
1921 strcpy(result, "-");
1922 offset = -offset;
1923 }
1924 seconds = offset % SECSPERMIN;
1925 offset /= SECSPERMIN;
1926 minutes = offset % MINSPERHOUR;
1927 offset /= MINSPERHOUR;
1928 hours = offset;
1929 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
1930 result[0] = '\0';
1931 return false;
1932 }
1933 sprintf(end(result), "%d", hours);
1934 if (minutes != 0 || seconds != 0) {
1935 sprintf(end(result), ":%02d", minutes);
1936 if (seconds != 0)
1937 sprintf(end(result), ":%02d", seconds);
1938 }
1939 return true;
1940 }
1941
1942 static int
1943 stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
1944 const zic_t gmtoff)
1945 {
1946 zic_t tod = rp->r_tod;
1947 int compat = 0;
1948
1949 result = end(result);
1950 if (rp->r_dycode == DC_DOM) {
1951 int month, total;
1952
1953 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
1954 return -1;
1955 total = 0;
1956 for (month = 0; month < rp->r_month; ++month)
1957 total += len_months[0][month];
1958 /* Omit the "J" in Jan and Feb, as that's shorter. */
1959 if (rp->r_month <= 1)
1960 sprintf(result, "%d", total + rp->r_dayofmonth - 1);
1961 else
1962 sprintf(result, "J%d", total + rp->r_dayofmonth);
1963 } else {
1964 int week;
1965 int wday = rp->r_wday;
1966 int wdayoff;
1967
1968 if (rp->r_dycode == DC_DOWGEQ) {
1969 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
1970 if (wdayoff)
1971 compat = 2013;
1972 wday -= wdayoff;
1973 tod += wdayoff * SECSPERDAY;
1974 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
1975 } else if (rp->r_dycode == DC_DOWLEQ) {
1976 if (rp->r_dayofmonth == len_months[1][rp->r_month])
1977 week = 5;
1978 else {
1979 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
1980 if (wdayoff)
1981 compat = 2013;
1982 wday -= wdayoff;
1983 tod += wdayoff * SECSPERDAY;
1984 week = rp->r_dayofmonth / DAYSPERWEEK;
1985 }
1986 } else return -1; /* "cannot happen" */
1987 if (wday < 0)
1988 wday += DAYSPERWEEK;
1989 sprintf(result, "M%d.%d.%d",
1990 rp->r_month + 1, week, wday);
1991 }
1992 if (rp->r_todisgmt)
1993 tod += gmtoff;
1994 if (rp->r_todisstd && rp->r_stdoff == 0)
1995 tod += dstoff;
1996 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
1997 strcat(result, "/");
1998 if (! stringoffset(end(result), tod))
1999 return -1;
2000 if (tod < 0) {
2001 if (compat < 2013)
2002 compat = 2013;
2003 } else if (SECSPERDAY <= tod) {
2004 if (compat < 1994)
2005 compat = 1994;
2006 }
2007 }
2008 return compat;
2009 }
2010
2011 static int
2012 rule_cmp(struct rule const *a, struct rule const *b)
2013 {
2014 if (!a)
2015 return -!!b;
2016 if (!b)
2017 return 1;
2018 if (a->r_hiyear != b->r_hiyear)
2019 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2020 if (a->r_month - b->r_month != 0)
2021 return a->r_month - b->r_month;
2022 return a->r_dayofmonth - b->r_dayofmonth;
2023 }
2024
2025 enum { YEAR_BY_YEAR_ZONE = 1 };
2026
2027 static int
2028 stringzone(char *result, const int resultlen, const struct zone *const zpfirst,
2029 const int zonecount)
2030 {
2031 const struct zone * zp;
2032 struct rule * rp;
2033 struct rule * stdrp;
2034 struct rule * dstrp;
2035 int i;
2036 const char * abbrvar;
2037 int compat = 0;
2038 int c;
2039 struct rule stdr, dstr;
2040
2041 result[0] = '\0';
2042 zp = zpfirst + zonecount - 1;
2043 stdrp = dstrp = NULL;
2044 for (i = 0; i < zp->z_nrules; ++i) {
2045 rp = &zp->z_rules[i];
2046 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
2047 continue;
2048 if (rp->r_yrtype != NULL)
2049 continue;
2050 if (rp->r_stdoff == 0) {
2051 if (stdrp == NULL)
2052 stdrp = rp;
2053 else return -1;
2054 } else {
2055 if (dstrp == NULL)
2056 dstrp = rp;
2057 else return -1;
2058 }
2059 }
2060 if (stdrp == NULL && dstrp == NULL) {
2061 /*
2062 ** There are no rules running through "max".
2063 ** Find the latest std rule in stdabbrrp
2064 ** and latest rule of any type in stdrp.
2065 */
2066 struct rule *stdabbrrp = NULL;
2067 for (i = 0; i < zp->z_nrules; ++i) {
2068 rp = &zp->z_rules[i];
2069 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2070 stdabbrrp = rp;
2071 if (rule_cmp(stdrp, rp) < 0)
2072 stdrp = rp;
2073 }
2074 /*
2075 ** Horrid special case: if year is 2037,
2076 ** presume this is a zone handled on a year-by-year basis;
2077 ** do not try to apply a rule to the zone.
2078 */
2079 if (stdrp != NULL && stdrp->r_hiyear == 2037)
2080 return YEAR_BY_YEAR_ZONE;
2081
2082 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2083 /* Perpetual DST. */
2084 dstr.r_month = TM_JANUARY;
2085 dstr.r_dycode = DC_DOM;
2086 dstr.r_dayofmonth = 1;
2087 dstr.r_tod = 0;
2088 dstr.r_todisstd = dstr.r_todisgmt = false;
2089 dstr.r_stdoff = stdrp->r_stdoff;
2090 dstr.r_abbrvar = stdrp->r_abbrvar;
2091 stdr.r_month = TM_DECEMBER;
2092 stdr.r_dycode = DC_DOM;
2093 stdr.r_dayofmonth = 31;
2094 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
2095 stdr.r_todisstd = stdr.r_todisgmt = false;
2096 stdr.r_stdoff = 0;
2097 stdr.r_abbrvar
2098 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2099 dstrp = &dstr;
2100 stdrp = &stdr;
2101 }
2102 }
2103 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2104 return -1;
2105 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
2106 doabbr(result, resultlen, zp->z_format, abbrvar, false, true);
2107 if (! stringoffset(end(result), -zp->z_gmtoff)) {
2108 result[0] = '\0';
2109 return -1;
2110 }
2111 if (dstrp == NULL)
2112 return compat;
2113 doabbr(end(result), resultlen - strlen(result),
2114 zp->z_format, dstrp->r_abbrvar, true, true);
2115 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
2116 if (! stringoffset(end(result),
2117 -(zp->z_gmtoff + dstrp->r_stdoff))) {
2118 result[0] = '\0';
2119 return -1;
2120 }
2121 (void) strcat(result, ",");
2122 c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2123 if (c < 0) {
2124 result[0] = '\0';
2125 return -1;
2126 }
2127 if (compat < c)
2128 compat = c;
2129 strcat(result, ",");
2130 c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2131 if (c < 0) {
2132 result[0] = '\0';
2133 return -1;
2134 }
2135 if (compat < c)
2136 compat = c;
2137 return compat;
2138 }
2139
2140 static void
2141 outzone(const struct zone *const zpfirst, const int zonecount)
2142 {
2143 const struct zone * zp;
2144 struct rule * rp;
2145 int i, j;
2146 bool usestart, useuntil;
2147 zic_t starttime, untiltime;
2148 zic_t gmtoff;
2149 zic_t stdoff;
2150 zic_t year;
2151 zic_t startoff;
2152 bool startttisstd;
2153 bool startttisgmt;
2154 int type;
2155 char * startbuf;
2156 char * ab;
2157 char * envvar;
2158 size_t max_abbr_len;
2159 size_t max_envvar_len;
2160 bool prodstic; /* all rules are min to max */
2161 int compat;
2162 bool do_extend;
2163 int version;
2164
2165 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2166 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2167 startbuf = emalloc(max_abbr_len + 1);
2168 ab = emalloc(max_abbr_len + 1);
2169 envvar = emalloc(max_envvar_len + 1);
2170 INITIALIZE(untiltime);
2171 INITIALIZE(starttime);
2172 /*
2173 ** Now. . .finally. . .generate some useful data!
2174 */
2175 timecnt = 0;
2176 typecnt = 0;
2177 charcnt = 0;
2178 prodstic = zonecount == 1;
2179 /*
2180 ** Thanks to Earl Chew
2181 ** for noting the need to unconditionally initialize startttisstd.
2182 */
2183 startttisstd = false;
2184 startttisgmt = false;
2185 min_year = max_year = EPOCH_YEAR;
2186 if (leapseen) {
2187 updateminmax(leapminyear);
2188 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
2189 }
2190 for (i = 0; i < zonecount; ++i) {
2191 zp = &zpfirst[i];
2192 if (i < zonecount - 1)
2193 updateminmax(zp->z_untilrule.r_loyear);
2194 for (j = 0; j < zp->z_nrules; ++j) {
2195 rp = &zp->z_rules[j];
2196 if (rp->r_lowasnum)
2197 updateminmax(rp->r_loyear);
2198 if (rp->r_hiwasnum)
2199 updateminmax(rp->r_hiyear);
2200 if (rp->r_lowasnum || rp->r_hiwasnum)
2201 prodstic = false;
2202 }
2203 }
2204 /*
2205 ** Generate lots of data if a rule can't cover all future times.
2206 */
2207 compat = stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
2208 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2209 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2210 if (noise) {
2211 if (!*envvar)
2212 warning("%s %s",
2213 _("no POSIX environment variable for zone"),
2214 zpfirst->z_name);
2215 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2216 /* Circa-COMPAT clients, and earlier clients, might
2217 not work for this zone when given dates before
2218 1970 or after 2038. */
2219 warning(_("%s: pre-%d clients may mishandle"
2220 " distant timestamps"),
2221 zpfirst->z_name, compat);
2222 }
2223 }
2224 if (do_extend) {
2225 /*
2226 ** Search through a couple of extra years past the obvious
2227 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2228 ** rule applies from 2012 onwards and has transitions in March
2229 ** and September, plus some one-off transitions in November
2230 ** 2013. If zic looked only at the last 400 years, it would
2231 ** set max_year=2413, with the intent that the 400 years 2014
2232 ** through 2413 will be repeated. The last transition listed
2233 ** in the tzfile would be in 2413-09, less than 400 years
2234 ** after the last one-off transition in 2013-11. Two years
2235 ** might be overkill, but with the kind of edge cases
2236 ** available we're not sure that one year would suffice.
2237 */
2238 enum { years_of_observations = YEARSPERREPEAT + 2 };
2239
2240 if (min_year >= ZIC_MIN + years_of_observations)
2241 min_year -= years_of_observations;
2242 else min_year = ZIC_MIN;
2243 if (max_year <= ZIC_MAX - years_of_observations)
2244 max_year += years_of_observations;
2245 else max_year = ZIC_MAX;
2246 /*
2247 ** Regardless of any of the above,
2248 ** for a "proDSTic" zone which specifies that its rules
2249 ** always have and always will be in effect,
2250 ** we only need one cycle to define the zone.
2251 */
2252 if (prodstic) {
2253 min_year = 1900;
2254 max_year = min_year + years_of_observations;
2255 }
2256 }
2257 /*
2258 ** For the benefit of older systems,
2259 ** generate data from 1900 through 2037.
2260 */
2261 if (min_year > 1900)
2262 min_year = 1900;
2263 if (max_year < 2037)
2264 max_year = 2037;
2265 for (i = 0; i < zonecount; ++i) {
2266 /*
2267 ** A guess that may well be corrected later.
2268 */
2269 stdoff = 0;
2270 zp = &zpfirst[i];
2271 usestart = i > 0 && (zp - 1)->z_untiltime > big_bang_time;
2272 useuntil = i < (zonecount - 1);
2273 if (useuntil && zp->z_untiltime <= big_bang_time)
2274 continue;
2275 gmtoff = zp->z_gmtoff;
2276 eat(zp->z_filename, zp->z_linenum);
2277 *startbuf = '\0';
2278 startoff = zp->z_gmtoff;
2279 if (zp->z_nrules == 0) {
2280 stdoff = zp->z_stdoff;
2281 doabbr(startbuf, max_abbr_len + 1, zp->z_format,
2282 NULL, stdoff != 0, false);
2283 type = addtype(oadd(zp->z_gmtoff, stdoff),
2284 startbuf, stdoff != 0, startttisstd,
2285 startttisgmt);
2286 if (usestart) {
2287 addtt(starttime, type);
2288 usestart = false;
2289 } else addtt(big_bang_time, type);
2290 } else for (year = min_year; year <= max_year; ++year) {
2291 if (useuntil && year > zp->z_untilrule.r_hiyear)
2292 break;
2293 /*
2294 ** Mark which rules to do in the current year.
2295 ** For those to do, calculate rpytime(rp, year);
2296 */
2297 for (j = 0; j < zp->z_nrules; ++j) {
2298 rp = &zp->z_rules[j];
2299 eats(zp->z_filename, zp->z_linenum,
2300 rp->r_filename, rp->r_linenum);
2301 rp->r_todo = year >= rp->r_loyear &&
2302 year <= rp->r_hiyear &&
2303 yearistype(year, rp->r_yrtype);
2304 if (rp->r_todo)
2305 rp->r_temp = rpytime(rp, year);
2306 }
2307 for ( ; ; ) {
2308 int k;
2309 zic_t jtime, ktime;
2310 zic_t offset;
2311
2312 INITIALIZE(ktime);
2313 if (useuntil) {
2314 /*
2315 ** Turn untiltime into UT
2316 ** assuming the current gmtoff and
2317 ** stdoff values.
2318 */
2319 untiltime = zp->z_untiltime;
2320 if (!zp->z_untilrule.r_todisgmt)
2321 untiltime = tadd(untiltime,
2322 -gmtoff);
2323 if (!zp->z_untilrule.r_todisstd)
2324 untiltime = tadd(untiltime,
2325 -stdoff);
2326 }
2327 /*
2328 ** Find the rule (of those to do, if any)
2329 ** that takes effect earliest in the year.
2330 */
2331 k = -1;
2332 for (j = 0; j < zp->z_nrules; ++j) {
2333 rp = &zp->z_rules[j];
2334 if (!rp->r_todo)
2335 continue;
2336 eats(zp->z_filename, zp->z_linenum,
2337 rp->r_filename, rp->r_linenum);
2338 offset = rp->r_todisgmt ? 0 : gmtoff;
2339 if (!rp->r_todisstd)
2340 offset = oadd(offset, stdoff);
2341 jtime = rp->r_temp;
2342 if (jtime == min_time ||
2343 jtime == max_time)
2344 continue;
2345 jtime = tadd(jtime, -offset);
2346 if (k < 0 || jtime < ktime) {
2347 k = j;
2348 ktime = jtime;
2349 }
2350 }
2351 if (k < 0)
2352 break; /* go on to next year */
2353 rp = &zp->z_rules[k];
2354 rp->r_todo = false;
2355 if (useuntil && ktime >= untiltime)
2356 break;
2357 stdoff = rp->r_stdoff;
2358 if (usestart && ktime == starttime)
2359 usestart = false;
2360 if (usestart) {
2361 if (ktime < starttime) {
2362 startoff = oadd(zp->z_gmtoff,
2363 stdoff);
2364 doabbr(startbuf,
2365 max_abbr_len + 1,
2366 zp->z_format,
2367 rp->r_abbrvar,
2368 rp->r_stdoff != 0,
2369 false);
2370 continue;
2371 }
2372 if (*startbuf == '\0' &&
2373 startoff == oadd(zp->z_gmtoff,
2374 stdoff)) {
2375 doabbr(startbuf,
2376 max_abbr_len + 1,
2377 zp->z_format,
2378 rp->r_abbrvar,
2379 rp->r_stdoff !=
2380 0,
2381 false);
2382 }
2383 }
2384 eats(zp->z_filename, zp->z_linenum,
2385 rp->r_filename, rp->r_linenum);
2386 doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar,
2387 rp->r_stdoff != 0, false);
2388 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2389 type = addtype(offset, ab, rp->r_stdoff != 0,
2390 rp->r_todisstd, rp->r_todisgmt);
2391 addtt(ktime, type);
2392 }
2393 }
2394 if (usestart) {
2395 if (*startbuf == '\0' &&
2396 zp->z_format != NULL &&
2397 strchr(zp->z_format, '%') == NULL &&
2398 strchr(zp->z_format, '/') == NULL)
2399 (void)strncpy(startbuf, zp->z_format,
2400 max_abbr_len + 1 - 1);
2401 eat(zp->z_filename, zp->z_linenum);
2402 if (*startbuf == '\0')
2403 error(_("can't determine time zone abbreviation to use just after until time"));
2404 else addtt(starttime,
2405 addtype(startoff, startbuf,
2406 startoff != zp->z_gmtoff,
2407 startttisstd,
2408 startttisgmt));
2409 }
2410 /*
2411 ** Now we may get to set starttime for the next zone line.
2412 */
2413 if (useuntil) {
2414 startttisstd = zp->z_untilrule.r_todisstd;
2415 startttisgmt = zp->z_untilrule.r_todisgmt;
2416 starttime = zp->z_untiltime;
2417 if (!startttisstd)
2418 starttime = tadd(starttime, -stdoff);
2419 if (!startttisgmt)
2420 starttime = tadd(starttime, -gmtoff);
2421 }
2422 }
2423 if (do_extend) {
2424 /*
2425 ** If we're extending the explicitly listed observations
2426 ** for 400 years because we can't fill the POSIX-TZ field,
2427 ** check whether we actually ended up explicitly listing
2428 ** observations through that period. If there aren't any
2429 ** near the end of the 400-year period, add a redundant
2430 ** one at the end of the final year, to make it clear
2431 ** that we are claiming to have definite knowledge of
2432 ** the lack of transitions up to that point.
2433 */
2434 struct rule xr;
2435 struct attype *lastat;
2436 xr.r_month = TM_JANUARY;
2437 xr.r_dycode = DC_DOM;
2438 xr.r_dayofmonth = 1;
2439 xr.r_tod = 0;
2440 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2441 if (attypes[i].at > lastat->at)
2442 lastat = &attypes[i];
2443 if (lastat->at < rpytime(&xr, max_year - 1)) {
2444 /*
2445 ** Create new type code for the redundant entry,
2446 ** to prevent it being optimized away.
2447 */
2448 if (typecnt >= TZ_MAX_TYPES) {
2449 error(_("too many local time types"));
2450 exit(EXIT_FAILURE);
2451 }
2452 gmtoffs[typecnt] = gmtoffs[lastat->type];
2453 isdsts[typecnt] = isdsts[lastat->type];
2454 ttisstds[typecnt] = ttisstds[lastat->type];
2455 ttisgmts[typecnt] = ttisgmts[lastat->type];
2456 abbrinds[typecnt] = abbrinds[lastat->type];
2457 ++typecnt;
2458 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2459 }
2460 }
2461 writezone(zpfirst->z_name, envvar, version);
2462 free(startbuf);
2463 free(ab);
2464 free(envvar);
2465 }
2466
2467 static void
2468 addtt(const zic_t starttime, int type)
2469 {
2470 if (starttime <= big_bang_time ||
2471 (timecnt == 1 && attypes[0].at < big_bang_time)) {
2472 gmtoffs[0] = gmtoffs[type];
2473 isdsts[0] = isdsts[type];
2474 ttisstds[0] = ttisstds[type];
2475 ttisgmts[0] = ttisgmts[type];
2476 if (abbrinds[type] != 0)
2477 strcpy(chars, &chars[abbrinds[type]]);
2478 abbrinds[0] = 0;
2479 charcnt = strlen(chars) + 1;
2480 typecnt = 1;
2481 timecnt = 0;
2482 type = 0;
2483 }
2484 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
2485 attypes[timecnt].at = starttime;
2486 attypes[timecnt].type = type;
2487 ++timecnt;
2488 }
2489
2490 static int
2491 addtype(zic_t gmtoff, char *const abbr, bool isdst, bool ttisstd, bool ttisgmt)
2492 {
2493 int i, j;
2494
2495 /*
2496 ** See if there's already an entry for this zone type.
2497 ** If so, just return its index.
2498 */
2499 for (i = 0; i < typecnt; ++i) {
2500 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2501 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2502 ttisstd == ttisstds[i] &&
2503 ttisgmt == ttisgmts[i])
2504 return i;
2505 }
2506 /*
2507 ** There isn't one; add a new one, unless there are already too
2508 ** many.
2509 */
2510 if (typecnt >= TZ_MAX_TYPES) {
2511 error(_("too many local time types"));
2512 exit(EXIT_FAILURE);
2513 }
2514 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
2515 error(_("UT offset out of range"));
2516 exit(EXIT_FAILURE);
2517 }
2518 gmtoffs[i] = gmtoff;
2519 isdsts[i] = isdst;
2520 ttisstds[i] = ttisstd;
2521 ttisgmts[i] = ttisgmt;
2522
2523 for (j = 0; j < charcnt; ++j)
2524 if (strcmp(&chars[j], abbr) == 0)
2525 break;
2526 if (j == charcnt)
2527 newabbr(abbr);
2528 abbrinds[i] = j;
2529 ++typecnt;
2530 return i;
2531 }
2532
2533 static void
2534 leapadd(zic_t t, bool positive, int rolling, int count)
2535 {
2536 int i, j;
2537
2538 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2539 error(_("too many leap seconds"));
2540 exit(EXIT_FAILURE);
2541 }
2542 for (i = 0; i < leapcnt; ++i)
2543 if (t <= trans[i]) {
2544 if (t == trans[i]) {
2545 error(_("repeated leap second moment"));
2546 exit(EXIT_FAILURE);
2547 }
2548 break;
2549 }
2550 do {
2551 for (j = leapcnt; j > i; --j) {
2552 trans[j] = trans[j - 1];
2553 corr[j] = corr[j - 1];
2554 roll[j] = roll[j - 1];
2555 }
2556 trans[i] = t;
2557 corr[i] = positive ? 1 : -count;
2558 roll[i] = rolling;
2559 ++leapcnt;
2560 } while (positive && --count != 0);
2561 }
2562
2563 static void
2564 adjleap(void)
2565 {
2566 int i;
2567 zic_t last = 0;
2568
2569 /*
2570 ** propagate leap seconds forward
2571 */
2572 for (i = 0; i < leapcnt; ++i) {
2573 trans[i] = tadd(trans[i], last);
2574 last = corr[i] += last;
2575 }
2576 }
2577
2578 static bool
2579 yearistype(const int year, const char *const type)
2580 {
2581 static char * buf;
2582 int result;
2583
2584 if (type == NULL || *type == '\0')
2585 return true;
2586 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
2587 (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */
2588 result = system(buf);
2589 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2590 case 0:
2591 return true;
2592 case 1:
2593 return false;
2594 }
2595 error(_("Wild result from command execution"));
2596 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2597 progname, buf, result);
2598 for ( ; ; )
2599 exit(EXIT_FAILURE);
2600 }
2601
2602 /* Is A a space character in the C locale? */
2603 static bool
2604 is_space(char a)
2605 {
2606 switch (a) {
2607 default:
2608 return false;
2609 case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
2610 return true;
2611 }
2612 }
2613
2614 /* Is A an alphabetic character in the C locale? */
2615 static bool
2616 is_alpha(char a)
2617 {
2618 switch (a) {
2619 default:
2620 return 0;
2621 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2622 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
2623 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
2624 case 'V': case 'W': case 'X': case 'Y': case 'Z':
2625 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
2626 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
2627 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
2628 case 'v': case 'w': case 'x': case 'y': case 'z':
2629 return true;
2630 }
2631 }
2632
2633 /* If A is an uppercase character in the C locale, return its lowercase
2634 counterpart. Otherwise, return A. */
2635 static char
2636 lowerit(char a)
2637 {
2638 switch (a) {
2639 default: return a;
2640 case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c';
2641 case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f';
2642 case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i';
2643 case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l';
2644 case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o';
2645 case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r';
2646 case 'S': return 's'; case 'T': return 't'; case 'U': return 'u';
2647 case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x';
2648 case 'Y': return 'y'; case 'Z': return 'z';
2649 }
2650 }
2651
2652 /* case-insensitive equality */
2653 static ATTRIBUTE_PURE bool
2654 ciequal(const char *ap, const char *bp)
2655 {
2656 while (lowerit(*ap) == lowerit(*bp++))
2657 if (*ap++ == '\0')
2658 return true;
2659 return false;
2660 }
2661
2662 static ATTRIBUTE_PURE bool
2663 itsabbr(const char *abbr, const char *word)
2664 {
2665 if (lowerit(*abbr) != lowerit(*word))
2666 return false;
2667 ++word;
2668 while (*++abbr != '\0')
2669 do {
2670 if (*word == '\0')
2671 return false;
2672 } while (lowerit(*word++) != lowerit(*abbr));
2673 return true;
2674 }
2675
2676 static ATTRIBUTE_PURE const struct lookup *
2677 byword(const char *const word, const struct lookup *const table)
2678 {
2679 const struct lookup * foundlp;
2680 const struct lookup * lp;
2681
2682 if (word == NULL || table == NULL)
2683 return NULL;
2684 /*
2685 ** Look for exact match.
2686 */
2687 for (lp = table; lp->l_word != NULL; ++lp)
2688 if (ciequal(word, lp->l_word))
2689 return lp;
2690 /*
2691 ** Look for inexact match.
2692 */
2693 foundlp = NULL;
2694 for (lp = table; lp->l_word != NULL; ++lp)
2695 if (itsabbr(word, lp->l_word)) {
2696 if (foundlp == NULL)
2697 foundlp = lp;
2698 else return NULL; /* multiple inexact matches */
2699 }
2700 return foundlp;
2701 }
2702
2703 static char **
2704 getfields(char *cp)
2705 {
2706 char * dp;
2707 char ** array;
2708 int nsubs;
2709
2710 if (cp == NULL)
2711 return NULL;
2712 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
2713 nsubs = 0;
2714 for ( ; ; ) {
2715 while (is_space(*cp))
2716 ++cp;
2717 if (*cp == '\0' || *cp == '#')
2718 break;
2719 array[nsubs++] = dp = cp;
2720 do {
2721 if ((*dp = *cp++) != '"')
2722 ++dp;
2723 else while ((*dp = *cp++) != '"')
2724 if (*dp != '\0')
2725 ++dp;
2726 else {
2727 error(_(
2728 "Odd number of quotation marks"
2729 ));
2730 exit(1);
2731 }
2732 } while (*cp && *cp != '#' && !is_space(*cp));
2733 if (is_space(*cp))
2734 ++cp;
2735 *dp = '\0';
2736 }
2737 array[nsubs] = NULL;
2738 return array;
2739 }
2740
2741 static ATTRIBUTE_PURE zic_t
2742 oadd(const zic_t t1, const zic_t t2)
2743 {
2744 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) {
2745 error(_("time overflow"));
2746 exit(EXIT_FAILURE);
2747 }
2748 return t1 + t2;
2749 }
2750
2751 static ATTRIBUTE_PURE zic_t
2752 tadd(const zic_t t1, const zic_t t2)
2753 {
2754 if (t1 == max_time && t2 > 0)
2755 return max_time;
2756 if (t1 == min_time && t2 < 0)
2757 return min_time;
2758 if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
2759 error(_("time overflow"));
2760 exit(EXIT_FAILURE);
2761 }
2762 return t1 + t2;
2763 }
2764
2765 /*
2766 ** Given a rule, and a year, compute the date (in seconds since January 1,
2767 ** 1970, 00:00 LOCAL time) in that year that the rule refers to.
2768 */
2769
2770 static zic_t
2771 rpytime(const struct rule *const rp, const zic_t wantedy)
2772 {
2773 int m, i;
2774 zic_t dayoff; /* with a nod to Margaret O. */
2775 zic_t t, y;
2776
2777 if (wantedy == ZIC_MIN)
2778 return min_time;
2779 if (wantedy == ZIC_MAX)
2780 return max_time;
2781 dayoff = 0;
2782 m = TM_JANUARY;
2783 y = EPOCH_YEAR;
2784 while (wantedy != y) {
2785 if (wantedy > y) {
2786 i = len_years[isleap(y)];
2787 ++y;
2788 } else {
2789 --y;
2790 i = -len_years[isleap(y)];
2791 }
2792 dayoff = oadd(dayoff, i);
2793 }
2794 while (m != rp->r_month) {
2795 i = len_months[isleap(y)][m];
2796 dayoff = oadd(dayoff, i);
2797 ++m;
2798 }
2799 i = rp->r_dayofmonth;
2800 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
2801 if (rp->r_dycode == DC_DOWLEQ)
2802 --i;
2803 else {
2804 error(_("use of 2/29 in non leap-year"));
2805 exit(EXIT_FAILURE);
2806 }
2807 }
2808 --i;
2809 dayoff = oadd(dayoff, i);
2810 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2811 zic_t wday;
2812
2813 #define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
2814 wday = EPOCH_WDAY;
2815 /*
2816 ** Don't trust mod of negative numbers.
2817 */
2818 if (dayoff >= 0)
2819 wday = (wday + dayoff) % LDAYSPERWEEK;
2820 else {
2821 wday -= ((-dayoff) % LDAYSPERWEEK);
2822 if (wday < 0)
2823 wday += LDAYSPERWEEK;
2824 }
2825 while (wday != rp->r_wday)
2826 if (rp->r_dycode == DC_DOWGEQ) {
2827 dayoff = oadd(dayoff, (zic_t) 1);
2828 if (++wday >= LDAYSPERWEEK)
2829 wday = 0;
2830 ++i;
2831 } else {
2832 dayoff = oadd(dayoff, (zic_t) -1);
2833 if (--wday < 0)
2834 wday = LDAYSPERWEEK - 1;
2835 --i;
2836 }
2837 if (i < 0 || i >= len_months[isleap(y)][m]) {
2838 if (noise)
2839 warning(_("rule goes past start/end of month; \
2840 will not work with pre-2004 versions of zic"));
2841 }
2842 }
2843 if (dayoff < min_time / SECSPERDAY)
2844 return min_time;
2845 if (dayoff > max_time / SECSPERDAY)
2846 return max_time;
2847 t = (zic_t) dayoff * SECSPERDAY;
2848 return tadd(t, rp->r_tod);
2849 }
2850
2851 static void
2852 newabbr(const char *const string)
2853 {
2854 int i;
2855
2856 if (strcmp(string, GRANDPARENTED) != 0) {
2857 const char * cp;
2858 const char * mp;
2859
2860 /*
2861 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
2862 ** optionally followed by a + or - and a number from 1 to 14.
2863 */
2864 cp = string;
2865 mp = NULL;
2866 while (is_alpha(*cp))
2867 ++cp;
2868 if (cp - string == 0)
2869 mp = _("time zone abbreviation lacks alphabetic at start");
2870 if (noise && cp - string < 3)
2871 mp = _("time zone abbreviation has fewer than 3 alphabetics");
2872 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
2873 mp = _("time zone abbreviation has too many alphabetics");
2874 if (mp == NULL && (*cp == '+' || *cp == '-')) {
2875 ++cp;
2876 if (is_digit(*cp))
2877 if (*cp++ == '1' &&
2878 *cp >= '0' && *cp <= '4')
2879 ++cp;
2880 }
2881 if (*cp != '\0')
2882 mp = _("time zone abbreviation differs from POSIX standard");
2883 if (mp != NULL)
2884 warning("%s (%s)", mp, string);
2885 }
2886 i = strlen(string) + 1;
2887 if (charcnt + i > TZ_MAX_CHARS) {
2888 error(_("too many, or too long, time zone abbreviations"));
2889 exit(EXIT_FAILURE);
2890 }
2891 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1);
2892 charcnt += i;
2893 }
2894
2895 static bool
2896 mkdirs(char *argname)
2897 {
2898 char * name;
2899 char * cp;
2900
2901 if (argname == NULL || *argname == '\0')
2902 return true;
2903 cp = name = ecpyalloc(argname);
2904 while ((cp = strchr(cp + 1, '/')) != 0) {
2905 *cp = '\0';
2906 #ifdef HAVE_DOS_FILE_NAMES
2907 /*
2908 ** DOS drive specifier?
2909 */
2910 if (is_alpha(name[0]) && name[1] == ':' && name[2] == '\0') {
2911 *cp = '/';
2912 continue;
2913 }
2914 #endif
2915 /*
2916 ** Try to create it. It's OK if creation fails because
2917 ** the directory already exists, perhaps because some
2918 ** other process just created it.
2919 */
2920 if (mkdir(name, MKDIR_UMASK) != 0) {
2921 int err = errno;
2922 if (itsdir(name) <= 0) {
2923 char const *e = strerror(err);
2924 warning(_("%s: Can't create directory"
2925 " %s: %s\n"),
2926 progname, name, e);
2927 free(name);
2928 return false;
2929 }
2930 }
2931 *cp = '/';
2932 }
2933 free(name);
2934 return true;
2935 }
2936