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