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