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