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