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