Branch data Line data Source code
1 : : /* Compile .zi time zone data into TZif binary files. */
2 : :
3 : : /*
4 : : * This file is in the public domain, so clarified as of
5 : : * 2006-07-17 by Arthur David Olson.
6 : : *
7 : : * IDENTIFICATION
8 : : * src/timezone/zic.c
9 : : */
10 : :
11 : : #include "postgres_fe.h"
12 : :
13 : : /*
14 : : * Disable some warnings on MSVC. See also
15 : : * <https://lists.iana.org/hyperkitty/list/tz@iana.org/thread/PJBVERYHQZEXIREYIHC5OJGZMNVQC2SD/>.
16 : : */
17 : : #ifdef _MSC_VER
18 : : /* warning C4146: unary minus operator applied to unsigned type, result still unsigned */
19 : : #pragma warning(disable: 4146)
20 : : /* warning C5287: operands are different enum types */
21 : : #pragma warning(disable: 5287)
22 : : #endif
23 : :
24 : : #include <fcntl.h>
25 : : #include <grp.h>
26 : : #include <pwd.h>
27 : : #include <signal.h>
28 : : #include <sys/stat.h>
29 : : #include <time.h>
30 : :
31 : : #include "pg_getopt.h"
32 : :
33 : : #include "private.h"
34 : : #include "tzfile.h"
35 : :
36 : : #ifndef O_BINARY
37 : : #define O_BINARY 0 /* MS-Windows */
38 : : #endif
39 : :
40 : : typedef int_fast64_t zic_t;
41 : : static zic_t const
42 : : ZIC_MIN = INT_FAST64_MIN,
43 : : ZIC_MAX = INT_FAST64_MAX,
44 : : ZIC32_MIN = -1 - (zic_t) TWO_31_MINUS_1,
45 : : ZIC32_MAX = TWO_31_MINUS_1;
46 : : #define SCNdZIC SCNdFAST64
47 : :
48 : : #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
49 : : #define ZIC_MAX_ABBR_LEN_WO_WARN 6
50 : : #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
51 : :
52 : : /* Minimum and maximum years, assuming signed 32-bit pg_time_t. */
53 : : enum
54 : : {
55 : : YEAR_32BIT_MIN = 1901, YEAR_32BIT_MAX = 2038};
56 : :
57 : : /* An upper bound on how much a format might grow due to concatenation. */
58 : : enum
59 : : {
60 : : FORMAT_LEN_GROWTH_BOUND = 5};
61 : :
62 : : /* All file permission bits. */
63 : : #define ALL_PERMS (S_IRWXU | S_IRWXG | S_IRWXO)
64 : :
65 : : /* Troublesome file permission bits. */
66 : : #define TROUBLE_PERMS (S_IWGRP | S_IWOTH)
67 : :
68 : : /*
69 : : * File permission bits for making directories.
70 : : * The umask modifies these bits.
71 : : */
72 : : #define MKDIR_PERMS (ALL_PERMS & ~TROUBLE_PERMS)
73 : :
74 : : /*
75 : : * File permission bits for making regular files.
76 : : * The umask modifies these bits.
77 : : */
78 : : #define CREAT_PERMS (MKDIR_PERMS & ~(S_IXUSR | S_IXGRP | S_IXOTH))
79 : : static mode_t creat_perms = CREAT_PERMS;
80 : :
81 : : static gid_t const no_gid = -1;
82 : : static uid_t const no_uid = -1;
83 : : static gid_t output_group = -1;
84 : : static uid_t output_owner = -1;
85 : : #ifndef GID_T_MAX
86 : : #define GID_T_MAX MAXVAL(gid_t, TYPE_BIT(gid_t))
87 : : #endif
88 : : #ifndef UID_T_MAX
89 : : #define UID_T_MAX MAXVAL(uid_t, TYPE_BIT(uid_t))
90 : : #endif
91 : :
92 : : /*
93 : : * The minimum alignment of a type, for pre-C23 platforms.
94 : : * The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks
95 : : * <stdalign.h> even though __STDC_VERSION__ == 201112.
96 : : */
97 : : #if __STDC_VERSION__ < 201112 || defined __SUNPRO_C
98 : : #define alignof(type) offsetof(struct { char a; type b; }, b)
99 : : #elif __STDC_VERSION__ < 202311
100 : : #include <stdalign.h>
101 : : #endif
102 : :
103 : : /* The name used for the file implementing the obsolete -p option. */
104 : : #ifndef TZDEFRULES
105 : : #define TZDEFRULES "posixrules"
106 : : #endif
107 : :
108 : : /* The maximum length of a text line, including the trailing newline. */
109 : : #ifndef _POSIX2_LINE_MAX
110 : : #define _POSIX2_LINE_MAX 2048
111 : : #endif
112 : :
113 : : /*
114 : : * The type for line numbers. Use PRIdMAX to format them; formerly
115 : : * there was also "#define PRIdLINENO PRIdMAX" and formats used
116 : : * PRIdLINENO, but xgettext cannot grok that.
117 : : */
118 : : typedef intmax_t lineno_t;
119 : :
120 : : struct rule
121 : : {
122 : : int r_filenum;
123 : : lineno_t r_linenum;
124 : : const char *r_name;
125 : :
126 : : zic_t r_loyear; /* for example, 1986 */
127 : : zic_t r_hiyear; /* for example, 1986 */
128 : : bool r_hiwasnum;
129 : :
130 : : int r_month; /* 0..11 */
131 : :
132 : : int r_dycode; /* see below */
133 : : int r_dayofmonth;
134 : : int r_wday;
135 : :
136 : : zic_t r_tod; /* time from midnight */
137 : : bool r_todisstd; /* is r_tod standard time? */
138 : : bool r_todisut; /* is r_tod UT? */
139 : : bool r_isdst; /* is this daylight saving time? */
140 : : zic_t r_save; /* offset from standard time */
141 : : const char *r_abbrvar; /* variable part of abbreviation */
142 : :
143 : : bool r_todo; /* a rule to do (used in outzone) */
144 : : zic_t r_temp; /* used in outzone */
145 : : };
146 : :
147 : : /*
148 : : * r_dycode r_dayofmonth r_wday
149 : : */
150 : : enum
151 : : {
152 : : DC_DOM, /* 1..31 */ /* unused */
153 : : DC_DOWGEQ, /* 1..31 */ /* 0..6 (Sun..Sat) */
154 : : DC_DOWLEQ /* 1..31 */ /* 0..6 (Sun..Sat) */
155 : : };
156 : :
157 : : struct zone
158 : : {
159 : : int z_filenum;
160 : : lineno_t z_linenum;
161 : :
162 : : const char *z_name;
163 : : zic_t z_stdoff;
164 : : char *z_rule;
165 : : const char *z_format;
166 : : char z_format_specifier;
167 : :
168 : : bool z_isdst;
169 : : zic_t z_save;
170 : :
171 : : struct rule *z_rules;
172 : : ptrdiff_t z_nrules;
173 : :
174 : : struct rule z_untilrule;
175 : : zic_t z_untiltime;
176 : : };
177 : :
178 : : #ifndef AT_SYMLINK_FOLLOW
179 : : #define linkat(targetdir, target, linknamedir, linkname, flag) \
180 : : (errno = ENOTSUP, -1)
181 : : #endif
182 : :
183 : : static void verror(const char *const string, va_list args) pg_attribute_printf(1, 0);
184 : : static void error(const char *const string, ...) pg_attribute_printf(1, 2);
185 : : static void warning(const char *const string, ...) pg_attribute_printf(1, 2);
186 : : static int addabbr(char chs[TZ_MAX_CHARS], int *pnchs, char const *abbr);
187 : : static void addtt(zic_t starttime, int type);
188 : : static int addtype(zic_t utoff, char const *abbr,
189 : : bool isdst, bool ttisstd, bool ttisut);
190 : : static void adjleap(void);
191 : : static void associate(void);
192 : : static void checkabbr(char const *string);
193 : : static void check_for_signal(void);
194 : : static void dolink(char const *target, char const *linkname, bool staysymlink);
195 : : static int getfields(char *cp, char **array, int arrayelts);
196 : : static zic_t gethms(const char *string, const char *errstring);
197 : : static zic_t getsave(char *field, bool *isdst);
198 : : static void inexpires(char **fields, int nfields);
199 : : static void infile(int fnum, char const *name);
200 : : static void inleap(char **fields, int nfields);
201 : : static void inlink(char **fields, int nfields);
202 : : static void inrule(char **fields, int nfields);
203 : : static bool inzcont(char **fields, int nfields);
204 : : static bool inzone(char **fields, int nfields);
205 : : static bool inzsub(char **fields, int nfields, bool iscont);
206 : : static bool is_alpha(char a);
207 : : static int itssymlink(char const *name, int *cache);
208 : : static void leapadd(zic_t t, int correction, int rolling);
209 : : static char lowerit(char a);
210 : : static void mkdirs(char const *argname, bool ancestors);
211 : : static zic_t oadd(zic_t t1, zic_t t2);
212 : : static zic_t omul(zic_t t1, zic_t t2);
213 : : static void outzone(const struct zone *zpfirst, ptrdiff_t zonecount);
214 : : static zic_t rpytime(const struct rule *rp, zic_t wantedy);
215 : : static bool rulesub(struct rule *rp,
216 : : const char *loyearp, const char *hiyearp,
217 : : const char *typep, const char *monthp,
218 : : const char *dayp, const char *timep);
219 : : static zic_t tadd(zic_t t1, zic_t t2);
220 : :
221 : : /* Is C an ASCII digit? */
222 : : static bool
223 : 145556 : is_digit(char c)
224 : : {
225 [ + + + - ]: 145556 : return '0' <= c && c <= '9';
226 : : }
227 : :
228 : : /* Bound on length of what %z can expand to. */
229 : : enum
230 : : {
231 : : PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
232 : :
233 : : static int charcnt;
234 : : static bool errors;
235 : : static bool warnings;
236 : : static int filenum;
237 : : static ptrdiff_t leapcnt;
238 : : static ptrdiff_t leap_alloc;
239 : : static bool leapseen;
240 : : static zic_t leapminyear;
241 : : static zic_t leapmaxyear;
242 : : static lineno_t linenum;
243 : : static int max_abbrvar_len = PERCENT_Z_LEN_BOUND;
244 : : static int max_format_len;
245 : : static zic_t max_year;
246 : : static zic_t min_year;
247 : : static bool noise;
248 : : static bool print_abbrevs;
249 : : static zic_t print_cutoff;
250 : : static bool skip_mkdir;
251 : : static int rfilenum;
252 : : static lineno_t rlinenum;
253 : : static const char *progname;
254 : : static char const *leapsec;
255 : : static char *const *main_argv;
256 : : static ptrdiff_t timecnt;
257 : : static ptrdiff_t timecnt_alloc;
258 : : static int typecnt;
259 : : static int unspecifiedtype;
260 : :
261 : : /*
262 : : * Line codes.
263 : : */
264 : :
265 : : enum
266 : : {
267 : : LC_RULE,
268 : : LC_ZONE,
269 : : LC_LINK,
270 : : LC_LEAP,
271 : : LC_EXPIRES
272 : : };
273 : :
274 : : /*
275 : : * Which fields are which on a Zone line.
276 : : */
277 : :
278 : : enum
279 : : {
280 : : ZF_NAME = 1,
281 : : ZF_STDOFF,
282 : : ZF_RULE,
283 : : ZF_FORMAT,
284 : : ZF_TILYEAR,
285 : : ZF_TILMONTH,
286 : : ZF_TILDAY,
287 : : ZF_TILTIME,
288 : : ZONE_MAXFIELDS,
289 : : ZONE_MINFIELDS = ZF_TILYEAR
290 : : };
291 : :
292 : : /*
293 : : * Which fields are which on a Zone continuation line.
294 : : */
295 : :
296 : : enum
297 : : {
298 : : ZFC_STDOFF,
299 : : ZFC_RULE,
300 : : ZFC_FORMAT,
301 : : ZFC_TILYEAR,
302 : : ZFC_TILMONTH,
303 : : ZFC_TILDAY,
304 : : ZFC_TILTIME,
305 : : ZONEC_MAXFIELDS,
306 : : ZONEC_MINFIELDS = ZFC_TILYEAR
307 : : };
308 : :
309 : : /*
310 : : * Which files are which on a Rule line.
311 : : */
312 : :
313 : : enum
314 : : {
315 : : RF_NAME = 1,
316 : : RF_LOYEAR,
317 : : RF_HIYEAR,
318 : : RF_COMMAND,
319 : : RF_MONTH,
320 : : RF_DAY,
321 : : RF_TOD,
322 : : RF_SAVE,
323 : : RF_ABBRVAR,
324 : : RULE_FIELDS
325 : : };
326 : :
327 : : /*
328 : : * Which fields are which on a Link line.
329 : : */
330 : :
331 : : enum
332 : : {
333 : : LF_TARGET = 1,
334 : : LF_LINKNAME,
335 : : LINK_FIELDS
336 : : };
337 : :
338 : : /*
339 : : * Which fields are which on a Leap line.
340 : : */
341 : :
342 : : enum
343 : : {
344 : : LP_YEAR = 1,
345 : : LP_MONTH,
346 : : LP_DAY,
347 : : LP_TIME,
348 : : LP_CORR,
349 : : LP_ROLL,
350 : : LEAP_FIELDS,
351 : :
352 : : /*
353 : : * Expires lines are like Leap lines, except without CORR and ROLL fields.
354 : : */
355 : : EXPIRES_FIELDS = LP_TIME + 1
356 : : };
357 : :
358 : : /*
359 : : * The maximum number of fields on any of the above lines.
360 : : * (The "+"s pacify gcc -Wenum-compare.)
361 : : */
362 : : enum
363 : : {
364 : : MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS),
365 : : max(+LEAP_FIELDS, +EXPIRES_FIELDS))
366 : : };
367 : :
368 : : /*
369 : : * Year synonyms.
370 : : */
371 : :
372 : : enum
373 : : {
374 : : YR_MINIMUM, /* "minimum" is for backward compatibility
375 : : * only */
376 : : YR_MAXIMUM,
377 : : YR_ONLY
378 : : };
379 : :
380 : : static struct rule *rules;
381 : : static ptrdiff_t nrules; /* number of rules */
382 : : static ptrdiff_t nrules_alloc;
383 : :
384 : : static struct zone *zones;
385 : : static ptrdiff_t nzones; /* number of zones */
386 : : static ptrdiff_t nzones_alloc;
387 : :
388 : : struct link
389 : : {
390 : : int l_filenum;
391 : : lineno_t l_linenum;
392 : : const char *l_target;
393 : : const char *l_linkname;
394 : : };
395 : :
396 : : static struct link *links;
397 : : static ptrdiff_t nlinks;
398 : : static ptrdiff_t nlinks_alloc;
399 : :
400 : : struct lookup
401 : : {
402 : : const char *l_word;
403 : : const int l_value;
404 : : };
405 : :
406 : : static struct lookup const *byword(const char *word,
407 : : const struct lookup *table);
408 : :
409 : : static struct lookup const zi_line_codes[] = {
410 : : {"Rule", LC_RULE},
411 : : {"Zone", LC_ZONE},
412 : : {"Link", LC_LINK},
413 : : {NULL, 0}
414 : : };
415 : : static struct lookup const leap_line_codes[] = {
416 : : {"Leap", LC_LEAP},
417 : : {"Expires", LC_EXPIRES},
418 : : {NULL, 0}
419 : : };
420 : :
421 : : static struct lookup const mon_names[] = {
422 : : {"January", TM_JANUARY},
423 : : {"February", TM_FEBRUARY},
424 : : {"March", TM_MARCH},
425 : : {"April", TM_APRIL},
426 : : {"May", TM_MAY},
427 : : {"June", TM_JUNE},
428 : : {"July", TM_JULY},
429 : : {"August", TM_AUGUST},
430 : : {"September", TM_SEPTEMBER},
431 : : {"October", TM_OCTOBER},
432 : : {"November", TM_NOVEMBER},
433 : : {"December", TM_DECEMBER},
434 : : {NULL, 0}
435 : : };
436 : :
437 : : static struct lookup const wday_names[] = {
438 : : {"Sunday", TM_SUNDAY},
439 : : {"Monday", TM_MONDAY},
440 : : {"Tuesday", TM_TUESDAY},
441 : : {"Wednesday", TM_WEDNESDAY},
442 : : {"Thursday", TM_THURSDAY},
443 : : {"Friday", TM_FRIDAY},
444 : : {"Saturday", TM_SATURDAY},
445 : : {NULL, 0}
446 : : };
447 : :
448 : : static struct lookup const lasts[] = {
449 : : {"last-Sunday", TM_SUNDAY},
450 : : {"last-Monday", TM_MONDAY},
451 : : {"last-Tuesday", TM_TUESDAY},
452 : : {"last-Wednesday", TM_WEDNESDAY},
453 : : {"last-Thursday", TM_THURSDAY},
454 : : {"last-Friday", TM_FRIDAY},
455 : : {"last-Saturday", TM_SATURDAY},
456 : : {NULL, 0}
457 : : };
458 : :
459 : : static struct lookup const begin_years[] = {
460 : : {"minimum", YR_MINIMUM},
461 : : {NULL, 0}
462 : : };
463 : :
464 : : static struct lookup const end_years[] = {
465 : : {"maximum", YR_MAXIMUM},
466 : : {"only", YR_ONLY},
467 : : {NULL, 0}
468 : : };
469 : :
470 : : static struct lookup const leap_types[] = {
471 : : {"Rolling", true},
472 : : {"Stationary", false},
473 : : {NULL, 0}
474 : : };
475 : :
476 : : static const int len_months[2][MONSPERYEAR] = {
477 : : {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
478 : : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
479 : : };
480 : :
481 : : static const int len_years[2] = {
482 : : DAYSPERNYEAR, DAYSPERLYEAR
483 : : };
484 : :
485 : : static struct attype
486 : : {
487 : : zic_t at;
488 : : bool dontmerge;
489 : : unsigned char type;
490 : : } *attypes;
491 : : static zic_t utoffs[TZ_MAX_TYPES];
492 : : static char isdsts[TZ_MAX_TYPES];
493 : : static unsigned char desigidx[TZ_MAX_TYPES];
494 : : static bool ttisstds[TZ_MAX_TYPES];
495 : : static bool ttisuts[TZ_MAX_TYPES];
496 : : static char chars[TZ_MAX_CHARS];
497 : : static struct
498 : : {
499 : : zic_t trans;
500 : : zic_t corr;
501 : : char roll;
502 : : } *leap;
503 : :
504 : : /*
505 : : * Memory allocation.
506 : : */
507 : :
508 : : ATTRIBUTE_NORETURN static void
509 : 0 : memory_exhausted(const char *msg)
510 : : {
511 : 0 : fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
512 : 0 : exit(EXIT_FAILURE);
513 : : }
514 : :
515 : : ATTRIBUTE_NORETURN static void
516 : 0 : size_overflow(void)
517 : : {
518 : 0 : memory_exhausted(_("size overflow"));
519 : : }
520 : :
521 : : ATTRIBUTE_PURE_114833_HACK
522 : : static ptrdiff_t
523 : 3242 : size_sum(size_t a, size_t b)
524 : : {
525 : : #ifdef ckd_add
526 : : ptrdiff_t sum;
527 : :
528 [ + - ]: 3242 : if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX)
529 : 3242 : return sum;
530 : : #else
531 : : if (a <= INDEX_MAX && b <= INDEX_MAX - a)
532 : : return a + b;
533 : : #endif
534 : 0 : size_overflow();
535 : : }
536 : :
537 : : ATTRIBUTE_PURE_114833_HACK
538 : : static ptrdiff_t
539 : 1364 : size_product(ptrdiff_t nitems, ptrdiff_t itemsize)
540 : : {
541 : : #ifdef ckd_mul
542 : : ptrdiff_t product;
543 : :
544 [ + - ]: 1364 : if (!ckd_mul(&product, nitems, itemsize) && product <= INDEX_MAX)
545 : 1364 : return product;
546 : : #else
547 : : ptrdiff_t nitems_max = INDEX_MAX / itemsize;
548 : :
549 : : if (nitems <= nitems_max)
550 : : return nitems * itemsize;
551 : : #endif
552 : 0 : size_overflow();
553 : : }
554 : :
555 : : ATTRIBUTE_PURE_114833_HACK
556 : : static ptrdiff_t
557 : 1364 : align_to(ptrdiff_t size, ptrdiff_t alignment)
558 : : {
559 : 1364 : ptrdiff_t lo_bits = alignment - 1,
560 : 1364 : sum = size_sum(size, lo_bits);
561 : :
562 : 1364 : return sum & ~lo_bits;
563 : : }
564 : :
565 : : static void *
566 : 71036 : memcheck(void *ptr)
567 : : {
568 [ - + ]: 71036 : if (ptr == NULL)
569 : 0 : memory_exhausted(strerror(errno));
570 : 71036 : return ptr;
571 : : }
572 : :
573 : : static void *
574 : 7334 : xmalloc(size_t size)
575 : : {
576 : 7334 : return memcheck(malloc(size));
577 : : }
578 : :
579 : : static void *
580 : 248 : xrealloc(void *ptr, size_t size)
581 : : {
582 : 248 : return memcheck(realloc(ptr, size));
583 : : }
584 : :
585 : : static char *
586 : 63454 : xstrdup(char const *str)
587 : : {
588 : 63454 : return memcheck(strdup(str));
589 : : }
590 : :
591 : : static ptrdiff_t
592 : 248 : grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize)
593 : : {
594 : 248 : ptrdiff_t addend = (*nitems_alloc >> 1) + 1;
595 : : #if defined ckd_add && defined ckd_mul
596 : : ptrdiff_t product;
597 : :
598 [ + - ]: 248 : if (!ckd_add(nitems_alloc, *nitems_alloc, addend)
599 [ + - ]: 248 : && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= INDEX_MAX)
600 : 248 : return product;
601 : : #else
602 : : if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize)
603 : : {
604 : : *nitems_alloc += addend;
605 : : return *nitems_alloc * itemsize;
606 : : }
607 : : #endif
608 : 0 : memory_exhausted(_("integer overflow"));
609 : : }
610 : :
611 : : static void *
612 : 85680 : growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems,
613 : : ptrdiff_t *nitems_alloc)
614 : : {
615 : 85680 : return (nitems < *nitems_alloc
616 : : ? ptr
617 [ + + ]: 85680 : : xrealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize)));
618 : : }
619 : :
620 : : /*
621 : : * Error handling.
622 : : */
623 : :
624 : : /*
625 : : * In most of the code, an input file name is represented by its index
626 : : * into the main argument vector, except that LEAPSEC_FILENUM stands
627 : : * for leapsec and COMMAND_LINE_FILENUM stands for the command line.
628 : : */
629 : : enum
630 : : {
631 : : LEAPSEC_FILENUM = -2, COMMAND_LINE_FILENUM = -1};
632 : :
633 : : /* Return the name of the Ith input file, for diagnostics. */
634 : : static char const *
635 : 4 : filename(int i)
636 : : {
637 [ - + ]: 4 : if (i == COMMAND_LINE_FILENUM)
638 : 0 : return _("command line");
639 : : else
640 : : {
641 [ + - ]: 4 : char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i];
642 : :
643 [ + - ]: 4 : return strcmp(fname, "-") == 0 ? _("standard input") : fname;
644 : : }
645 : : }
646 : :
647 : : static void
648 : 5535192 : eats(int fnum, lineno_t num, int rfnum, lineno_t rnum)
649 : : {
650 : 5535192 : filenum = fnum;
651 : 5535192 : linenum = num;
652 : 5535192 : rfilenum = rfnum;
653 : 5535192 : rlinenum = rnum;
654 : 5535192 : }
655 : :
656 : : static void
657 : 33216 : eat(int fnum, lineno_t num)
658 : : {
659 : 33216 : eats(fnum, num, 0, -1);
660 : 33216 : }
661 : :
662 : : static void
663 : 0 : verror(const char *const string, va_list args)
664 : : {
665 : 0 : check_for_signal();
666 : :
667 : : /*
668 : : * Match the format of "cc" to allow sh users to zic ... 2>&1 | error -t
669 : : * "*" -v on BSD systems.
670 : : */
671 [ # # ]: 0 : if (filenum)
672 : 0 : fprintf(stderr, _("\"%s\", line %" PRIdMAX ": "),
673 : : filename(filenum), linenum);
674 : 0 : vfprintf(stderr, string, args);
675 [ # # ]: 0 : if (rfilenum)
676 : 0 : fprintf(stderr, _(" (rule from \"%s\", line %" PRIdMAX ")"),
677 : : filename(rfilenum), rlinenum);
678 : 0 : fprintf(stderr, "\n");
679 : 0 : }
680 : :
681 : : static void
682 : 0 : error(const char *const string, ...)
683 : : {
684 : : va_list args;
685 : :
686 : 0 : va_start(args, string);
687 : 0 : verror(string, args);
688 : 0 : va_end(args);
689 : 0 : errors = true;
690 : 0 : }
691 : :
692 : : static void
693 : 0 : warning(const char *const string, ...)
694 : : {
695 : : va_list args;
696 : :
697 : 0 : fprintf(stderr, _("warning: "));
698 : 0 : va_start(args, string);
699 : 0 : verror(string, args);
700 : 0 : va_end(args);
701 : 0 : warnings = true;
702 : 0 : }
703 : :
704 : : /*
705 : : * Convert ARG, a string in base BASE, to an unsigned long value no
706 : : * greater than MAXVAL. On failure, diagnose with MSGID and exit.
707 : : */
708 : : static unsigned long
709 : 0 : arg2num(char const *arg, int base, unsigned long maxval, char const *msgid)
710 : : {
711 : : unsigned long n;
712 : : char *ep;
713 : :
714 : 0 : errno = 0;
715 : 0 : n = strtoul(arg, &ep, base);
716 [ # # # # : 0 : if (ep == arg || *ep || maxval < n || errno)
# # # # ]
717 : : {
718 : 0 : fprintf(stderr, _(msgid), progname, arg);
719 : 0 : exit(EXIT_FAILURE);
720 : : }
721 : 0 : return n;
722 : : }
723 : :
724 : : #ifndef MODE_T_MAX
725 : : #define MODE_T_MAX MAXVAL(mode_t, TYPE_BIT(mode_t))
726 : : #endif
727 : :
728 : : #ifndef HAVE_SETMODE
729 : : #if (defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
730 : : || (defined __APPLE__ && defined __MACH__))
731 : : #define HAVE_SETMODE 1
732 : : #else
733 : : #define HAVE_SETMODE 0
734 : : #endif
735 : : #endif
736 : :
737 : : static mode_t const no_mode = -1;
738 : : static mode_t output_mode = -1;
739 : :
740 : : static mode_t
741 : 0 : mode_option(char const *arg)
742 : : {
743 : : #if HAVE_SETMODE
744 : : void *set = setmode(arg);
745 : :
746 : : if (set)
747 : : {
748 : : mode_t mode = getmode(set, CREAT_PERMS);
749 : :
750 : : free(set);
751 : : return mode;
752 : : }
753 : : #endif
754 : 0 : return arg2num(arg, 8, min(MODE_T_MAX, ULONG_MAX),
755 : : N_("%s: -m '%s': invalid mode\n"));
756 : : }
757 : :
758 : : static int
759 : 1364 : chmetadata(FILE *stream)
760 : : {
761 : : #ifndef WIN32
762 [ + - - + ]: 1364 : if (output_owner != no_uid || output_group != no_gid)
763 : : {
764 : 0 : int r = fchown(fileno(stream), output_owner, output_group);
765 : :
766 [ # # ]: 0 : if (r < 0)
767 : 0 : return r;
768 : : }
769 [ - + ]: 1364 : return output_mode == no_mode ? 0 : fchmod(fileno(stream), output_mode);
770 : : #else
771 : : return 0;
772 : : #endif
773 : : }
774 : :
775 : : /*
776 : : * Close STREAM.
777 : : * If it had an I/O error, report it against DIR/NAME,
778 : : * remove TEMPNAME if nonnull, and then exit.
779 : : * If TEMPNAME is nonnull, and if requested,
780 : : * change the stream's metadata before closing.
781 : : */
782 : : static void
783 : 1368 : close_file(FILE *stream, char const *dir, char const *name,
784 : : char const *tempname)
785 : : {
786 : 1368 : char const *e = (ferror(stream) ? _("I/O error")
787 [ + - + + ]: 2736 : : ((tempname
788 [ + - + - ]: 1364 : && (fflush(stream) < 0 || chmetadata(stream) < 0))
789 [ - + ]: 1368 : || fclose(stream) < 0)
790 : 0 : ? strerror(errno) : NULL);
791 : :
792 [ - + ]: 1368 : if (e)
793 : : {
794 [ # # # # ]: 0 : if (name && *name == '/')
795 : 0 : dir = NULL;
796 [ # # # # : 0 : fprintf(stderr, "%s: %s%s%s%s%s\n", progname,
# # # # ]
797 : : dir ? dir : "", dir ? "/" : "",
798 : : name ? name : "", name ? ": " : "",
799 : : e);
800 [ # # ]: 0 : if (tempname)
801 : 0 : remove(tempname);
802 : 0 : exit(EXIT_FAILURE);
803 : : }
804 : 1368 : }
805 : :
806 : : ATTRIBUTE_NORETURN static void
807 : 0 : duplicate_options(char const *opt)
808 : : {
809 : 0 : fprintf(stderr, _("%s: More than one %s option specified\n"), progname, opt);
810 : 0 : exit(EXIT_FAILURE);
811 : : }
812 : :
813 : : ATTRIBUTE_NORETURN static void
814 : 0 : usage(FILE *stream, int status)
815 : : {
816 : 0 : fprintf(stream,
817 : : _("%s: usage is %s [ --version ] [ --help ] [ -v ] [ -P ] \\\n"
818 : : "\t[ -b {slim|fat} ] [ -d directory ] [ -D ] \\\n"
819 : : "\t[ -l localtime ] [ -L leapseconds ] [ -m mode ] \\\n"
820 : : "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R @hi ] \\\n"
821 : : "\t[ -t localtime-link ] [ -u 'owner[:group]' ] \\\n"
822 : : "\t[ filename ... ]\n\n"
823 : : "Report bugs to %s.\n"),
824 : : progname, progname, PACKAGE_BUGREPORT);
825 [ # # ]: 0 : if (status == EXIT_SUCCESS)
826 : 0 : close_file(stream, NULL, NULL, NULL);
827 : 0 : exit(status);
828 : : }
829 : :
830 : : static void
831 : 0 : group_option(char const *arg)
832 : : {
833 : : #ifndef WIN32
834 [ # # ]: 0 : if (*arg)
835 : : {
836 [ # # ]: 0 : if (output_group != no_gid)
837 : : {
838 : 0 : fprintf(stderr, _("multiple groups specified"));
839 : 0 : exit(EXIT_FAILURE);
840 : : }
841 : : else
842 : : {
843 : 0 : struct group *gr = getgrnam(arg);
844 : :
845 [ # # ]: 0 : output_group = (gr ? gr->gr_gid
846 : 0 : : arg2num(arg, 10, min(GID_T_MAX, ULONG_MAX),
847 : : N_("%s: invalid group: %s\n")));
848 : : }
849 : : }
850 : : #endif
851 : 0 : }
852 : :
853 : : static void
854 : 0 : owner_option(char const *arg)
855 : : {
856 : : #ifndef WIN32
857 [ # # ]: 0 : if (*arg)
858 : : {
859 [ # # ]: 0 : if (output_owner != no_uid)
860 : : {
861 : 0 : fprintf(stderr, _("multiple owners specified"));
862 : 0 : exit(EXIT_FAILURE);
863 : : }
864 : : else
865 : : {
866 : 0 : struct passwd *pw = getpwnam(arg);
867 : :
868 [ # # ]: 0 : output_owner = (pw ? pw->pw_uid
869 : 0 : : arg2num(arg, 10, min(UID_T_MAX, ULONG_MAX),
870 : : N_("%s: invalid owner: %s\n")));
871 : : }
872 : : }
873 : : #endif
874 : 0 : }
875 : :
876 : : /*
877 : : * If setting owner or group, use temp file permissions that avoid
878 : : * security races before the fchmod at the end.
879 : : */
880 : : static void
881 : 4 : use_safe_temp_permissions(void)
882 : : {
883 [ + - - + ]: 4 : if (output_owner != no_uid || output_group != no_gid)
884 : : {
885 : :
886 : : /* The mode when done with the file. */
887 : : mode_t omode;
888 : :
889 [ # # ]: 0 : if (output_mode == no_mode)
890 : : {
891 : 0 : mode_t cmask = umask(0);
892 : :
893 : 0 : umask(cmask);
894 : 0 : omode = CREAT_PERMS & ~cmask;
895 : : }
896 : : else
897 : 0 : omode = output_mode;
898 : :
899 : : /*
900 : : * The mode passed to open+O_CREAT. Do not bother with executable
901 : : * permissions, as they should not be used and this mode is merely a
902 : : * nicety (even a mode of 0 still work).
903 : : */
904 : 0 : creat_perms = ((((omode & (S_IRUSR | S_IRGRP | S_IROTH))
905 : : == (S_IRUSR | S_IRGRP | S_IROTH))
906 [ # # ]: 0 : ? S_IRUSR | S_IRGRP | S_IROTH : 0)
907 : 0 : | (((omode & (S_IWUSR | S_IWGRP | S_IWOTH))
908 : : == (S_IWUSR | S_IWGRP | S_IWOTH))
909 [ # # ]: 0 : ? S_IWUSR | S_IWGRP | S_IWOTH : 0));
910 : :
911 : : /*
912 : : * If creat_perms is not the final mode, arrange to run fchmod later,
913 : : * even if -m was not used.
914 : : */
915 [ # # ]: 0 : if (creat_perms != omode)
916 : 0 : output_mode = omode;
917 : : }
918 : 4 : }
919 : :
920 : : /*
921 : : * Change the working directory to DIR, possibly creating DIR and its
922 : : * ancestors. After this is done, all files are accessed with names
923 : : * relative to DIR.
924 : : */
925 : : static void
926 : 4 : change_directory(char const *dir)
927 : : {
928 [ + + ]: 4 : if (chdir(dir) != 0)
929 : : {
930 : 2 : int chdir_errno = errno;
931 : :
932 [ + - ]: 2 : if (chdir_errno == ENOENT)
933 : : {
934 : 2 : mkdirs(dir, false);
935 [ - + ]: 2 : chdir_errno = chdir(dir) == 0 ? 0 : errno;
936 : : }
937 [ - + ]: 2 : if (chdir_errno != 0)
938 : : {
939 : 0 : fprintf(stderr, _("%s: Can't chdir to %s: %s\n"),
940 : : progname, dir, strerror(chdir_errno));
941 : 0 : exit(EXIT_FAILURE);
942 : : }
943 : : }
944 : 4 : }
945 : :
946 : : /* Compare the two links A and B, for a stable sort by link name. */
947 : : static int
948 : 8408 : qsort_linkcmp(void const *a, void const *b)
949 : : {
950 : 8408 : struct link const *l = a;
951 : 8408 : struct link const *m = b;
952 : 8408 : int cmp = strcmp(l->l_linkname, m->l_linkname);
953 : :
954 [ + - ]: 8408 : if (cmp)
955 : 8408 : return cmp;
956 : :
957 : : /*
958 : : * The link names are the same. Make the sort stable by comparing file
959 : : * numbers (where subtraction cannot overflow) and possibly line numbers
960 : : * (where it can).
961 : : */
962 : 0 : cmp = l->l_filenum - m->l_filenum;
963 [ # # ]: 0 : if (cmp)
964 : 0 : return cmp;
965 : 0 : return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum);
966 : : }
967 : :
968 : : /* Compare the string KEY to the link B, for bsearch. */
969 : : static int
970 : 7108 : bsearch_linkcmp(void const *key, void const *b)
971 : : {
972 : 7108 : struct link const *m = b;
973 : :
974 : 7108 : return strcmp(key, m->l_linkname);
975 : : }
976 : :
977 : : /* Make the links specified by the Link lines. */
978 : : static void
979 : 4 : make_links(void)
980 : : {
981 : : ptrdiff_t i,
982 : : j,
983 : : nalinks,
984 : : pass_size;
985 : :
986 [ + - ]: 4 : if (1 < nlinks)
987 : 4 : qsort(links, nlinks, sizeof *links, qsort_linkcmp);
988 : :
989 : : /* Ignore each link superseded by a later link with the same name. */
990 : 4 : j = 0;
991 [ + + ]: 1032 : for (i = 0; i < nlinks; i++)
992 : : {
993 : 1028 : while (i + 1 < nlinks
994 [ + + - + ]: 1028 : && strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0)
995 : 0 : i++;
996 : 1028 : links[j++] = links[i];
997 : : }
998 : 4 : nlinks = pass_size = j;
999 : :
1000 : : /*
1001 : : * Walk through the link array making links. However, if a link's target
1002 : : * has not been made yet, append a copy to the end of the array. The end
1003 : : * of the array will gradually fill up with a small sorted subsequence of
1004 : : * not-yet-made links. nalinks counts all the links in the array,
1005 : : * including copies. When we reach the copied subsequence, it may still
1006 : : * contain a link to a not-yet-made link, so the process repeats. At any
1007 : : * given point in time, the link array consists of the following
1008 : : * subregions, where 0 <= i <= j <= nalinks and 0 <= nlinks <= nalinks:
1009 : : *
1010 : : * 0 .. (i - 1): links that either have been made, or have been copied to
1011 : : * a later point point in the array (this later point can be in any of the
1012 : : * three subregions) i .. (j - 1): not-yet-made links for this pass j ..
1013 : : * (nalinks - 1): not-yet-made links that this pass has skipped because
1014 : : * they were links to not-yet-made links
1015 : : *
1016 : : * The first subregion might not be sorted if nlinks < i; the other two
1017 : : * subregions are sorted. This algorithm does not alter entries 0 ..
1018 : : * (nlinks - 1), which remain sorted.
1019 : : *
1020 : : * If there are L links, this algorithm is O(C*L*log(L)) where C is the
1021 : : * length of the longest link chain. Usually C is short (e.g., 3) though
1022 : : * its worst-case value is L.
1023 : : */
1024 : :
1025 : 4 : j = nalinks = nlinks;
1026 : :
1027 [ + + ]: 1032 : for (i = 0; i < nalinks; i++)
1028 : : {
1029 : : struct link *l;
1030 : :
1031 : 1028 : eat(links[i].l_filenum, links[i].l_linenum);
1032 : :
1033 : : /* If this pass examined all its links, start the next pass. */
1034 [ - + ]: 1028 : if (i == j)
1035 : : {
1036 [ # # ]: 0 : if (nalinks - i == pass_size)
1037 : : {
1038 : 0 : error(_("\"Link %s %s\" is part of a link cycle"),
1039 : 0 : links[i].l_target, links[i].l_linkname);
1040 : 0 : break;
1041 : : }
1042 : 0 : j = nalinks;
1043 : 0 : pass_size = nalinks - i;
1044 : : }
1045 : :
1046 : : /*
1047 : : * Diagnose self links, which the cycle detection algorithm would not
1048 : : * otherwise catch.
1049 : : */
1050 [ - + ]: 1028 : if (strcmp(links[i].l_target, links[i].l_linkname) == 0)
1051 : : {
1052 : 0 : error(_("link %s targets itself"), links[i].l_target);
1053 : 0 : continue;
1054 : : }
1055 : :
1056 : : /* Make this link unless its target has not been made yet. */
1057 : 1028 : l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1),
1058 : : sizeof *links, bsearch_linkcmp);
1059 [ + - ]: 1028 : if (!l)
1060 : 1028 : l = bsearch(links[i].l_target, &links[j], nalinks - j,
1061 : : sizeof *links, bsearch_linkcmp);
1062 [ + - ]: 1028 : if (!l)
1063 : 1028 : dolink(links[i].l_target, links[i].l_linkname, false);
1064 : : else
1065 : : {
1066 : : /*
1067 : : * The link target has not been made yet; copy the link to the
1068 : : * end.
1069 : : */
1070 : 0 : links = growalloc(links, sizeof *links, nalinks, &nlinks_alloc);
1071 : 0 : links[nalinks++] = links[i];
1072 : : }
1073 : :
1074 [ - + - - ]: 1028 : if (noise && i < nlinks)
1075 : : {
1076 [ # # ]: 0 : if (l)
1077 : 0 : warning(_("link %s targeting link %s mishandled by pre-2023 zic"),
1078 : 0 : links[i].l_linkname, links[i].l_target);
1079 [ # # ]: 0 : else if (bsearch(links[i].l_target, links, nlinks, sizeof *links,
1080 : : bsearch_linkcmp))
1081 : 0 : warning(_("link %s targeting link %s"),
1082 : 0 : links[i].l_linkname, links[i].l_target);
1083 : : }
1084 : 1028 : check_for_signal();
1085 : : }
1086 : 4 : }
1087 : :
1088 : : /*
1089 : : * Simple signal handling: just set a flag that is checked
1090 : : * periodically outside critical sections. To set up the handler,
1091 : : * prefer sigaction if available to close a signal race.
1092 : : */
1093 : :
1094 : : static sig_atomic_t got_signal;
1095 : :
1096 : : static void
1097 : 0 : signal_handler(int sig)
1098 : : {
1099 : : #ifndef SA_SIGINFO
1100 : : signal(sig, signal_handler);
1101 : : #endif
1102 : 0 : got_signal = sig;
1103 : 0 : }
1104 : :
1105 : : /* Arrange for SIGINT etc. to be caught by the handler. */
1106 : : static void
1107 : 4 : catch_signals(void)
1108 : : {
1109 : : static int const signals[] = {
1110 : : #ifdef SIGHUP
1111 : : SIGHUP,
1112 : : #endif
1113 : : SIGINT,
1114 : : #ifdef SIGPIPE
1115 : : SIGPIPE,
1116 : : #endif
1117 : : SIGTERM
1118 : : };
1119 : : size_t i;
1120 : :
1121 [ + + ]: 20 : for (i = 0; i < sizeof signals / sizeof signals[0]; i++)
1122 : : {
1123 : : #ifdef SA_SIGINFO
1124 : : struct sigaction act0,
1125 : : act;
1126 : :
1127 : 16 : act.sa_handler = signal_handler;
1128 : 16 : sigemptyset(&act.sa_mask);
1129 : 16 : act.sa_flags = 0;
1130 [ + - ]: 16 : if (sigaction(signals[i], &act, &act0) == 0
1131 [ + - - + ]: 16 : && !(act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN)
1132 : : {
1133 : 0 : sigaction(signals[i], &act0, NULL);
1134 : 0 : got_signal = 0;
1135 : : }
1136 : : #else
1137 : : if (signal(signals[i], signal_handler) == SIG_IGN)
1138 : : {
1139 : : signal(signals[i], SIG_IGN);
1140 : : got_signal = 0;
1141 : : }
1142 : : #endif
1143 : : }
1144 : 4 : }
1145 : :
1146 : : /* If a signal has arrived, terminate zic with appropriate status. */
1147 : : static void
1148 : 425790 : check_for_signal(void)
1149 : : {
1150 : 425790 : int sig = got_signal;
1151 : :
1152 [ - + ]: 425790 : if (sig)
1153 : : {
1154 : 0 : signal(sig, SIG_DFL);
1155 : 0 : raise(sig);
1156 : 0 : abort(); /* A bug in 'raise'. */
1157 : : }
1158 : 425790 : }
1159 : :
1160 : : enum
1161 : : {
1162 : : TIME_T_BITS_IN_FILE = 64};
1163 : :
1164 : : /* The minimum and maximum values representable in a TZif file. */
1165 : : static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
1166 : : static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
1167 : :
1168 : : /*
1169 : : * The minimum, and one less than the maximum, values specified by
1170 : : * the -r option. These default to MIN_TIME and MAX_TIME.
1171 : : */
1172 : : static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
1173 : : static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
1174 : :
1175 : : /*
1176 : : * The time specified by the -R option, defaulting to MIN_TIME;
1177 : : * or lo_time, whichever is greater.
1178 : : */
1179 : : static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE);
1180 : :
1181 : : /* The time specified by an Expires line, or negative if no such line. */
1182 : : static zic_t leapexpires = -1;
1183 : :
1184 : : /*
1185 : : * Set the time range of the output to TIMERANGE.
1186 : : * Return true if successful.
1187 : : */
1188 : : static bool
1189 : 0 : timerange_option(char *timerange)
1190 : : {
1191 : 0 : intmax_t lo = min_time,
1192 : 0 : hi = max_time;
1193 : 0 : char *lo_end = timerange,
1194 : : *hi_end;
1195 : :
1196 [ # # ]: 0 : if (*timerange == '@')
1197 : : {
1198 : 0 : errno = 0;
1199 : 0 : lo = strtoimax(timerange + 1, &lo_end, 10);
1200 [ # # # # : 0 : if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE))
# # ]
1201 : 0 : return false;
1202 : : }
1203 : 0 : hi_end = lo_end;
1204 [ # # # # ]: 0 : if (lo_end[0] == '/' && lo_end[1] == '@')
1205 : : {
1206 : 0 : errno = 0;
1207 : 0 : hi = strtoimax(lo_end + 2, &hi_end, 10);
1208 [ # # # # ]: 0 : if (hi_end == lo_end + 2 || hi == INTMAX_MIN)
1209 : 0 : return false;
1210 [ # # # # ]: 0 : hi -= !(hi == INTMAX_MAX && errno == ERANGE);
1211 : : }
1212 [ # # # # : 0 : if (*hi_end || hi < lo || max_time < lo || hi < min_time)
# # # # ]
1213 : 0 : return false;
1214 : 0 : lo_time = max(lo, min_time);
1215 : 0 : hi_time = min(hi, max_time);
1216 : 0 : return true;
1217 : : }
1218 : :
1219 : : /* Generate redundant time stamps up to OPT. Return true if successful. */
1220 : : static bool
1221 : 0 : redundant_time_option(char *opt)
1222 : : {
1223 [ # # ]: 0 : if (*opt == '@')
1224 : : {
1225 : : intmax_t redundant;
1226 : : char *opt_end;
1227 : :
1228 : 0 : redundant = strtoimax(opt + 1, &opt_end, 10);
1229 [ # # # # ]: 0 : if (opt_end != opt + 1 && !*opt_end)
1230 : : {
1231 : 0 : redundant_time = max(redundant_time, redundant);
1232 : 0 : return true;
1233 : : }
1234 : : }
1235 : 0 : return false;
1236 : : }
1237 : :
1238 : : static const char *psxrules;
1239 : : static const char *lcltime;
1240 : : static const char *directory;
1241 : : static const char *tzdefault;
1242 : :
1243 : : /* True if DIRECTORY ends in '/'. */
1244 : : static bool directory_ends_in_slash;
1245 : :
1246 : : /*
1247 : : * -1 if the TZif output file should be slim, 0 if default, 1 if the
1248 : : * output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT
1249 : : * determines the default.
1250 : : */
1251 : : static int bloat;
1252 : :
1253 : : static bool
1254 : 79884 : want_bloat(void)
1255 : : {
1256 : 79884 : return 0 <= bloat;
1257 : : }
1258 : :
1259 : : #ifndef ZIC_BLOAT_DEFAULT
1260 : : #define ZIC_BLOAT_DEFAULT "slim"
1261 : : #endif
1262 : :
1263 : : int
1264 : 4 : main(int argc, char **argv)
1265 : 6484 : {
1266 : : int c,
1267 : : k;
1268 : : ptrdiff_t i,
1269 : : j;
1270 : 4 : bool timerange_given = false;
1271 : :
1272 : 4 : main_argv = argv;
1273 [ + - ]: 4 : progname = argv[0] ? argv[0] : "zic";
1274 : : if (TYPE_BIT(zic_t) < 64)
1275 : : {
1276 : : fprintf(stderr, "%s: %s\n", progname,
1277 : : _("wild compilation-time specification of zic_t"));
1278 : : return EXIT_FAILURE;
1279 : : }
1280 [ + + ]: 16 : for (k = 1; k < argc; k++)
1281 [ - + ]: 12 : if (strcmp(argv[k], "--version") == 0)
1282 : : {
1283 : 0 : printf("zic %s\n", PG_VERSION);
1284 : 0 : close_file(stdout, NULL, NULL, NULL);
1285 : 0 : return EXIT_SUCCESS;
1286 : : }
1287 [ - + ]: 12 : else if (strcmp(argv[k], "--help") == 0)
1288 : : {
1289 : 0 : usage(stdout, EXIT_SUCCESS);
1290 : : }
1291 [ + + ]: 8 : while ((c = getopt(argc, argv, "b:d:Dg:l:L:m:p:Pr:R:st:u:vy:")) != -1)
1292 [ - - + - : 4 : switch (c)
- - - - -
- - - - -
- - - ]
1293 : : {
1294 : 0 : default:
1295 : 0 : usage(stderr, EXIT_FAILURE);
1296 : 0 : case 'b':
1297 [ # # ]: 0 : if (strcmp(optarg, "slim") == 0)
1298 : : {
1299 [ # # ]: 0 : if (0 < bloat)
1300 : 0 : error(_("incompatible -b options"));
1301 : 0 : bloat = -1;
1302 : : }
1303 [ # # ]: 0 : else if (strcmp(optarg, "fat") == 0)
1304 : : {
1305 [ # # ]: 0 : if (bloat < 0)
1306 : 0 : error(_("incompatible -b options"));
1307 : 0 : bloat = 1;
1308 : : }
1309 : : else
1310 : 0 : error(_("invalid option: -b '%s'"), optarg);
1311 : 0 : break;
1312 : 4 : case 'd':
1313 [ - + ]: 4 : if (directory)
1314 : 0 : duplicate_options("-d");
1315 : 4 : directory = strdup(optarg);
1316 : 4 : break;
1317 : 0 : case 'D':
1318 : 0 : skip_mkdir = true;
1319 : 0 : break;
1320 : 0 : case 'g':
1321 : :
1322 : : /*
1323 : : * This undocumented option is present for compatibility with
1324 : : * FreeBSD 14.
1325 : : */
1326 : 0 : group_option(optarg);
1327 : 0 : break;
1328 : 0 : case 'l':
1329 [ # # ]: 0 : if (lcltime)
1330 : 0 : duplicate_options("-l");
1331 : 0 : lcltime = strdup(optarg);
1332 : 0 : break;
1333 : 0 : case 'm':
1334 [ # # ]: 0 : if (output_mode != no_mode)
1335 : 0 : duplicate_options("-m");
1336 : 0 : output_mode = mode_option(optarg);
1337 : 0 : break;
1338 : 0 : case 'p':
1339 [ # # ]: 0 : if (psxrules)
1340 : 0 : duplicate_options("-p");
1341 [ # # ]: 0 : if (strcmp(optarg, "-") != 0)
1342 : 0 : warning(_("-p is obsolete"
1343 : : " and likely ineffective"));
1344 : 0 : psxrules = strdup(optarg);
1345 : 0 : break;
1346 : 0 : case 't':
1347 [ # # ]: 0 : if (tzdefault)
1348 : 0 : duplicate_options("-t");
1349 : 0 : tzdefault = strdup(optarg);
1350 : 0 : break;
1351 : 0 : case 'u':
1352 : : {
1353 : 0 : char *colon = strchr(optarg, ':');
1354 : :
1355 [ # # ]: 0 : if (colon)
1356 : 0 : *colon = '\0';
1357 : 0 : owner_option(optarg);
1358 [ # # ]: 0 : if (colon)
1359 : 0 : group_option(colon + 1);
1360 : : }
1361 : 0 : break;
1362 : 0 : case 'y':
1363 : 0 : warning(_("-y ignored"));
1364 : 0 : break;
1365 : 0 : case 'L':
1366 [ # # ]: 0 : if (leapsec)
1367 : 0 : duplicate_options("-L");
1368 : 0 : leapsec = strdup(optarg);
1369 : 0 : break;
1370 : 0 : case 'v':
1371 : 0 : noise = true;
1372 : 0 : break;
1373 : 0 : case 'P':
1374 : 0 : print_abbrevs = true;
1375 : 0 : print_cutoff = time(NULL);
1376 : 0 : break;
1377 : 0 : case 'r':
1378 [ # # ]: 0 : if (timerange_given)
1379 : 0 : duplicate_options("-r");
1380 [ # # ]: 0 : if (!timerange_option(optarg))
1381 : : {
1382 : 0 : fprintf(stderr,
1383 : : _("%s: invalid time range: %s\n"),
1384 : : progname, optarg);
1385 : 0 : return EXIT_FAILURE;
1386 : : }
1387 : 0 : timerange_given = true;
1388 : 0 : break;
1389 : 0 : case 'R':
1390 [ # # ]: 0 : if (!redundant_time_option(optarg))
1391 : : {
1392 : 0 : fprintf(stderr, _("%s: invalid time: %s\n"),
1393 : : progname, optarg);
1394 : 0 : return EXIT_FAILURE;
1395 : : }
1396 : 0 : break;
1397 : 0 : case 's':
1398 : 0 : warning(_("-s ignored"));
1399 : 0 : break;
1400 : : }
1401 [ + - - + ]: 4 : if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
1402 : 0 : usage(stderr, EXIT_FAILURE); /* usage message by request */
1403 [ - + ]: 4 : if (hi_time + (hi_time < ZIC_MAX) < redundant_time)
1404 : : {
1405 : 0 : fprintf(stderr, _("%s: -R time exceeds -r cutoff\n"), progname);
1406 : 0 : return EXIT_FAILURE;
1407 : : }
1408 [ - + ]: 4 : if (redundant_time < lo_time)
1409 : 0 : redundant_time = lo_time;
1410 [ + - ]: 4 : if (bloat == 0)
1411 : : {
1412 : : static char const bloat_default[] = ZIC_BLOAT_DEFAULT;
1413 : :
1414 [ + - ]: 4 : if (strcmp(bloat_default, "slim") == 0)
1415 : 4 : bloat = -1;
1416 [ # # ]: 0 : else if (strcmp(bloat_default, "fat") == 0)
1417 : 0 : bloat = 1;
1418 : : else
1419 : 0 : abort(); /* Configuration error. */
1420 : : }
1421 [ - + ]: 4 : if (directory == NULL)
1422 : 0 : directory = "data";
1423 [ + - ]: 4 : if (tzdefault == NULL)
1424 : 4 : tzdefault = TZDEFAULT;
1425 : :
1426 [ + - - + ]: 4 : if (optind < argc && leapsec != NULL)
1427 : : {
1428 : 0 : infile(LEAPSEC_FILENUM, leapsec);
1429 : 0 : adjleap();
1430 : : }
1431 : :
1432 [ + + ]: 8 : for (k = optind; k < argc; k++)
1433 : 4 : infile(k, argv[k]);
1434 [ - + ]: 4 : if (errors)
1435 : 0 : return EXIT_FAILURE;
1436 : 4 : associate();
1437 : 4 : use_safe_temp_permissions();
1438 : 4 : change_directory(directory);
1439 : 4 : directory_ends_in_slash = directory[strlen(directory) - 1] == '/';
1440 : 4 : catch_signals();
1441 [ + + ]: 1368 : for (i = 0; i < nzones; i = j)
1442 : : {
1443 : : /*
1444 : : * Find the next non-continuation zone entry.
1445 : : */
1446 [ + + + + ]: 7848 : for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
1447 : 6484 : continue;
1448 : 1364 : outzone(&zones[i], j - i);
1449 : 1364 : check_for_signal();
1450 : : }
1451 : 4 : make_links();
1452 [ - + ]: 4 : if (lcltime != NULL)
1453 : : {
1454 : 0 : eat(COMMAND_LINE_FILENUM, 1);
1455 : 0 : dolink(lcltime, tzdefault, true);
1456 : : }
1457 [ - + ]: 4 : if (psxrules != NULL)
1458 : : {
1459 : 0 : eat(COMMAND_LINE_FILENUM, 1);
1460 : 0 : dolink(psxrules, TZDEFRULES, true);
1461 : : }
1462 [ - + - - : 4 : if (warnings && (ferror(stderr) || fclose(stderr) != 0))
- - ]
1463 : 0 : return EXIT_FAILURE;
1464 : 4 : return errors ? EXIT_FAILURE : EXIT_SUCCESS;
1465 : : }
1466 : :
1467 : : static bool
1468 : 4708 : componentcheck(char const *name, char const *component,
1469 : : char const *component_end)
1470 : : {
1471 : : enum
1472 : : {
1473 : : component_len_max = 14};
1474 : 4708 : ptrdiff_t component_len = component_end - component;
1475 : :
1476 [ - + ]: 4708 : if (component_len == 0)
1477 : : {
1478 [ # # ]: 0 : if (!*name)
1479 : 0 : error(_("empty file name"));
1480 : : else
1481 [ # # # # ]: 0 : error(_(component == name
1482 : : ? "file name '%s' begins with '/'"
1483 : : : *component_end
1484 : : ? "file name '%s' contains '//'"
1485 : : : "file name '%s' ends with '/'"),
1486 : : name);
1487 : 0 : return false;
1488 : : }
1489 [ + - + + ]: 4708 : if (0 < component_len && component_len <= 2
1490 [ - + - - ]: 56 : && component[0] == '.' && component_end[-1] == '.')
1491 : : {
1492 : 0 : int len = component_len;
1493 : :
1494 : 0 : error(_("file name '%s' contains '%.*s' component"),
1495 : : name, len, component);
1496 : 0 : return false;
1497 : : }
1498 [ - + ]: 4708 : if (noise)
1499 : : {
1500 [ # # # # ]: 0 : if (0 < component_len && component[0] == '-')
1501 : 0 : warning(_("file name '%s' component contains leading '-'"),
1502 : : name);
1503 [ # # ]: 0 : if (component_len_max < component_len)
1504 : 0 : warning(_("file name '%s' contains overlength component"
1505 : : " '%.*s...'"),
1506 : : name, component_len_max, component);
1507 : : }
1508 : 4708 : return true;
1509 : : }
1510 : :
1511 : : static bool
1512 : 2392 : namecheck(const char *name)
1513 : : {
1514 : : char const *cp;
1515 : :
1516 : : /* Benign characters in a portable file name. */
1517 : : static char const benign[] =
1518 : : "-/_"
1519 : : "abcdefghijklmnopqrstuvwxyz"
1520 : : "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1521 : :
1522 : : /*
1523 : : * Non-control chars in the POSIX portable character set, excluding the
1524 : : * benign characters.
1525 : : */
1526 : : static char const printable_and_not_benign[] =
1527 : : " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~";
1528 : :
1529 : 2392 : char const *component = name;
1530 : :
1531 [ + + ]: 36408 : for (cp = name; *cp; cp++)
1532 : : {
1533 : 34016 : unsigned char c = *cp;
1534 : :
1535 [ - + - - ]: 34016 : if (noise && !strchr(benign, c))
1536 : : {
1537 [ # # ]: 0 : warning((strchr(printable_and_not_benign, c)
1538 : : ? _("file name '%s' contains byte '%c'")
1539 : : : _("file name '%s' contains byte '\\%o'")),
1540 : : name, c);
1541 : : }
1542 [ + + ]: 34016 : if (c == '/')
1543 : : {
1544 [ - + ]: 2316 : if (!componentcheck(name, component, cp))
1545 : 0 : return false;
1546 : 2316 : component = cp + 1;
1547 : : }
1548 : : }
1549 : 2392 : return componentcheck(name, component, cp);
1550 : : }
1551 : :
1552 : : /* Return a random uint_fast64_t. */
1553 : : static uint_fast64_t
1554 : 1878 : get_rand_u64(void)
1555 : : {
1556 : : #if HAVE_GETRANDOM
1557 : : static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))];
1558 : : static int nwords;
1559 : :
1560 : : if (!nwords)
1561 : : {
1562 : : ssize_t s;
1563 : :
1564 : : for (;; check_for_signal())
1565 : : {
1566 : : s = getrandom(entropy_buffer, sizeof entropy_buffer, 0);
1567 : : if (!(s < 0 && errno == EINTR))
1568 : : break;
1569 : : }
1570 : :
1571 : : nwords = s < 0 ? -1 : s / sizeof *entropy_buffer;
1572 : : }
1573 : : if (0 < nwords)
1574 : : return entropy_buffer[--nwords];
1575 : : #endif
1576 : :
1577 : : /*
1578 : : * getrandom didn't work, so fall back on portable code that is not the
1579 : : * best because the seed isn't cryptographically random and 'rand' might
1580 : : * not be cryptographically secure.
1581 : : */
1582 : : {
1583 : : static bool initialized;
1584 : :
1585 [ + + ]: 1878 : if (!initialized)
1586 : : {
1587 : 4 : srand(time(NULL));
1588 : 4 : initialized = true;
1589 : : }
1590 : : }
1591 : :
1592 : : /*
1593 : : * Return a random number if rand() yields a random number and in the
1594 : : * typical case where RAND_MAX is one less than a power of two. In other
1595 : : * cases this code yields a sort-of-random number.
1596 : : */
1597 : : {
1598 : 1878 : uint_fast64_t rand_max = RAND_MAX,
1599 [ + - ]: 1878 : nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
1600 : 1878 : rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
1601 : 1878 : r = 0,
1602 : 1878 : rmax = 0;
1603 : :
1604 : 3756 : for (;; check_for_signal())
1605 : 3756 : {
1606 : 5634 : uint_fast64_t rmax1 = rmax;
1607 : :
1608 [ - + ]: 5634 : if (rmod)
1609 : : {
1610 : : /*
1611 : : * Avoid signed integer overflow on theoretical platforms
1612 : : * where uint_fast64_t promotes to int.
1613 : : */
1614 : 0 : rmax1 %= rmod;
1615 : 0 : r %= rmod;
1616 : : }
1617 : 5634 : rmax1 = nrand * rmax1 + rand_max;
1618 : 5634 : r = nrand * r + rand();
1619 [ + - ]: 5634 : rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
1620 [ + + ]: 5634 : if (UINT_FAST64_MAX <= rmax)
1621 : 1878 : break;
1622 : : }
1623 : :
1624 : 1878 : return r;
1625 : : }
1626 : : }
1627 : :
1628 : : /*
1629 : : * Generate a randomish name in the same directory as *NAME. If
1630 : : * *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be
1631 : : * that returned by a previous call and is thus already almost set up
1632 : : * and equal to *NAME; otherwise, allocate a new name and put its
1633 : : * address into both *NAMEALLOC and *NAME.
1634 : : */
1635 : : static void
1636 : 1878 : random_dirent(char const **name, char **namealloc)
1637 : : {
1638 : 1878 : char const *src = *name;
1639 : 1878 : char *dst = *namealloc;
1640 : : static char const prefix[] = ".zic";
1641 : : static char const alphabet[] =
1642 : : "abcdefghijklmnopqrstuvwxyz"
1643 : : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1644 : : "0123456789";
1645 : : enum
1646 : : {
1647 : : prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1};
1648 : 1878 : int suffixlen = 6;
1649 : 1878 : char const *lastslash = strrchr(src, '/');
1650 [ + + ]: 1878 : ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0;
1651 : : int i;
1652 : : uint_fast64_t r;
1653 : 1878 : uint_fast64_t base = alphabetlen;
1654 : :
1655 : : /* BASE**6 */
1656 : 1878 : uint_fast64_t base__6 = base * base * base * base * base * base;
1657 : :
1658 : : /*
1659 : : * The largest uintmax_t that is a multiple of BASE**6. Any random
1660 : : * uintmax_t value that is this value or greater, yields a biased
1661 : : * remainder when divided by BASE**6. UNFAIR_MIN equals the mathematical
1662 : : * value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6) computed
1663 : : * without overflow.
1664 : : */
1665 : 1878 : uint_fast64_t unfair_min = -((UINTMAX_MAX % base__6 + 1) % base__6);
1666 : :
1667 [ + - ]: 1878 : if (!dst)
1668 : : {
1669 : 1878 : char *cp = dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1));
1670 : :
1671 : 1878 : memcpy(cp, src, dirlen);
1672 : 1878 : cp += dirlen;
1673 : 1878 : memcpy(cp, prefix, prefixlen);
1674 : 1878 : cp += prefixlen;
1675 : 1878 : cp[suffixlen] = '\0';
1676 : 1878 : *name = *namealloc = dst;
1677 : : }
1678 : :
1679 : 0 : for (;; check_for_signal())
1680 : : {
1681 : 1878 : r = get_rand_u64();
1682 [ + - ]: 1878 : if (r < unfair_min)
1683 : 1878 : break;
1684 : : }
1685 : :
1686 [ + + ]: 13146 : for (i = 0; i < suffixlen; i++)
1687 : : {
1688 : 11268 : dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen];
1689 : 11268 : r /= alphabetlen;
1690 : : }
1691 : 1878 : }
1692 : :
1693 : : /*
1694 : : * For diagnostics the directory, and file name relative to that
1695 : : * directory, respectively. A diagnostic routine can name FILENAME by
1696 : : * outputting diagdir(FILENAME), then diagslash(FILENAME), then FILENAME.
1697 : : */
1698 : : static char const *
1699 : 0 : diagdir(char const *filename)
1700 : : {
1701 [ # # ]: 0 : return *filename == '/' ? "" : directory;
1702 : : }
1703 : : static char const *
1704 : 0 : diagslash(char const *filename)
1705 : : {
1706 [ # # # # ]: 0 : return &"/"[*filename == '/' || directory_ends_in_slash];
1707 : : }
1708 : :
1709 : : /*
1710 : : * Prepare to write to the file *OUTNAME, using *TEMPNAME to store the
1711 : : * name of the temporary file that will eventually be renamed to
1712 : : * *OUTNAME. Assign the temporary file's name to both *OUTNAME and
1713 : : * *TEMPNAME. If *TEMPNAME is null, allocate the name of any such
1714 : : * temporary file; otherwise, reuse *TEMPNAME's storage, which is
1715 : : * already set up and only needs its trailing suffix updated.
1716 : : */
1717 : : static FILE *
1718 : 1364 : open_outfile(char const **outname, char **tempname)
1719 : : {
1720 : 1364 : bool dirs_made = false;
1721 : :
1722 [ + - ]: 1364 : if (!*tempname)
1723 : 1364 : random_dirent(outname, tempname);
1724 : :
1725 : 28 : for (;; check_for_signal())
1726 : 28 : {
1727 : 1392 : int oflags = O_WRONLY | O_BINARY | O_CREAT | O_EXCL;
1728 : 1392 : int fd = open(*outname, oflags, creat_perms);
1729 : : int err;
1730 : :
1731 [ + + ]: 1392 : if (fd < 0)
1732 : 28 : err = errno;
1733 : : else
1734 : : {
1735 : 1364 : FILE *fp = fdopen(fd, "wb");
1736 : :
1737 [ + - ]: 1364 : if (fp)
1738 : 1364 : return fp;
1739 : 0 : err = errno;
1740 : 0 : close(fd);
1741 : : }
1742 [ + - + - ]: 28 : if (err == ENOENT && !dirs_made)
1743 : : {
1744 : 28 : mkdirs(*outname, true);
1745 : 28 : dirs_made = true;
1746 : : }
1747 [ # # ]: 0 : else if (err == EEXIST)
1748 : 0 : random_dirent(outname, tempname);
1749 : : else
1750 : : {
1751 : 0 : fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"),
1752 : : progname, diagdir(*outname), diagslash(*outname), *outname,
1753 : : strerror(err));
1754 : 0 : exit(EXIT_FAILURE);
1755 : : }
1756 : : }
1757 : : }
1758 : :
1759 : : /*
1760 : : * If TEMPNAME, the result is in the temporary file TEMPNAME even
1761 : : * though the user wanted it in NAME, so rename TEMPNAME to NAME.
1762 : : * Report an error and exit if there is trouble. Also, free TEMPNAME.
1763 : : */
1764 : : static void
1765 : 2392 : rename_dest(char *tempname, char const *name)
1766 : : {
1767 [ + + ]: 2392 : if (tempname)
1768 : : {
1769 [ - + ]: 1878 : if (rename(tempname, name) != 0)
1770 : : {
1771 : 0 : int rename_errno = errno;
1772 : :
1773 : 0 : remove(tempname);
1774 : 0 : fprintf(stderr, _("%s: rename to %s%s%s: %s\n"),
1775 : : progname, diagdir(name), diagslash(name), name,
1776 : : strerror(rename_errno));
1777 : 0 : exit(EXIT_FAILURE);
1778 : : }
1779 : 1878 : free(tempname);
1780 : : }
1781 : 2392 : }
1782 : :
1783 : : /*
1784 : : * Create symlink contents suitable for symlinking TARGET to LINKNAME, as a
1785 : : * freshly allocated string. TARGET should be a relative file name, and
1786 : : * is relative to the global variable DIRECTORY. LINKNAME can be either
1787 : : * relative or absolute. Return a null pointer if the symlink contents
1788 : : * was not computed because LINKNAME is absolute but DIRECTORY is not.
1789 : : */
1790 : : #ifdef HAVE_SYMLINK
1791 : : static char *
1792 : 0 : relname(char const *target, char const *linkname)
1793 : : {
1794 : : size_t i,
1795 : : taillen,
1796 : 0 : dir_len = 0,
1797 : 0 : dotdots = 0;
1798 : : ptrdiff_t dotdotetcsize,
1799 : 0 : linksize = INDEX_MAX;
1800 : 0 : char const *f = target;
1801 : 0 : char *result = NULL;
1802 : :
1803 [ # # ]: 0 : if (*linkname == '/')
1804 : : {
1805 : : /* Make F absolute too. */
1806 : 0 : size_t len = strlen(directory);
1807 [ # # # # ]: 0 : bool needs_slash = len && directory[len - 1] != '/';
1808 : 0 : size_t lenslash = len + needs_slash;
1809 : 0 : size_t targetsize = strlen(target) + 1;
1810 : : char *cp;
1811 : :
1812 [ # # ]: 0 : if (*directory != '/')
1813 : 0 : return NULL;
1814 : 0 : linksize = size_sum(lenslash, targetsize);
1815 : 0 : f = cp = result = xmalloc(linksize);
1816 : 0 : memcpy(cp, directory, len);
1817 : 0 : cp += len;
1818 : 0 : *cp = '/';
1819 : 0 : memcpy(cp + needs_slash, target, targetsize);
1820 : : }
1821 [ # # # # ]: 0 : for (i = 0; f[i] && f[i] == linkname[i]; i++)
1822 [ # # ]: 0 : if (f[i] == '/')
1823 : 0 : dir_len = i + 1;
1824 [ # # ]: 0 : for (; linkname[i]; i++)
1825 [ # # # # ]: 0 : dotdots += linkname[i] == '/' && linkname[i - 1] != '/';
1826 : 0 : taillen = strlen(f + dir_len);
1827 : 0 : dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1);
1828 [ # # ]: 0 : if (dotdotetcsize <= linksize)
1829 : : {
1830 : : char *cp;
1831 : :
1832 [ # # ]: 0 : if (!result)
1833 : 0 : result = xmalloc(dotdotetcsize);
1834 : 0 : cp = result;
1835 [ # # ]: 0 : for (i = 0; i < dotdots; i++)
1836 : : {
1837 : 0 : memcpy(cp, "../", 3);
1838 : 0 : cp += 3;
1839 : : }
1840 : 0 : memmove(cp, f + dir_len, taillen + 1);
1841 : : }
1842 : 0 : return result;
1843 : : }
1844 : : #endif /* HAVE_SYMLINK */
1845 : :
1846 : : /*
1847 : : * Return true if A and B must have the same parent dir if A and B exist.
1848 : : * Return false if this is not necessarily true (though it might be true).
1849 : : * Keep it simple, and do not inspect the file system.
1850 : : */
1851 : : ATTRIBUTE_PURE_114833
1852 : : static bool
1853 : 0 : same_parent_dirs(char const *a, char const *b)
1854 : : {
1855 [ # # ]: 0 : for (; *a == *b; a++, b++)
1856 [ # # ]: 0 : if (!*a)
1857 : 0 : return true;
1858 [ # # # # ]: 0 : return !(strchr(a, '/') || strchr(b, '/'));
1859 : : }
1860 : :
1861 : : static void
1862 : 1028 : dolink(char const *target, char const *linkname, bool staysymlink)
1863 : : {
1864 : 1028 : bool linkdirs_made = false;
1865 : : int link_errno;
1866 : 1028 : char *tempname = NULL;
1867 : 1028 : char const *outname = linkname;
1868 : 1028 : int targetissym = -2,
1869 : 1028 : linknameissym = -2;
1870 : :
1871 [ - + ]: 1028 : if (strcmp(target, "-") == 0)
1872 : : {
1873 [ # # # # : 0 : if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR)
# # ]
1874 : 0 : return;
1875 : : else
1876 : : {
1877 : 0 : char const *e = strerror(errno);
1878 : :
1879 : 0 : fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"),
1880 : : progname, diagdir(linkname), diagslash(linkname), linkname,
1881 : : e);
1882 : 0 : exit(EXIT_FAILURE);
1883 : : }
1884 : : }
1885 : :
1886 : 526 : for (;; check_for_signal())
1887 : : {
1888 [ + + ]: 1554 : if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW)
1889 : : == 0)
1890 : : {
1891 : 1028 : link_errno = 0;
1892 : 1028 : break;
1893 : : }
1894 : 526 : link_errno = errno;
1895 : : /* Linux 2.6.16 and 2.6.17 mishandle AT_SYMLINK_FOLLOW. */
1896 [ - + ]: 526 : if (link_errno == EINVAL)
1897 : 0 : link_errno = ENOTSUP;
1898 : :
1899 : : /*
1900 : : * If linkat is not supported, fall back on link(A, B). However, skip
1901 : : * this if A is a relative symlink and A and B might not have the same
1902 : : * parent directory. On some platforms link(A, B) does not follow a
1903 : : * symlink A, and if A is relative it might misbehave elsewhere.
1904 : : */
1905 [ - + ]: 526 : if (link_errno == ENOTSUP
1906 [ # # ]: 0 : && (same_parent_dirs(target, outname)
1907 [ # # ]: 0 : || 0 <= itssymlink(target, &targetissym)))
1908 : : {
1909 [ # # ]: 0 : if (link(target, outname) == 0)
1910 : : {
1911 : 0 : link_errno = 0;
1912 : 0 : break;
1913 : : }
1914 : 0 : link_errno = errno;
1915 : : }
1916 [ + - + - ]: 526 : if (link_errno == EXDEV || link_errno == ENOTSUP)
1917 : : break;
1918 : :
1919 [ + + ]: 526 : if (link_errno == EEXIST)
1920 : : {
1921 : 514 : staysymlink &= !tempname;
1922 : 514 : random_dirent(&outname, &tempname);
1923 [ - + - - ]: 514 : if (staysymlink && itssymlink(linkname, &linknameissym))
1924 : 0 : break;
1925 : : }
1926 [ + - + - ]: 12 : else if (link_errno == ENOENT && !linkdirs_made)
1927 : : {
1928 : 12 : mkdirs(linkname, true);
1929 : 12 : linkdirs_made = true;
1930 : : }
1931 : : else
1932 : : {
1933 : 0 : fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"),
1934 : : progname, diagdir(target), diagslash(target), target,
1935 : : diagdir(outname), diagslash(outname), outname,
1936 : : strerror(link_errno));
1937 : 0 : exit(EXIT_FAILURE);
1938 : : }
1939 : : }
1940 [ - + ]: 1028 : if (link_errno != 0)
1941 : : {
1942 : : #ifdef HAVE_SYMLINK
1943 : 0 : bool absolute = *target == '/';
1944 [ # # ]: 0 : char *linkalloc = absolute ? NULL : relname(target, linkname);
1945 [ # # ]: 0 : char const *contents = absolute ? target : linkalloc;
1946 : 0 : int symlink_errno = -1;
1947 : :
1948 [ # # ]: 0 : if (contents)
1949 : : {
1950 : 0 : for (;; check_for_signal())
1951 : : {
1952 [ # # ]: 0 : if (symlink(contents, outname) == 0)
1953 : : {
1954 : 0 : symlink_errno = 0;
1955 : 0 : break;
1956 : : }
1957 : 0 : symlink_errno = errno;
1958 [ # # ]: 0 : if (symlink_errno == EEXIST)
1959 : 0 : random_dirent(&outname, &tempname);
1960 [ # # # # ]: 0 : else if (symlink_errno == ENOENT && !linkdirs_made)
1961 : : {
1962 : 0 : mkdirs(linkname, true);
1963 : 0 : linkdirs_made = true;
1964 : : }
1965 : : else
1966 : : break;
1967 : : }
1968 : : }
1969 : 0 : free(linkalloc);
1970 [ # # ]: 0 : if (symlink_errno == 0)
1971 : : {
1972 [ # # # # ]: 0 : if (link_errno != ENOTSUP && link_errno != EEXIST)
1973 : 0 : warning(_("symbolic link used because hard link failed: %s"),
1974 : : strerror(link_errno));
1975 : : }
1976 : : else
1977 : : #endif /* HAVE_SYMLINK */
1978 : : {
1979 : : FILE *fp,
1980 : : *tp;
1981 : : int c;
1982 : :
1983 : 0 : fp = fopen(target, "rb");
1984 [ # # ]: 0 : if (!fp)
1985 : : {
1986 : 0 : char const *e = strerror(errno);
1987 : :
1988 : 0 : fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"),
1989 : : progname, diagdir(target), diagslash(target), target, e);
1990 : 0 : exit(EXIT_FAILURE);
1991 : : }
1992 : 0 : tp = open_outfile(&outname, &tempname);
1993 [ # # ]: 0 : for (; (c = getc(fp)) != EOF; check_for_signal())
1994 : 0 : putc(c, tp);
1995 : 0 : close_file(tp, directory, linkname, tempname);
1996 : 0 : close_file(fp, directory, target, NULL);
1997 [ # # ]: 0 : if (link_errno != ENOTSUP)
1998 : 0 : warning(_("copy used because hard link failed: %s"),
1999 : : strerror(link_errno));
2000 : : #ifdef HAVE_SYMLINK
2001 [ # # ]: 0 : else if (symlink_errno < 0)
2002 : 0 : warning(_("copy used because symbolic link not obvious"));
2003 [ # # ]: 0 : else if (symlink_errno != ENOTSUP)
2004 : 0 : warning(_("copy used because symbolic link failed: %s"),
2005 : : strerror(symlink_errno));
2006 : : #endif
2007 : : }
2008 : : }
2009 : 1028 : rename_dest(tempname, linkname);
2010 : : }
2011 : :
2012 : : /*
2013 : : * Return 1 if NAME is an absolute symbolic link, -1 if it is relative,
2014 : : * 0 if it is not a symbolic link. If *CACHE is not -2, it is the
2015 : : * cached result of a previous call to this function with the same NAME.
2016 : : */
2017 : : static int
2018 : 0 : itssymlink(char const *name, int *cache)
2019 : : {
2020 : : #ifdef HAVE_SYMLINK
2021 [ # # ]: 0 : if (*cache == -2)
2022 : : {
2023 : 0 : char c = '\0';
2024 : :
2025 [ # # # # ]: 0 : *cache = readlink(name, &c, 1) < 0 ? 0 : c == '/' ? 1 : -1;
2026 : : }
2027 : 0 : return *cache;
2028 : : #else
2029 : : return false;
2030 : : #endif
2031 : : }
2032 : :
2033 : : /*
2034 : : * Associate sets of rules with zones.
2035 : : */
2036 : :
2037 : : /*
2038 : : * Sort by rule name.
2039 : : */
2040 : :
2041 : : static int
2042 : 50852 : rcomp(const void *cp1, const void *cp2)
2043 : : {
2044 : 50852 : struct rule const *r1 = cp1,
2045 : 50852 : *r2 = cp2;
2046 : :
2047 : 50852 : return strcmp(r1->r_name, r2->r_name);
2048 : : }
2049 : :
2050 : : static void
2051 : 4 : associate(void)
2052 : : {
2053 : : struct zone *zp;
2054 : : struct rule *rp;
2055 : : ptrdiff_t i,
2056 : : j,
2057 : : base,
2058 : : out;
2059 : :
2060 [ + - ]: 4 : if (1 < nrules)
2061 : : {
2062 : 4 : qsort(rules, nrules, sizeof *rules, rcomp);
2063 [ + + ]: 7832 : for (i = 0; i < nrules - 1; ++i)
2064 : : {
2065 : 8344 : if (strcmp(rules[i].r_name,
2066 [ + + ]: 7828 : rules[i + 1].r_name) != 0)
2067 : 516 : continue;
2068 [ + - ]: 7312 : if (rules[i].r_filenum == rules[i + 1].r_filenum)
2069 : 7312 : continue;
2070 : 0 : eat(rules[i].r_filenum, rules[i].r_linenum);
2071 : 0 : warning(_("same rule name in multiple files"));
2072 : 0 : eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum);
2073 : 0 : warning(_("same rule name in multiple files"));
2074 [ # # ]: 0 : for (j = i + 2; j < nrules; ++j)
2075 : : {
2076 : 0 : if (strcmp(rules[i].r_name,
2077 [ # # ]: 0 : rules[j].r_name) != 0)
2078 : 0 : break;
2079 [ # # ]: 0 : if (rules[i].r_filenum == rules[j].r_filenum)
2080 : 0 : continue;
2081 : 0 : if (rules[i + 1].r_filenum
2082 [ # # ]: 0 : == rules[j].r_filenum)
2083 : 0 : continue;
2084 : 0 : break;
2085 : : }
2086 : 0 : i = j - 1;
2087 : : }
2088 : : }
2089 [ + + ]: 7852 : for (i = 0; i < nzones; ++i)
2090 : : {
2091 : 7848 : zp = &zones[i];
2092 : 7848 : zp->z_rules = NULL;
2093 : 7848 : zp->z_nrules = 0;
2094 : : }
2095 [ + + ]: 524 : for (base = 0; base < nrules; base = out)
2096 : : {
2097 : 520 : rp = &rules[base];
2098 [ + + ]: 7832 : for (out = base + 1; out < nrules; ++out)
2099 [ + + ]: 7828 : if (strcmp(rp->r_name, rules[out].r_name) != 0)
2100 : 516 : break;
2101 [ + + ]: 1020760 : for (i = 0; i < nzones; ++i)
2102 : : {
2103 : 1020240 : zp = &zones[i];
2104 [ + + ]: 1020240 : if (strcmp(zp->z_rule, rp->r_name) != 0)
2105 : 1017208 : continue;
2106 : 3032 : zp->z_rules = rp;
2107 : 3032 : zp->z_nrules = out - base;
2108 : : }
2109 : : }
2110 [ + + ]: 7852 : for (i = 0; i < nzones; ++i)
2111 : : {
2112 : 7848 : zp = &zones[i];
2113 [ + + ]: 7848 : if (zp->z_nrules == 0)
2114 : : {
2115 : : /*
2116 : : * Maybe we have a local standard time offset.
2117 : : */
2118 : 4816 : eat(zp->z_filenum, zp->z_linenum);
2119 : 4816 : zp->z_save = getsave(zp->z_rule, &zp->z_isdst);
2120 : :
2121 : : /*
2122 : : * Note, though, that if there's no rule, a '%s' in the format is
2123 : : * a bad thing.
2124 : : */
2125 [ - + ]: 4816 : if (zp->z_format_specifier == 's')
2126 : 0 : error("%s", _("%s in ruleless zone"));
2127 : : }
2128 : : }
2129 [ - + ]: 4 : if (errors)
2130 : 0 : exit(EXIT_FAILURE);
2131 : 4 : }
2132 : :
2133 : : /*
2134 : : * Read a text line from FP into BUF, which is of size BUFSIZE.
2135 : : * Terminate it with a NUL byte instead of a newline.
2136 : : * Return true if successful, false if EOF.
2137 : : * On error, report the error and exit.
2138 : : */
2139 : : static bool
2140 : 16724 : inputline(FILE *fp, char *buf, ptrdiff_t bufsize)
2141 : : {
2142 : 16724 : ptrdiff_t linelen = 0,
2143 : : ch;
2144 : :
2145 [ + + ]: 417728 : for (; (ch = getc(fp)) != '\n'; check_for_signal())
2146 : : {
2147 [ + + ]: 401008 : if (ch < 0)
2148 : : {
2149 [ - + ]: 4 : if (ferror(fp))
2150 : : {
2151 : 0 : error(_("input error"));
2152 : 0 : exit(EXIT_FAILURE);
2153 : : }
2154 [ + - ]: 4 : if (linelen == 0)
2155 : 4 : return false;
2156 : 0 : error(_("unterminated line"));
2157 : 0 : exit(EXIT_FAILURE);
2158 : : }
2159 [ - + ]: 401004 : if (!ch)
2160 : : {
2161 : 0 : error(_("NUL input byte"));
2162 : 0 : exit(EXIT_FAILURE);
2163 : : }
2164 : 401004 : buf[linelen++] = ch;
2165 [ - + ]: 401004 : if (linelen == bufsize)
2166 : : {
2167 : 0 : error(_("line too long"));
2168 : 0 : exit(EXIT_FAILURE);
2169 : : }
2170 : : }
2171 : 16720 : buf[linelen] = '\0';
2172 : 16720 : return true;
2173 : : }
2174 : :
2175 : : static void
2176 : 4 : infile(int fnum, char const *name)
2177 : : {
2178 : : FILE *fp;
2179 : : const struct lookup *lp;
2180 : : bool wantcont;
2181 : : lineno_t num;
2182 : :
2183 [ - + ]: 4 : if (strcmp(name, "-") == 0)
2184 : : {
2185 : 0 : fp = stdin;
2186 : : }
2187 [ - + ]: 4 : else if ((fp = fopen(name, "r")) == NULL)
2188 : : {
2189 : 0 : const char *e = strerror(errno);
2190 : :
2191 : 0 : fprintf(stderr, _("%s: Cannot open %s: %s\n"),
2192 : : progname, name, e);
2193 : 0 : exit(EXIT_FAILURE);
2194 : : }
2195 : 4 : wantcont = false;
2196 : 4 : for (num = 1;; ++num)
2197 : 16720 : {
2198 : : enum
2199 : : {
2200 : : bufsize_bound
2201 : : = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND)};
2202 : : char buf[min(_POSIX2_LINE_MAX, bufsize_bound)];
2203 : : int nfields;
2204 : : char *fields[MAX_FIELDS];
2205 : :
2206 : 16724 : eat(fnum, num);
2207 [ + + ]: 16724 : if (!inputline(fp, buf, sizeof buf))
2208 : 4 : break;
2209 : 16720 : nfields = getfields(buf, fields,
2210 : : sizeof fields / sizeof *fields);
2211 [ + + ]: 16720 : if (nfields == 0)
2212 : : {
2213 : : /* nothing to do */
2214 : : }
2215 [ + + ]: 16708 : else if (wantcont)
2216 : : {
2217 : 6484 : wantcont = inzcont(fields, nfields);
2218 : : }
2219 : : else
2220 : : {
2221 : 10224 : struct lookup const *line_codes
2222 [ - + ]: 10224 : = fnum < 0 ? leap_line_codes : zi_line_codes;
2223 : :
2224 : 10224 : lp = byword(fields[0], line_codes);
2225 [ - + ]: 10224 : if (lp == NULL)
2226 : 0 : error(_("input line of unknown type"));
2227 : : else
2228 [ + + + - : 10224 : switch (lp->l_value)
- - ]
2229 : : {
2230 : 7832 : case LC_RULE:
2231 : 7832 : inrule(fields, nfields);
2232 : 7832 : wantcont = false;
2233 : 7832 : break;
2234 : 1364 : case LC_ZONE:
2235 : 1364 : wantcont = inzone(fields, nfields);
2236 : 1364 : break;
2237 : 1028 : case LC_LINK:
2238 : 1028 : inlink(fields, nfields);
2239 : 1028 : wantcont = false;
2240 : 1028 : break;
2241 : 0 : case LC_LEAP:
2242 : 0 : inleap(fields, nfields);
2243 : 0 : wantcont = false;
2244 : 0 : break;
2245 : 0 : case LC_EXPIRES:
2246 : 0 : inexpires(fields, nfields);
2247 : 0 : wantcont = false;
2248 : 0 : break;
2249 : 0 : default:
2250 : 0 : unreachable();
2251 : : }
2252 : : }
2253 : 16720 : check_for_signal();
2254 : : }
2255 : 4 : close_file(fp, NULL, filename(fnum), NULL);
2256 [ - + ]: 4 : if (wantcont)
2257 : 0 : error(_("expected continuation line not found"));
2258 : 4 : }
2259 : :
2260 : : /*
2261 : : * Convert a string of one of the forms
2262 : : * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
2263 : : * into a number of seconds.
2264 : : * A null string maps to zero.
2265 : : * Call error with errstring and return zero on errors.
2266 : : */
2267 : :
2268 : : static zic_t
2269 : 34812 : gethms(char const *string, char const *errstring)
2270 : : {
2271 : : zic_t hh;
2272 : : int sign,
2273 : 34812 : mm = 0,
2274 : 34812 : ss = 0;
2275 : : char hhx,
2276 : : mmx,
2277 : : ssx,
2278 : 34812 : xr = '0',
2279 : : xs;
2280 : 34812 : int tenths = 0;
2281 : 34812 : bool ok = true;
2282 : :
2283 [ + - + + ]: 34812 : if (string == NULL || *string == '\0')
2284 : 4564 : return 0;
2285 [ + + ]: 30248 : if (*string == '-')
2286 : : {
2287 : 3704 : sign = -1;
2288 : 3704 : ++string;
2289 : : }
2290 : : else
2291 : 26544 : sign = 1;
2292 [ - - - + : 30248 : switch (sscanf(string,
+ + ]
2293 : : "%" SCNdZIC "%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c",
2294 : : &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs))
2295 : : {
2296 : 0 : default:
2297 : 0 : ok = false;
2298 : 0 : break;
2299 : 0 : case 8:
2300 : 0 : ok = is_digit(xr);
2301 : : ATTRIBUTE_FALLTHROUGH;
2302 : 0 : case 7:
2303 : 0 : ok &= ssx == '.';
2304 [ # # # # ]: 0 : if (ok && noise)
2305 : 0 : warning(_("fractional seconds rejected by"
2306 : : " pre-2018 versions of zic"));
2307 : : ATTRIBUTE_FALLTHROUGH;
2308 : : case 5:
2309 : 1588 : ok &= mmx == ':';
2310 : : ATTRIBUTE_FALLTHROUGH;
2311 : 2420 : case 3:
2312 : 2420 : ok &= hhx == ':';
2313 : : ATTRIBUTE_FALLTHROUGH;
2314 : 30248 : case 1:
2315 : 30248 : break;
2316 : : }
2317 [ - + ]: 30248 : if (!ok)
2318 : : {
2319 : 0 : error("%s", errstring);
2320 : 0 : return 0;
2321 : : }
2322 [ + - ]: 30248 : if (hh < 0 ||
2323 [ + - + - ]: 30248 : mm < 0 || mm >= MINSPERHOUR ||
2324 [ + - - + ]: 30248 : ss < 0 || ss > SECSPERMIN)
2325 : : {
2326 : 0 : error("%s", errstring);
2327 : 0 : return 0;
2328 : : }
2329 : 30248 : ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */
2330 [ - + - - ]: 30248 : if (noise && (hh > HOURSPERDAY ||
2331 [ # # # # : 0 : (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
# # ]
2332 : 0 : warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
2333 : 30248 : return oadd(omul(hh, sign * SECSPERHOUR),
2334 : 30248 : sign * (mm * SECSPERMIN + ss));
2335 : : }
2336 : :
2337 : : static zic_t
2338 : 12648 : getsave(char *field, bool *isdst)
2339 : : {
2340 : 12648 : int dst = -1;
2341 : : zic_t save;
2342 : 12648 : ptrdiff_t fieldlen = strlen(field);
2343 : :
2344 [ + + ]: 12648 : if (fieldlen != 0)
2345 : : {
2346 : 8084 : char *ep = field + fieldlen - 1;
2347 : :
2348 [ - - + ]: 8084 : switch (*ep)
2349 : : {
2350 : 0 : case 'd':
2351 : 0 : dst = 1;
2352 : 0 : *ep = '\0';
2353 : 0 : break;
2354 : 0 : case 's':
2355 : 0 : dst = 0;
2356 : 0 : *ep = '\0';
2357 : 0 : break;
2358 : : }
2359 : : }
2360 : 12648 : save = gethms(field, _("invalid saved time"));
2361 [ + - ]: 12648 : *isdst = dst < 0 ? save != 0 : dst;
2362 : 12648 : return save;
2363 : : }
2364 : :
2365 : : static void
2366 : 7832 : inrule(char **fields, int nfields)
2367 : : {
2368 : : struct rule r;
2369 : :
2370 [ - + ]: 7832 : if (nfields != RULE_FIELDS)
2371 : : {
2372 : 0 : error(_("wrong number of fields on Rule line"));
2373 : 0 : return;
2374 : : }
2375 [ - + ]: 7832 : switch (*fields[RF_NAME])
2376 : : {
2377 : 0 : case '\0':
2378 : : case ' ':
2379 : : case '\f':
2380 : : case '\n':
2381 : : case '\r':
2382 : : case '\t':
2383 : : case '\v':
2384 : : case '+':
2385 : : case '-':
2386 : : case '0':
2387 : : case '1':
2388 : : case '2':
2389 : : case '3':
2390 : : case '4':
2391 : : case '5':
2392 : : case '6':
2393 : : case '7':
2394 : : case '8':
2395 : : case '9':
2396 : 0 : error(_("Invalid rule name \"%s\""), fields[RF_NAME]);
2397 : 0 : return;
2398 : : }
2399 : 7832 : r.r_filenum = filenum;
2400 : 7832 : r.r_linenum = linenum;
2401 : 7832 : r.r_save = getsave(fields[RF_SAVE], &r.r_isdst);
2402 [ - + ]: 7832 : if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR],
2403 : 7832 : fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY],
2404 : 7832 : fields[RF_TOD]))
2405 : 0 : return;
2406 : 7832 : r.r_name = xstrdup(fields[RF_NAME]);
2407 : 7832 : r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]);
2408 [ - + ]: 7832 : if (max_abbrvar_len < strlen(r.r_abbrvar))
2409 : 0 : max_abbrvar_len = strlen(r.r_abbrvar);
2410 : 7832 : rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
2411 : 7832 : rules[nrules++] = r;
2412 : : }
2413 : :
2414 : : static bool
2415 : 1364 : inzone(char **fields, int nfields)
2416 : : {
2417 : : ptrdiff_t i;
2418 : :
2419 [ + - - + ]: 1364 : if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS)
2420 : : {
2421 : 0 : error(_("wrong number of fields on Zone line"));
2422 : 0 : return false;
2423 : : }
2424 [ - + - - ]: 1364 : if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0)
2425 : : {
2426 : 0 : error(_("\"Zone %s\" line and -l option are mutually exclusive"),
2427 : : tzdefault);
2428 : 0 : return false;
2429 : : }
2430 [ - + - - ]: 1364 : if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL)
2431 : : {
2432 : 0 : error(_("\"Zone %s\" line and -p option are mutually exclusive"),
2433 : : TZDEFRULES);
2434 : 0 : return false;
2435 : : }
2436 [ + + ]: 1427504 : for (i = 0; i < nzones; ++i)
2437 [ + + ]: 1426140 : if (zones[i].z_name != NULL &&
2438 [ - + ]: 231880 : strcmp(zones[i].z_name, fields[ZF_NAME]) == 0)
2439 : : {
2440 : 0 : error(_("duplicate zone name %s"
2441 : : " (file \"%s\", line %" PRIdMAX ")"),
2442 : 0 : fields[ZF_NAME],
2443 : 0 : filename(zones[i].z_filenum),
2444 : 0 : zones[i].z_linenum);
2445 : 0 : return false;
2446 : : }
2447 : 1364 : return inzsub(fields, nfields, false);
2448 : : }
2449 : :
2450 : : static bool
2451 : 6484 : inzcont(char **fields, int nfields)
2452 : : {
2453 [ + - - + ]: 6484 : if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS)
2454 : : {
2455 : 0 : error(_("wrong number of fields on Zone continuation line"));
2456 : 0 : return false;
2457 : : }
2458 : 6484 : return inzsub(fields, nfields, true);
2459 : : }
2460 : :
2461 : : static bool
2462 : 7848 : inzsub(char **fields, int nfields, bool iscont)
2463 : : {
2464 : : char *cp;
2465 : : char *cp1;
2466 : : struct zone z;
2467 : : int format_len;
2468 : : int i_stdoff,
2469 : : i_rule,
2470 : : i_format;
2471 : : int i_untilyear,
2472 : : i_untilmonth;
2473 : : int i_untilday,
2474 : : i_untiltime;
2475 : : bool hasuntil;
2476 : :
2477 [ + + ]: 7848 : if (iscont)
2478 : : {
2479 : 6484 : i_stdoff = ZFC_STDOFF;
2480 : 6484 : i_rule = ZFC_RULE;
2481 : 6484 : i_format = ZFC_FORMAT;
2482 : 6484 : i_untilyear = ZFC_TILYEAR;
2483 : 6484 : i_untilmonth = ZFC_TILMONTH;
2484 : 6484 : i_untilday = ZFC_TILDAY;
2485 : 6484 : i_untiltime = ZFC_TILTIME;
2486 : : }
2487 [ - + ]: 1364 : else if (!namecheck(fields[ZF_NAME]))
2488 : 0 : return false;
2489 : : else
2490 : : {
2491 : 1364 : i_stdoff = ZF_STDOFF;
2492 : 1364 : i_rule = ZF_RULE;
2493 : 1364 : i_format = ZF_FORMAT;
2494 : 1364 : i_untilyear = ZF_TILYEAR;
2495 : 1364 : i_untilmonth = ZF_TILMONTH;
2496 : 1364 : i_untilday = ZF_TILDAY;
2497 : 1364 : i_untiltime = ZF_TILTIME;
2498 : : }
2499 : 7848 : z.z_filenum = filenum;
2500 : 7848 : z.z_linenum = linenum;
2501 : 7848 : z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset"));
2502 : 7848 : cp = strchr(fields[i_format], '%');
2503 [ + + ]: 7848 : if (cp)
2504 : : {
2505 [ + + + - : 4868 : if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%')
+ - ]
2506 [ - + ]: 4868 : || strchr(fields[i_format], '/'))
2507 : : {
2508 : 0 : error(_("invalid abbreviation format"));
2509 : 0 : return false;
2510 : : }
2511 : : }
2512 [ + + ]: 7848 : z.z_format_specifier = cp ? *cp : '\0';
2513 : 7848 : format_len = strlen(fields[i_format]);
2514 [ + + ]: 7848 : if (max_format_len < format_len)
2515 : 12 : max_format_len = format_len;
2516 : 7848 : hasuntil = nfields > i_untilyear;
2517 [ + + ]: 7848 : if (hasuntil)
2518 : : {
2519 : 6484 : z.z_untilrule.r_filenum = filenum;
2520 : 6484 : z.z_untilrule.r_linenum = linenum;
2521 [ + + + + : 19020 : if (!rulesub(
+ + - + ]
2522 : : &z.z_untilrule,
2523 : 6484 : fields[i_untilyear],
2524 : : "only",
2525 : : "",
2526 : : (nfields > i_untilmonth) ?
2527 : 4968 : fields[i_untilmonth] : "Jan",
2528 : 4004 : (nfields > i_untilday) ? fields[i_untilday] : "1",
2529 : 2048 : (nfields > i_untiltime) ? fields[i_untiltime] : "0"))
2530 : 0 : return false;
2531 : 6484 : z.z_untiltime = rpytime(&z.z_untilrule,
2532 : : z.z_untilrule.r_loyear);
2533 [ + + + - ]: 6484 : if (iscont && nzones > 0 &&
2534 [ - + ]: 5236 : zones[nzones - 1].z_untiltime >= z.z_untiltime)
2535 : : {
2536 : 0 : error(_("Zone continuation line end time is"
2537 : : " not after end time of previous line"));
2538 : 0 : return false;
2539 : : }
2540 : : }
2541 [ + + ]: 7848 : z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]);
2542 : 7848 : z.z_rule = xstrdup(fields[i_rule]);
2543 : 7848 : z.z_format = cp1 = xstrdup(fields[i_format]);
2544 [ + + ]: 7848 : if (z.z_format_specifier == 'z')
2545 : : {
2546 : 3084 : cp1[cp - fields[i_format]] = 's';
2547 [ - + ]: 3084 : if (noise)
2548 : 0 : warning(_("format '%s' not handled by pre-2015 versions of zic"),
2549 : 0 : fields[i_format]);
2550 : : }
2551 : 7848 : zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
2552 : 7848 : zones[nzones++] = z;
2553 : :
2554 : : /*
2555 : : * If there was an UNTIL field on this line, there's more information
2556 : : * about the zone on the next line.
2557 : : */
2558 : 7848 : return hasuntil;
2559 : : }
2560 : :
2561 : : static zic_t
2562 : 0 : getleapdatetime(char **fields, bool expire_line)
2563 : : {
2564 : : const char *cp;
2565 : : const struct lookup *lp;
2566 : : zic_t i,
2567 : : j;
2568 : : zic_t year;
2569 : : int month,
2570 : : day;
2571 : : zic_t dayoff,
2572 : : tod;
2573 : : zic_t t;
2574 : : char xs;
2575 : :
2576 : 0 : dayoff = 0;
2577 : 0 : cp = fields[LP_YEAR];
2578 [ # # ]: 0 : if (sscanf(cp, "%" SCNdZIC "%c", &year, &xs) != 1)
2579 : : {
2580 : : /*
2581 : : * Leapin' Lizards!
2582 : : */
2583 : 0 : error(_("invalid leaping year"));
2584 : 0 : return -1;
2585 : : }
2586 [ # # ]: 0 : if (!expire_line)
2587 : : {
2588 [ # # # # ]: 0 : if (!leapseen || leapmaxyear < year)
2589 : 0 : leapmaxyear = year;
2590 [ # # # # ]: 0 : if (!leapseen || leapminyear > year)
2591 : 0 : leapminyear = year;
2592 : 0 : leapseen = true;
2593 : : }
2594 : 0 : j = EPOCH_YEAR;
2595 [ # # ]: 0 : while (j != year)
2596 : : {
2597 [ # # ]: 0 : if (year > j)
2598 : : {
2599 [ # # # # : 0 : i = len_years[isleap(j)];
# # ]
2600 : 0 : ++j;
2601 : : }
2602 : : else
2603 : : {
2604 : 0 : --j;
2605 [ # # # # : 0 : i = -len_years[isleap(j)];
# # ]
2606 : : }
2607 : 0 : dayoff = oadd(dayoff, i);
2608 : : }
2609 [ # # ]: 0 : if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL)
2610 : : {
2611 : 0 : error(_("invalid month name"));
2612 : 0 : return -1;
2613 : : }
2614 : 0 : month = lp->l_value;
2615 : 0 : j = TM_JANUARY;
2616 [ # # ]: 0 : while (j != month)
2617 : : {
2618 [ # # # # : 0 : i = len_months[isleap(year)][j];
# # ]
2619 : 0 : dayoff = oadd(dayoff, i);
2620 : 0 : ++j;
2621 : : }
2622 : 0 : cp = fields[LP_DAY];
2623 [ # # ]: 0 : if (sscanf(cp, "%d%c", &day, &xs) != 1 ||
2624 [ # # # # : 0 : day <= 0 || day > len_months[isleap(year)][month])
# # # # #
# ]
2625 : : {
2626 : 0 : error(_("invalid day of month"));
2627 : 0 : return -1;
2628 : : }
2629 : 0 : dayoff = oadd(dayoff, day - 1);
2630 : 0 : t = omul(dayoff, SECSPERDAY);
2631 : 0 : tod = gethms(fields[LP_TIME], _("invalid time of day"));
2632 : 0 : t = tadd(t, tod);
2633 [ # # ]: 0 : if (t < 0)
2634 : 0 : error(_("leap second precedes Epoch"));
2635 : 0 : return t;
2636 : : }
2637 : :
2638 : : static void
2639 : 0 : inleap(char **fields, int nfields)
2640 : : {
2641 [ # # ]: 0 : if (nfields != LEAP_FIELDS)
2642 : 0 : error(_("wrong number of fields on Leap line"));
2643 : : else
2644 : : {
2645 : 0 : zic_t t = getleapdatetime(fields, false);
2646 : :
2647 [ # # ]: 0 : if (0 <= t)
2648 : : {
2649 : 0 : struct lookup const *lp = byword(fields[LP_ROLL], leap_types);
2650 : :
2651 [ # # ]: 0 : if (!lp)
2652 : 0 : error(_("invalid Rolling/Stationary field on Leap line"));
2653 : : else
2654 : : {
2655 : 0 : int correction = 0;
2656 : :
2657 [ # # ]: 0 : if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */
2658 : 0 : correction = -1;
2659 [ # # ]: 0 : else if (strcmp(fields[LP_CORR], "+") == 0)
2660 : 0 : correction = 1;
2661 : : else
2662 : 0 : error(_("invalid CORRECTION field on Leap line"));
2663 [ # # ]: 0 : if (correction)
2664 : 0 : leapadd(t, correction, lp->l_value);
2665 : : }
2666 : : }
2667 : : }
2668 : 0 : }
2669 : :
2670 : : static void
2671 : 0 : inexpires(char **fields, int nfields)
2672 : : {
2673 [ # # ]: 0 : if (nfields != EXPIRES_FIELDS)
2674 : 0 : error(_("wrong number of fields on Expires line"));
2675 [ # # ]: 0 : else if (0 <= leapexpires)
2676 : 0 : error(_("multiple Expires lines"));
2677 : : else
2678 : 0 : leapexpires = getleapdatetime(fields, true);
2679 : 0 : }
2680 : :
2681 : : static void
2682 : 1028 : inlink(char **fields, int nfields)
2683 : : {
2684 : : struct link l;
2685 : :
2686 [ - + ]: 1028 : if (nfields != LINK_FIELDS)
2687 : : {
2688 : 0 : error(_("wrong number of fields on Link line"));
2689 : 0 : return;
2690 : : }
2691 [ - + ]: 1028 : if (*fields[LF_TARGET] == '\0')
2692 : : {
2693 : 0 : error(_("blank TARGET field on Link line"));
2694 : 0 : return;
2695 : : }
2696 [ - + ]: 1028 : if (!namecheck(fields[LF_LINKNAME]))
2697 : 0 : return;
2698 : 1028 : l.l_filenum = filenum;
2699 : 1028 : l.l_linenum = linenum;
2700 : 1028 : l.l_target = xstrdup(fields[LF_TARGET]);
2701 : 1028 : l.l_linkname = xstrdup(fields[LF_LINKNAME]);
2702 : 1028 : links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
2703 : 1028 : links[nlinks++] = l;
2704 : : }
2705 : :
2706 : : static bool
2707 : 14316 : rulesub(struct rule *rp, const char *loyearp, const char *hiyearp,
2708 : : const char *typep, const char *monthp, const char *dayp,
2709 : : const char *timep)
2710 : : {
2711 : : const struct lookup *lp;
2712 : : const char *cp;
2713 : : char *dp;
2714 : : char *ep;
2715 : : char xs;
2716 : :
2717 [ - + ]: 14316 : if ((lp = byword(monthp, mon_names)) == NULL)
2718 : : {
2719 : 0 : error(_("invalid month name"));
2720 : 0 : return false;
2721 : : }
2722 : 14316 : rp->r_month = lp->l_value;
2723 : 14316 : rp->r_todisstd = false;
2724 : 14316 : rp->r_todisut = false;
2725 : 14316 : dp = xstrdup(timep);
2726 [ + - ]: 14316 : if (*dp != '\0')
2727 : : {
2728 : 14316 : ep = dp + strlen(dp) - 1;
2729 [ + - + + ]: 14316 : switch (lowerit(*ep))
2730 : : {
2731 : 2740 : case 's': /* Standard */
2732 : 2740 : rp->r_todisstd = true;
2733 : 2740 : rp->r_todisut = false;
2734 : 2740 : *ep = '\0';
2735 : 2740 : break;
2736 : 0 : case 'w': /* Wall */
2737 : 0 : rp->r_todisstd = false;
2738 : 0 : rp->r_todisut = false;
2739 : 0 : *ep = '\0';
2740 : 0 : break;
2741 : 676 : case 'g': /* Greenwich */
2742 : : case 'u': /* Universal */
2743 : : case 'z': /* Zulu */
2744 : 676 : rp->r_todisstd = true;
2745 : 676 : rp->r_todisut = true;
2746 : 676 : *ep = '\0';
2747 : 676 : break;
2748 : : }
2749 : : }
2750 : 14316 : rp->r_tod = gethms(dp, _("invalid time of day"));
2751 : 14316 : free(dp);
2752 : :
2753 : : /*
2754 : : * Year work.
2755 : : */
2756 : 14316 : cp = loyearp;
2757 : 14316 : lp = byword(cp, begin_years);
2758 [ - + ]: 14316 : if (lp)
2759 [ # # ]: 0 : switch (lp->l_value)
2760 : : {
2761 : 0 : case YR_MINIMUM:
2762 : 0 : warning(_("FROM year \"%s\" is obsolete;"
2763 : : " treated as %d"),
2764 : : cp, YEAR_32BIT_MIN - 1);
2765 : 0 : rp->r_loyear = YEAR_32BIT_MIN - 1;
2766 : 0 : break;
2767 : 0 : default:
2768 : 0 : unreachable();
2769 : : }
2770 [ - + ]: 14316 : else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_loyear, &xs) != 1)
2771 : : {
2772 : 0 : error(_("invalid starting year"));
2773 : 0 : return false;
2774 : : }
2775 : 14316 : cp = hiyearp;
2776 : 14316 : lp = byword(cp, end_years);
2777 : 14316 : rp->r_hiwasnum = lp == NULL;
2778 [ + + ]: 14316 : if (!rp->r_hiwasnum)
2779 [ + + - ]: 11856 : switch (lp->l_value)
2780 : : {
2781 : 184 : case YR_MAXIMUM:
2782 : 184 : rp->r_hiyear = ZIC_MAX;
2783 : 184 : break;
2784 : 11672 : case YR_ONLY:
2785 : 11672 : rp->r_hiyear = rp->r_loyear;
2786 : 11672 : break;
2787 : 0 : default:
2788 : 0 : unreachable();
2789 : : }
2790 [ - + ]: 2460 : else if (sscanf(cp, "%" SCNdZIC "%c", &rp->r_hiyear, &xs) != 1)
2791 : : {
2792 : 0 : error(_("invalid ending year"));
2793 : 0 : return false;
2794 : : }
2795 [ - + ]: 14316 : if (rp->r_loyear > rp->r_hiyear)
2796 : : {
2797 : 0 : error(_("starting year greater than ending year"));
2798 : 0 : return false;
2799 : : }
2800 [ - + ]: 14316 : if (*typep != '\0')
2801 : : {
2802 : 0 : error(_("year type \"%s\" is unsupported; use \"-\" instead"),
2803 : : typep);
2804 : 0 : return false;
2805 : : }
2806 : :
2807 : : /*
2808 : : * Day work. Accept things such as: 1 lastSunday last-Sunday
2809 : : * (undocumented; warn about this) Sun<=20 Sun>=7
2810 : : */
2811 : 14316 : dp = xstrdup(dayp);
2812 [ + + ]: 14316 : if ((lp = byword(dp, lasts)) != NULL)
2813 : : {
2814 : 1368 : rp->r_dycode = DC_DOWLEQ;
2815 : 1368 : rp->r_wday = lp->l_value;
2816 : 1368 : rp->r_dayofmonth = len_months[1][rp->r_month];
2817 : : }
2818 : : else
2819 : : {
2820 : 12948 : ep = strchr(dp, '<');
2821 [ + + ]: 12948 : if (ep)
2822 : 40 : rp->r_dycode = DC_DOWLEQ;
2823 : : else
2824 : : {
2825 : 12908 : ep = strchr(dp, '>');
2826 [ + + ]: 12908 : if (ep)
2827 : 1584 : rp->r_dycode = DC_DOWGEQ;
2828 : : else
2829 : : {
2830 : 11324 : ep = dp;
2831 : 11324 : rp->r_dycode = DC_DOM;
2832 : : }
2833 : : }
2834 [ + + ]: 12948 : if (rp->r_dycode != DC_DOM)
2835 : : {
2836 : 1624 : *ep++ = 0;
2837 [ - + ]: 1624 : if (*ep++ != '=')
2838 : : {
2839 : 0 : error(_("invalid day of month"));
2840 : 0 : free(dp);
2841 : 0 : return false;
2842 : : }
2843 [ - + ]: 1624 : if ((lp = byword(dp, wday_names)) == NULL)
2844 : : {
2845 : 0 : error(_("invalid weekday name"));
2846 : 0 : free(dp);
2847 : 0 : return false;
2848 : : }
2849 : 1624 : rp->r_wday = lp->l_value;
2850 : : }
2851 [ + - ]: 12948 : if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 ||
2852 [ + - ]: 12948 : rp->r_dayofmonth <= 0 ||
2853 [ - + ]: 12948 : (rp->r_dayofmonth > len_months[1][rp->r_month]))
2854 : : {
2855 : 0 : error(_("invalid day of month"));
2856 : 0 : free(dp);
2857 : 0 : return false;
2858 : : }
2859 : : }
2860 : 14316 : free(dp);
2861 : 14316 : return true;
2862 : : }
2863 : :
2864 : : static void
2865 : 24088 : convert(uint_fast32_t val, char *buf)
2866 : : {
2867 : : int i;
2868 : : int shift;
2869 : 24088 : unsigned char *const b = (unsigned char *) buf;
2870 : :
2871 [ + + ]: 120440 : for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
2872 : 96352 : b[i] = (val >> shift) & 0xff;
2873 : 24088 : }
2874 : :
2875 : : static void
2876 : 66524 : convert64(uint_fast64_t val, char *buf)
2877 : : {
2878 : : int i;
2879 : : int shift;
2880 : 66524 : unsigned char *const b = (unsigned char *) buf;
2881 : :
2882 [ + + ]: 598716 : for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
2883 : 532192 : b[i] = (val >> shift) & 0xff;
2884 : 66524 : }
2885 : :
2886 : : static void
2887 : 7720 : puttzcode(zic_t val, FILE *fp)
2888 : : {
2889 : : char buf[4];
2890 : :
2891 : 7720 : convert(val, buf);
2892 : 7720 : fwrite(buf, sizeof buf, 1, fp);
2893 : 7720 : }
2894 : :
2895 : : static void
2896 : 66524 : puttzcodepass(zic_t val, FILE *fp, int pass)
2897 : : {
2898 [ - + ]: 66524 : if (pass == 1)
2899 : 0 : puttzcode(val, fp);
2900 : : else
2901 : : {
2902 : : char buf[8];
2903 : :
2904 : 66524 : convert64(val, buf);
2905 : 66524 : fwrite(buf, sizeof buf, 1, fp);
2906 : : }
2907 : 66524 : }
2908 : :
2909 : : static int
2910 : 815716 : atcomp(const void *avp, const void *bvp)
2911 : : {
2912 : 815716 : struct attype const *ap = avp,
2913 : 815716 : *bp = bvp;
2914 : 815716 : zic_t a = ap->at,
2915 : 815716 : b = bp->at;
2916 : :
2917 [ + + ]: 815716 : return a < b ? -1 : a > b;
2918 : : }
2919 : :
2920 : : struct timerange
2921 : : {
2922 : : int defaulttype;
2923 : : ptrdiff_t base,
2924 : : count;
2925 : : ptrdiff_t leapbase,
2926 : : leapcount;
2927 : : bool leapexpiry;
2928 : : };
2929 : :
2930 : : static struct timerange
2931 : 2728 : limitrange(struct timerange r, zic_t lo, zic_t hi,
2932 : : zic_t const *ats, unsigned char const *types)
2933 : : {
2934 : : /* Omit ordinary transitions < LO. */
2935 [ + + + + ]: 3468 : while (0 < r.count && ats[r.base] < lo)
2936 : : {
2937 : 740 : r.defaulttype = types[r.base];
2938 : 740 : r.count--;
2939 : 740 : r.base++;
2940 : : }
2941 : :
2942 : : /*
2943 : : * Omit as many initial leap seconds as possible, such that the first leap
2944 : : * second in the truncated list is <= LO, and is a positive leap second if
2945 : : * and only if it has a positive correction. This supports common TZif
2946 : : * readers that assume that the first leap second is positive if and only
2947 : : * if its correction is positive.
2948 : : */
2949 [ - + - - ]: 2728 : while (1 < r.leapcount && leap[r.leapbase + 1].trans <= lo)
2950 : : {
2951 : 0 : r.leapcount--;
2952 : 0 : r.leapbase++;
2953 : : }
2954 : 2728 : while (0 < r.leapbase
2955 [ - + ]: 2728 : && ((leap[r.leapbase - 1].corr < leap[r.leapbase].corr)
2956 [ # # ]: 0 : != (0 < leap[r.leapbase].corr)))
2957 : : {
2958 : 0 : r.leapcount++;
2959 : 0 : r.leapbase--;
2960 : : }
2961 : :
2962 : :
2963 : : /* Omit ordinary and leap second transitions greater than HI + 1. */
2964 [ + + ]: 2728 : if (hi < max_time)
2965 : : {
2966 [ + + + + ]: 2628 : while (0 < r.count && hi + 1 < ats[r.base + r.count - 1])
2967 : 1264 : r.count--;
2968 [ - + - - ]: 1364 : while (0 < r.leapcount && hi + 1 < leap[r.leapbase + r.leapcount - 1].trans)
2969 : 0 : r.leapcount--;
2970 : : }
2971 : :
2972 : : /* Determine whether to append an expiration to the leap second table. */
2973 [ - + - - ]: 2728 : r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi;
2974 : :
2975 : 2728 : return r;
2976 : : }
2977 : :
2978 : : static void
2979 : 1364 : writezone(const char *const name, const char *const string, char version,
2980 : : int defaulttype)
2981 : : {
2982 : : FILE *fp;
2983 : : ptrdiff_t i,
2984 : : j;
2985 : : int pass;
2986 : 1364 : char *tempname = NULL;
2987 : 1364 : char const *outname = name;
2988 : :
2989 : : /*
2990 : : * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
2991 : : * faster. Do not malloc(0) if !timecnt, as that might return NULL even
2992 : : * on success.
2993 : : */
2994 : 1364 : zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt,
2995 : : sizeof *ats + 1),
2996 : : alignof(zic_t)));
2997 : 1364 : void *typesptr = ats + timecnt;
2998 : 1364 : unsigned char *types = typesptr;
2999 : 1364 : struct timerange rangeall = {0}, range32, range64;
3000 : :
3001 : : /*
3002 : : * Sort.
3003 : : */
3004 [ + + ]: 1364 : if (timecnt > 1)
3005 : 1196 : qsort(attypes, timecnt, sizeof *attypes, atcomp);
3006 : :
3007 : : /*
3008 : : * Optimize and skip unwanted transitions.
3009 : : */
3010 : : {
3011 : : ptrdiff_t fromi,
3012 : : toi;
3013 : :
3014 : 1364 : toi = 0;
3015 : 1364 : fromi = 0;
3016 [ + + ]: 69396 : for (; fromi < timecnt; ++fromi)
3017 : : {
3018 [ + + ]: 68032 : if (toi != 0)
3019 : : {
3020 : : /*
3021 : : * Skip the previous transition if it is unwanted because its
3022 : : * local time is not earlier. The UT offset additions can't
3023 : : * overflow because of how the times were calculated.
3024 : : */
3025 [ + + ]: 66784 : unsigned char type_2 =
3026 : 65576 : toi == 1 ? 0 : attypes[toi - 2].type;
3027 : :
3028 : 67148 : if ((attypes[fromi].at
3029 : 66784 : + utoffs[attypes[toi - 1].type])
3030 [ + + ]: 66784 : <= attypes[toi - 1].at + utoffs[type_2])
3031 : : {
3032 [ + + ]: 364 : if (attypes[fromi].type == type_2)
3033 : 4 : toi--;
3034 : : else
3035 : 360 : attypes[toi - 1].type =
3036 : 360 : attypes[fromi].type;
3037 : 364 : continue;
3038 : : }
3039 : : }
3040 : :
3041 : : /*
3042 : : * Use a transition if it is the first one, or if it cannot be
3043 : : * merged for other reasons, or if it transitions to different
3044 : : * timekeeping.
3045 : : */
3046 [ + + ]: 67668 : if (toi == 0
3047 [ + + ]: 66420 : || attypes[fromi].dontmerge
3048 : 66012 : || (utoffs[attypes[toi - 1].type]
3049 [ + + ]: 66012 : != utoffs[attypes[fromi].type])
3050 : 1800 : || (isdsts[attypes[toi - 1].type]
3051 [ + + ]: 1800 : != isdsts[attypes[fromi].type])
3052 : 1404 : || (desigidx[attypes[toi - 1].type]
3053 [ + + ]: 1404 : != desigidx[attypes[fromi].type]))
3054 : 66528 : attypes[toi++] = attypes[fromi];
3055 : : }
3056 : 1364 : timecnt = toi;
3057 : : }
3058 : :
3059 [ - + ]: 1364 : if (noise)
3060 : : {
3061 [ # # ]: 0 : if (1200 < timecnt)
3062 : : {
3063 [ # # ]: 0 : if (TZ_MAX_TIMES < timecnt)
3064 : 0 : warning(_("reference clients mishandle"
3065 : : " more than %d transition times"),
3066 : : TZ_MAX_TIMES);
3067 : : else
3068 : 0 : warning(_("pre-2014 clients may mishandle"
3069 : : " more than 1200 transition times"));
3070 : : }
3071 [ # # ]: 0 : if (TZ_MAX_LEAPS < leapcnt)
3072 : 0 : warning(_("reference clients mishandle more than %d leap seconds"),
3073 : : TZ_MAX_LEAPS);
3074 : : }
3075 : :
3076 : : /*
3077 : : * Transfer.
3078 : : */
3079 [ + + ]: 67888 : for (i = 0; i < timecnt; ++i)
3080 : : {
3081 : 66524 : ats[i] = attypes[i].at;
3082 : 66524 : types[i] = attypes[i].type;
3083 : : }
3084 : :
3085 : : /*
3086 : : * Correct for leap seconds.
3087 : : */
3088 [ + + ]: 67888 : for (i = 0; i < timecnt; ++i)
3089 : : {
3090 : 66524 : j = leapcnt;
3091 [ - + ]: 66524 : while (--j >= 0)
3092 [ # # ]: 0 : if (leap[j].trans - leap[j].corr < ats[i])
3093 : : {
3094 : 0 : ats[i] = tadd(ats[i], leap[j].corr);
3095 : 0 : break;
3096 : : }
3097 : : }
3098 : :
3099 : 1364 : rangeall.defaulttype = defaulttype;
3100 : 1364 : rangeall.count = timecnt;
3101 : 1364 : rangeall.leapcount = leapcnt;
3102 : 1364 : range64 = limitrange(rangeall, lo_time,
3103 : 1364 : max(hi_time,
3104 : : redundant_time - (ZIC_MIN < redundant_time)),
3105 : : ats, types);
3106 : 1364 : range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types);
3107 : :
3108 : : /*
3109 : : * TZif version 4 is needed if a no-op transition is appended to indicate
3110 : : * the expiration of the leap second table, or if the first leap second
3111 : : * transition is not to a +1 or -1 correction.
3112 : : */
3113 [ + + ]: 4092 : for (pass = 1; pass <= 2; pass++)
3114 : : {
3115 [ + + ]: 2728 : struct timerange const *r = pass == 1 ? &range32 : &range64;
3116 : :
3117 [ + + + - ]: 2728 : if (pass == 1 && !want_bloat())
3118 : 1364 : continue;
3119 [ - + ]: 1364 : if (r->leapexpiry)
3120 : : {
3121 [ # # ]: 0 : if (noise)
3122 : 0 : warning(_("%s: pre-2021b clients may mishandle"
3123 : : " leap second expiry"),
3124 : : name);
3125 : 0 : version = '4';
3126 : : }
3127 [ - + ]: 1364 : if (0 < r->leapcount
3128 [ # # # # ]: 0 : && leap[r->leapbase].corr != 1 && leap[r->leapbase].corr != -1)
3129 : : {
3130 [ # # ]: 0 : if (noise)
3131 : 0 : warning(_("%s: pre-2021b clients may mishandle"
3132 : : " leap second table truncation"),
3133 : : name);
3134 : 0 : version = '4';
3135 : : }
3136 [ - + ]: 1364 : if (version == '4')
3137 : 0 : break;
3138 : : }
3139 : :
3140 : 1364 : fp = open_outfile(&outname, &tempname);
3141 : :
3142 [ + + ]: 4092 : for (pass = 1; pass <= 2; ++pass)
3143 : : {
3144 : : ptrdiff_t thistimei,
3145 : : thistimecnt,
3146 : : thistimelim;
3147 : : ptrdiff_t thisleapi,
3148 : : thisleapcnt,
3149 : : thisleaplim;
3150 : : struct tzhead tzh;
3151 : 2728 : int pretranstype = -1,
3152 : : thisdefaulttype;
3153 : : bool locut,
3154 : : hicut,
3155 : : thisleapexpiry;
3156 : : zic_t lo,
3157 : : thismin,
3158 : : thismax;
3159 : : int old0;
3160 : : char omittype[TZ_MAX_TYPES];
3161 : : int typemap[TZ_MAX_TYPES];
3162 : : int thistypecnt,
3163 : : stdcnt,
3164 : : utcnt;
3165 : : char thischars[TZ_MAX_CHARS];
3166 : : int thischarcnt;
3167 : : bool toomanytimes;
3168 : : int indmap[TZ_MAX_CHARS];
3169 : :
3170 [ + + ]: 2728 : if (pass == 1)
3171 : : {
3172 : 1364 : thisdefaulttype = range32.defaulttype;
3173 : 1364 : thistimei = range32.base;
3174 : 1364 : thistimecnt = range32.count;
3175 : 1364 : toomanytimes = thistimecnt >> 31 >> 1 != 0;
3176 : 1364 : thisleapi = range32.leapbase;
3177 : 1364 : thisleapcnt = range32.leapcount;
3178 : 1364 : thisleapexpiry = range32.leapexpiry;
3179 : 1364 : thismin = ZIC32_MIN;
3180 : 1364 : thismax = ZIC32_MAX;
3181 : : }
3182 : : else
3183 : : {
3184 : 1364 : thisdefaulttype = range64.defaulttype;
3185 : 1364 : thistimei = range64.base;
3186 : 1364 : thistimecnt = range64.count;
3187 : 1364 : toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0;
3188 : 1364 : thisleapi = range64.leapbase;
3189 : 1364 : thisleapcnt = range64.leapcount;
3190 : 1364 : thisleapexpiry = range64.leapexpiry;
3191 : 1364 : thismin = min_time;
3192 : 1364 : thismax = max_time;
3193 : : }
3194 [ - + ]: 2728 : if (toomanytimes)
3195 : 0 : error(_("too many transition times"));
3196 : :
3197 [ - + - - ]: 2728 : locut = thismin < lo_time && lo_time <= thismax;
3198 [ + - - + ]: 2728 : hicut = thismin <= hi_time && hi_time < thismax;
3199 : 2728 : thistimelim = thistimei + thistimecnt;
3200 : 2728 : memset(omittype, true, typecnt);
3201 : :
3202 : : /*
3203 : : * Determine whether to output a transition before the first
3204 : : * transition in range. This is needed when the output is truncated
3205 : : * at the start, and is also useful when catering to buggy 32-bit
3206 : : * clients that do not use time type 0 for timestamps before the first
3207 : : * transition.
3208 : : */
3209 [ + - + + : 2728 : if ((locut || (pass == 1 && thistimei))
+ + ]
3210 [ + + + - ]: 648 : && !(thistimecnt && ats[thistimei] == lo_time))
3211 : : {
3212 : 648 : pretranstype = thisdefaulttype;
3213 : 648 : omittype[pretranstype] = false;
3214 : : }
3215 : :
3216 : : /*
3217 : : * Arguably the default time type in the 32-bit data should be
3218 : : * range32.defaulttype, which is suited for timestamps just before
3219 : : * ZIC32_MIN. However, zic traditionally used the time type of the
3220 : : * indefinite past instead. Internet RFC 8532 says readers should
3221 : : * ignore 32-bit data, so this discrepancy matters only to obsolete
3222 : : * readers where the traditional type might be more appropriate even
3223 : : * if it's "wrong". So, use the historical zic value, unless -r
3224 : : * specifies a low cutoff that excludes some 32-bit timestamps.
3225 : : */
3226 [ + + + - ]: 2728 : if (pass == 1 && lo_time <= thismin)
3227 : 1364 : thisdefaulttype = range64.defaulttype;
3228 : :
3229 [ - + ]: 2728 : if (locut)
3230 : 0 : thisdefaulttype = unspecifiedtype;
3231 : 2728 : omittype[thisdefaulttype] = false;
3232 [ + + ]: 133772 : for (i = thistimei; i < thistimelim; i++)
3233 : 131044 : omittype[types[i]] = false;
3234 [ - + ]: 2728 : if (hicut)
3235 : 0 : omittype[unspecifiedtype] = false;
3236 : :
3237 : : /*
3238 : : * Reorder types to make THISDEFAULTTYPE type 0. Use TYPEMAP to swap
3239 : : * OLD0 and THISDEFAULTTYPE so that THISDEFAULTTYPE appears as type 0
3240 : : * in the output instead of OLD0. TYPEMAP also omits unused types.
3241 : : */
3242 : 2728 : old0 = strlen(omittype);
3243 : :
3244 : : #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
3245 : :
3246 : : /*
3247 : : * For some pre-2011 systems: if the last-to-be-written standard (or
3248 : : * daylight) type has an offset different from the most recently used
3249 : : * offset, append an (unused) copy of the most recently used type (to
3250 : : * help get global "altzone" and "timezone" variables set correctly).
3251 : : */
3252 [ - + ]: 2728 : if (want_bloat())
3253 : : {
3254 : : int mrudst,
3255 : : mrustd,
3256 : : hidst,
3257 : : histd,
3258 : : type;
3259 : :
3260 : 0 : hidst = histd = mrudst = mrustd = -1;
3261 [ # # ]: 0 : if (0 <= pretranstype)
3262 : : {
3263 [ # # ]: 0 : if (isdsts[pretranstype])
3264 : 0 : mrudst = pretranstype;
3265 : : else
3266 : 0 : mrustd = pretranstype;
3267 : : }
3268 [ # # ]: 0 : for (i = thistimei; i < thistimelim; i++)
3269 [ # # ]: 0 : if (isdsts[types[i]])
3270 : 0 : mrudst = types[i];
3271 : : else
3272 : 0 : mrustd = types[i];
3273 [ # # ]: 0 : for (i = old0; i < typecnt; i++)
3274 : : {
3275 [ # # ]: 0 : int h = (i == old0 ? thisdefaulttype
3276 [ # # ]: 0 : : i == thisdefaulttype ? old0 : i);
3277 : :
3278 [ # # ]: 0 : if (!omittype[h])
3279 : : {
3280 [ # # ]: 0 : if (isdsts[h])
3281 : 0 : hidst = i;
3282 : : else
3283 : 0 : histd = i;
3284 : : }
3285 : : }
3286 [ # # # # : 0 : if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
# # ]
3287 [ # # ]: 0 : utoffs[hidst] != utoffs[mrudst])
3288 : : {
3289 : 0 : isdsts[mrudst] = -1;
3290 : 0 : type = addtype(utoffs[mrudst],
3291 : 0 : &chars[desigidx[mrudst]],
3292 : : true,
3293 : 0 : ttisstds[mrudst],
3294 : 0 : ttisuts[mrudst]);
3295 : 0 : isdsts[mrudst] = 1;
3296 : 0 : omittype[type] = false;
3297 : : }
3298 [ # # # # : 0 : if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
# # ]
3299 [ # # ]: 0 : utoffs[histd] != utoffs[mrustd])
3300 : : {
3301 : 0 : isdsts[mrustd] = -1;
3302 : 0 : type = addtype(utoffs[mrustd],
3303 : 0 : &chars[desigidx[mrustd]],
3304 : : false,
3305 : 0 : ttisstds[mrustd],
3306 : 0 : ttisuts[mrustd]);
3307 : 0 : isdsts[mrustd] = 0;
3308 : 0 : omittype[type] = false;
3309 : : }
3310 : : }
3311 : : #endif /* !defined
3312 : : * LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
3313 : 2728 : thistypecnt = 0;
3314 [ + + ]: 15472 : for (i = old0; i < typecnt; i++)
3315 [ + + ]: 12744 : if (!omittype[i])
3316 : 12620 : typemap[i == old0 ? thisdefaulttype
3317 [ - + ]: 12620 : : i == thisdefaulttype ? old0 : i]
3318 [ + + ]: 25240 : = thistypecnt++;
3319 : :
3320 : 2728 : thischarcnt = stdcnt = utcnt = 0;
3321 [ + + ]: 15472 : for (i = old0; i < typecnt; i++)
3322 : : {
3323 [ + + ]: 12744 : if (omittype[i])
3324 : 124 : continue;
3325 [ - + ]: 12620 : if (ttisstds[i])
3326 : 0 : stdcnt = thistypecnt;
3327 [ - + ]: 12620 : if (ttisuts[i])
3328 : 0 : utcnt = thistypecnt;
3329 : 12620 : addabbr(thischars, &thischarcnt, &chars[desigidx[i]]);
3330 : : }
3331 : :
3332 : : /*
3333 : : * Now that all abbrevs have been added to THISCHARS, it is safe to
3334 : : * set INDMAP without worrying about whether the abbrevs might move
3335 : : * later.
3336 : : */
3337 [ + + ]: 701096 : for (i = 0; i < TZ_MAX_CHARS; i++)
3338 : 698368 : indmap[i] = -1;
3339 [ + + ]: 15472 : for (i = old0; i < typecnt; i++)
3340 [ + + + + ]: 12744 : if (!omittype[i] && indmap[desigidx[i]] < 0)
3341 : 11572 : indmap[desigidx[i]] = addabbr(thischars, &thischarcnt,
3342 : 11572 : &chars[desigidx[i]]);
3343 : :
3344 [ + + + - ]: 2728 : if (pass == 1 && !want_bloat())
3345 : : {
3346 : 1364 : hicut = thisleapexpiry = false;
3347 : 1364 : pretranstype = -1;
3348 : 1364 : thistimecnt = thisleapcnt = 0;
3349 : 1364 : thistypecnt = thischarcnt = 1;
3350 : : }
3351 : : #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp)
3352 : 2728 : memset(&tzh, 0, sizeof tzh);
3353 : 2728 : memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
3354 : 2728 : tzh.tzh_version[0] = version;
3355 : 2728 : convert(utcnt, tzh.tzh_ttisutcnt);
3356 : 2728 : convert(stdcnt, tzh.tzh_ttisstdcnt);
3357 : 2728 : convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt);
3358 : 2728 : convert((0 <= pretranstype) + thistimecnt + hicut,
3359 : : tzh.tzh_timecnt);
3360 : 2728 : convert(thistypecnt, tzh.tzh_typecnt);
3361 : 2728 : convert(thischarcnt, tzh.tzh_charcnt);
3362 : 2728 : DO(tzh_magic);
3363 : 2728 : DO(tzh_version);
3364 : 2728 : DO(tzh_reserved);
3365 : 2728 : DO(tzh_ttisutcnt);
3366 : 2728 : DO(tzh_ttisstdcnt);
3367 : 2728 : DO(tzh_leapcnt);
3368 : 2728 : DO(tzh_timecnt);
3369 : 2728 : DO(tzh_typecnt);
3370 : 2728 : DO(tzh_charcnt);
3371 : : #undef DO
3372 [ + + + - ]: 2728 : if (pass == 1 && !want_bloat())
3373 : : {
3374 : : /* Output a minimal data block with just one time type. */
3375 : 1364 : puttzcode(0, fp); /* utoff */
3376 : 1364 : putc(0, fp); /* dst */
3377 : 1364 : putc(0, fp); /* index of abbreviation */
3378 : 1364 : putc(0, fp); /* empty-string abbreviation */
3379 : 1364 : continue;
3380 : : }
3381 : :
3382 : : /* PG: print current timezone abbreviations if requested */
3383 [ - + - - ]: 1364 : if (print_abbrevs && pass == 2)
3384 : : {
3385 : : /* Print "type" data for periods ending after print_cutoff */
3386 [ # # ]: 0 : for (i = thistimei; i < thistimelim; ++i)
3387 : : {
3388 [ # # # # ]: 0 : if (i == thistimelim - 1 || ats[i + 1] > print_cutoff)
3389 : : {
3390 : 0 : unsigned char tm = types[i];
3391 : 0 : char *thisabbrev = &thischars[indmap[desigidx[tm]]];
3392 : :
3393 : 0 : fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
3394 : : thisabbrev,
3395 : : utoffs[tm],
3396 [ # # ]: 0 : isdsts[tm] ? "\tD" : "");
3397 : : }
3398 : : }
3399 : : /* Print the default type if we have no transitions at all */
3400 [ # # ]: 0 : if (thistimei >= thistimelim)
3401 : : {
3402 : 0 : unsigned char tm = defaulttype;
3403 : 0 : char *thisabbrev = &thischars[indmap[desigidx[tm]]];
3404 : :
3405 : 0 : fprintf(stdout, "%s\t%" PRIdFAST64 "%s\n",
3406 : : thisabbrev,
3407 : : utoffs[tm],
3408 [ # # ]: 0 : isdsts[tm] ? "\tD" : "");
3409 : : }
3410 : : }
3411 : :
3412 [ + - - + : 1364 : if (pass == 2 && noise && 50 < thischarcnt)
- - ]
3413 : 0 : warning(_("%s: pre-2026 reference clients mishandle"
3414 : : " more than 50 bytes of abbreviations"),
3415 : : name);
3416 : :
3417 : : /*
3418 : : * Output a LO_TIME transition if needed; see limitrange. But do not
3419 : : * go below the minimum representable value for this pass.
3420 : : */
3421 [ - + - - ]: 1364 : lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time;
3422 : :
3423 [ - + ]: 1364 : if (0 <= pretranstype)
3424 : 0 : puttzcodepass(lo, fp, pass);
3425 [ + + ]: 67888 : for (i = thistimei; i < thistimelim; ++i)
3426 : : {
3427 : 66524 : puttzcodepass(ats[i], fp, pass);
3428 : : }
3429 [ - + ]: 1364 : if (hicut)
3430 : 0 : puttzcodepass(hi_time + 1, fp, pass);
3431 [ - + ]: 1364 : if (0 <= pretranstype)
3432 : 0 : putc(typemap[pretranstype], fp);
3433 [ + + ]: 67888 : for (i = thistimei; i < thistimelim; i++)
3434 : 66524 : putc(typemap[types[i]], fp);
3435 [ - + ]: 1364 : if (hicut)
3436 : 0 : putc(typemap[unspecifiedtype], fp);
3437 : :
3438 [ + + ]: 7736 : for (i = old0; i < typecnt; i++)
3439 : : {
3440 [ + + ]: 11380 : int h = (i == old0 ? thisdefaulttype
3441 [ + - ]: 5008 : : i == thisdefaulttype ? old0 : i);
3442 : :
3443 [ + + ]: 6372 : if (!omittype[h])
3444 : : {
3445 : 6356 : puttzcode(utoffs[h], fp);
3446 : 6356 : putc(isdsts[h], fp);
3447 : 6356 : putc(indmap[desigidx[h]], fp);
3448 : : }
3449 : : }
3450 [ + - ]: 1364 : if (thischarcnt != 0)
3451 : 1364 : fwrite(thischars, sizeof thischars[0],
3452 : : thischarcnt, fp);
3453 : 1364 : thisleaplim = thisleapi + thisleapcnt;
3454 [ - + ]: 1364 : for (i = thisleapi; i < thisleaplim; ++i)
3455 : : {
3456 : : zic_t todo;
3457 : :
3458 [ # # ]: 0 : if (leap[i].roll)
3459 : : {
3460 [ # # # # ]: 0 : if (timecnt == 0 || leap[i].trans < ats[0])
3461 : : {
3462 : 0 : j = 0;
3463 [ # # ]: 0 : while (isdsts[j])
3464 [ # # ]: 0 : if (++j >= typecnt)
3465 : : {
3466 : 0 : j = 0;
3467 : 0 : break;
3468 : : }
3469 : : }
3470 : : else
3471 : : {
3472 : 0 : j = 1;
3473 [ # # ]: 0 : while (j < timecnt &&
3474 [ # # ]: 0 : ats[j] <= leap[i].trans)
3475 : 0 : ++j;
3476 : 0 : j = types[j - 1];
3477 : : }
3478 : 0 : todo = tadd(leap[i].trans, -utoffs[j]);
3479 : : }
3480 : : else
3481 : 0 : todo = leap[i].trans;
3482 : 0 : puttzcodepass(todo, fp, pass);
3483 : 0 : puttzcode(leap[i].corr, fp);
3484 : : }
3485 [ - + ]: 1364 : if (thisleapexpiry)
3486 : : {
3487 : : /*
3488 : : * Append a no-op leap correction indicating when the leap second
3489 : : * table expires. Although this does not conform to Internet RFC
3490 : : * 9636, most clients seem to accept this and the plan is to amend
3491 : : * the RFC to allow this in version 4 TZif files.
3492 : : */
3493 : 0 : puttzcodepass(leapexpires, fp, pass);
3494 [ # # ]: 0 : puttzcode(thisleaplim ? leap[thisleaplim - 1].corr : 0, fp);
3495 : : }
3496 [ - + ]: 1364 : if (stdcnt != 0)
3497 [ # # ]: 0 : for (i = old0; i < typecnt; i++)
3498 [ # # ]: 0 : if (!omittype[i])
3499 : 0 : putc(ttisstds[i], fp);
3500 [ - + ]: 1364 : if (utcnt != 0)
3501 [ # # ]: 0 : for (i = old0; i < typecnt; i++)
3502 [ # # ]: 0 : if (!omittype[i])
3503 : 0 : putc(ttisuts[i], fp);
3504 : : }
3505 : 1364 : fprintf(fp, "\n%s\n", string);
3506 : 1364 : close_file(fp, directory, name, tempname);
3507 : 1364 : rename_dest(tempname, name);
3508 : 1364 : free(ats);
3509 : 1364 : }
3510 : :
3511 : : static char const *
3512 : 54096 : abbroffset(char *buf, zic_t offset)
3513 : : {
3514 : 54096 : char sign = '+';
3515 : : int seconds,
3516 : : minutes;
3517 : :
3518 [ + + ]: 54096 : if (offset < 0)
3519 : : {
3520 : 26244 : offset = -offset;
3521 : 26244 : sign = '-';
3522 : : }
3523 : :
3524 : 54096 : seconds = offset % SECSPERMIN;
3525 : 54096 : offset /= SECSPERMIN;
3526 : 54096 : minutes = offset % MINSPERHOUR;
3527 : 54096 : offset /= MINSPERHOUR;
3528 [ - + ]: 54096 : if (100 <= offset)
3529 : : {
3530 : 0 : error(_("%%z UT offset magnitude exceeds 99:59:59"));
3531 : 0 : return "%z";
3532 : : }
3533 : : else
3534 : : {
3535 : 54096 : char *p = buf;
3536 : :
3537 : 54096 : *p++ = sign;
3538 : 54096 : *p++ = '0' + offset / 10;
3539 : 54096 : *p++ = '0' + offset % 10;
3540 [ + + ]: 54096 : if (minutes | seconds)
3541 : : {
3542 : 1620 : *p++ = '0' + minutes / 10;
3543 : 1620 : *p++ = '0' + minutes % 10;
3544 [ - + ]: 1620 : if (seconds)
3545 : : {
3546 : 0 : *p++ = '0' + seconds / 10;
3547 : 0 : *p++ = '0' + seconds % 10;
3548 : : }
3549 : : }
3550 : 54096 : *p = '\0';
3551 : 54096 : return buf;
3552 : : }
3553 : : }
3554 : :
3555 : : static char const disable_percent_s[] = "";
3556 : :
3557 : : static ptrdiff_t
3558 : 136456 : doabbr(char *abbr, struct zone const *zp, char const *letters,
3559 : : bool isdst, zic_t save, bool doquotes)
3560 : 3380 : {
3561 : : char *cp;
3562 : : ptrdiff_t len;
3563 : 136456 : char const *format = zp->z_format;
3564 : 136456 : char const *slashp = strchr(format, '/');
3565 : :
3566 [ + + ]: 136456 : if (slashp == NULL)
3567 : : {
3568 : : char letterbuf[PERCENT_Z_LEN_BOUND + 1];
3569 : :
3570 [ + + ]: 132924 : if (zp->z_format_specifier == 'z')
3571 : 54096 : letters = abbroffset(letterbuf, zp->z_stdoff + save);
3572 [ + + ]: 78828 : else if (!letters)
3573 : 3068 : letters = "%s";
3574 [ - + ]: 75760 : else if (letters == disable_percent_s)
3575 : 0 : return 0;
3576 : 132924 : sprintf(abbr, format, letters);
3577 : : }
3578 [ + + ]: 3532 : else if (isdst)
3579 : 1940 : strcpy(abbr, slashp + 1);
3580 : : else
3581 : : {
3582 : 1592 : memcpy(abbr, format, slashp - format);
3583 : 1592 : abbr[slashp - format] = '\0';
3584 : : }
3585 : 136456 : len = strlen(abbr);
3586 [ + + ]: 136456 : if (!doquotes)
3587 : 134680 : return len;
3588 [ + + ]: 5156 : for (cp = abbr; is_alpha(*cp); cp++)
3589 : 3380 : continue;
3590 [ + - + + ]: 1776 : if (len > 0 && *cp == '\0')
3591 : 1036 : return len;
3592 : 740 : abbr[len + 2] = '\0';
3593 : 740 : abbr[len + 1] = '>';
3594 : 740 : memmove(abbr + 1, abbr, len);
3595 : 740 : abbr[0] = '<';
3596 : 740 : return len + 2;
3597 : : }
3598 : :
3599 : : static void
3600 : 82904 : updateminmax(const zic_t x)
3601 : : {
3602 [ + + ]: 82904 : if (min_year > x)
3603 : 1440 : min_year = x;
3604 [ + + ]: 82904 : if (max_year < x)
3605 : 4160 : max_year = x;
3606 : 82904 : }
3607 : :
3608 : : static int
3609 : 1684 : stringoffset(char *result, zic_t offset)
3610 : : {
3611 : : int hours;
3612 : : int minutes;
3613 : : int seconds;
3614 : 1684 : bool negative = offset < 0;
3615 : 1684 : int len = negative;
3616 : :
3617 [ + + ]: 1684 : if (negative)
3618 : : {
3619 : 720 : offset = -offset;
3620 : 720 : result[0] = '-';
3621 : : }
3622 : 1684 : seconds = offset % SECSPERMIN;
3623 : 1684 : offset /= SECSPERMIN;
3624 : 1684 : minutes = offset % MINSPERHOUR;
3625 : 1684 : offset /= MINSPERHOUR;
3626 [ - + ]: 1684 : if (offset >= HOURSPERDAY * DAYSPERWEEK)
3627 : : {
3628 : 0 : result[0] = '\0';
3629 : 0 : return 0;
3630 : : }
3631 : 1684 : hours = offset;
3632 : 1684 : len += sprintf(result + len, "%d", hours);
3633 [ + + - + ]: 1684 : if (minutes != 0 || seconds != 0)
3634 : : {
3635 : 64 : len += sprintf(result + len, ":%02d", minutes);
3636 [ - + ]: 64 : if (seconds != 0)
3637 : 0 : len += sprintf(result + len, ":%02d", seconds);
3638 : : }
3639 : 1684 : return len;
3640 : : }
3641 : :
3642 : : static int
3643 : 824 : stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff)
3644 : : {
3645 : 824 : zic_t tod = rp->r_tod;
3646 : 824 : int compat = 0;
3647 : :
3648 [ - + ]: 824 : if (rp->r_dycode == DC_DOM)
3649 : : {
3650 : : int month,
3651 : : total;
3652 : :
3653 [ # # # # ]: 0 : if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
3654 : 0 : return -1;
3655 : 0 : total = 0;
3656 [ # # ]: 0 : for (month = 0; month < rp->r_month; ++month)
3657 : 0 : total += len_months[0][month];
3658 : : /* Omit the "J" in Jan and Feb, as that's shorter. */
3659 [ # # ]: 0 : if (rp->r_month <= 1)
3660 : 0 : result += sprintf(result, "%d", total + rp->r_dayofmonth - 1);
3661 : : else
3662 : 0 : result += sprintf(result, "J%d", total + rp->r_dayofmonth);
3663 : : }
3664 : : else
3665 : : {
3666 : : int week;
3667 : 824 : int wday = rp->r_wday;
3668 : : int wdayoff;
3669 : :
3670 [ + + ]: 824 : if (rp->r_dycode == DC_DOWGEQ)
3671 : : {
3672 : 484 : wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
3673 [ + + ]: 484 : if (wdayoff)
3674 : 20 : compat = 2013;
3675 : 484 : wday -= wdayoff;
3676 : 484 : tod += wdayoff * SECSPERDAY;
3677 : 484 : week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
3678 : : }
3679 [ + - ]: 340 : else if (rp->r_dycode == DC_DOWLEQ)
3680 : : {
3681 [ + + ]: 340 : if (rp->r_dayofmonth == len_months[1][rp->r_month])
3682 : 324 : week = 5;
3683 : : else
3684 : : {
3685 : 16 : wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
3686 [ + - ]: 16 : if (wdayoff)
3687 : 16 : compat = 2013;
3688 : 16 : wday -= wdayoff;
3689 : 16 : tod += wdayoff * SECSPERDAY;
3690 : 16 : week = rp->r_dayofmonth / DAYSPERWEEK;
3691 : : }
3692 : : }
3693 : : else
3694 : 0 : return -1; /* "cannot happen" */
3695 [ + + ]: 824 : if (wday < 0)
3696 : 16 : wday += DAYSPERWEEK;
3697 : 824 : result += sprintf(result, "M%d.%d.%d",
3698 : 824 : rp->r_month + 1, week, wday);
3699 : : }
3700 [ + + ]: 824 : if (rp->r_todisut)
3701 : 312 : tod += stdoff;
3702 [ + + + + ]: 824 : if (rp->r_todisstd && !rp->r_isdst)
3703 : 196 : tod += save;
3704 [ + + ]: 824 : if (tod != 2 * SECSPERMIN * MINSPERHOUR)
3705 : : {
3706 : 308 : *result++ = '/';
3707 [ - + ]: 308 : if (!stringoffset(result, tod))
3708 : 0 : return -1;
3709 [ + + ]: 308 : if (tod < 0)
3710 : : {
3711 [ + - ]: 8 : if (compat < 2013)
3712 : 8 : compat = 2013;
3713 : : }
3714 [ + + ]: 300 : else if (SECSPERDAY <= tod)
3715 : : {
3716 [ + + ]: 32 : if (compat < 1994)
3717 : 4 : compat = 1994;
3718 : : }
3719 : : }
3720 : 824 : return compat;
3721 : : }
3722 : :
3723 : : static int
3724 : 9200 : rule_cmp(struct rule const *a, struct rule const *b)
3725 : : {
3726 [ + + ]: 9200 : if (!a)
3727 : 1248 : return -!!b;
3728 [ - + ]: 7952 : if (!b)
3729 : 0 : return 1;
3730 [ + + ]: 7952 : if (a->r_hiyear != b->r_hiyear)
3731 [ + + ]: 7420 : return a->r_hiyear < b->r_hiyear ? -1 : 1;
3732 [ + + ]: 532 : if (a->r_hiyear == ZIC_MAX)
3733 : 412 : return 0;
3734 [ + - ]: 120 : if (a->r_month - b->r_month != 0)
3735 : 120 : return a->r_month - b->r_month;
3736 : 0 : return a->r_dayofmonth - b->r_dayofmonth;
3737 : : }
3738 : :
3739 : : /*
3740 : : * Store into RESULT a proleptic TZ string that represent the future
3741 : : * predictions for the zone ZPFIRST with ZONECOUNT entries. Return a
3742 : : * compatibility indicator (a TZDB release year) if successful, a
3743 : : * negative integer if no such TZ string exists.
3744 : : */
3745 : : static int
3746 : 1364 : stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount)
3747 : : {
3748 : : const struct zone *zp;
3749 : : struct rule *rp;
3750 : : struct rule *stdrp;
3751 : : struct rule *dstrp;
3752 : : ptrdiff_t i;
3753 : 1364 : int compat = 0;
3754 : : int c;
3755 : : int offsetlen;
3756 : : struct rule stdr,
3757 : : dstr;
3758 : : ptrdiff_t len;
3759 : : int dstcmp;
3760 : 1364 : struct rule *lastrp[2] = {NULL, NULL};
3761 : : struct zone zstr[2];
3762 : : struct zone const *stdzp;
3763 : : struct zone const *dstzp;
3764 : :
3765 : 1364 : result[0] = '\0';
3766 : :
3767 : : /*
3768 : : * Internet RFC 9636 section 6.1 says to use an empty TZ string if future
3769 : : * timestamps are truncated.
3770 : : */
3771 [ - + ]: 1364 : if (hi_time < max_time)
3772 : 0 : return -1;
3773 : :
3774 : 1364 : zp = zpfirst + zonecount - 1;
3775 [ + + ]: 9940 : for (i = 0; i < zp->z_nrules; ++i)
3776 : : {
3777 : : struct rule **last;
3778 : : int cmp;
3779 : :
3780 : 8576 : rp = &zp->z_rules[i];
3781 : 8576 : last = &lastrp[rp->r_isdst];
3782 : 8576 : cmp = rule_cmp(*last, rp);
3783 [ + + ]: 8576 : if (cmp < 0)
3784 : 3484 : *last = rp;
3785 [ - + ]: 5092 : else if (cmp == 0)
3786 : 0 : return -1;
3787 : : }
3788 : 1364 : stdrp = lastrp[false];
3789 : 1364 : dstrp = lastrp[true];
3790 [ + + - + ]: 1364 : dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1;
3791 : 1364 : stdzp = dstzp = zp;
3792 : :
3793 [ + + ]: 1364 : if (dstcmp < 0)
3794 : : {
3795 : : /* Standard time all year. */
3796 : 952 : dstrp = NULL;
3797 : : }
3798 [ - + ]: 412 : else if (0 < dstcmp)
3799 : : {
3800 : : /*
3801 : : * DST all year. Use an abbreviation like "XXX3EDT4,0/0,J365/23" for
3802 : : * EDT (-04) all year.
3803 : : */
3804 [ # # ]: 0 : zic_t save = dstrp ? dstrp->r_save : zp->z_save;
3805 : :
3806 [ # # ]: 0 : if (0 <= save)
3807 : : {
3808 : : /*
3809 : : * Positive DST, the typical case for all-year DST. Fake a
3810 : : * timezone with negative DST.
3811 : : */
3812 : 0 : stdzp = &zstr[0];
3813 : 0 : dstzp = &zstr[1];
3814 : 0 : zstr[0].z_stdoff = zp->z_stdoff + 2 * save;
3815 : 0 : zstr[0].z_format = "XXX"; /* Any 3 letters will do. */
3816 : 0 : zstr[0].z_format_specifier = 0;
3817 : 0 : zstr[1].z_stdoff = zstr[0].z_stdoff;
3818 : 0 : zstr[1].z_format = zp->z_format;
3819 : 0 : zstr[1].z_format_specifier = zp->z_format_specifier;
3820 : : }
3821 : 0 : dstr.r_month = TM_JANUARY;
3822 : 0 : dstr.r_dycode = DC_DOM;
3823 : 0 : dstr.r_dayofmonth = 1;
3824 : 0 : dstr.r_tod = 0;
3825 : 0 : dstr.r_todisstd = dstr.r_todisut = false;
3826 : 0 : dstr.r_isdst = true;
3827 : 0 : dstr.r_save = save < 0 ? save : -save;
3828 [ # # ]: 0 : dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL;
3829 : 0 : stdr.r_month = TM_DECEMBER;
3830 : 0 : stdr.r_dycode = DC_DOM;
3831 : 0 : stdr.r_dayofmonth = 31;
3832 : 0 : stdr.r_tod = SECSPERDAY + dstr.r_save;
3833 : 0 : stdr.r_todisstd = stdr.r_todisut = false;
3834 : 0 : stdr.r_isdst = false;
3835 : 0 : stdr.r_save = 0;
3836 [ # # # # ]: 0 : stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL;
3837 : 0 : dstrp = &dstr;
3838 : 0 : stdrp = &stdr;
3839 : : }
3840 [ + + ]: 1364 : len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL,
3841 : : false, 0, true);
3842 : 1364 : offsetlen = stringoffset(result + len, -stdzp->z_stdoff);
3843 [ - + ]: 1364 : if (!offsetlen)
3844 : : {
3845 : 0 : result[0] = '\0';
3846 : 0 : return -1;
3847 : : }
3848 : 1364 : len += offsetlen;
3849 [ + + ]: 1364 : if (dstrp == NULL)
3850 : 952 : return compat;
3851 : 824 : len += doabbr(result + len, dstzp, dstrp->r_abbrvar,
3852 : 412 : dstrp->r_isdst, dstrp->r_save, true);
3853 [ + + ]: 412 : if (dstrp->r_save != SECSPERMIN * MINSPERHOUR)
3854 : : {
3855 : 12 : offsetlen = stringoffset(result + len,
3856 : 12 : -(dstzp->z_stdoff + dstrp->r_save));
3857 [ - + ]: 12 : if (!offsetlen)
3858 : : {
3859 : 0 : result[0] = '\0';
3860 : 0 : return -1;
3861 : : }
3862 : 12 : len += offsetlen;
3863 : : }
3864 : 412 : result[len++] = ',';
3865 : 412 : c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff);
3866 [ - + ]: 412 : if (c < 0)
3867 : : {
3868 : 0 : result[0] = '\0';
3869 : 0 : return -1;
3870 : : }
3871 [ + + ]: 412 : if (compat < c)
3872 : 28 : compat = c;
3873 : 412 : len += strlen(result + len);
3874 : 412 : result[len++] = ',';
3875 : 412 : c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff);
3876 [ - + ]: 412 : if (c < 0)
3877 : : {
3878 : 0 : result[0] = '\0';
3879 : 0 : return -1;
3880 : : }
3881 [ + + ]: 412 : if (compat < c)
3882 : 4 : compat = c;
3883 : 412 : return compat;
3884 : : }
3885 : :
3886 : : static void
3887 : 1364 : outzone(const struct zone *zpfirst, ptrdiff_t zonecount)
3888 : : {
3889 : : ptrdiff_t i,
3890 : : j;
3891 : : zic_t starttime,
3892 : : untiltime;
3893 : : bool startttisstd;
3894 : : bool startttisut;
3895 : : char *startbuf;
3896 : : char *ab;
3897 : : char *envvar;
3898 : : int max_abbr_len;
3899 : : int max_envvar_len;
3900 : : int compat;
3901 : : bool do_extend;
3902 : : char version;
3903 : 1364 : zic_t nonTZlimtime = ZIC_MIN;
3904 : 1364 : int nonTZlimtype = -1;
3905 : : zic_t max_year0;
3906 : 1364 : int defaulttype = -1;
3907 : 1364 : int max_stringoffset_len = sizeof "-167:59:59" - 1;
3908 : 1364 : int max_comma_stringrule_len = (sizeof ",M12.5.6/" - 1
3909 : 1364 : + max_stringoffset_len);
3910 : :
3911 : 1364 : check_for_signal();
3912 : :
3913 : : /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */
3914 : 1364 : max_abbr_len = 2 + max_format_len + max_abbrvar_len;
3915 : 1364 : max_envvar_len = 2 * (max_abbr_len + max_stringoffset_len
3916 : 1364 : + max_comma_stringrule_len);
3917 : :
3918 : 1364 : startbuf = xmalloc(max_abbr_len + 1);
3919 : 1364 : ab = xmalloc(max_abbr_len + 1);
3920 : 1364 : envvar = xmalloc(max_envvar_len + 1);
3921 : 1364 : INITIALIZE(untiltime);
3922 : 1364 : INITIALIZE(starttime);
3923 : :
3924 : : /*
3925 : : * Now. . .finally. . .generate some useful data!
3926 : : */
3927 : 1364 : timecnt = 0;
3928 : 1364 : typecnt = 0;
3929 : 1364 : charcnt = 0;
3930 : :
3931 : : /*
3932 : : * Thanks to Earl Chew for noting the need to unconditionally initialize
3933 : : * startttisstd.
3934 : : */
3935 : 1364 : startttisstd = false;
3936 : 1364 : startttisut = false;
3937 : 1364 : min_year = max_year = EPOCH_YEAR;
3938 [ - + ]: 1364 : if (leapseen)
3939 : : {
3940 : 0 : updateminmax(leapminyear);
3941 : 0 : updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
3942 : : }
3943 [ + + ]: 9212 : for (i = 0; i < zonecount; ++i)
3944 : : {
3945 : 7848 : struct zone const *zp = &zpfirst[i];
3946 : :
3947 [ + + ]: 7848 : if (i < zonecount - 1)
3948 : 6484 : updateminmax(zp->z_untilrule.r_loyear);
3949 [ + + ]: 66604 : for (j = 0; j < zp->z_nrules; ++j)
3950 : : {
3951 : 58756 : struct rule *rp = &zp->z_rules[j];
3952 : :
3953 : 58756 : updateminmax(rp->r_loyear);
3954 [ + + ]: 58756 : if (rp->r_hiwasnum)
3955 : 17664 : updateminmax(rp->r_hiyear);
3956 : : }
3957 : : }
3958 : :
3959 : : /*
3960 : : * Generate lots of data if a rule can't cover all future times.
3961 : : */
3962 : 1364 : compat = stringzone(envvar, zpfirst, zonecount);
3963 [ + + ]: 1364 : version = compat < 2013 ? '2' : '3';
3964 : 1364 : do_extend = compat < 0;
3965 [ - + ]: 1364 : if (noise)
3966 : : {
3967 [ # # ]: 0 : if (!*envvar)
3968 : 0 : warning("%s %s",
3969 : : _("no proleptic TZ string for zone"),
3970 : 0 : zpfirst->z_name);
3971 [ # # ]: 0 : else if (compat != 0)
3972 : : {
3973 : : /*
3974 : : * Circa-COMPAT clients, and earlier clients, might not work for
3975 : : * this zone when given dates before 1970 or after 2038.
3976 : : */
3977 : 0 : warning(_("%s: pre-%d clients may mishandle"
3978 : : " distant timestamps"),
3979 : 0 : zpfirst->z_name, compat);
3980 : : }
3981 : : }
3982 [ - + ]: 1364 : if (do_extend)
3983 : : {
3984 [ # # ]: 0 : if (min_year >= ZIC_MIN + years_of_observations)
3985 : 0 : min_year -= years_of_observations;
3986 : : else
3987 : 0 : min_year = ZIC_MIN;
3988 [ # # ]: 0 : if (max_year <= ZIC_MAX - years_of_observations)
3989 : 0 : max_year += years_of_observations;
3990 : : else
3991 : 0 : max_year = ZIC_MAX;
3992 : : }
3993 : 1364 : max_year = max(max_year, (redundant_time / (SECSPERDAY * DAYSPERNYEAR)
3994 : : + EPOCH_YEAR + 1));
3995 : 1364 : max_year0 = max_year;
3996 [ - + ]: 1364 : if (want_bloat())
3997 : : {
3998 : : /*
3999 : : * For the benefit of older systems, generate data from 1900 through
4000 : : * 2038.
4001 : : */
4002 [ # # ]: 0 : if (min_year > YEAR_32BIT_MIN - 1)
4003 : 0 : min_year = YEAR_32BIT_MIN - 1;
4004 [ # # ]: 0 : if (max_year < YEAR_32BIT_MAX)
4005 : 0 : max_year = YEAR_32BIT_MAX;
4006 : : }
4007 : :
4008 [ + - - + ]: 1364 : if (min_time < lo_time || hi_time < max_time)
4009 : 0 : unspecifiedtype = addtype(0, "-00", false, false, false);
4010 : :
4011 [ + + ]: 9212 : for (i = 0; i < zonecount; ++i)
4012 : : {
4013 : : /*
4014 : : * A guess that may well be corrected later.
4015 : : */
4016 : 7848 : zic_t save = 0;
4017 : 7848 : struct zone const *zp = &zpfirst[i];
4018 [ + + + - ]: 7848 : bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
4019 : 7848 : bool useuntil = i < (zonecount - 1);
4020 : 7848 : zic_t stdoff = zp->z_stdoff;
4021 : 7848 : zic_t startoff = stdoff;
4022 : :
4023 [ + + - + ]: 7848 : if (useuntil && zp->z_untiltime <= min_time)
4024 : 0 : continue;
4025 : 7848 : eat(zp->z_filenum, zp->z_linenum);
4026 : 7848 : *startbuf = '\0';
4027 [ + + ]: 7848 : if (zp->z_nrules == 0)
4028 : : {
4029 : : int type;
4030 : :
4031 : 4816 : save = zp->z_save;
4032 : 4816 : doabbr(startbuf, zp, NULL, zp->z_isdst, save, false);
4033 : 4816 : type = addtype(oadd(zp->z_stdoff, save),
4034 : 4816 : startbuf, zp->z_isdst, startttisstd,
4035 : : startttisut);
4036 [ + + ]: 4816 : if (usestart)
4037 : : {
4038 : 3452 : addtt(starttime, type);
4039 [ + - ]: 3452 : if (nonTZlimtime < starttime)
4040 : : {
4041 : 3452 : nonTZlimtime = starttime;
4042 : 3452 : nonTZlimtype = type;
4043 : : }
4044 : 3452 : usestart = false;
4045 : : }
4046 : : else
4047 : 1364 : defaulttype = type;
4048 : : }
4049 : : else
4050 : : {
4051 : : zic_t year;
4052 : :
4053 [ + + ]: 273544 : for (year = min_year; year <= max_year; ++year)
4054 : : {
4055 [ + + + + ]: 272748 : if (useuntil && year > zp->z_untilrule.r_hiyear)
4056 : 2236 : break;
4057 : :
4058 : : /*
4059 : : * Mark which rules to do in the current year. For those to
4060 : : * do, calculate rpytime(rp, year); The former TYPE field was
4061 : : * also considered here.
4062 : : */
4063 [ + + ]: 5510240 : for (j = 0; j < zp->z_nrules; ++j)
4064 : : {
4065 : 5239728 : zic_t one = 1;
4066 : 5239728 : zic_t y2038_boundary = one << 31;
4067 : 5239728 : struct rule *rp = &zp->z_rules[j];
4068 : :
4069 : 5239728 : eats(zp->z_filenum, zp->z_linenum,
4070 : : rp->r_filenum, rp->r_linenum);
4071 [ + + ]: 6890116 : rp->r_todo = year >= rp->r_loyear &&
4072 [ + + ]: 1650388 : year <= rp->r_hiyear;
4073 [ + + ]: 5239728 : if (rp->r_todo)
4074 : : {
4075 : 131356 : rp->r_temp = rpytime(rp, year);
4076 : : rp->r_todo
4077 : 262712 : = (rp->r_temp < y2038_boundary
4078 [ + + + - ]: 131356 : || year <= max_year0);
4079 : : }
4080 : : }
4081 : : for (;;)
4082 : 129076 : {
4083 : : ptrdiff_t k;
4084 : : zic_t jtime,
4085 : : ktime;
4086 : : zic_t offset;
4087 : : struct rule *rp;
4088 : : int type;
4089 : :
4090 : 399588 : INITIALIZE(ktime);
4091 [ + + ]: 399588 : if (useuntil)
4092 : : {
4093 : : /*
4094 : : * Turn untiltime into UT assuming the current stdoff
4095 : : * and save values.
4096 : : */
4097 : 291364 : untiltime = zp->z_untiltime;
4098 [ + + ]: 291364 : if (!zp->z_untilrule.r_todisut)
4099 : 284800 : untiltime = tadd(untiltime,
4100 : : -stdoff);
4101 [ + + ]: 291364 : if (!zp->z_untilrule.r_todisstd)
4102 : 215024 : untiltime = tadd(untiltime,
4103 : : -save);
4104 : : }
4105 : :
4106 : : /*
4107 : : * Find the rule (of those to do, if any) that takes
4108 : : * effect earliest in the year.
4109 : : */
4110 : 399588 : k = -1;
4111 [ + + ]: 8547828 : for (j = 0; j < zp->z_nrules; ++j)
4112 : : {
4113 : 8148240 : struct rule *r = &zp->z_rules[j];
4114 : :
4115 [ + + ]: 8148240 : if (!r->r_todo)
4116 : 7948712 : continue;
4117 : 199528 : eats(zp->z_filenum, zp->z_linenum,
4118 : : r->r_filenum, r->r_linenum);
4119 [ + + ]: 199528 : offset = r->r_todisut ? 0 : stdoff;
4120 [ + + ]: 199528 : if (!r->r_todisstd)
4121 : 133048 : offset = oadd(offset, save);
4122 : 199528 : jtime = r->r_temp;
4123 : 199528 : jtime = tadd(jtime, -offset);
4124 [ + + + + ]: 199528 : if (k < 0 || jtime < ktime)
4125 : : {
4126 : 151556 : k = j;
4127 : 151556 : ktime = jtime;
4128 : : }
4129 [ - + ]: 47972 : else if (jtime == ktime)
4130 : : {
4131 : 0 : char const *dup_rules_msg =
4132 : : _("two rules for same instant");
4133 : :
4134 : 0 : eats(zp->z_filenum, zp->z_linenum,
4135 : : r->r_filenum, r->r_linenum);
4136 : 0 : warning("%s", dup_rules_msg);
4137 : 0 : r = &zp->z_rules[k];
4138 : 0 : eats(zp->z_filenum, zp->z_linenum,
4139 : : r->r_filenum, r->r_linenum);
4140 : 0 : error("%s", dup_rules_msg);
4141 : : }
4142 : : }
4143 [ + + ]: 399588 : if (k < 0)
4144 : 269048 : break; /* go on to next year */
4145 : 130540 : rp = &zp->z_rules[k];
4146 : 130540 : rp->r_todo = false;
4147 [ + + + + ]: 130540 : if (useuntil && ktime >= untiltime)
4148 : : {
4149 [ - + ]: 1464 : if (!*startbuf
4150 [ # # ]: 0 : && (oadd(zp->z_stdoff, rp->r_save)
4151 : : == startoff))
4152 : 0 : doabbr(startbuf, zp, rp->r_abbrvar,
4153 : 0 : rp->r_isdst, rp->r_save,
4154 : : false);
4155 : 1464 : break;
4156 : : }
4157 : 129076 : save = rp->r_save;
4158 [ + + + + ]: 129076 : if (usestart && ktime == starttime)
4159 : 232 : usestart = false;
4160 [ + + ]: 129076 : if (usestart)
4161 : : {
4162 [ + + ]: 124488 : if (ktime < starttime)
4163 : : {
4164 : 66356 : startoff = oadd(zp->z_stdoff,
4165 : : save);
4166 : 66356 : doabbr(startbuf, zp,
4167 : : rp->r_abbrvar,
4168 : 66356 : rp->r_isdst,
4169 : : rp->r_save,
4170 : : false);
4171 : 66356 : continue;
4172 : : }
4173 [ + + ]: 58132 : if (*startbuf == '\0'
4174 [ + + ]: 1576 : && startoff == oadd(zp->z_stdoff,
4175 : : save))
4176 : : {
4177 : 788 : doabbr(startbuf,
4178 : : zp,
4179 : : rp->r_abbrvar,
4180 : 788 : rp->r_isdst,
4181 : : rp->r_save,
4182 : : false);
4183 : : }
4184 : : }
4185 : 62720 : eats(zp->z_filenum, zp->z_linenum,
4186 : : rp->r_filenum, rp->r_linenum);
4187 : 62720 : doabbr(ab, zp, rp->r_abbrvar,
4188 : 62720 : rp->r_isdst, rp->r_save, false);
4189 : 62720 : offset = oadd(zp->z_stdoff, rp->r_save);
4190 : 62720 : type = addtype(offset, ab, rp->r_isdst,
4191 : 62720 : rp->r_todisstd, rp->r_todisut);
4192 [ - + - - ]: 62720 : if (defaulttype < 0 && !rp->r_isdst)
4193 : 0 : defaulttype = type;
4194 : 62720 : addtt(ktime, type);
4195 [ + - ]: 62720 : if (nonTZlimtime < ktime
4196 [ + + + + ]: 62720 : && (useuntil || rp->r_hiyear != ZIC_MAX))
4197 : : {
4198 : 59856 : nonTZlimtime = ktime;
4199 : 59856 : nonTZlimtype = type;
4200 : : }
4201 : : }
4202 : : }
4203 : : }
4204 [ + + ]: 7848 : if (usestart)
4205 : : {
4206 : 2800 : bool isdst = startoff != zp->z_stdoff;
4207 : :
4208 [ - + - - ]: 2800 : if (*startbuf == '\0' && zp->z_format)
4209 : 0 : doabbr(startbuf, zp, disable_percent_s,
4210 : : isdst, save, false);
4211 : 2800 : eat(zp->z_filenum, zp->z_linenum);
4212 [ - + ]: 2800 : if (*startbuf == '\0')
4213 : 0 : error(_("cannot determine time zone abbreviation"
4214 : : " to use just after until time"));
4215 : : else
4216 : : {
4217 : 2800 : int type = addtype(startoff, startbuf, isdst,
4218 : : startttisstd, startttisut);
4219 : :
4220 [ - + - - ]: 2800 : if (defaulttype < 0 && !isdst)
4221 : 0 : defaulttype = type;
4222 : 2800 : addtt(starttime, type);
4223 : : }
4224 : : }
4225 : :
4226 : : /*
4227 : : * Now we may get to set starttime for the next zone line.
4228 : : */
4229 [ + + ]: 7848 : if (useuntil)
4230 : : {
4231 : 6484 : startttisstd = zp->z_untilrule.r_todisstd;
4232 : 6484 : startttisut = zp->z_untilrule.r_todisut;
4233 : 6484 : starttime = zp->z_untiltime;
4234 [ + + ]: 6484 : if (!startttisstd)
4235 : 5408 : starttime = tadd(starttime, -save);
4236 [ + + ]: 6484 : if (!startttisut)
4237 : 6188 : starttime = tadd(starttime, -stdoff);
4238 : : }
4239 : : }
4240 [ - + ]: 1364 : if (defaulttype < 0)
4241 : 0 : defaulttype = 0;
4242 [ + - + - ]: 1364 : if (!do_extend && !want_bloat())
4243 : : {
4244 : : /* Keep trailing transitions that are no greater than this. */
4245 : : zic_t keep_at_max;
4246 : :
4247 : : /* The earliest transition into a time governed by the TZ string. */
4248 : 1364 : zic_t TZstarttime = ZIC_MAX;
4249 : :
4250 [ + + ]: 70336 : for (i = 0; i < timecnt; i++)
4251 : : {
4252 : 68972 : zic_t at = attypes[i].at;
4253 : :
4254 [ + + + + ]: 68972 : if (nonTZlimtime < at && at < TZstarttime)
4255 : 488 : TZstarttime = at;
4256 : : }
4257 [ + + ]: 1364 : if (TZstarttime == ZIC_MAX)
4258 : 952 : TZstarttime = nonTZlimtime;
4259 : :
4260 : : /*
4261 : : * Omit trailing transitions deducible from the TZ string, and not
4262 : : * needed for -r or -R.
4263 : : */
4264 : 1364 : keep_at_max = max(TZstarttime, redundant_time);
4265 [ + + ]: 70336 : for (i = j = 0; i < timecnt; i++)
4266 [ + + ]: 68972 : if (attypes[i].at <= keep_at_max)
4267 : : {
4268 : 68032 : attypes[j].at = attypes[i].at;
4269 : 136064 : attypes[j].dontmerge = (attypes[i].at == TZstarttime
4270 [ + + + + ]: 68940 : && (nonTZlimtype != attypes[i].type
4271 [ + + ]: 908 : || strchr(envvar, ',')));
4272 : 68032 : attypes[j].type = attypes[i].type;
4273 : 68032 : j++;
4274 : : }
4275 : 1364 : timecnt = j;
4276 : : }
4277 [ - + ]: 1364 : if (do_extend)
4278 : : {
4279 : : /*
4280 : : * If we're extending the explicitly listed observations for 400 years
4281 : : * because we can't fill the proleptic TZ field, check whether we
4282 : : * actually ended up explicitly listing observations through that
4283 : : * period. If there aren't any near the end of the 400-year period,
4284 : : * add a redundant one at the end of the final year, to make it clear
4285 : : * that we are claiming to have definite knowledge of the lack of
4286 : : * transitions up to that point.
4287 : : */
4288 : : struct rule xr;
4289 : : struct attype *lastat;
4290 : :
4291 : 0 : xr.r_month = TM_JANUARY;
4292 : 0 : xr.r_dycode = DC_DOM;
4293 : 0 : xr.r_dayofmonth = 1;
4294 : 0 : xr.r_tod = 0;
4295 [ # # ]: 0 : for (lastat = attypes, i = 1; i < timecnt; i++)
4296 [ # # ]: 0 : if (attypes[i].at > lastat->at)
4297 : 0 : lastat = &attypes[i];
4298 [ # # # # ]: 0 : if (!lastat || lastat->at < rpytime(&xr, max_year - 1))
4299 : : {
4300 [ # # ]: 0 : addtt(rpytime(&xr, max_year + 1),
4301 : 0 : lastat ? lastat->type : defaulttype);
4302 : 0 : attypes[timecnt - 1].dontmerge = true;
4303 : : }
4304 : : }
4305 : 1364 : writezone(zpfirst->z_name, envvar, version, defaulttype);
4306 : 1364 : free(startbuf);
4307 : 1364 : free(ab);
4308 : 1364 : free(envvar);
4309 : 1364 : }
4310 : :
4311 : : static void
4312 : 68972 : addtt(zic_t starttime, int type)
4313 : : {
4314 : 68972 : attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
4315 : 68972 : attypes[timecnt].at = starttime;
4316 : 68972 : attypes[timecnt].dontmerge = false;
4317 : 68972 : attypes[timecnt].type = type;
4318 : 68972 : ++timecnt;
4319 : 68972 : }
4320 : :
4321 : : static int
4322 : 70336 : addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
4323 : : {
4324 : : int i,
4325 : : j;
4326 : : int charcnt0;
4327 : :
4328 : : /* RFC 9636 section 3.2 specifies this range for utoff. */
4329 [ + - - + ]: 70336 : if (!(-TWO_31_MINUS_1 <= utoff && utoff <= TWO_31_MINUS_1))
4330 : : {
4331 : 0 : error(_("UT offset out of range"));
4332 : 0 : exit(EXIT_FAILURE);
4333 : : }
4334 [ + - ]: 70336 : if (!want_bloat())
4335 : 70336 : ttisstd = ttisut = false;
4336 : :
4337 : 70336 : checkabbr(abbr);
4338 : :
4339 : 70336 : charcnt0 = charcnt;
4340 : 70336 : j = addabbr(chars, &charcnt, abbr);
4341 [ + + ]: 70336 : if (charcnt0 < charcnt)
4342 : : {
4343 : : /*
4344 : : * If an abbreviation was inserted, increment indexes no earlier than
4345 : : * the insert by the size of the insertion, so that they continue to
4346 : : * point to the same contents.
4347 : : */
4348 [ + + ]: 18156 : for (i = 0; i < typecnt; i++)
4349 [ + + ]: 12340 : if (j <= desigidx[i])
4350 : 4 : desigidx[i] += charcnt - charcnt0;
4351 : : }
4352 : : else
4353 : : {
4354 : : /* If there's already an entry, return its index. */
4355 [ + + ]: 238236 : for (i = 0; i < typecnt; i++)
4356 [ + + + + : 237680 : if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i]
+ + ]
4357 [ + - + - ]: 63964 : && ttisstd == ttisstds[i] && ttisut == ttisuts[i])
4358 : 63964 : return i;
4359 : : }
4360 : :
4361 : : /*
4362 : : * There isn't one; add a new one, unless there are already too many.
4363 : : */
4364 [ - + ]: 6372 : if (typecnt >= TZ_MAX_TYPES)
4365 : : {
4366 : 0 : error(_("too many local time types"));
4367 : 0 : exit(EXIT_FAILURE);
4368 : : }
4369 : 6372 : i = typecnt++;
4370 : 6372 : utoffs[i] = utoff;
4371 : 6372 : isdsts[i] = isdst;
4372 : 6372 : ttisstds[i] = ttisstd;
4373 : 6372 : ttisuts[i] = ttisut;
4374 : 6372 : desigidx[i] = j;
4375 : 6372 : return i;
4376 : : }
4377 : :
4378 : : static void
4379 : 0 : leapadd(zic_t t, int correction, int rolling)
4380 : : {
4381 : : ptrdiff_t i;
4382 : :
4383 [ # # # # : 0 : if (rolling && (lo_time != min_time || hi_time != max_time))
# # ]
4384 : : {
4385 : 0 : error(_("Rolling leap seconds not supported with -r"));
4386 : 0 : exit(EXIT_FAILURE);
4387 : : }
4388 : 0 : leap = growalloc(leap, sizeof *leap, leapcnt, &leap_alloc);
4389 [ # # ]: 0 : for (i = 0; i < leapcnt; ++i)
4390 [ # # ]: 0 : if (t <= leap[i].trans)
4391 : 0 : break;
4392 : 0 : memmove(&leap[i + 1], &leap[i], (leapcnt - i) * sizeof *leap);
4393 : 0 : leap[i].trans = t;
4394 : 0 : leap[i].corr = correction;
4395 : 0 : leap[i].roll = rolling;
4396 : 0 : ++leapcnt;
4397 : 0 : }
4398 : :
4399 : : static void
4400 : 0 : adjleap(void)
4401 : : {
4402 : : ptrdiff_t i;
4403 : 0 : zic_t last = 0;
4404 : 0 : zic_t prevtrans = 0;
4405 : :
4406 : : /*
4407 : : * propagate leap seconds forward
4408 : : */
4409 [ # # ]: 0 : for (i = 0; i < leapcnt; ++i)
4410 : : {
4411 [ # # ]: 0 : if (leap[i].trans - prevtrans < 28 * SECSPERDAY)
4412 : : {
4413 : 0 : error(_("Leap seconds too close together"));
4414 : 0 : exit(EXIT_FAILURE);
4415 : : }
4416 : 0 : prevtrans = leap[i].trans;
4417 : 0 : leap[i].trans = tadd(prevtrans, last);
4418 : 0 : last = leap[i].corr += last;
4419 : : }
4420 : :
4421 [ # # ]: 0 : if (0 <= leapexpires)
4422 : : {
4423 : 0 : leapexpires = oadd(leapexpires, last);
4424 [ # # # # ]: 0 : if (!(leapcnt == 0 || (leap[leapcnt - 1].trans < leapexpires)))
4425 : : {
4426 : 0 : error(_("last Leap time does not precede Expires time"));
4427 : 0 : exit(EXIT_FAILURE);
4428 : : }
4429 : : }
4430 : 0 : }
4431 : :
4432 : : /* Is A a space character in the C locale? */
4433 : : static bool
4434 : 542592 : is_space(char a)
4435 : : {
4436 [ + + ]: 542592 : switch (a)
4437 : : {
4438 : 325648 : default:
4439 : 325648 : return false;
4440 : 216944 : case ' ':
4441 : : case '\f':
4442 : : case '\n':
4443 : : case '\r':
4444 : : case '\t':
4445 : : case '\v':
4446 : 216944 : return true;
4447 : : }
4448 : : }
4449 : :
4450 : : /* Is A an alphabetic character in the C locale? */
4451 : : static bool
4452 : 299888 : is_alpha(char a)
4453 : : {
4454 [ + + ]: 299888 : switch (a)
4455 : : {
4456 : 147332 : default:
4457 : 147332 : return false;
4458 : 152556 : case 'A':
4459 : : case 'B':
4460 : : case 'C':
4461 : : case 'D':
4462 : : case 'E':
4463 : : case 'F':
4464 : : case 'G':
4465 : : case 'H':
4466 : : case 'I':
4467 : : case 'J':
4468 : : case 'K':
4469 : : case 'L':
4470 : : case 'M':
4471 : : case 'N':
4472 : : case 'O':
4473 : : case 'P':
4474 : : case 'Q':
4475 : : case 'R':
4476 : : case 'S':
4477 : : case 'T':
4478 : : case 'U':
4479 : : case 'V':
4480 : : case 'W':
4481 : : case 'X':
4482 : : case 'Y':
4483 : : case 'Z':
4484 : : case 'a':
4485 : : case 'b':
4486 : : case 'c':
4487 : : case 'd':
4488 : : case 'e':
4489 : : case 'f':
4490 : : case 'g':
4491 : : case 'h':
4492 : : case 'i':
4493 : : case 'j':
4494 : : case 'k':
4495 : : case 'l':
4496 : : case 'm':
4497 : : case 'n':
4498 : : case 'o':
4499 : : case 'p':
4500 : : case 'q':
4501 : : case 'r':
4502 : : case 's':
4503 : : case 't':
4504 : : case 'u':
4505 : : case 'v':
4506 : : case 'w':
4507 : : case 'x':
4508 : : case 'y':
4509 : : case 'z':
4510 : 152556 : return true;
4511 : : }
4512 : : }
4513 : :
4514 : : /*
4515 : : * If A is an uppercase character in the C locale, return its lowercase
4516 : : * counterpart. Otherwise, return A.
4517 : : */
4518 : : static char
4519 : 1665092 : lowerit(char a)
4520 : : {
4521 [ + + - - : 1665092 : switch (a)
+ - + - -
- + - + +
+ + - - +
+ + - - +
- - + ]
4522 : : {
4523 : 786316 : default:
4524 : 786316 : return a;
4525 : 112920 : case 'A':
4526 : 112920 : return 'a';
4527 : 0 : case 'B':
4528 : 0 : return 'b';
4529 : 0 : case 'C':
4530 : 0 : return 'c';
4531 : 35880 : case 'D':
4532 : 35880 : return 'd';
4533 : 0 : case 'E':
4534 : 0 : return 'e';
4535 : 46380 : case 'F':
4536 : 46380 : return 'f';
4537 : 0 : case 'G':
4538 : 0 : return 'g';
4539 : 0 : case 'H':
4540 : 0 : return 'h';
4541 : 0 : case 'I':
4542 : 0 : return 'i';
4543 : 153408 : case 'J':
4544 : 153408 : return 'j';
4545 : 0 : case 'K':
4546 : 0 : return 'k';
4547 : 26616 : case 'L':
4548 : 26616 : return 'l';
4549 : 115584 : case 'M':
4550 : 115584 : return 'm';
4551 : 41832 : case 'N':
4552 : 41832 : return 'n';
4553 : 90216 : case 'O':
4554 : 90216 : return 'o';
4555 : 0 : case 'P':
4556 : 0 : return 'p';
4557 : 0 : case 'Q':
4558 : 0 : return 'q';
4559 : 67440 : case 'R':
4560 : 67440 : return 'r';
4561 : 141240 : case 'S':
4562 : 141240 : return 's';
4563 : 12644 : case 'T':
4564 : 12644 : return 't';
4565 : 0 : case 'U':
4566 : 0 : return 'u';
4567 : 0 : case 'V':
4568 : 0 : return 'v';
4569 : 5984 : case 'W':
4570 : 5984 : return 'w';
4571 : 0 : case 'X':
4572 : 0 : return 'x';
4573 : 0 : case 'Y':
4574 : 0 : return 'y';
4575 : 28632 : case 'Z':
4576 : 28632 : return 'z';
4577 : : }
4578 : : }
4579 : :
4580 : : /* case-insensitive equality */
4581 : : ATTRIBUTE_PURE_114833
4582 : : static bool
4583 : 349768 : ciequal(const char *ap, const char *bp)
4584 : : {
4585 [ + + ]: 444032 : while (lowerit(*ap) == lowerit(*bp++))
4586 [ + + ]: 101780 : if (*ap++ == '\0')
4587 : 7516 : return true;
4588 : 342252 : return false;
4589 : : }
4590 : :
4591 : : ATTRIBUTE_PURE_114833
4592 : : static bool
4593 : 0 : itsabbr(const char *abbr, const char *word)
4594 : : {
4595 [ # # ]: 0 : if (lowerit(*abbr) != lowerit(*word))
4596 : 0 : return false;
4597 : 0 : ++word;
4598 [ # # ]: 0 : while (*++abbr != '\0')
4599 : : do
4600 : : {
4601 [ # # ]: 0 : if (*word == '\0')
4602 : 0 : return false;
4603 [ # # ]: 0 : } while (lowerit(*word++) != lowerit(*abbr));
4604 : 0 : return true;
4605 : : }
4606 : :
4607 : : /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */
4608 : :
4609 : : ATTRIBUTE_PURE_114833
4610 : : static bool
4611 : 345956 : ciprefix(char const *abbr, char const *word)
4612 : : {
4613 : : do
4614 [ + + ]: 414596 : if (!*abbr)
4615 : 33240 : return true;
4616 [ + + ]: 381356 : while (lowerit(*abbr++) == lowerit(*word++));
4617 : :
4618 : 312716 : return false;
4619 : : }
4620 : :
4621 : : static const struct lookup *
4622 : 69112 : byword(const char *word, const struct lookup *table)
4623 : : {
4624 : : const struct lookup *foundlp;
4625 : : const struct lookup *lp;
4626 : :
4627 [ + - - + ]: 69112 : if (word == NULL || table == NULL)
4628 : 0 : return NULL;
4629 : :
4630 : : /*
4631 : : * If TABLE is LASTS and the word starts with "last" followed by a
4632 : : * non-'-', skip the "last" and look in WDAY_NAMES instead. Warn about any
4633 : : * usage of the undocumented prefix "last-".
4634 : : */
4635 [ + + + + : 69112 : if (table == lasts && ciprefix("last", word) && word[4])
+ - ]
4636 : : {
4637 [ - + ]: 1368 : if (word[4] == '-')
4638 : 0 : warning(_("\"%s\" is undocumented; use \"last%s\" instead"),
4639 : : word, word + 5);
4640 : : else
4641 : : {
4642 : 1368 : word += 4;
4643 : 1368 : table = wday_names;
4644 : : }
4645 : : }
4646 : :
4647 : : /*
4648 : : * Look for exact match.
4649 : : */
4650 [ + + ]: 411364 : for (lp = table; lp->l_word != NULL; ++lp)
4651 [ + + ]: 349768 : if (ciequal(word, lp->l_word))
4652 : 7516 : return lp;
4653 : :
4654 : : /*
4655 : : * Look for inexact match.
4656 : : */
4657 : 61596 : foundlp = NULL;
4658 [ + + ]: 393236 : for (lp = table; lp->l_word != NULL; ++lp)
4659 [ + + ]: 331640 : if (ciprefix(word, lp->l_word))
4660 : : {
4661 [ + - ]: 31872 : if (foundlp == NULL)
4662 : 31872 : foundlp = lp;
4663 : : else
4664 : 0 : return NULL; /* multiple inexact matches */
4665 : : }
4666 : :
4667 [ + + - + ]: 61596 : if (foundlp && noise)
4668 : : {
4669 : : /* Warn about any backward-compatibility issue with pre-2017c zic. */
4670 : 0 : bool pre_2017c_match = false;
4671 : :
4672 [ # # ]: 0 : for (lp = table; lp->l_word; lp++)
4673 [ # # ]: 0 : if (itsabbr(word, lp->l_word))
4674 : : {
4675 [ # # ]: 0 : if (pre_2017c_match)
4676 : : {
4677 : 0 : warning(_("\"%s\" is ambiguous in pre-2017c zic"), word);
4678 : 0 : break;
4679 : : }
4680 : 0 : pre_2017c_match = true;
4681 : : }
4682 : : }
4683 : :
4684 : 61596 : return foundlp;
4685 : : }
4686 : :
4687 : : static int
4688 : 16720 : getfields(char *cp, char **array, int arrayelts)
4689 : : {
4690 : : char *dp;
4691 : : int nsubs;
4692 : :
4693 : 16720 : nsubs = 0;
4694 : : for (;;)
4695 : 125180 : {
4696 : : char *dstart;
4697 : :
4698 [ - + ]: 141900 : while (is_space(*cp))
4699 : 0 : ++cp;
4700 [ + + + + ]: 141900 : if (*cp == '\0' || *cp == '#')
4701 : : break;
4702 : 125180 : dstart = dp = cp;
4703 : : do
4704 : : {
4705 [ + - ]: 292220 : if ((*dp = *cp++) != '"')
4706 : 292220 : ++dp;
4707 : : else
4708 [ # # ]: 0 : while ((*dp = *cp++) != '"')
4709 [ # # ]: 0 : if (*dp != '\0')
4710 : 0 : ++dp;
4711 : : else
4712 : : {
4713 : 0 : error(_("Odd number of quotation marks"));
4714 : 0 : exit(EXIT_FAILURE);
4715 : : }
4716 [ + + + - : 292220 : } while (*cp && *cp != '#' && !is_space(*cp));
+ + ]
4717 [ + + ]: 125180 : if (is_space(*cp))
4718 : 108472 : ++cp;
4719 : 125180 : *dp = '\0';
4720 [ - + ]: 125180 : if (nsubs == arrayelts)
4721 : : {
4722 : 0 : error(_("Too many input fields"));
4723 : 0 : exit(EXIT_FAILURE);
4724 : : }
4725 [ + + + + ]: 125180 : array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1);
4726 : : }
4727 : 16720 : return nsubs;
4728 : : }
4729 : :
4730 : : ATTRIBUTE_NORETURN static void
4731 : 0 : time_overflow(void)
4732 : : {
4733 : 0 : error(_("time overflow"));
4734 : 0 : exit(EXIT_FAILURE);
4735 : : }
4736 : :
4737 : : /* Return T1 + T2, but diagnose any overflow and exit. */
4738 : : ATTRIBUTE_PURE_114833_HACK
4739 : : static zic_t
4740 : 22949196 : oadd(zic_t t1, zic_t t2)
4741 : : {
4742 : : #ifdef ckd_add
4743 : : zic_t sum;
4744 : :
4745 [ + - ]: 22949196 : if (!ckd_add(&sum, t1, t2))
4746 : 22949196 : return sum;
4747 : : #else
4748 : : if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1)
4749 : : return t1 + t2;
4750 : : #endif
4751 : 0 : time_overflow();
4752 : : }
4753 : :
4754 : : /*
4755 : : * Return T1 + T2, but diagnose any overflow and exit.
4756 : : * This is like oadd, except the result must fit in min_time..max_time range,
4757 : : * which on oddball machines can be a smaller range than ZIC_MIN..ZIC_MAX.
4758 : : */
4759 : : ATTRIBUTE_PURE_114833_HACK
4760 : : static zic_t
4761 : 848788 : tadd(zic_t t1, zic_t t2)
4762 : : {
4763 : 848788 : zic_t sum = oadd(t1, t2);
4764 : :
4765 [ + - + - ]: 848788 : if (min_time <= sum && sum <= max_time)
4766 : 848788 : return sum;
4767 : 0 : time_overflow();
4768 : : }
4769 : :
4770 : : /* Return T1 * T2, but diagnose any overflow and exit. */
4771 : : ATTRIBUTE_PURE_114833_HACK
4772 : : static zic_t
4773 : 168088 : omul(zic_t t1, zic_t t2)
4774 : : {
4775 : : #ifdef ckd_mul
4776 : : zic_t product;
4777 : :
4778 [ + - ]: 168088 : if (!ckd_mul(&product, t1, t2))
4779 : 168088 : return product;
4780 : : #else
4781 : : if (t2 < 0
4782 : : ? ZIC_MAX / t2 <= t1 && (t2 == -1 || t1 <= ZIC_MIN / t2)
4783 : : : t2 == 0 || (ZIC_MIN / t2 <= t1 && t1 <= ZIC_MAX / t2))
4784 : : return t1 * t2;
4785 : : #endif
4786 : 0 : time_overflow();
4787 : : }
4788 : :
4789 : : /*
4790 : : * Given a rule, and a year, compute the date (in seconds since January 1,
4791 : : * 1970, 00:00 LOCAL time) in that year that the rule refers to.
4792 : : * Do not count leap seconds. On error, diagnose and exit.
4793 : : */
4794 : :
4795 : : static zic_t
4796 : 137840 : rpytime(const struct rule *rp, zic_t wantedy)
4797 : : {
4798 : : int m,
4799 : : i;
4800 : : zic_t dayoff; /* with a nod to Margaret O. */
4801 : : zic_t t,
4802 : : y;
4803 : : int yrem;
4804 : :
4805 : 137840 : m = TM_JANUARY;
4806 : 137840 : y = EPOCH_YEAR;
4807 : :
4808 : : /*
4809 : : * dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, sans
4810 : : * overflow.
4811 : : */
4812 : 137840 : yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
4813 : 137840 : dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
4814 : 137840 : + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
4815 : : * DAYSPERREPEAT);
4816 : : /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */
4817 : 137840 : wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
4818 : :
4819 [ + + ]: 20766504 : while (wantedy != y)
4820 : : {
4821 [ + + + + : 20628664 : i = len_years[isleap(y)];
+ + ]
4822 : 20628664 : dayoff = oadd(dayoff, i);
4823 : 20628664 : y++;
4824 : : }
4825 [ + + ]: 912664 : while (m != rp->r_month)
4826 : : {
4827 [ + + + + : 774824 : i = len_months[isleap(y)][m];
+ + ]
4828 : 774824 : dayoff = oadd(dayoff, i);
4829 : 774824 : ++m;
4830 : : }
4831 : 137840 : i = rp->r_dayofmonth;
4832 [ + + + + : 137840 : if (m == TM_FEBRUARY && i == 29 && !isleap(y))
+ + + + -
+ ]
4833 : : {
4834 [ + - ]: 304 : if (rp->r_dycode == DC_DOWLEQ)
4835 : 304 : --i;
4836 : : else
4837 : : {
4838 : 0 : error(_("use of 2/29 in non leap-year"));
4839 : 0 : exit(EXIT_FAILURE);
4840 : : }
4841 : : }
4842 : 137840 : --i;
4843 : 137840 : dayoff = oadd(dayoff, i);
4844 [ + + + + ]: 137840 : if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ)
4845 : : {
4846 : : /*
4847 : : * Don't trust mod of negative numbers.
4848 : : */
4849 : 89684 : zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
4850 : : % DAYSPERWEEK);
4851 : :
4852 [ + + ]: 350000 : while (wday != rp->r_wday)
4853 [ + + ]: 260316 : if (rp->r_dycode == DC_DOWGEQ)
4854 : : {
4855 : 81020 : dayoff = oadd(dayoff, 1);
4856 [ + + ]: 81020 : if (++wday >= DAYSPERWEEK)
4857 : 21648 : wday = 0;
4858 : 81020 : ++i;
4859 : : }
4860 : : else
4861 : : {
4862 : 179296 : dayoff = oadd(dayoff, -1);
4863 [ + + ]: 179296 : if (--wday < 0)
4864 : 1572 : wday = DAYSPERWEEK - 1;
4865 : 179296 : --i;
4866 : : }
4867 [ + + + + : 89684 : if (i < 0 || i >= len_months[isleap(y)][m])
+ + + - +
+ ]
4868 : : {
4869 [ - + ]: 124 : if (noise)
4870 : 0 : warning(_("rule goes past start/end of month; \
4871 : : will not work with pre-2004 versions of zic"));
4872 : : }
4873 : : }
4874 : 137840 : t = omul(dayoff, SECSPERDAY);
4875 : 137840 : return tadd(t, rp->r_tod);
4876 : : }
4877 : :
4878 : : static void
4879 : 70336 : checkabbr(char const *string)
4880 : : {
4881 [ + - ]: 70336 : if (strcmp(string, GRANDPARENTED) != 0)
4882 : : {
4883 : : const char *cp;
4884 : : const char *mp;
4885 : :
4886 : 70336 : cp = string;
4887 : 70336 : mp = NULL;
4888 [ + + ]: 440288 : while (is_alpha(*cp) || is_digit(*cp)
4889 [ + + + + : 389256 : || *cp == '-' || *cp == '+')
+ + ]
4890 : 224396 : ++cp;
4891 [ - + - - ]: 70336 : if (noise && cp - string < 3)
4892 : 0 : mp = _("time zone abbreviation has fewer than 3 characters");
4893 [ - + ]: 70336 : if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
4894 : 0 : mp = _("time zone abbreviation has too many characters");
4895 [ - + ]: 70336 : if (*cp != '\0')
4896 : 0 : mp = _("time zone abbreviation differs from POSIX standard");
4897 [ - + ]: 70336 : if (mp != NULL)
4898 : 0 : warning("%s (%s)", mp, string);
4899 : : }
4900 : 70336 : }
4901 : :
4902 : : /*
4903 : : * Put into CHS, which currently contains *PNCHS bytes containing
4904 : : * NUL-terminated abbreviations none of which are suffixes of another,
4905 : : * the abbreviation ABBR including its trailing NUL.
4906 : : * If ABBR does not already appear in CHS,
4907 : : * possibly as a suffix of an existing abbreviation,
4908 : : * add ABBR to CHS, remove from CHS any abbreviation
4909 : : * that is a suffix of ABBR, and increment *PNCHS accordingly.
4910 : : * Return the index of ABBR after any modifications to CHS are made.
4911 : : *
4912 : : * If all abbreviations have already been added, this function
4913 : : * lets the caller look up the index of an existing abbreviation.
4914 : : */
4915 : : static int
4916 : 94528 : addabbr(char chs[TZ_MAX_CHARS], int *pnchs, char const *abbr)
4917 : : {
4918 : 94528 : int nchs = *pnchs;
4919 : 94528 : int alen = strlen(abbr),
4920 : 94528 : nchs_incr = alen + 1;
4921 : : int i;
4922 : :
4923 [ + + ]: 315016 : for (i = 0; i < nchs;)
4924 : : {
4925 : 297648 : int clen = strlen(&chs[i]);
4926 : :
4927 [ + + ]: 297648 : if (alen <= clen)
4928 : : {
4929 : : /*
4930 : : * If ABBR is a suffix of an abbreviation in CHS, return the index
4931 : : * of ABBR in CHS.
4932 : : */
4933 : 264080 : int isuff = i + (clen - alen);
4934 : :
4935 [ + + ]: 264080 : if (memcmp(&chs[isuff], abbr, alen) == 0)
4936 : 77148 : return isuff;
4937 : : }
4938 [ + + ]: 33568 : else if (memcmp(&chs[i], &abbr[alen - clen], clen) == 0)
4939 : : {
4940 : : /*
4941 : : * An abbreviation in CHS is a substring of ABBR. Replace it with
4942 : : * ABBR, instead of the more-common actions of appending ABBR or
4943 : : * doing nothing.
4944 : : */
4945 : 12 : nchs_incr = alen - clen;
4946 : 12 : break;
4947 : : }
4948 : 220488 : i += clen + 1;
4949 : : }
4950 [ - + ]: 17380 : if (TZ_MAX_CHARS < nchs + nchs_incr)
4951 : : {
4952 : 0 : error(_("too many, or too long, time zone abbreviations"));
4953 : 0 : exit(EXIT_FAILURE);
4954 : : }
4955 : 17380 : memmove(&chs[i + nchs_incr], &chs[i], nchs - i);
4956 : 17380 : memcpy(&chs[i], abbr, nchs_incr);
4957 : 17380 : *pnchs = nchs + nchs_incr;
4958 : 17380 : return i;
4959 : : }
4960 : :
4961 : : /*
4962 : : * Ensure that the directories of ARGNAME exist, by making any missing
4963 : : * ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise,
4964 : : * do it for ARGNAME too. Exit with failure if there is trouble.
4965 : : * Do not consider an existing file to be trouble.
4966 : : */
4967 : : static void
4968 : 42 : mkdirs(char const *argname, bool ancestors)
4969 : : {
4970 : : /*
4971 : : * If -D was specified, do not create directories. If a file operation's
4972 : : * parent directory is missing, the operation will fail and be diagnosed.
4973 : : */
4974 [ + - ]: 42 : if (!skip_mkdir)
4975 : : {
4976 : :
4977 : 42 : char *name = xstrdup(argname);
4978 : 42 : char *cp = name;
4979 : :
4980 : : /*
4981 : : * On MS-Windows systems, do not worry about drive letters or
4982 : : * backslashes, as this should suffice in practice. Time zone names
4983 : : * do not use drive letters and backslashes. If the -d option of zic
4984 : : * does not name an already-existing directory, it can use slashes to
4985 : : * separate the already-existing ancestor prefix from the
4986 : : * to-be-created subdirectories.
4987 : : */
4988 : :
4989 : : /* Do not mkdir a root directory, as it must exist. */
4990 [ + + ]: 44 : while (*cp == '/')
4991 : 2 : cp++;
4992 : :
4993 [ + + + + : 152 : while (cp && ((cp = strchr(cp, '/')) || !ancestors))
+ + ]
4994 : : {
4995 [ + + ]: 68 : if (cp)
4996 : 66 : *cp = '\0';
4997 : :
4998 : : /*
4999 : : * Try to create it. It's OK if creation fails because the
5000 : : * directory already exists, perhaps because some other process
5001 : : * just created it. For simplicity do not check first whether it
5002 : : * already exists, as that is checked anyway if the mkdir fails.
5003 : : */
5004 [ + + ]: 68 : if (mkdir(name, MKDIR_PERMS) < 0)
5005 : : {
5006 : : /*
5007 : : * Do not report an error if err == EEXIST, because some other
5008 : : * process might have made the directory in the meantime.
5009 : : * Likewise for ENOSYS, because Solaris 10 mkdir fails with
5010 : : * ENOSYS if the directory is an automounted mount point.
5011 : : * Likewise for EACCES, since mkdir can fail with EACCES
5012 : : * merely because the parent directory is unwritable. Likewise
5013 : : * for most other error numbers.
5014 : : */
5015 : 26 : int err = errno;
5016 : :
5017 [ + - + - ]: 26 : if (err == ELOOP || err == ENAMETOOLONG
5018 [ + - - + ]: 26 : || err == ENOENT || err == ENOTDIR)
5019 : : {
5020 : 0 : error(_("%s: Cannot create directory %s: %s"),
5021 : : progname, name, strerror(err));
5022 : 0 : exit(EXIT_FAILURE);
5023 : : }
5024 : : }
5025 [ + + ]: 68 : if (cp)
5026 : 66 : *cp++ = '/';
5027 : : }
5028 : 42 : free(name);
5029 : : }
5030 : 42 : }
|