blob: 54576780d5f64bbf4c4174c2276ffd48484f3780 [file] [log] [blame]
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001/*
2** This file is in the public domain, so clarified as of
3** 2006-07-17 by Arthur David Olson.
4*/
5
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08006/* Enable extensions and modifications for ICU. */
7#define ICU
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00008
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08009/* Continue executing after link failure. Even if ICU is undefined
10 * (for vanilla zic behavior), ICU_LINKS should be defined, since zic
11 * appears to fail on the 2003 data the first time through during the
12 * linking phase. Running zic twice, with ICU_LINKS defined, causes
13 * links to be handled correctly. */
14#define ICU_LINKS
15
16#define LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
17
18#ifdef ICU
19/* These constants are embedded in dynamically generated header
20 * version.h in the standard tzcode distribution. */
21static char const PKGVERSION[]="N/A";
22static char const TZVERSION[]="N/A";
23static char const REPORT_BUGS_TO[]="N/A";
24#else
25#include "version.h"
26#endif
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000027#include "private.h"
28#include "locale.h"
29#include "tzfile.h"
30
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080031#include <stdarg.h>
Frank Tang1f164ee2022-11-08 12:31:27 -080032#include <stdbool.h>
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080033
34#define ZIC_VERSION_PRE_2013 '2'
35#define ZIC_VERSION '3'
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000036
37typedef int_fast64_t zic_t;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080038#define ZIC_MIN INT_FAST64_MIN
39#define ZIC_MAX INT_FAST64_MAX
40#define SCNdZIC SCNdFAST64
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000041
42#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
43#define ZIC_MAX_ABBR_LEN_WO_WARN 6
44#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
45
46#if HAVE_SYS_STAT_H
47#include "sys/stat.h"
48#endif
49#ifdef S_IRUSR
50#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
51#else
52#define MKDIR_UMASK 0755
53#endif
54
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000055#ifdef ICU
56#include "tz2icu.h"
57#endif
58
59/*
60** On some ancient hosts, predicates like `isspace(C)' are defined
61** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
62** which says they are defined only if C == ((unsigned char) C) || C == EOF.
63** Neither the C Standard nor Posix require that `isascii' exist.
64** For portability, we check both ancient and modern requirements.
65** If isascii is not defined, the isascii check succeeds trivially.
66*/
67#include "ctype.h"
68#ifndef isascii
69#define isascii(x) 1
70#endif
71
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000072#define end(cp) (strchr((cp), '\0'))
73
74struct rule {
75 const char * r_filename;
76 int r_linenum;
77 const char * r_name;
78
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080079 zic_t r_loyear; /* for example, 1986 */
80 zic_t r_hiyear; /* for example, 1986 */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000081 const char * r_yrtype;
82 int r_lowasnum;
83 int r_hiwasnum;
84
85 int r_month; /* 0..11 */
86
87 int r_dycode; /* see below */
88 int r_dayofmonth;
89 int r_wday;
90
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080091 zic_t r_tod; /* time from midnight */
Frank Tang1f164ee2022-11-08 12:31:27 -080092 int r_todisstd; /* above is standard time if true */
93 /* or wall clock time if false */
94 int r_todisgmt; /* above is GMT if true */
95 /* or local time if false */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080096 zic_t r_stdoff; /* offset from standard time */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000097 const char * r_abbrvar; /* variable part of abbreviation */
98
99 int r_todo; /* a rule to do (used in outzone) */
100 zic_t r_temp; /* used in outzone */
101};
102
103/*
104** r_dycode r_dayofmonth r_wday
105*/
106
107#define DC_DOM 0 /* 1..31 */ /* unused */
108#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
109#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
110
111struct zone {
112 const char * z_filename;
113 int z_linenum;
114
115 const char * z_name;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800116 zic_t z_gmtoff;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000117 const char * z_rule;
118 const char * z_format;
119
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800120 zic_t z_stdoff;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000121
122 struct rule * z_rules;
123 int z_nrules;
124
125 struct rule z_untilrule;
126 zic_t z_untiltime;
127};
128
129extern int getopt(int argc, char * const argv[],
130 const char * options);
131extern int link(const char * fromname, const char * toname);
132extern char * optarg;
133extern int optind;
134
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800135#if ! HAVE_LINK
136# define link(from, to) (-1)
137#endif
138#if ! HAVE_SYMLINK
139# define symlink(from, to) (-1)
140#endif
141
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000142static void addtt(zic_t starttime, int type);
143#ifdef ICU
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800144static int addtype(const zic_t gmtoff, const zic_t rawoff, const zic_t dstoff,
145 char *const abbr, int isdst,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000146 int ttisstd, int ttisgmt);
147#else
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800148static int addtype(zic_t gmtoff, const char * abbr, int isdst,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000149 int ttisstd, int ttisgmt);
150#endif
151static void leapadd(zic_t t, int positive, int rolling, int count);
152static void adjleap(void);
153static void associate(void);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000154static void dolink(const char * fromfield, const char * tofield);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000155static char ** getfields(char * buf);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800156static zic_t gethms(const char * string, const char * errstrng,
157 int signable);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000158static void infile(const char * filename);
159static void inleap(char ** fields, int nfields);
160static void inlink(char ** fields, int nfields);
161static void inrule(char ** fields, int nfields);
162static int inzcont(char ** fields, int nfields);
163static int inzone(char ** fields, int nfields);
164static int inzsub(char ** fields, int nfields, int iscont);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000165static int itsdir(const char * name);
166static int lowerit(int c);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000167static int mkdirs(char * filename);
168static void newabbr(const char * abbr);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800169static zic_t oadd(zic_t t1, zic_t t2);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000170static void outzone(const struct zone * zp, int ntzones);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800171static zic_t rpytime(const struct rule * rp, zic_t wantedy);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000172static void rulesub(struct rule * rp,
173 const char * loyearp, const char * hiyearp,
174 const char * typep, const char * monthp,
175 const char * dayp, const char * timep);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800176static zic_t tadd(zic_t t1, zic_t t2);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000177static int yearistype(int year, const char * type);
178#ifdef ICU
179static void emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset,
180 const struct rule* rule,
181 int ruleIndex, int startYear);
182static void emit_icu_link(FILE* f, const char* from, const char* to);
183static void emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex);
184static int add_icu_final_rules(const struct rule* r1, const struct rule* r2);
185#endif
186
187static int charcnt;
188static int errors;
189static const char * filename;
190static int leapcnt;
191static int leapseen;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800192static zic_t leapminyear;
193static zic_t leapmaxyear;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000194static int linenum;
195static int max_abbrvar_len;
196static int max_format_len;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800197static zic_t max_year;
198static zic_t min_year;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000199static int noise;
200static const char * rfilename;
201static int rlinenum;
202static const char * progname;
203static int timecnt;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800204static int timecnt_alloc;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000205static int typecnt;
206
207/*
208** Line codes.
209*/
210
211#define LC_RULE 0
212#define LC_ZONE 1
213#define LC_LINK 2
214#define LC_LEAP 3
215
216/*
217** Which fields are which on a Zone line.
218*/
219
220#define ZF_NAME 1
221#define ZF_GMTOFF 2
222#define ZF_RULE 3
223#define ZF_FORMAT 4
224#define ZF_TILYEAR 5
225#define ZF_TILMONTH 6
226#define ZF_TILDAY 7
227#define ZF_TILTIME 8
228#define ZONE_MINFIELDS 5
229#define ZONE_MAXFIELDS 9
230
231/*
232** Which fields are which on a Zone continuation line.
233*/
234
235#define ZFC_GMTOFF 0
236#define ZFC_RULE 1
237#define ZFC_FORMAT 2
238#define ZFC_TILYEAR 3
239#define ZFC_TILMONTH 4
240#define ZFC_TILDAY 5
241#define ZFC_TILTIME 6
242#define ZONEC_MINFIELDS 3
243#define ZONEC_MAXFIELDS 7
244
245/*
246** Which files are which on a Rule line.
247*/
248
249#define RF_NAME 1
250#define RF_LOYEAR 2
251#define RF_HIYEAR 3
252#define RF_COMMAND 4
253#define RF_MONTH 5
254#define RF_DAY 6
255#define RF_TOD 7
256#define RF_STDOFF 8
257#define RF_ABBRVAR 9
258#define RULE_FIELDS 10
259
260/*
261** Which fields are which on a Link line.
262*/
263
264#define LF_FROM 1
265#define LF_TO 2
266#define LINK_FIELDS 3
267
268/*
269** Which fields are which on a Leap line.
270*/
271
272#define LP_YEAR 1
273#define LP_MONTH 2
274#define LP_DAY 3
275#define LP_TIME 4
276#define LP_CORR 5
277#define LP_ROLL 6
278#define LEAP_FIELDS 7
279
280/*
281** Year synonyms.
282*/
283
284#define YR_MINIMUM 0
285#define YR_MAXIMUM 1
286#define YR_ONLY 2
287
288static struct rule * rules;
289static int nrules; /* number of rules */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800290static int nrules_alloc;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000291
292static struct zone * zones;
293static int nzones; /* number of zones */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800294static int nzones_alloc;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000295
296struct link {
297 const char * l_filename;
298 int l_linenum;
299 const char * l_from;
300 const char * l_to;
301};
302
303static struct link * links;
304static int nlinks;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800305static int nlinks_alloc;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000306
307struct lookup {
308 const char * l_word;
309 const int l_value;
310};
311
312#ifdef ICU
313/* Indices into rules[] for final rules. They will occur in pairs,
314 * with finalRules[i] occurring before finalRules[i+1] in the year.
315 * Each zone need only store a start year, a standard offset, and an
316 * index into finalRules[]. FinalRules[] are aliases into rules[]. */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800317static const struct rule ** finalRules = NULL;
318static int finalRulesCount = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000319#endif
320
321static struct lookup const * byword(const char * string,
322 const struct lookup * lp);
323
324static struct lookup const line_codes[] = {
325 { "Rule", LC_RULE },
326 { "Zone", LC_ZONE },
327 { "Link", LC_LINK },
328 { "Leap", LC_LEAP },
329 { NULL, 0}
330};
331
332static struct lookup const mon_names[] = {
333 { "January", TM_JANUARY },
334 { "February", TM_FEBRUARY },
335 { "March", TM_MARCH },
336 { "April", TM_APRIL },
337 { "May", TM_MAY },
338 { "June", TM_JUNE },
339 { "July", TM_JULY },
340 { "August", TM_AUGUST },
341 { "September", TM_SEPTEMBER },
342 { "October", TM_OCTOBER },
343 { "November", TM_NOVEMBER },
344 { "December", TM_DECEMBER },
345 { NULL, 0 }
346};
347
348static struct lookup const wday_names[] = {
349 { "Sunday", TM_SUNDAY },
350 { "Monday", TM_MONDAY },
351 { "Tuesday", TM_TUESDAY },
352 { "Wednesday", TM_WEDNESDAY },
353 { "Thursday", TM_THURSDAY },
354 { "Friday", TM_FRIDAY },
355 { "Saturday", TM_SATURDAY },
356 { NULL, 0 }
357};
358
359static struct lookup const lasts[] = {
360 { "last-Sunday", TM_SUNDAY },
361 { "last-Monday", TM_MONDAY },
362 { "last-Tuesday", TM_TUESDAY },
363 { "last-Wednesday", TM_WEDNESDAY },
364 { "last-Thursday", TM_THURSDAY },
365 { "last-Friday", TM_FRIDAY },
366 { "last-Saturday", TM_SATURDAY },
367 { NULL, 0 }
368};
369
370static struct lookup const begin_years[] = {
371 { "minimum", YR_MINIMUM },
372 { "maximum", YR_MAXIMUM },
373 { NULL, 0 }
374};
375
376static struct lookup const end_years[] = {
377 { "minimum", YR_MINIMUM },
378 { "maximum", YR_MAXIMUM },
379 { "only", YR_ONLY },
380 { NULL, 0 }
381};
382
383static struct lookup const leap_types[] = {
Frank Tang1f164ee2022-11-08 12:31:27 -0800384 { "Rolling", true },
385 { "Stationary", false },
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000386 { NULL, 0 }
387};
388
389static const int len_months[2][MONSPERYEAR] = {
390 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
391 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
392};
393
394static const int len_years[2] = {
395 DAYSPERNYEAR, DAYSPERLYEAR
396};
397
398static struct attype {
399 zic_t at;
400 unsigned char type;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800401} * attypes;
402static zic_t gmtoffs[TZ_MAX_TYPES];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000403#ifdef ICU
404/* gmtoffs[i] = rawoffs[i] + dstoffs[i] */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800405static zic_t rawoffs[TZ_MAX_TYPES];
406static zic_t dstoffs[TZ_MAX_TYPES];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000407#endif
408static char isdsts[TZ_MAX_TYPES];
409static unsigned char abbrinds[TZ_MAX_TYPES];
410static char ttisstds[TZ_MAX_TYPES];
411static char ttisgmts[TZ_MAX_TYPES];
412static char chars[TZ_MAX_CHARS];
413static zic_t trans[TZ_MAX_LEAPS];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800414static zic_t corr[TZ_MAX_LEAPS];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000415static char roll[TZ_MAX_LEAPS];
416
417/*
418** Memory allocation.
419*/
420
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800421static _Noreturn void
422memory_exhausted(const char *msg)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000423{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800424 fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg);
425 exit(EXIT_FAILURE);
426}
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000427
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800428static ATTRIBUTE_PURE size_t
429size_product(size_t nitems, size_t itemsize)
430{
431 if (SIZE_MAX / itemsize < nitems)
432 memory_exhausted("size overflow");
433 return nitems * itemsize;
434}
435
436static ATTRIBUTE_PURE void *
437memcheck(void *const ptr)
438{
439 if (ptr == NULL)
440 memory_exhausted(strerror(errno));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000441 return ptr;
442}
443
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800444#define emalloc(size) memcheck(malloc(size))
445#define erealloc(ptr, size) memcheck(realloc(ptr, size))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000446#define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
447#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
448
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800449static void *
450growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
451{
452 if (nitems < *nitems_alloc)
453 return ptr;
454 else {
455 int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX;
456 if ((amax - 1) / 3 * 2 < *nitems_alloc)
457 memory_exhausted("int overflow");
458 *nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
459 return erealloc(ptr, size_product(*nitems_alloc, itemsize));
460 }
461}
462
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000463/*
464** Error handling.
465*/
466
467static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800468eats(const char *const name, const int num, const char *const rname,
469 const int rnum)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000470{
471 filename = name;
472 linenum = num;
473 rfilename = rname;
474 rlinenum = rnum;
475}
476
477static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800478eat(const char *const name, const int num)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000479{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800480 eats(name, num, NULL, -1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000481}
482
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800483static void ATTRIBUTE_FORMAT((printf, 1, 0))
484verror(const char *const string, va_list args)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000485{
486 /*
487 ** Match the format of "cc" to allow sh users to
488 ** zic ... 2>&1 | error -t "*" -v
489 ** on BSD systems.
490 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800491 fprintf(stderr, _("\"%s\", line %d: "), filename, linenum);
492 vfprintf(stderr, string, args);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000493 if (rfilename != NULL)
494 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
495 rfilename, rlinenum);
496 (void) fprintf(stderr, "\n");
497 ++errors;
498}
499
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800500static void ATTRIBUTE_FORMAT((printf, 1, 2))
501error(const char *const string, ...)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000502{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800503 va_list args;
504 va_start(args, string);
505 verror(string, args);
506 va_end(args);
507}
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000508
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800509static void ATTRIBUTE_FORMAT((printf, 1, 2))
510warning(const char *const string, ...)
511{
512 va_list args;
513 fprintf(stderr, _("warning: "));
514 va_start(args, string);
515 verror(string, args);
516 va_end(args);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000517 --errors;
518}
519
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800520static _Noreturn void
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000521usage(FILE *stream, int status)
522{
523 (void) fprintf(stream, _("%s: usage is %s \
524[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
525\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
526\n\
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800527Report bugs to %s.\n"),
528 progname, progname, REPORT_BUGS_TO);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000529 exit(status);
530}
531
532#ifdef ICU
533/* File into which we will write supplemental ICU data. */
534static FILE * icuFile;
535
536static void
537emit_icu_zone(FILE* f, const char* zoneName, int zoneOffset,
538 const struct rule* rule,
539 int ruleIndex, int startYear) {
540 /* machine-readable section */
541 fprintf(f, "zone %s %d %d %s", zoneName, zoneOffset, startYear, rule->r_name);
542
543 /* human-readable section */
544 fprintf(f, " # zone %s, offset %d, year >= %d, rule %s (%d)\n",
545 zoneName, zoneOffset, startYear,
546 rule->r_name, ruleIndex);
547}
548
549static void
550emit_icu_link(FILE* f, const char* from, const char* to) {
551 /* machine-readable section */
552 fprintf(f, "link %s %s\n", from, to);
553}
554
555static const char* DYCODE[] = {"DOM", "DOWGEQ", "DOWLEQ"};
556
557static void
558emit_icu_rule(FILE* f, const struct rule* r, int ruleIndex) {
559 if (r->r_yrtype != NULL) {
560 warning("year types not supported by ICU");
561 fprintf(stderr, "rule %s, file %s, line %d\n",
562 r->r_name, r->r_filename, r->r_linenum);
563 }
564
565 /* machine-readable section */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800566 fprintf(f, "rule %s %s %d %d %d %lld %d %d %lld",
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000567 r->r_name, DYCODE[r->r_dycode],
568 r->r_month, r->r_dayofmonth,
569 (r->r_dycode == DC_DOM ? -1 : r->r_wday),
570 r->r_tod, r->r_todisstd, r->r_todisgmt, r->r_stdoff
571 );
572
573 /* human-readable section */
574 fprintf(f, " # %d: %s, file %s, line %d",
575 ruleIndex, r->r_name, r->r_filename, r->r_linenum);
576 fprintf(f, ", mode %s", DYCODE[r->r_dycode]);
577 fprintf(f, ", %s, dom %d", mon_names[r->r_month].l_word, r->r_dayofmonth);
578 if (r->r_dycode != DC_DOM) {
579 fprintf(f, ", %s", wday_names[r->r_wday].l_word);
580 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800581 fprintf(f, ", time %lld", r->r_tod);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000582 fprintf(f, ", isstd %d", r->r_todisstd);
583 fprintf(f, ", isgmt %d", r->r_todisgmt);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800584 fprintf(f, ", offset %lld", r->r_stdoff);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000585 fprintf(f, "\n");
586}
587
588static int
589add_icu_final_rules(const struct rule* r1, const struct rule* r2) {
590 int i;
591
592 for (i=0; i<finalRulesCount; ++i) { /* i+=2 should work too */
593 if (r1==finalRules[i]) return i; /* [sic] pointer comparison */
594 }
595
596 finalRules = (const struct rule**) (void*) erealloc((char *) finalRules,
597 (finalRulesCount + 2) * sizeof(*finalRules));
598 finalRules[finalRulesCount++] = r1;
599 finalRules[finalRulesCount++] = r2;
600 return finalRulesCount - 2;
601}
602#endif
603
604static const char * psxrules;
605static const char * lcltime;
606static const char * directory;
607static const char * leapsec;
608static const char * yitcommand;
609
610int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800611main(int argc, char **argv)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000612{
613 register int i;
614 register int j;
615 register int c;
616
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800617#ifdef S_IWGRP
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000618 (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800619#endif
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000620#if HAVE_GETTEXT
621 (void) setlocale(LC_ALL, "");
622#ifdef TZ_DOMAINDIR
623 (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
624#endif /* defined TEXTDOMAINDIR */
625 (void) textdomain(TZ_DOMAIN);
626#endif /* HAVE_GETTEXT */
627 progname = argv[0];
628 if (TYPE_BIT(zic_t) < 64) {
629 (void) fprintf(stderr, "%s: %s\n", progname,
630 _("wild compilation-time specification of zic_t"));
631 exit(EXIT_FAILURE);
632 }
633 for (i = 1; i < argc; ++i)
634 if (strcmp(argv[i], "--version") == 0) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800635 (void) printf("zic %s%s\n", PKGVERSION, TZVERSION);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000636 exit(EXIT_SUCCESS);
637 } else if (strcmp(argv[i], "--help") == 0) {
638 usage(stdout, EXIT_SUCCESS);
639 }
640 while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)
641 switch (c) {
642 default:
643 usage(stderr, EXIT_FAILURE);
644 case 'd':
645 if (directory == NULL)
646 directory = optarg;
647 else {
648 (void) fprintf(stderr,
649_("%s: More than one -d option specified\n"),
650 progname);
651 exit(EXIT_FAILURE);
652 }
653 break;
654 case 'l':
655 if (lcltime == NULL)
656 lcltime = optarg;
657 else {
658 (void) fprintf(stderr,
659_("%s: More than one -l option specified\n"),
660 progname);
661 exit(EXIT_FAILURE);
662 }
663 break;
664 case 'p':
665 if (psxrules == NULL)
666 psxrules = optarg;
667 else {
668 (void) fprintf(stderr,
669_("%s: More than one -p option specified\n"),
670 progname);
671 exit(EXIT_FAILURE);
672 }
673 break;
674 case 'y':
675 if (yitcommand == NULL)
676 yitcommand = optarg;
677 else {
678 (void) fprintf(stderr,
679_("%s: More than one -y option specified\n"),
680 progname);
681 exit(EXIT_FAILURE);
682 }
683 break;
684 case 'L':
685 if (leapsec == NULL)
686 leapsec = optarg;
687 else {
688 (void) fprintf(stderr,
689_("%s: More than one -L option specified\n"),
690 progname);
691 exit(EXIT_FAILURE);
692 }
693 break;
694 case 'v':
Frank Tang1f164ee2022-11-08 12:31:27 -0800695 noise = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000696 break;
697 case 's':
698 (void) printf("%s: -s ignored\n", progname);
699 break;
700 }
701 if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
702 usage(stderr, EXIT_FAILURE); /* usage message by request */
703 if (directory == NULL)
704 directory = TZDIR;
705 if (yitcommand == NULL)
706 yitcommand = "yearistype";
707
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000708 if (optind < argc && leapsec != NULL) {
709 infile(leapsec);
710 adjleap();
711 }
712
713#ifdef ICU
714 if ((icuFile = fopen(ICU_ZONE_FILE, "w")) == NULL) {
715 const char *e = strerror(errno);
716 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
717 progname, ICU_ZONE_FILE, e);
718 (void) exit(EXIT_FAILURE);
719 }
720#endif
721 for (i = optind; i < argc; ++i)
722 infile(argv[i]);
723 if (errors)
724 exit(EXIT_FAILURE);
725 associate();
726 for (i = 0; i < nzones; i = j) {
727 /*
728 ** Find the next non-continuation zone entry.
729 */
730 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
731 continue;
732 outzone(&zones[i], j - i);
733 }
734 /*
735 ** Make links.
736 */
737 for (i = 0; i < nlinks; ++i) {
738 eat(links[i].l_filename, links[i].l_linenum);
739 dolink(links[i].l_from, links[i].l_to);
740#ifdef ICU
741 emit_icu_link(icuFile, links[i].l_from, links[i].l_to);
742#endif
743 if (noise)
744 for (j = 0; j < nlinks; ++j)
745 if (strcmp(links[i].l_to,
746 links[j].l_from) == 0)
747 warning(_("link to link"));
748 }
749 if (lcltime != NULL) {
750 eat("command line", 1);
751 dolink(lcltime, TZDEFAULT);
752 }
753 if (psxrules != NULL) {
754 eat("command line", 1);
755 dolink(psxrules, TZDEFRULES);
756 }
757#ifdef ICU
758 for (i=0; i<finalRulesCount; ++i) {
759 emit_icu_rule(icuFile, finalRules[i], i);
760 }
761#endif /*ICU*/
762 return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
763}
764
765static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800766dolink(const char *const fromfield, const char *const tofield)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000767{
768 register char * fromname;
769 register char * toname;
770
771 if (fromfield[0] == '/')
772 fromname = ecpyalloc(fromfield);
773 else {
774 fromname = ecpyalloc(directory);
775 fromname = ecatalloc(fromname, "/");
776 fromname = ecatalloc(fromname, fromfield);
777 }
778 if (tofield[0] == '/')
779 toname = ecpyalloc(tofield);
780 else {
781 toname = ecpyalloc(directory);
782 toname = ecatalloc(toname, "/");
783 toname = ecatalloc(toname, tofield);
784 }
785 /*
786 ** We get to be careful here since
787 ** there's a fair chance of root running us.
788 */
789 if (!itsdir(toname))
790 (void) remove(toname);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800791 if (link(fromname, toname) != 0
792 && access(fromname, F_OK) == 0 && !itsdir(fromname)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000793 int result;
794
795 if (mkdirs(toname) != 0)
796 exit(EXIT_FAILURE);
797
798 result = link(fromname, toname);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800799 if (result != 0) {
800 const char *s = fromfield;
801 const char *t;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000802 register char * symlinkcontents = NULL;
803
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800804 do
805 t = s;
806 while ((s = strchr(s, '/'))
807 && ! strncmp (fromfield, tofield,
808 ++s - fromfield));
809
810 for (s = tofield + (t - fromfield);
811 (s = strchr(s, '/'));
812 s++)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000813 symlinkcontents =
814 ecatalloc(symlinkcontents,
815 "../");
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800816 symlinkcontents = ecatalloc(symlinkcontents, t);
817 result = symlink(symlinkcontents, toname);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000818 if (result == 0)
819warning(_("hard link failed, symbolic link used"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800820 free(symlinkcontents);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000821 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000822 if (result != 0) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800823 FILE *fp, *tp;
824 int c;
825 fp = fopen(fromname, "rb");
826 if (!fp) {
827 const char *e = strerror(errno);
828 (void) fprintf(stderr,
829 _("%s: Can't read %s: %s\n"),
830 progname, fromname, e);
831 exit(EXIT_FAILURE);
832 }
833 tp = fopen(toname, "wb");
834 if (!tp) {
835 const char *e = strerror(errno);
836 (void) fprintf(stderr,
837 _("%s: Can't create %s: %s\n"),
838 progname, toname, e);
839 exit(EXIT_FAILURE);
840 }
841 while ((c = getc(fp)) != EOF)
842 putc(c, tp);
843 if (ferror(fp) || fclose(fp)) {
844 (void) fprintf(stderr,
845 _("%s: Error reading %s\n"),
846 progname, fromname);
847 exit(EXIT_FAILURE);
848 }
849 if (ferror(tp) || fclose(tp)) {
850 (void) fprintf(stderr,
851 _("%s: Error writing %s\n"),
852 progname, toname);
853 exit(EXIT_FAILURE);
854 }
855 warning(_("link failed, copy used"));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000856#ifndef ICU_LINKS
857 exit(EXIT_FAILURE);
858#endif
859 }
860 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800861 free(fromname);
862 free(toname);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000863}
864
865#define TIME_T_BITS_IN_FILE 64
866
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800867static const zic_t min_time = (zic_t) -1 << (TIME_T_BITS_IN_FILE - 1);
868static const zic_t max_time = -1 - ((zic_t) -1 << (TIME_T_BITS_IN_FILE - 1));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000869
870static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800871itsdir(const char *const name)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000872{
873 register char * myname;
874 register int accres;
875
876 myname = ecpyalloc(name);
877 myname = ecatalloc(myname, "/.");
878 accres = access(myname, F_OK);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800879 free(myname);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000880 return accres == 0;
881}
882
883/*
884** Associate sets of rules with zones.
885*/
886
887/*
888** Sort by rule name.
889*/
890
891static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800892rcomp(const void *cp1, const void *cp2)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000893{
894 return strcmp(((const struct rule *) cp1)->r_name,
895 ((const struct rule *) cp2)->r_name);
896}
897
898static void
899associate(void)
900{
901 register struct zone * zp;
902 register struct rule * rp;
903 register int base, out;
904 register int i, j;
905
906 if (nrules != 0) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800907 (void) qsort(rules, nrules, sizeof *rules, rcomp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000908 for (i = 0; i < nrules - 1; ++i) {
909 if (strcmp(rules[i].r_name,
910 rules[i + 1].r_name) != 0)
911 continue;
912 if (strcmp(rules[i].r_filename,
913 rules[i + 1].r_filename) == 0)
914 continue;
915 eat(rules[i].r_filename, rules[i].r_linenum);
916 warning(_("same rule name in multiple files"));
917 eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
918 warning(_("same rule name in multiple files"));
919 for (j = i + 2; j < nrules; ++j) {
920 if (strcmp(rules[i].r_name,
921 rules[j].r_name) != 0)
922 break;
923 if (strcmp(rules[i].r_filename,
924 rules[j].r_filename) == 0)
925 continue;
926 if (strcmp(rules[i + 1].r_filename,
927 rules[j].r_filename) == 0)
928 continue;
929 break;
930 }
931 i = j - 1;
932 }
933 }
934 for (i = 0; i < nzones; ++i) {
935 zp = &zones[i];
936 zp->z_rules = NULL;
937 zp->z_nrules = 0;
938 }
939 for (base = 0; base < nrules; base = out) {
940 rp = &rules[base];
941 for (out = base + 1; out < nrules; ++out)
942 if (strcmp(rp->r_name, rules[out].r_name) != 0)
943 break;
944 for (i = 0; i < nzones; ++i) {
945 zp = &zones[i];
946 if (strcmp(zp->z_rule, rp->r_name) != 0)
947 continue;
948 zp->z_rules = rp;
949 zp->z_nrules = out - base;
950 }
951 }
952 for (i = 0; i < nzones; ++i) {
953 zp = &zones[i];
954 if (zp->z_nrules == 0) {
955 /*
956 ** Maybe we have a local standard time offset.
957 */
958 eat(zp->z_filename, zp->z_linenum);
959 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
Frank Tang1f164ee2022-11-08 12:31:27 -0800960 true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000961 /*
962 ** Note, though, that if there's no rule,
963 ** a '%s' in the format is a bad thing.
964 */
965 if (strchr(zp->z_format, '%') != 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800966 error("%s", _("%s in ruleless zone"));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000967 }
968 }
969 if (errors)
970 exit(EXIT_FAILURE);
971}
972
973static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800974infile(const char *name)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000975{
976 register FILE * fp;
977 register char ** fields;
978 register char * cp;
979 register const struct lookup * lp;
980 register int nfields;
981 register int wantcont;
982 register int num;
983 char buf[BUFSIZ];
984
985 if (strcmp(name, "-") == 0) {
986 name = _("standard input");
987 fp = stdin;
988 } else if ((fp = fopen(name, "r")) == NULL) {
989 const char *e = strerror(errno);
990
991 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
992 progname, name, e);
993 exit(EXIT_FAILURE);
994 }
Frank Tang1f164ee2022-11-08 12:31:27 -0800995 wantcont = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000996 for (num = 1; ; ++num) {
997 eat(name, num);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800998 if (fgets(buf, sizeof buf, fp) != buf)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000999 break;
1000 cp = strchr(buf, '\n');
1001 if (cp == NULL) {
1002 error(_("line too long"));
1003 exit(EXIT_FAILURE);
1004 }
1005 *cp = '\0';
1006 fields = getfields(buf);
1007 nfields = 0;
1008 while (fields[nfields] != NULL) {
1009 static char nada;
1010
1011 if (strcmp(fields[nfields], "-") == 0)
1012 fields[nfields] = &nada;
1013 ++nfields;
1014 }
1015 if (nfields == 0) {
1016 /* nothing to do */
1017 } else if (wantcont) {
1018 wantcont = inzcont(fields, nfields);
1019 } else {
1020 lp = byword(fields[0], line_codes);
1021 if (lp == NULL)
1022 error(_("input line of unknown type"));
1023 else switch ((int) (lp->l_value)) {
1024 case LC_RULE:
1025 inrule(fields, nfields);
Frank Tang1f164ee2022-11-08 12:31:27 -08001026 wantcont = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001027 break;
1028 case LC_ZONE:
1029 wantcont = inzone(fields, nfields);
1030 break;
1031 case LC_LINK:
1032 inlink(fields, nfields);
Frank Tang1f164ee2022-11-08 12:31:27 -08001033 wantcont = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001034 break;
1035 case LC_LEAP:
1036 if (name != leapsec)
1037 (void) fprintf(stderr,
1038_("%s: Leap line in non leap seconds file %s\n"),
1039 progname, name);
1040 else inleap(fields, nfields);
Frank Tang1f164ee2022-11-08 12:31:27 -08001041 wantcont = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001042 break;
1043 default: /* "cannot happen" */
1044 (void) fprintf(stderr,
1045_("%s: panic: Invalid l_value %d\n"),
1046 progname, lp->l_value);
1047 exit(EXIT_FAILURE);
1048 }
1049 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001050 free(fields);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001051 }
1052 if (ferror(fp)) {
1053 (void) fprintf(stderr, _("%s: Error reading %s\n"),
1054 progname, filename);
1055 exit(EXIT_FAILURE);
1056 }
1057 if (fp != stdin && fclose(fp)) {
1058 const char *e = strerror(errno);
1059
1060 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
1061 progname, filename, e);
1062 exit(EXIT_FAILURE);
1063 }
1064 if (wantcont)
1065 error(_("expected continuation line not found"));
1066}
1067
1068/*
1069** Convert a string of one of the forms
1070** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
1071** into a number of seconds.
1072** A null string maps to zero.
1073** Call error with errstring and return zero on errors.
1074*/
1075
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001076static zic_t
1077gethms(const char *string, const char *const errstring, const int signable)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001078{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001079 zic_t hh;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001080 int mm, ss, sign;
1081
1082 if (string == NULL || *string == '\0')
1083 return 0;
1084 if (!signable)
1085 sign = 1;
1086 else if (*string == '-') {
1087 sign = -1;
1088 ++string;
1089 } else sign = 1;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001090 if (sscanf(string, scheck(string, "%"SCNdZIC), &hh) == 1)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001091 mm = ss = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001092 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d"), &hh, &mm) == 2)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001093 ss = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001094 else if (sscanf(string, scheck(string, "%"SCNdZIC":%d:%d"),
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001095 &hh, &mm, &ss) != 3) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001096 error("%s", errstring);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001097 return 0;
1098 }
1099 if (hh < 0 ||
1100 mm < 0 || mm >= MINSPERHOUR ||
1101 ss < 0 || ss > SECSPERMIN) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001102 error("%s", errstring);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001103 return 0;
1104 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001105 if (ZIC_MAX / SECSPERHOUR < hh) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001106 error(_("time overflow"));
1107 return 0;
1108 }
1109 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
1110 warning(_("24:00 not handled by pre-1998 versions of zic"));
1111 if (noise && (hh > HOURSPERDAY ||
1112 (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
1113warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001114 return oadd(sign * hh * SECSPERHOUR,
1115 sign * (mm * SECSPERMIN + ss));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001116}
1117
1118static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001119inrule(register char **const fields, const int nfields)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001120{
1121 static struct rule r;
1122
1123 if (nfields != RULE_FIELDS) {
1124 error(_("wrong number of fields on Rule line"));
1125 return;
1126 }
1127 if (*fields[RF_NAME] == '\0') {
1128 error(_("nameless rule"));
1129 return;
1130 }
1131 r.r_filename = filename;
1132 r.r_linenum = linenum;
Frank Tang1f164ee2022-11-08 12:31:27 -08001133 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001134 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
1135 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
1136 r.r_name = ecpyalloc(fields[RF_NAME]);
1137 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
1138 if (max_abbrvar_len < strlen(r.r_abbrvar))
1139 max_abbrvar_len = strlen(r.r_abbrvar);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001140 rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001141 rules[nrules++] = r;
1142}
1143
1144static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001145inzone(register char **const fields, const int nfields)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001146{
1147 register int i;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001148
1149 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
1150 error(_("wrong number of fields on Zone line"));
Frank Tang1f164ee2022-11-08 12:31:27 -08001151 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001152 }
1153 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001154 error(
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001155_("\"Zone %s\" line and -l option are mutually exclusive"),
1156 TZDEFAULT);
Frank Tang1f164ee2022-11-08 12:31:27 -08001157 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001158 }
1159 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001160 error(
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001161_("\"Zone %s\" line and -p option are mutually exclusive"),
1162 TZDEFRULES);
Frank Tang1f164ee2022-11-08 12:31:27 -08001163 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001164 }
1165 for (i = 0; i < nzones; ++i)
1166 if (zones[i].z_name != NULL &&
1167 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001168 error(
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001169_("duplicate zone name %s (file \"%s\", line %d)"),
1170 fields[ZF_NAME],
1171 zones[i].z_filename,
1172 zones[i].z_linenum);
Frank Tang1f164ee2022-11-08 12:31:27 -08001173 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001174 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001175 return inzsub(fields, nfields, false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001176}
1177
1178static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001179inzcont(register char **const fields, const int nfields)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001180{
1181 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
1182 error(_("wrong number of fields on Zone continuation line"));
Frank Tang1f164ee2022-11-08 12:31:27 -08001183 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001184 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001185 return inzsub(fields, nfields, true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001186}
1187
1188static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001189inzsub(register char **const fields, const int nfields, const int iscont)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001190{
1191 register char * cp;
1192 static struct zone z;
1193 register int i_gmtoff, i_rule, i_format;
1194 register int i_untilyear, i_untilmonth;
1195 register int i_untilday, i_untiltime;
1196 register int hasuntil;
1197
1198 if (iscont) {
1199 i_gmtoff = ZFC_GMTOFF;
1200 i_rule = ZFC_RULE;
1201 i_format = ZFC_FORMAT;
1202 i_untilyear = ZFC_TILYEAR;
1203 i_untilmonth = ZFC_TILMONTH;
1204 i_untilday = ZFC_TILDAY;
1205 i_untiltime = ZFC_TILTIME;
1206 z.z_name = NULL;
1207 } else {
1208 i_gmtoff = ZF_GMTOFF;
1209 i_rule = ZF_RULE;
1210 i_format = ZF_FORMAT;
1211 i_untilyear = ZF_TILYEAR;
1212 i_untilmonth = ZF_TILMONTH;
1213 i_untilday = ZF_TILDAY;
1214 i_untiltime = ZF_TILTIME;
1215 z.z_name = ecpyalloc(fields[ZF_NAME]);
1216 }
1217 z.z_filename = filename;
1218 z.z_linenum = linenum;
Frank Tang1f164ee2022-11-08 12:31:27 -08001219 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UT offset"), true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001220 if ((cp = strchr(fields[i_format], '%')) != 0) {
1221 if (*++cp != 's' || strchr(cp, '%') != 0) {
1222 error(_("invalid abbreviation format"));
Frank Tang1f164ee2022-11-08 12:31:27 -08001223 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001224 }
1225 }
1226 z.z_rule = ecpyalloc(fields[i_rule]);
1227 z.z_format = ecpyalloc(fields[i_format]);
1228 if (max_format_len < strlen(z.z_format))
1229 max_format_len = strlen(z.z_format);
1230 hasuntil = nfields > i_untilyear;
1231 if (hasuntil) {
1232 z.z_untilrule.r_filename = filename;
1233 z.z_untilrule.r_linenum = linenum;
1234 rulesub(&z.z_untilrule,
1235 fields[i_untilyear],
1236 "only",
1237 "",
1238 (nfields > i_untilmonth) ?
1239 fields[i_untilmonth] : "Jan",
1240 (nfields > i_untilday) ? fields[i_untilday] : "1",
1241 (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1242 z.z_untiltime = rpytime(&z.z_untilrule,
1243 z.z_untilrule.r_loyear);
1244 if (iscont && nzones > 0 &&
1245 z.z_untiltime > min_time &&
1246 z.z_untiltime < max_time &&
1247 zones[nzones - 1].z_untiltime > min_time &&
1248 zones[nzones - 1].z_untiltime < max_time &&
1249 zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1250 error(_(
1251"Zone continuation line end time is not after end time of previous line"
1252 ));
Frank Tang1f164ee2022-11-08 12:31:27 -08001253 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001254 }
1255 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001256 zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001257 zones[nzones++] = z;
1258 /*
1259 ** If there was an UNTIL field on this line,
1260 ** there's more information about the zone on the next line.
1261 */
1262 return hasuntil;
1263}
1264
1265static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001266inleap(register char ** const fields, const int nfields)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001267{
1268 register const char * cp;
1269 register const struct lookup * lp;
1270 register int i, j;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001271 zic_t year;
1272 int month, day;
1273 zic_t dayoff, tod;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001274 zic_t t;
1275
1276 if (nfields != LEAP_FIELDS) {
1277 error(_("wrong number of fields on Leap line"));
1278 return;
1279 }
1280 dayoff = 0;
1281 cp = fields[LP_YEAR];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001282 if (sscanf(cp, scheck(cp, "%"SCNdZIC), &year) != 1) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001283 /*
1284 ** Leapin' Lizards!
1285 */
1286 error(_("invalid leaping year"));
1287 return;
1288 }
1289 if (!leapseen || leapmaxyear < year)
1290 leapmaxyear = year;
1291 if (!leapseen || leapminyear > year)
1292 leapminyear = year;
Frank Tang1f164ee2022-11-08 12:31:27 -08001293 leapseen = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001294 j = EPOCH_YEAR;
1295 while (j != year) {
1296 if (year > j) {
1297 i = len_years[isleap(j)];
1298 ++j;
1299 } else {
1300 --j;
1301 i = -len_years[isleap(j)];
1302 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001303 dayoff = oadd(dayoff, i);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001304 }
1305 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1306 error(_("invalid month name"));
1307 return;
1308 }
1309 month = lp->l_value;
1310 j = TM_JANUARY;
1311 while (j != month) {
1312 i = len_months[isleap(year)][j];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001313 dayoff = oadd(dayoff, i);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001314 ++j;
1315 }
1316 cp = fields[LP_DAY];
1317 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1318 day <= 0 || day > len_months[isleap(year)][month]) {
1319 error(_("invalid day of month"));
1320 return;
1321 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001322 dayoff = oadd(dayoff, day - 1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001323 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
1324 error(_("time before zero"));
1325 return;
1326 }
1327 if (dayoff < min_time / SECSPERDAY) {
1328 error(_("time too small"));
1329 return;
1330 }
1331 if (dayoff > max_time / SECSPERDAY) {
1332 error(_("time too large"));
1333 return;
1334 }
1335 t = (zic_t) dayoff * SECSPERDAY;
Frank Tang1f164ee2022-11-08 12:31:27 -08001336 tod = gethms(fields[LP_TIME], _("invalid time of day"), false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001337 cp = fields[LP_CORR];
1338 {
1339 register int positive;
1340 int count;
1341
1342 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
Frank Tang1f164ee2022-11-08 12:31:27 -08001343 positive = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001344 count = 1;
1345 } else if (strcmp(cp, "--") == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001346 positive = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001347 count = 2;
1348 } else if (strcmp(cp, "+") == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001349 positive = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001350 count = 1;
1351 } else if (strcmp(cp, "++") == 0) {
Frank Tang1f164ee2022-11-08 12:31:27 -08001352 positive = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001353 count = 2;
1354 } else {
1355 error(_("illegal CORRECTION field on Leap line"));
1356 return;
1357 }
1358 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1359 error(_(
1360 "illegal Rolling/Stationary field on Leap line"
1361 ));
1362 return;
1363 }
1364 leapadd(tadd(t, tod), positive, lp->l_value, count);
1365 }
1366}
1367
1368static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001369inlink(register char **const fields, const int nfields)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001370{
1371 struct link l;
1372
1373 if (nfields != LINK_FIELDS) {
1374 error(_("wrong number of fields on Link line"));
1375 return;
1376 }
1377 if (*fields[LF_FROM] == '\0') {
1378 error(_("blank FROM field on Link line"));
1379 return;
1380 }
1381 if (*fields[LF_TO] == '\0') {
1382 error(_("blank TO field on Link line"));
1383 return;
1384 }
1385 l.l_filename = filename;
1386 l.l_linenum = linenum;
1387 l.l_from = ecpyalloc(fields[LF_FROM]);
1388 l.l_to = ecpyalloc(fields[LF_TO]);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001389 links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001390 links[nlinks++] = l;
1391}
1392
1393static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001394rulesub(register struct rule *const rp,
1395 const char *const loyearp,
1396 const char *const hiyearp,
1397 const char *const typep,
1398 const char *const monthp,
1399 const char *const dayp,
1400 const char *const timep)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001401{
1402 register const struct lookup * lp;
1403 register const char * cp;
1404 register char * dp;
1405 register char * ep;
1406
1407 if ((lp = byword(monthp, mon_names)) == NULL) {
1408 error(_("invalid month name"));
1409 return;
1410 }
1411 rp->r_month = lp->l_value;
Frank Tang1f164ee2022-11-08 12:31:27 -08001412 rp->r_todisstd = false;
1413 rp->r_todisgmt = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001414 dp = ecpyalloc(timep);
1415 if (*dp != '\0') {
1416 ep = dp + strlen(dp) - 1;
1417 switch (lowerit(*ep)) {
1418 case 's': /* Standard */
Frank Tang1f164ee2022-11-08 12:31:27 -08001419 rp->r_todisstd = true;
1420 rp->r_todisgmt = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001421 *ep = '\0';
1422 break;
1423 case 'w': /* Wall */
Frank Tang1f164ee2022-11-08 12:31:27 -08001424 rp->r_todisstd = false;
1425 rp->r_todisgmt = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001426 *ep = '\0';
1427 break;
1428 case 'g': /* Greenwich */
1429 case 'u': /* Universal */
1430 case 'z': /* Zulu */
Frank Tang1f164ee2022-11-08 12:31:27 -08001431 rp->r_todisstd = true;
1432 rp->r_todisgmt = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001433 *ep = '\0';
1434 break;
1435 }
1436 }
Frank Tang1f164ee2022-11-08 12:31:27 -08001437 rp->r_tod = gethms(dp, _("invalid time of day"), false);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001438 free(dp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001439 /*
1440 ** Year work.
1441 */
1442 cp = loyearp;
1443 lp = byword(cp, begin_years);
1444 rp->r_lowasnum = lp == NULL;
1445 if (!rp->r_lowasnum) switch ((int) lp->l_value) {
1446 case YR_MINIMUM:
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001447 rp->r_loyear = ZIC_MIN;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001448 break;
1449 case YR_MAXIMUM:
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001450 rp->r_loyear = ZIC_MAX;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001451 break;
1452 default: /* "cannot happen" */
1453 (void) fprintf(stderr,
1454 _("%s: panic: Invalid l_value %d\n"),
1455 progname, lp->l_value);
1456 exit(EXIT_FAILURE);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001457 } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_loyear) != 1) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001458 error(_("invalid starting year"));
1459 return;
1460 }
1461 cp = hiyearp;
1462 lp = byword(cp, end_years);
1463 rp->r_hiwasnum = lp == NULL;
1464 if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
1465 case YR_MINIMUM:
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001466 rp->r_hiyear = ZIC_MIN;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001467 break;
1468 case YR_MAXIMUM:
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001469 rp->r_hiyear = ZIC_MAX;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001470 break;
1471 case YR_ONLY:
1472 rp->r_hiyear = rp->r_loyear;
1473 break;
1474 default: /* "cannot happen" */
1475 (void) fprintf(stderr,
1476 _("%s: panic: Invalid l_value %d\n"),
1477 progname, lp->l_value);
1478 exit(EXIT_FAILURE);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001479 } else if (sscanf(cp, scheck(cp, "%"SCNdZIC), &rp->r_hiyear) != 1) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001480 error(_("invalid ending year"));
1481 return;
1482 }
1483 if (rp->r_loyear > rp->r_hiyear) {
1484 error(_("starting year greater than ending year"));
1485 return;
1486 }
1487 if (*typep == '\0')
1488 rp->r_yrtype = NULL;
1489 else {
1490 if (rp->r_loyear == rp->r_hiyear) {
1491 error(_("typed single year"));
1492 return;
1493 }
1494 rp->r_yrtype = ecpyalloc(typep);
1495 }
1496 /*
1497 ** Day work.
1498 ** Accept things such as:
1499 ** 1
1500 ** last-Sunday
1501 ** Sun<=20
1502 ** Sun>=7
1503 */
1504 dp = ecpyalloc(dayp);
1505 if ((lp = byword(dp, lasts)) != NULL) {
1506 rp->r_dycode = DC_DOWLEQ;
1507 rp->r_wday = lp->l_value;
1508 rp->r_dayofmonth = len_months[1][rp->r_month];
1509 } else {
1510 if ((ep = strchr(dp, '<')) != 0)
1511 rp->r_dycode = DC_DOWLEQ;
1512 else if ((ep = strchr(dp, '>')) != 0)
1513 rp->r_dycode = DC_DOWGEQ;
1514 else {
1515 ep = dp;
1516 rp->r_dycode = DC_DOM;
1517 }
1518 if (rp->r_dycode != DC_DOM) {
1519 *ep++ = 0;
1520 if (*ep++ != '=') {
1521 error(_("invalid day of month"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001522 free(dp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001523 return;
1524 }
1525 if ((lp = byword(dp, wday_names)) == NULL) {
1526 error(_("invalid weekday name"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001527 free(dp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001528 return;
1529 }
1530 rp->r_wday = lp->l_value;
1531 }
1532 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1533 rp->r_dayofmonth <= 0 ||
1534 (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1535 error(_("invalid day of month"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001536 free(dp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001537 return;
1538 }
1539 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001540 free(dp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001541}
1542
1543static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001544convert(const int_fast32_t val, char *const buf)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001545{
1546 register int i;
1547 register int shift;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001548 unsigned char *const b = (unsigned char *) buf;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001549
1550 for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001551 b[i] = val >> shift;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001552}
1553
1554static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001555convert64(const zic_t val, char *const buf)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001556{
1557 register int i;
1558 register int shift;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001559 unsigned char *const b = (unsigned char *) buf;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001560
1561 for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001562 b[i] = val >> shift;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001563}
1564
1565static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001566puttzcode(const int_fast32_t val, FILE *const fp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001567{
1568 char buf[4];
1569
1570 convert(val, buf);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001571 (void) fwrite(buf, sizeof buf, 1, fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001572}
1573
1574static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001575puttzcode64(const zic_t val, FILE *const fp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001576{
1577 char buf[8];
1578
1579 convert64(val, buf);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001580 (void) fwrite(buf, sizeof buf, 1, fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001581}
1582
1583static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001584atcomp(const void *avp, const void *bvp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001585{
1586 const zic_t a = ((const struct attype *) avp)->at;
1587 const zic_t b = ((const struct attype *) bvp)->at;
1588
1589 return (a < b) ? -1 : (a > b);
1590}
1591
1592static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001593is32(const zic_t x)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001594{
1595 return INT32_MIN <= x && x <= INT32_MAX;
1596}
1597
1598static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001599writezone(const char *const name, const char *const string, char version)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001600{
1601 register FILE * fp;
1602 register int i, j;
1603 register int leapcnt32, leapi32;
1604 register int timecnt32, timei32;
1605 register int pass;
1606 static char * fullname;
1607 static const struct tzhead tzh0;
1608 static struct tzhead tzh;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001609 zic_t *ats = emalloc(size_product(timecnt, sizeof *ats + 1));
1610 void *typesptr = ats + timecnt;
1611 unsigned char *types = typesptr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001612
1613 /*
1614 ** Sort.
1615 */
1616 if (timecnt > 1)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001617 (void) qsort(attypes, timecnt, sizeof *attypes, atcomp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001618 /*
1619 ** Optimize.
1620 */
1621 {
1622 int fromi;
1623 int toi;
1624
1625 toi = 0;
1626 fromi = 0;
1627 while (fromi < timecnt && attypes[fromi].at < min_time)
1628 ++fromi;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001629 /*
1630 ** Remember that type 0 is reserved.
1631 */
1632 if (isdsts[1] == 0)
1633 while (fromi < timecnt && attypes[fromi].type == 1)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001634 ++fromi; /* handled by default rule */
1635 for ( ; fromi < timecnt; ++fromi) {
1636 if (toi != 0 && ((attypes[fromi].at +
1637 gmtoffs[attypes[toi - 1].type]) <=
1638 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
1639 : attypes[toi - 2].type]))) {
1640 attypes[toi - 1].type =
1641 attypes[fromi].type;
1642 continue;
1643 }
1644 if (toi == 0 ||
1645 attypes[toi - 1].type != attypes[fromi].type)
1646 attypes[toi++] = attypes[fromi];
1647 }
1648 timecnt = toi;
1649 }
1650 /*
1651 ** Transfer.
1652 */
1653 for (i = 0; i < timecnt; ++i) {
1654 ats[i] = attypes[i].at;
1655 types[i] = attypes[i].type;
1656 }
1657 /*
1658 ** Correct for leap seconds.
1659 */
1660 for (i = 0; i < timecnt; ++i) {
1661 j = leapcnt;
1662 while (--j >= 0)
1663 if (ats[i] > trans[j] - corr[j]) {
1664 ats[i] = tadd(ats[i], corr[j]);
1665 break;
1666 }
1667 }
1668 /*
1669 ** Figure out 32-bit-limited starts and counts.
1670 */
1671 timecnt32 = timecnt;
1672 timei32 = 0;
1673 leapcnt32 = leapcnt;
1674 leapi32 = 0;
1675 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
1676 --timecnt32;
1677 while (timecnt32 > 0 && !is32(ats[timei32])) {
1678 --timecnt32;
1679 ++timei32;
1680 }
1681 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
1682 --leapcnt32;
1683 while (leapcnt32 > 0 && !is32(trans[leapi32])) {
1684 --leapcnt32;
1685 ++leapi32;
1686 }
1687 fullname = erealloc(fullname,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001688 strlen(directory) + 1 + strlen(name) + 1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001689 (void) sprintf(fullname, "%s/%s", directory, name);
1690 /*
1691 ** Remove old file, if any, to snap links.
1692 */
1693 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
1694 const char *e = strerror(errno);
1695
1696 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
1697 progname, fullname, e);
1698 exit(EXIT_FAILURE);
1699 }
1700 if ((fp = fopen(fullname, "wb")) == NULL) {
1701 if (mkdirs(fullname) != 0)
1702 exit(EXIT_FAILURE);
1703 if ((fp = fopen(fullname, "wb")) == NULL) {
1704 const char *e = strerror(errno);
1705
1706 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
1707 progname, fullname, e);
1708 exit(EXIT_FAILURE);
1709 }
1710 }
1711 for (pass = 1; pass <= 2; ++pass) {
1712 register int thistimei, thistimecnt;
1713 register int thisleapi, thisleapcnt;
1714 register int thistimelim, thisleaplim;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001715 int writetype[TZ_MAX_TYPES];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001716 int typemap[TZ_MAX_TYPES];
1717 register int thistypecnt;
1718 char thischars[TZ_MAX_CHARS];
1719 char thischarcnt;
1720 int indmap[TZ_MAX_CHARS];
1721
1722 if (pass == 1) {
1723 thistimei = timei32;
1724 thistimecnt = timecnt32;
1725 thisleapi = leapi32;
1726 thisleapcnt = leapcnt32;
1727 } else {
1728 thistimei = 0;
1729 thistimecnt = timecnt;
1730 thisleapi = 0;
1731 thisleapcnt = leapcnt;
1732 }
1733 thistimelim = thistimei + thistimecnt;
1734 thisleaplim = thisleapi + thisleapcnt;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001735 /*
1736 ** Remember that type 0 is reserved.
1737 */
Frank Tang1f164ee2022-11-08 12:31:27 -08001738 writetype[0] = false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001739 for (i = 1; i < typecnt; ++i)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001740 writetype[i] = thistimecnt == timecnt;
1741 if (thistimecnt == 0) {
1742 /*
1743 ** No transition times fall in the current
1744 ** (32- or 64-bit) window.
1745 */
1746 if (typecnt != 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001747 writetype[typecnt - 1] = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001748 } else {
1749 for (i = thistimei - 1; i < thistimelim; ++i)
1750 if (i >= 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001751 writetype[types[i]] = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001752 /*
1753 ** For America/Godthab and Antarctica/Palmer
1754 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001755 /*
1756 ** Remember that type 0 is reserved.
1757 */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001758 if (thistimei == 0)
Frank Tang1f164ee2022-11-08 12:31:27 -08001759 writetype[1] = true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001760 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001761#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
1762 /*
1763 ** For some pre-2011 systems: if the last-to-be-written
1764 ** standard (or daylight) type has an offset different from the
1765 ** most recently used offset,
1766 ** append an (unused) copy of the most recently used type
1767 ** (to help get global "altzone" and "timezone" variables
1768 ** set correctly).
1769 */
1770 {
1771 register int mrudst, mrustd, hidst, histd, type;
1772
1773 hidst = histd = mrudst = mrustd = -1;
1774 for (i = thistimei; i < thistimelim; ++i)
1775 if (isdsts[types[i]])
1776 mrudst = types[i];
1777 else mrustd = types[i];
1778 for (i = 0; i < typecnt; ++i)
1779 if (writetype[i]) {
1780 if (isdsts[i])
1781 hidst = i;
1782 else histd = i;
1783 }
1784 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
1785 gmtoffs[hidst] != gmtoffs[mrudst]) {
1786 isdsts[mrudst] = -1;
1787 type = addtype(gmtoffs[mrudst],
1788#ifdef ICU
1789 rawoffs[mrudst], dstoffs[mrudst],
1790#endif
1791 &chars[abbrinds[mrudst]],
Frank Tang1f164ee2022-11-08 12:31:27 -08001792 true,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001793 ttisstds[mrudst],
1794 ttisgmts[mrudst]);
Frank Tang1f164ee2022-11-08 12:31:27 -08001795 isdsts[mrudst] = true;
1796 writetype[type] = true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001797 }
1798 if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
1799 gmtoffs[histd] != gmtoffs[mrustd]) {
1800 isdsts[mrustd] = -1;
1801 type = addtype(gmtoffs[mrustd],
1802#ifdef ICU
1803 rawoffs[mrudst], dstoffs[mrudst],
1804#endif
1805 &chars[abbrinds[mrustd]],
Frank Tang1f164ee2022-11-08 12:31:27 -08001806 false,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001807 ttisstds[mrustd],
1808 ttisgmts[mrustd]);
Frank Tang1f164ee2022-11-08 12:31:27 -08001809 isdsts[mrustd] = false;
1810 writetype[type] = true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001811 }
1812 }
1813#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001814 thistypecnt = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001815 /*
1816 ** Potentially, set type 0 to that of lowest-valued time.
1817 */
1818 if (thistimei > 0) {
1819 for (i = 1; i < typecnt; ++i)
1820 if (writetype[i] && !isdsts[i])
1821 break;
1822 if (i != types[thistimei - 1]) {
1823 i = types[thistimei - 1];
1824 gmtoffs[0] = gmtoffs[i];
1825 isdsts[0] = isdsts[i];
1826 ttisstds[0] = ttisstds[i];
1827 ttisgmts[0] = ttisgmts[i];
1828 abbrinds[0] = abbrinds[i];
Frank Tang1f164ee2022-11-08 12:31:27 -08001829 writetype[0] = true;
1830 writetype[i] = false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001831 }
1832 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001833 for (i = 0; i < typecnt; ++i)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001834 typemap[i] = writetype[i] ? thistypecnt++ : 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001835 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
1836 indmap[i] = -1;
1837 thischarcnt = 0;
1838 for (i = 0; i < typecnt; ++i) {
1839 register char * thisabbr;
1840
1841 if (!writetype[i])
1842 continue;
1843 if (indmap[abbrinds[i]] >= 0)
1844 continue;
1845 thisabbr = &chars[abbrinds[i]];
1846 for (j = 0; j < thischarcnt; ++j)
1847 if (strcmp(&thischars[j], thisabbr) == 0)
1848 break;
1849 if (j == thischarcnt) {
1850 (void) strcpy(&thischars[(int) thischarcnt],
1851 thisabbr);
1852 thischarcnt += strlen(thisabbr) + 1;
1853 }
1854 indmap[abbrinds[i]] = j;
1855 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001856#define DO(field) ((void) fwrite(tzh.field, sizeof tzh.field, 1, fp))
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001857 tzh = tzh0;
1858#ifdef ICU
1859 * (ICUZoneinfoVersion*) &tzh.tzh_reserved = TZ_ICU_VERSION;
1860 (void) strncpy(tzh.tzh_magic, TZ_ICU_MAGIC, sizeof tzh.tzh_magic);
1861#else
1862 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1863#endif
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001864 tzh.tzh_version[0] = version;
1865 convert(thistypecnt, tzh.tzh_ttisgmtcnt);
1866 convert(thistypecnt, tzh.tzh_ttisstdcnt);
1867 convert(thisleapcnt, tzh.tzh_leapcnt);
1868 convert(thistimecnt, tzh.tzh_timecnt);
1869 convert(thistypecnt, tzh.tzh_typecnt);
1870 convert(thischarcnt, tzh.tzh_charcnt);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001871 DO(tzh_magic);
1872 DO(tzh_version);
1873 DO(tzh_reserved);
1874 DO(tzh_ttisgmtcnt);
1875 DO(tzh_ttisstdcnt);
1876 DO(tzh_leapcnt);
1877 DO(tzh_timecnt);
1878 DO(tzh_typecnt);
1879 DO(tzh_charcnt);
1880#undef DO
1881 for (i = thistimei; i < thistimelim; ++i)
1882 if (pass == 1)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001883 puttzcode(ats[i], fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001884 else puttzcode64(ats[i], fp);
1885 for (i = thistimei; i < thistimelim; ++i) {
1886 unsigned char uc;
1887
1888 uc = typemap[types[i]];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001889 (void) fwrite(&uc, sizeof uc, 1, fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001890 }
1891 for (i = 0; i < typecnt; ++i)
1892 if (writetype[i]) {
1893#ifdef ICU
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001894 puttzcode(rawoffs[i], fp);
1895 puttzcode(dstoffs[i], fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001896#else
1897 puttzcode(gmtoffs[i], fp);
1898#endif
1899 (void) putc(isdsts[i], fp);
1900 (void) putc((unsigned char) indmap[abbrinds[i]], fp);
1901 }
1902 if (thischarcnt != 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001903 (void) fwrite(thischars, sizeof thischars[0],
1904 thischarcnt, fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001905 for (i = thisleapi; i < thisleaplim; ++i) {
1906 register zic_t todo;
1907
1908 if (roll[i]) {
1909 if (timecnt == 0 || trans[i] < ats[0]) {
1910 j = 0;
1911 while (isdsts[j])
1912 if (++j >= typecnt) {
1913 j = 0;
1914 break;
1915 }
1916 } else {
1917 j = 1;
1918 while (j < timecnt &&
1919 trans[i] >= ats[j])
1920 ++j;
1921 j = types[j - 1];
1922 }
1923 todo = tadd(trans[i], -gmtoffs[j]);
1924 } else todo = trans[i];
1925 if (pass == 1)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001926 puttzcode(todo, fp);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001927 else puttzcode64(todo, fp);
1928 puttzcode(corr[i], fp);
1929 }
1930 for (i = 0; i < typecnt; ++i)
1931 if (writetype[i])
1932 (void) putc(ttisstds[i], fp);
1933 for (i = 0; i < typecnt; ++i)
1934 if (writetype[i])
1935 (void) putc(ttisgmts[i], fp);
1936 }
1937 (void) fprintf(fp, "\n%s\n", string);
1938 if (ferror(fp) || fclose(fp)) {
1939 (void) fprintf(stderr, _("%s: Error writing %s\n"),
1940 progname, fullname);
1941 exit(EXIT_FAILURE);
1942 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001943 free(ats);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001944}
1945
1946static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001947doabbr(char *const abbr, const char *const format, const char *const letters,
1948 const int isdst, const int doquotes)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001949{
1950 register char * cp;
1951 register char * slashp;
1952 register int len;
1953
1954 slashp = strchr(format, '/');
1955 if (slashp == NULL) {
1956 if (letters == NULL)
1957 (void) strcpy(abbr, format);
1958 else (void) sprintf(abbr, format, letters);
1959 } else if (isdst) {
1960 (void) strcpy(abbr, slashp + 1);
1961 } else {
1962 if (slashp > format)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001963 (void) strncpy(abbr, format, slashp - format);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001964 abbr[slashp - format] = '\0';
1965 }
1966 if (!doquotes)
1967 return;
1968 for (cp = abbr; *cp != '\0'; ++cp)
1969 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
1970 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
1971 break;
1972 len = strlen(abbr);
1973 if (len > 0 && *cp == '\0')
1974 return;
1975 abbr[len + 2] = '\0';
1976 abbr[len + 1] = '>';
1977 for ( ; len > 0; --len)
1978 abbr[len] = abbr[len - 1];
1979 abbr[0] = '<';
1980}
1981
1982static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001983updateminmax(const zic_t x)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001984{
1985 if (min_year > x)
1986 min_year = x;
1987 if (max_year < x)
1988 max_year = x;
1989}
1990
1991static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001992stringoffset(char *result, zic_t offset)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001993{
1994 register int hours;
1995 register int minutes;
1996 register int seconds;
1997
1998 result[0] = '\0';
1999 if (offset < 0) {
2000 (void) strcpy(result, "-");
2001 offset = -offset;
2002 }
2003 seconds = offset % SECSPERMIN;
2004 offset /= SECSPERMIN;
2005 minutes = offset % MINSPERHOUR;
2006 offset /= MINSPERHOUR;
2007 hours = offset;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002008 if (hours >= HOURSPERDAY * DAYSPERWEEK) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002009 result[0] = '\0';
2010 return -1;
2011 }
2012 (void) sprintf(end(result), "%d", hours);
2013 if (minutes != 0 || seconds != 0) {
2014 (void) sprintf(end(result), ":%02d", minutes);
2015 if (seconds != 0)
2016 (void) sprintf(end(result), ":%02d", seconds);
2017 }
2018 return 0;
2019}
2020
2021static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002022stringrule(char *result, const struct rule *const rp, const zic_t dstoff,
2023 const zic_t gmtoff)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002024{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002025 register zic_t tod = rp->r_tod;
2026 register int compat = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002027
2028 result = end(result);
2029 if (rp->r_dycode == DC_DOM) {
2030 register int month, total;
2031
2032 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
2033 return -1;
2034 total = 0;
2035 for (month = 0; month < rp->r_month; ++month)
2036 total += len_months[0][month];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002037 /* Omit the "J" in Jan and Feb, as that's shorter. */
2038 if (rp->r_month <= 1)
2039 (void) sprintf(result, "%d", total + rp->r_dayofmonth - 1);
2040 else
2041 (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002042 } else {
2043 register int week;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002044 register int wday = rp->r_wday;
2045 register int wdayoff;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002046
2047 if (rp->r_dycode == DC_DOWGEQ) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002048 wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK;
2049 if (wdayoff)
2050 compat = 2013;
2051 wday -= wdayoff;
2052 tod += wdayoff * SECSPERDAY;
2053 week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002054 } else if (rp->r_dycode == DC_DOWLEQ) {
2055 if (rp->r_dayofmonth == len_months[1][rp->r_month])
2056 week = 5;
2057 else {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002058 wdayoff = rp->r_dayofmonth % DAYSPERWEEK;
2059 if (wdayoff)
2060 compat = 2013;
2061 wday -= wdayoff;
2062 tod += wdayoff * SECSPERDAY;
2063 week = rp->r_dayofmonth / DAYSPERWEEK;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002064 }
2065 } else return -1; /* "cannot happen" */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002066 if (wday < 0)
2067 wday += DAYSPERWEEK;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002068 (void) sprintf(result, "M%d.%d.%d",
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002069 rp->r_month + 1, week, wday);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002070 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002071 if (rp->r_todisgmt)
2072 tod += gmtoff;
2073 if (rp->r_todisstd && rp->r_stdoff == 0)
2074 tod += dstoff;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002075 if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
2076 (void) strcat(result, "/");
2077 if (stringoffset(end(result), tod) != 0)
2078 return -1;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002079 if (tod < 0) {
2080 if (compat < 2013)
2081 compat = 2013;
2082 } else if (SECSPERDAY <= tod) {
2083 if (compat < 1994)
2084 compat = 1994;
2085 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002086 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002087 return compat;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002088}
2089
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002090static int
2091rule_cmp(struct rule const *a, struct rule const *b)
2092{
2093 if (!a)
2094 return -!!b;
2095 if (!b)
2096 return 1;
2097 if (a->r_hiyear != b->r_hiyear)
2098 return a->r_hiyear < b->r_hiyear ? -1 : 1;
2099 if (a->r_month - b->r_month != 0)
2100 return a->r_month - b->r_month;
2101 return a->r_dayofmonth - b->r_dayofmonth;
2102}
2103
2104enum { YEAR_BY_YEAR_ZONE = 1 };
2105
2106static int
2107stringzone(char *result, const struct zone *const zpfirst, const int zonecount)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002108{
2109 register const struct zone * zp;
2110 register struct rule * rp;
2111 register struct rule * stdrp;
2112 register struct rule * dstrp;
2113 register int i;
2114 register const char * abbrvar;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002115 register int compat = 0;
2116 register int c;
2117 struct rule stdr, dstr;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002118
2119 result[0] = '\0';
2120 zp = zpfirst + zonecount - 1;
2121 stdrp = dstrp = NULL;
2122 for (i = 0; i < zp->z_nrules; ++i) {
2123 rp = &zp->z_rules[i];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002124 if (rp->r_hiwasnum || rp->r_hiyear != ZIC_MAX)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002125 continue;
2126 if (rp->r_yrtype != NULL)
2127 continue;
2128 if (rp->r_stdoff == 0) {
2129 if (stdrp == NULL)
2130 stdrp = rp;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002131 else return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002132 } else {
2133 if (dstrp == NULL)
2134 dstrp = rp;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002135 else return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002136 }
2137 }
2138 if (stdrp == NULL && dstrp == NULL) {
2139 /*
2140 ** There are no rules running through "max".
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002141 ** Find the latest std rule in stdabbrrp
2142 ** and latest rule of any type in stdrp.
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002143 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002144 register struct rule *stdabbrrp = NULL;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002145 for (i = 0; i < zp->z_nrules; ++i) {
2146 rp = &zp->z_rules[i];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002147 if (rp->r_stdoff == 0 && rule_cmp(stdabbrrp, rp) < 0)
2148 stdabbrrp = rp;
2149 if (rule_cmp(stdrp, rp) < 0)
2150 stdrp = rp;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002151 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002152 /*
2153 ** Horrid special case: if year is 2037,
2154 ** presume this is a zone handled on a year-by-year basis;
2155 ** do not try to apply a rule to the zone.
2156 */
2157 if (stdrp != NULL && stdrp->r_hiyear == 2037)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002158 return YEAR_BY_YEAR_ZONE;
2159
2160 if (stdrp != NULL && stdrp->r_stdoff != 0) {
2161 /* Perpetual DST. */
2162 dstr.r_month = TM_JANUARY;
2163 dstr.r_dycode = DC_DOM;
2164 dstr.r_dayofmonth = 1;
2165 dstr.r_tod = 0;
Frank Tang1f164ee2022-11-08 12:31:27 -08002166 dstr.r_todisstd = dstr.r_todisgmt = false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002167 dstr.r_stdoff = stdrp->r_stdoff;
2168 dstr.r_abbrvar = stdrp->r_abbrvar;
2169 stdr.r_month = TM_DECEMBER;
2170 stdr.r_dycode = DC_DOM;
2171 stdr.r_dayofmonth = 31;
2172 stdr.r_tod = SECSPERDAY + stdrp->r_stdoff;
Frank Tang1f164ee2022-11-08 12:31:27 -08002173 stdr.r_todisstd = stdr.r_todisgmt = false;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002174 stdr.r_stdoff = 0;
2175 stdr.r_abbrvar
2176 = (stdabbrrp ? stdabbrrp->r_abbrvar : "");
2177 dstrp = &dstr;
2178 stdrp = &stdr;
2179 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002180 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002181 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
2182 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002183 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
Frank Tang1f164ee2022-11-08 12:31:27 -08002184 doabbr(result, zp->z_format, abbrvar, false, true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002185 if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
2186 result[0] = '\0';
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002187 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002188 }
2189 if (dstrp == NULL)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002190 return compat;
Frank Tang1f164ee2022-11-08 12:31:27 -08002191 doabbr(end(result), zp->z_format, dstrp->r_abbrvar, true, true);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002192 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
2193 if (stringoffset(end(result),
2194 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
2195 result[0] = '\0';
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002196 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002197 }
2198 (void) strcat(result, ",");
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002199 c = stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff);
2200 if (c < 0) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002201 result[0] = '\0';
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002202 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002203 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002204 if (compat < c)
2205 compat = c;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002206 (void) strcat(result, ",");
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002207 c = stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff);
2208 if (c < 0) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002209 result[0] = '\0';
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002210 return -1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002211 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002212 if (compat < c)
2213 compat = c;
2214 return compat;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002215}
2216
2217static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002218outzone(const struct zone * const zpfirst, const int zonecount)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002219{
2220 register const struct zone * zp;
2221 register struct rule * rp;
2222 register int i, j;
2223 register int usestart, useuntil;
2224 register zic_t starttime, untiltime;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002225 register zic_t gmtoff;
2226 register zic_t stdoff;
2227 register zic_t year;
2228 register zic_t startoff;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002229 register int startttisstd;
2230 register int startttisgmt;
2231 register int type;
2232 register char * startbuf;
2233 register char * ab;
2234 register char * envvar;
2235 register int max_abbr_len;
2236 register int max_envvar_len;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002237 register int prodstic; /* all rules are min to max */
2238 register int compat;
2239 register int do_extend;
2240 register char version;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002241#ifdef ICU
2242 int finalRuleYear, finalRuleIndex;
2243 const struct rule* finalRule1;
2244 const struct rule* finalRule2;
2245#endif
2246
2247 max_abbr_len = 2 + max_format_len + max_abbrvar_len;
2248 max_envvar_len = 2 * max_abbr_len + 5 * 9;
2249 startbuf = emalloc(max_abbr_len + 1);
2250 ab = emalloc(max_abbr_len + 1);
2251 envvar = emalloc(max_envvar_len + 1);
2252 INITIALIZE(untiltime);
2253 INITIALIZE(starttime);
2254 /*
2255 ** Now. . .finally. . .generate some useful data!
2256 */
2257 timecnt = 0;
2258 typecnt = 0;
2259 charcnt = 0;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002260 prodstic = zonecount == 1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002261 /*
2262 ** Thanks to Earl Chew
2263 ** for noting the need to unconditionally initialize startttisstd.
2264 */
Frank Tang1f164ee2022-11-08 12:31:27 -08002265 startttisstd = false;
2266 startttisgmt = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002267 min_year = max_year = EPOCH_YEAR;
2268 if (leapseen) {
2269 updateminmax(leapminyear);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002270 updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002271 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002272 /*
2273 ** Reserve type 0.
2274 */
2275 gmtoffs[0] = isdsts[0] = ttisstds[0] = ttisgmts[0] = abbrinds[0] = -1;
2276 typecnt = 1;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002277 for (i = 0; i < zonecount; ++i) {
2278 zp = &zpfirst[i];
2279 if (i < zonecount - 1)
2280 updateminmax(zp->z_untilrule.r_loyear);
2281 for (j = 0; j < zp->z_nrules; ++j) {
2282 rp = &zp->z_rules[j];
2283 if (rp->r_lowasnum)
2284 updateminmax(rp->r_loyear);
2285 if (rp->r_hiwasnum)
2286 updateminmax(rp->r_hiyear);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002287 if (rp->r_lowasnum || rp->r_hiwasnum)
Frank Tang1f164ee2022-11-08 12:31:27 -08002288 prodstic = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002289 }
2290 }
2291 /*
2292 ** Generate lots of data if a rule can't cover all future times.
2293 */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002294 compat = stringzone(envvar, zpfirst, zonecount);
2295 version = compat < 2013 ? ZIC_VERSION_PRE_2013 : ZIC_VERSION;
2296 do_extend = compat < 0 || compat == YEAR_BY_YEAR_ZONE;
2297#ifdef ICU
2298 do_extend = 0;
2299#endif
2300 if (noise) {
2301 if (!*envvar)
2302 warning("%s %s",
2303 _("no POSIX environment variable for zone"),
2304 zpfirst->z_name);
2305 else if (compat != 0 && compat != YEAR_BY_YEAR_ZONE) {
2306 /* Circa-COMPAT clients, and earlier clients, might
2307 not work for this zone when given dates before
2308 1970 or after 2038. */
2309 warning(_("%s: pre-%d clients may mishandle"
2310 " distant timestamps"),
2311 zpfirst->z_name, compat);
2312 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002313 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002314 if (do_extend) {
2315 /*
2316 ** Search through a couple of extra years past the obvious
2317 ** 400, to avoid edge cases. For example, suppose a non-POSIX
2318 ** rule applies from 2012 onwards and has transitions in March
2319 ** and September, plus some one-off transitions in November
2320 ** 2013. If zic looked only at the last 400 years, it would
2321 ** set max_year=2413, with the intent that the 400 years 2014
2322 ** through 2413 will be repeated. The last transition listed
2323 ** in the tzfile would be in 2413-09, less than 400 years
2324 ** after the last one-off transition in 2013-11. Two years
2325 ** might be overkill, but with the kind of edge cases
2326 ** available we're not sure that one year would suffice.
2327 */
2328 enum { years_of_observations = YEARSPERREPEAT + 2 };
2329
2330 if (min_year >= ZIC_MIN + years_of_observations)
2331 min_year -= years_of_observations;
2332 else min_year = ZIC_MIN;
2333 if (max_year <= ZIC_MAX - years_of_observations)
2334 max_year += years_of_observations;
2335 else max_year = ZIC_MAX;
2336 /*
2337 ** Regardless of any of the above,
2338 ** for a "proDSTic" zone which specifies that its rules
2339 ** always have and always will be in effect,
2340 ** we only need one cycle to define the zone.
2341 */
2342 if (prodstic) {
2343 min_year = 1900;
2344 max_year = min_year + years_of_observations;
2345 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002346 }
2347 /*
2348 ** For the benefit of older systems,
2349 ** generate data from 1900 through 2037.
2350 */
2351 if (min_year > 1900)
2352 min_year = 1900;
2353 if (max_year < 2037)
2354 max_year = 2037;
2355 for (i = 0; i < zonecount; ++i) {
2356 /*
2357 ** A guess that may well be corrected later.
2358 */
2359 stdoff = 0;
2360 zp = &zpfirst[i];
2361 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
2362 useuntil = i < (zonecount - 1);
2363 if (useuntil && zp->z_untiltime <= min_time)
2364 continue;
2365 gmtoff = zp->z_gmtoff;
2366 eat(zp->z_filename, zp->z_linenum);
2367 *startbuf = '\0';
2368 startoff = zp->z_gmtoff;
2369#ifdef ICU
2370 finalRuleYear = finalRuleIndex = -1;
2371 finalRule1 = finalRule2 = NULL;
2372 if (i == (zonecount - 1)) { /* !useuntil */
2373 /* Look for exactly 2 rules that end at 'max' and
2374 * note them. Determine max(r_loyear) for the 2 of
2375 * them. */
2376 for (j=0; j<zp->z_nrules; ++j) {
2377 rp = &zp->z_rules[j];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002378 if (rp->r_hiyear == ZIC_MAX) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002379 if (rp->r_loyear > finalRuleYear) {
2380 finalRuleYear = rp->r_loyear;
2381 }
2382 if (finalRule1 == NULL) {
2383 finalRule1 = rp;
2384 } else if (finalRule2 == NULL) {
2385 finalRule2 = rp;
2386 } else {
2387 error("more than two max rules found (ICU)");
2388 exit(EXIT_FAILURE);
2389 }
2390 } else if (rp->r_hiyear >= finalRuleYear) {
2391 /* There might be an overriding non-max rule
2392 * to be applied to a specific year after one of
2393 * max rule's start year. For example,
2394 *
2395 * Rule Foo 2010 max ...
2396 * Rule Foo 2015 only ...
2397 *
2398 * In this case, we need to change the start year of
2399 * the final (max) rules to the next year. */
2400 finalRuleYear = rp->r_hiyear + 1;
2401
2402 /* When above adjustment is done, max_year might need
2403 * to be adjusted, so the final rule will be properly
2404 * evaluated and emitted by the later code block.
2405 *
2406 * Note: This may push the start year of the final
2407 * rules ahead by 1 year unnecessarily. For example,
2408 * If there are two rules, non-max rule and max rule
2409 * starting in the same year, such as
2410 *
2411 * Rule Foo 2010 only ....
2412 * Rule Foo 2010 max ....
2413 *
2414 * In this case, the final (max) rule actually starts
2415 * in 2010, instead of 2010. We could make this tool
2416 * more intelligent to detect such situation. But pushing
2417 * final rule start year to 1 year ahead (in the worst case)
2418 * will just populate a few extra transitions, and it still
2419 * works fine. So for now, we're not trying to put additional
2420 * logic to optimize the case.
2421 */
2422 if (max_year < finalRuleYear) {
2423 max_year = finalRuleYear;
2424 }
2425 }
2426 }
2427 if (finalRule1 != NULL) {
2428 if (finalRule2 == NULL) {
2429 warning("only one max rule found (ICU)");
2430 finalRuleYear = finalRuleIndex = -1;
2431 finalRule1 = NULL;
2432 } else {
2433 if (finalRule1->r_stdoff == finalRule2->r_stdoff) {
2434 /* America/Resolute in 2009a uses a pair of rules
2435 * which does not change the offset. ICU ignores
2436 * such rules without actual time transitions. */
2437 finalRuleYear = finalRuleIndex = -1;
2438 finalRule1 = finalRule2 = NULL;
2439 } else {
2440 /* Swap if necessary so finalRule1 occurs before
2441 * finalRule2 */
2442 if (finalRule1->r_month > finalRule2->r_month) {
2443 const struct rule* t = finalRule1;
2444 finalRule1 = finalRule2;
2445 finalRule2 = t;
2446 }
2447 /* Add final rule to our list */
2448 finalRuleIndex = add_icu_final_rules(finalRule1, finalRule2);
2449 }
2450 }
2451 }
2452 }
2453#endif
2454
2455 if (zp->z_nrules == 0) {
2456 stdoff = zp->z_stdoff;
2457 doabbr(startbuf, zp->z_format,
Frank Tang1f164ee2022-11-08 12:31:27 -08002458 NULL, stdoff != 0, false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002459 type = addtype(oadd(zp->z_gmtoff, stdoff),
2460#ifdef ICU
2461 zp->z_gmtoff, stdoff,
2462#endif
2463 startbuf, stdoff != 0, startttisstd,
2464 startttisgmt);
2465 if (usestart) {
2466 addtt(starttime, type);
Frank Tang1f164ee2022-11-08 12:31:27 -08002467 usestart = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002468 } else if (stdoff != 0)
2469 addtt(min_time, type);
2470 } else for (year = min_year; year <= max_year; ++year) {
2471 if (useuntil && year > zp->z_untilrule.r_hiyear)
2472 break;
2473 /*
2474 ** Mark which rules to do in the current year.
2475 ** For those to do, calculate rpytime(rp, year);
2476 */
2477 for (j = 0; j < zp->z_nrules; ++j) {
2478 rp = &zp->z_rules[j];
2479 eats(zp->z_filename, zp->z_linenum,
2480 rp->r_filename, rp->r_linenum);
2481 rp->r_todo = year >= rp->r_loyear &&
2482 year <= rp->r_hiyear &&
2483 yearistype(year, rp->r_yrtype);
2484 if (rp->r_todo)
2485 rp->r_temp = rpytime(rp, year);
2486 }
2487 for ( ; ; ) {
2488 register int k;
2489 register zic_t jtime, ktime;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002490 register zic_t offset;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002491
2492 INITIALIZE(ktime);
2493 if (useuntil) {
2494 /*
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002495 ** Turn untiltime into UT
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002496 ** assuming the current gmtoff and
2497 ** stdoff values.
2498 */
2499 untiltime = zp->z_untiltime;
2500 if (!zp->z_untilrule.r_todisgmt)
2501 untiltime = tadd(untiltime,
2502 -gmtoff);
2503 if (!zp->z_untilrule.r_todisstd)
2504 untiltime = tadd(untiltime,
2505 -stdoff);
2506 }
2507 /*
2508 ** Find the rule (of those to do, if any)
2509 ** that takes effect earliest in the year.
2510 */
2511 k = -1;
2512 for (j = 0; j < zp->z_nrules; ++j) {
2513 rp = &zp->z_rules[j];
2514 if (!rp->r_todo)
2515 continue;
2516 eats(zp->z_filename, zp->z_linenum,
2517 rp->r_filename, rp->r_linenum);
2518 offset = rp->r_todisgmt ? 0 : gmtoff;
2519 if (!rp->r_todisstd)
2520 offset = oadd(offset, stdoff);
2521 jtime = rp->r_temp;
2522 if (jtime == min_time ||
2523 jtime == max_time)
2524 continue;
2525 jtime = tadd(jtime, -offset);
2526 if (k < 0 || jtime < ktime) {
2527 k = j;
2528 ktime = jtime;
2529 }
2530 }
2531 if (k < 0)
2532 break; /* go on to next year */
2533 rp = &zp->z_rules[k];
Frank Tang1f164ee2022-11-08 12:31:27 -08002534 rp->r_todo = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002535 if (useuntil && ktime >= untiltime)
2536 break;
2537 stdoff = rp->r_stdoff;
2538 if (usestart && ktime == starttime)
Frank Tang1f164ee2022-11-08 12:31:27 -08002539 usestart = false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002540 if (usestart) {
2541 if (ktime < starttime) {
2542 startoff = oadd(zp->z_gmtoff,
2543 stdoff);
2544 doabbr(startbuf, zp->z_format,
2545 rp->r_abbrvar,
2546 rp->r_stdoff != 0,
Frank Tang1f164ee2022-11-08 12:31:27 -08002547 false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002548 continue;
2549 }
2550 if (*startbuf == '\0' &&
2551 startoff == oadd(zp->z_gmtoff,
2552 stdoff)) {
2553 doabbr(startbuf,
2554 zp->z_format,
2555 rp->r_abbrvar,
2556 rp->r_stdoff !=
2557 0,
Frank Tang1f164ee2022-11-08 12:31:27 -08002558 false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002559 }
2560 }
2561#ifdef ICU
2562 if (year >= finalRuleYear && rp == finalRule1) {
2563 /* We want to shift final year 1 year after
2564 * the actual final rule takes effect (year + 1),
2565 * because the previous type is valid until the first
2566 * transition defined by the final rule. Otherwise
2567 * we may see unexpected offset shift at the
Frank Tang7e7574b2021-04-13 21:19:13 -07002568 * beginning of the year when the final rule takes
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002569 * effect.
2570 *
2571 * Note: This may results some 64bit second transitions
2572 * at the very end (year 2038). ICU 4.2 or older releases
2573 * cannot handle 64bit second transitions and they are
2574 * dropped from zoneinfo.txt. */
2575 emit_icu_zone(icuFile,
2576 zpfirst->z_name, zp->z_gmtoff,
2577 rp, finalRuleIndex, year + 1);
2578 /* only emit this for the first year */
2579 finalRule1 = NULL;
2580 }
2581#endif
2582 eats(zp->z_filename, zp->z_linenum,
2583 rp->r_filename, rp->r_linenum);
2584 doabbr(ab, zp->z_format, rp->r_abbrvar,
Frank Tang1f164ee2022-11-08 12:31:27 -08002585 rp->r_stdoff != 0, false);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002586 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
2587#ifdef ICU
2588 type = addtype(offset, zp->z_gmtoff, rp->r_stdoff,
2589 ab, rp->r_stdoff != 0,
2590 rp->r_todisstd, rp->r_todisgmt);
2591#else
2592 type = addtype(offset, ab, rp->r_stdoff != 0,
2593 rp->r_todisstd, rp->r_todisgmt);
2594#endif
2595 addtt(ktime, type);
2596 }
2597 }
2598 if (usestart) {
2599 if (*startbuf == '\0' &&
2600 zp->z_format != NULL &&
2601 strchr(zp->z_format, '%') == NULL &&
2602 strchr(zp->z_format, '/') == NULL)
2603 (void) strcpy(startbuf, zp->z_format);
2604 eat(zp->z_filename, zp->z_linenum);
2605 if (*startbuf == '\0')
2606error(_("can't determine time zone abbreviation to use just after until time"));
2607 else addtt(starttime,
2608#ifdef ICU
2609 addtype(startoff,
2610 zp->z_gmtoff, startoff - zp->z_gmtoff,
2611 startbuf,
2612 startoff != zp->z_gmtoff,
2613 startttisstd,
2614 startttisgmt));
2615#else
2616 addtype(startoff, startbuf,
2617 startoff != zp->z_gmtoff,
2618 startttisstd,
2619 startttisgmt));
2620#endif
2621 }
2622 /*
2623 ** Now we may get to set starttime for the next zone line.
2624 */
2625 if (useuntil) {
2626 startttisstd = zp->z_untilrule.r_todisstd;
2627 startttisgmt = zp->z_untilrule.r_todisgmt;
2628 starttime = zp->z_untiltime;
2629 if (!startttisstd)
2630 starttime = tadd(starttime, -stdoff);
2631 if (!startttisgmt)
2632 starttime = tadd(starttime, -gmtoff);
2633 }
2634 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002635 if (do_extend) {
2636 /*
2637 ** If we're extending the explicitly listed observations
2638 ** for 400 years because we can't fill the POSIX-TZ field,
2639 ** check whether we actually ended up explicitly listing
2640 ** observations through that period. If there aren't any
2641 ** near the end of the 400-year period, add a redundant
2642 ** one at the end of the final year, to make it clear
2643 ** that we are claiming to have definite knowledge of
2644 ** the lack of transitions up to that point.
2645 */
2646 struct rule xr;
2647 struct attype *lastat;
2648 xr.r_month = TM_JANUARY;
2649 xr.r_dycode = DC_DOM;
2650 xr.r_dayofmonth = 1;
2651 xr.r_tod = 0;
2652 for (lastat = &attypes[0], i = 1; i < timecnt; i++)
2653 if (attypes[i].at > lastat->at)
2654 lastat = &attypes[i];
2655 if (lastat->at < rpytime(&xr, max_year - 1)) {
2656 /*
2657 ** Create new type code for the redundant entry,
2658 ** to prevent it being optimised away.
2659 */
2660 if (typecnt >= TZ_MAX_TYPES) {
2661 error(_("too many local time types"));
2662 exit(EXIT_FAILURE);
2663 }
2664 gmtoffs[typecnt] = gmtoffs[lastat->type];
2665 isdsts[typecnt] = isdsts[lastat->type];
2666 ttisstds[typecnt] = ttisstds[lastat->type];
2667 ttisgmts[typecnt] = ttisgmts[lastat->type];
2668 abbrinds[typecnt] = abbrinds[lastat->type];
2669 ++typecnt;
2670 addtt(rpytime(&xr, max_year + 1), typecnt-1);
2671 }
2672 }
2673 writezone(zpfirst->z_name, envvar, version);
2674 free(startbuf);
2675 free(ab);
2676 free(envvar);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002677}
2678
2679static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002680addtt(const zic_t starttime, int type)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002681{
2682 if (starttime <= min_time ||
2683 (timecnt == 1 && attypes[0].at < min_time)) {
2684 gmtoffs[0] = gmtoffs[type];
2685#ifdef ICU
2686 rawoffs[0] = rawoffs[type];
2687 dstoffs[0] = dstoffs[type];
2688#endif
2689 isdsts[0] = isdsts[type];
2690 ttisstds[0] = ttisstds[type];
2691 ttisgmts[0] = ttisgmts[type];
2692 if (abbrinds[type] != 0)
2693 (void) strcpy(chars, &chars[abbrinds[type]]);
2694 abbrinds[0] = 0;
2695 charcnt = strlen(chars) + 1;
2696 typecnt = 1;
2697 timecnt = 0;
2698 type = 0;
2699 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002700 attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002701 attypes[timecnt].at = starttime;
2702 attypes[timecnt].type = type;
2703 ++timecnt;
2704}
2705
2706static int
2707#ifdef ICU
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002708addtype(const zic_t gmtoff, const zic_t rawoff, const zic_t dstoff, char *const abbr, const int isdst,
2709 const int ttisstd, const int ttisgmt)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002710#else
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002711addtype(const zic_t gmtoff, const char *const abbr, const int isdst,
2712 const int ttisstd, const int ttisgmt)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002713#endif
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002714{
2715 register int i, j;
2716
Frank Tang1f164ee2022-11-08 12:31:27 -08002717 if (isdst != true && isdst != false) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002718 error(_("internal error - addtype called with bad isdst"));
2719 exit(EXIT_FAILURE);
2720 }
Frank Tang1f164ee2022-11-08 12:31:27 -08002721 if (ttisstd != true && ttisstd != false) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002722 error(_("internal error - addtype called with bad ttisstd"));
2723 exit(EXIT_FAILURE);
2724 }
Frank Tang1f164ee2022-11-08 12:31:27 -08002725 if (ttisgmt != true && ttisgmt != false) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002726 error(_("internal error - addtype called with bad ttisgmt"));
2727 exit(EXIT_FAILURE);
2728 }
2729#ifdef ICU
2730 if (isdst != (dstoff != 0)) {
2731 error(_("internal error - addtype called with bad isdst/dstoff"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002732 exit(EXIT_FAILURE);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002733 }
2734 if (gmtoff != (rawoff + dstoff)) {
2735 error(_("internal error - addtype called with bad gmt/raw/dstoff"));
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002736 exit(EXIT_FAILURE);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002737 }
2738#endif
2739 /*
2740 ** See if there's already an entry for this zone type.
2741 ** If so, just return its index.
2742 */
2743 for (i = 0; i < typecnt; ++i) {
2744 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
2745#ifdef ICU
2746 rawoff == rawoffs[i] && dstoff == dstoffs[i] &&
2747#endif
2748 strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
2749 ttisstd == ttisstds[i] &&
2750 ttisgmt == ttisgmts[i])
2751 return i;
2752 }
2753 /*
2754 ** There isn't one; add a new one, unless there are already too
2755 ** many.
2756 */
2757 if (typecnt >= TZ_MAX_TYPES) {
2758 error(_("too many local time types"));
2759 exit(EXIT_FAILURE);
2760 }
2761 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002762 error(_("UT offset out of range"));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002763 exit(EXIT_FAILURE);
2764 }
2765 gmtoffs[i] = gmtoff;
2766#ifdef ICU
2767 rawoffs[i] = rawoff;
2768 dstoffs[i] = dstoff;
2769#endif
2770 isdsts[i] = isdst;
2771 ttisstds[i] = ttisstd;
2772 ttisgmts[i] = ttisgmt;
2773
2774 for (j = 0; j < charcnt; ++j)
2775 if (strcmp(&chars[j], abbr) == 0)
2776 break;
2777 if (j == charcnt)
2778 newabbr(abbr);
2779 abbrinds[i] = j;
2780 ++typecnt;
2781 return i;
2782}
2783
2784static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002785leapadd(const zic_t t, const int positive, const int rolling, int count)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002786{
2787 register int i, j;
2788
2789 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
2790 error(_("too many leap seconds"));
2791 exit(EXIT_FAILURE);
2792 }
2793 for (i = 0; i < leapcnt; ++i)
2794 if (t <= trans[i]) {
2795 if (t == trans[i]) {
2796 error(_("repeated leap second moment"));
2797 exit(EXIT_FAILURE);
2798 }
2799 break;
2800 }
2801 do {
2802 for (j = leapcnt; j > i; --j) {
2803 trans[j] = trans[j - 1];
2804 corr[j] = corr[j - 1];
2805 roll[j] = roll[j - 1];
2806 }
2807 trans[i] = t;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002808 corr[i] = positive ? 1 : -count;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002809 roll[i] = rolling;
2810 ++leapcnt;
2811 } while (positive && --count != 0);
2812}
2813
2814static void
2815adjleap(void)
2816{
2817 register int i;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002818 register zic_t last = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002819
2820 /*
2821 ** propagate leap seconds forward
2822 */
2823 for (i = 0; i < leapcnt; ++i) {
2824 trans[i] = tadd(trans[i], last);
2825 last = corr[i] += last;
2826 }
2827}
2828
2829static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002830yearistype(const int year, const char *const type)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002831{
2832 static char * buf;
2833 int result;
2834
2835 if (type == NULL || *type == '\0')
Frank Tang1f164ee2022-11-08 12:31:27 -08002836 return true;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002837 buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002838 (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
2839 result = system(buf);
2840 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
2841 case 0:
Frank Tang1f164ee2022-11-08 12:31:27 -08002842 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002843 case 1:
Frank Tang1f164ee2022-11-08 12:31:27 -08002844 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002845 }
2846 error(_("Wild result from command execution"));
2847 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
2848 progname, buf, result);
2849 for ( ; ; )
2850 exit(EXIT_FAILURE);
2851}
2852
2853static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002854lowerit(int a)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002855{
2856 a = (unsigned char) a;
2857 return (isascii(a) && isupper(a)) ? tolower(a) : a;
2858}
2859
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002860/* case-insensitive equality */
2861static ATTRIBUTE_PURE int
2862ciequal(register const char *ap, register const char *bp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002863{
2864 while (lowerit(*ap) == lowerit(*bp++))
2865 if (*ap++ == '\0')
Frank Tang1f164ee2022-11-08 12:31:27 -08002866 return true;
2867 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002868}
2869
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002870static ATTRIBUTE_PURE int
2871itsabbr(register const char *abbr, register const char *word)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002872{
2873 if (lowerit(*abbr) != lowerit(*word))
Frank Tang1f164ee2022-11-08 12:31:27 -08002874 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002875 ++word;
2876 while (*++abbr != '\0')
2877 do {
2878 if (*word == '\0')
Frank Tang1f164ee2022-11-08 12:31:27 -08002879 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002880 } while (lowerit(*word++) != lowerit(*abbr));
Frank Tang1f164ee2022-11-08 12:31:27 -08002881 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002882}
2883
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002884static ATTRIBUTE_PURE const struct lookup *
2885byword(register const char *const word,
2886 register const struct lookup *const table)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002887{
2888 register const struct lookup * foundlp;
2889 register const struct lookup * lp;
2890
2891 if (word == NULL || table == NULL)
2892 return NULL;
2893 /*
2894 ** Look for exact match.
2895 */
2896 for (lp = table; lp->l_word != NULL; ++lp)
2897 if (ciequal(word, lp->l_word))
2898 return lp;
2899 /*
2900 ** Look for inexact match.
2901 */
2902 foundlp = NULL;
2903 for (lp = table; lp->l_word != NULL; ++lp)
2904 if (itsabbr(word, lp->l_word)) {
2905 if (foundlp == NULL)
2906 foundlp = lp;
2907 else return NULL; /* multiple inexact matches */
2908 }
2909 return foundlp;
2910}
2911
2912static char **
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002913getfields(register char *cp)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002914{
2915 register char * dp;
2916 register char ** array;
2917 register int nsubs;
2918
2919 if (cp == NULL)
2920 return NULL;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002921 array = emalloc(size_product(strlen(cp) + 1, sizeof *array));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002922 nsubs = 0;
2923 for ( ; ; ) {
2924 while (isascii((unsigned char) *cp) &&
2925 isspace((unsigned char) *cp))
2926 ++cp;
2927 if (*cp == '\0' || *cp == '#')
2928 break;
2929 array[nsubs++] = dp = cp;
2930 do {
2931 if ((*dp = *cp++) != '"')
2932 ++dp;
2933 else while ((*dp = *cp++) != '"')
2934 if (*dp != '\0')
2935 ++dp;
2936 else {
2937 error(_(
2938 "Odd number of quotation marks"
2939 ));
2940 exit(1);
2941 }
2942 } while (*cp != '\0' && *cp != '#' &&
2943 (!isascii(*cp) || !isspace((unsigned char) *cp)));
2944 if (isascii(*cp) && isspace((unsigned char) *cp))
2945 ++cp;
2946 *dp = '\0';
2947 }
2948 array[nsubs] = NULL;
2949 return array;
2950}
2951
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002952static ATTRIBUTE_PURE zic_t
2953oadd(const zic_t t1, const zic_t t2)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002954{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002955 if (t1 < 0 ? t2 < ZIC_MIN - t1 : ZIC_MAX - t1 < t2) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002956 error(_("time overflow"));
2957 exit(EXIT_FAILURE);
2958 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002959 return t1 + t2;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002960}
2961
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002962static ATTRIBUTE_PURE zic_t
2963tadd(const zic_t t1, const zic_t t2)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002964{
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002965 if (t1 == max_time && t2 > 0)
2966 return max_time;
2967 if (t1 == min_time && t2 < 0)
2968 return min_time;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002969 if (t1 < 0 ? t2 < min_time - t1 : max_time - t1 < t2) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002970 error(_("time overflow"));
2971 exit(EXIT_FAILURE);
2972 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002973 return t1 + t2;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002974}
2975
2976/*
2977** Given a rule, and a year, compute the date - in seconds since January 1,
2978** 1970, 00:00 LOCAL time - in that year that the rule refers to.
2979*/
2980
2981static zic_t
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002982rpytime(register const struct rule *const rp, register const zic_t wantedy)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002983{
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002984 register int m, i;
2985 register zic_t dayoff; /* with a nod to Margaret O. */
2986 register zic_t t, y;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002987
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002988 if (wantedy == ZIC_MIN)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002989 return min_time;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08002990 if (wantedy == ZIC_MAX)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00002991 return max_time;
2992 dayoff = 0;
2993 m = TM_JANUARY;
2994 y = EPOCH_YEAR;
2995 while (wantedy != y) {
2996 if (wantedy > y) {
2997 i = len_years[isleap(y)];
2998 ++y;
2999 } else {
3000 --y;
3001 i = -len_years[isleap(y)];
3002 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003003 dayoff = oadd(dayoff, i);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003004 }
3005 while (m != rp->r_month) {
3006 i = len_months[isleap(y)][m];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003007 dayoff = oadd(dayoff, i);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003008 ++m;
3009 }
3010 i = rp->r_dayofmonth;
3011 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
3012 if (rp->r_dycode == DC_DOWLEQ)
3013 --i;
3014 else {
3015 error(_("use of 2/29 in non leap-year"));
3016 exit(EXIT_FAILURE);
3017 }
3018 }
3019 --i;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003020 dayoff = oadd(dayoff, i);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003021 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003022 register zic_t wday;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003023
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003024#define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
3025 wday = EPOCH_WDAY;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003026 /*
3027 ** Don't trust mod of negative numbers.
3028 */
3029 if (dayoff >= 0)
3030 wday = (wday + dayoff) % LDAYSPERWEEK;
3031 else {
3032 wday -= ((-dayoff) % LDAYSPERWEEK);
3033 if (wday < 0)
3034 wday += LDAYSPERWEEK;
3035 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003036 while (wday != rp->r_wday)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003037 if (rp->r_dycode == DC_DOWGEQ) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003038 dayoff = oadd(dayoff, 1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003039 if (++wday >= LDAYSPERWEEK)
3040 wday = 0;
3041 ++i;
3042 } else {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003043 dayoff = oadd(dayoff, -1);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003044 if (--wday < 0)
3045 wday = LDAYSPERWEEK - 1;
3046 --i;
3047 }
3048 if (i < 0 || i >= len_months[isleap(y)][m]) {
3049 if (noise)
3050 warning(_("rule goes past start/end of month--\
3051will not work with pre-2004 versions of zic"));
3052 }
3053 }
3054 if (dayoff < min_time / SECSPERDAY)
3055 return min_time;
3056 if (dayoff > max_time / SECSPERDAY)
3057 return max_time;
3058 t = (zic_t) dayoff * SECSPERDAY;
3059 return tadd(t, rp->r_tod);
3060}
3061
3062static void
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003063newabbr(const char *const string)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003064{
3065 register int i;
3066
3067 if (strcmp(string, GRANDPARENTED) != 0) {
3068 register const char * cp;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003069 const char * mp;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003070
3071 /*
3072 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
3073 ** optionally followed by a + or - and a number from 1 to 14.
3074 */
3075 cp = string;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003076 mp = NULL;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003077 while (isascii((unsigned char) *cp) &&
3078 isalpha((unsigned char) *cp))
3079 ++cp;
3080 if (cp - string == 0)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003081mp = _("time zone abbreviation lacks alphabetic at start");
3082 if (noise && cp - string < 3)
3083mp = _("time zone abbreviation has fewer than 3 alphabetics");
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003084 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003085mp = _("time zone abbreviation has too many alphabetics");
3086 if (mp == NULL && (*cp == '+' || *cp == '-')) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003087 ++cp;
3088 if (isascii((unsigned char) *cp) &&
3089 isdigit((unsigned char) *cp))
3090 if (*cp++ == '1' &&
3091 *cp >= '0' && *cp <= '4')
3092 ++cp;
3093 }
3094 if (*cp != '\0')
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003095mp = _("time zone abbreviation differs from POSIX standard");
3096 if (mp != NULL)
3097 warning("%s (%s)", mp, string);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003098 }
3099 i = strlen(string) + 1;
3100 if (charcnt + i > TZ_MAX_CHARS) {
3101 error(_("too many, or too long, time zone abbreviations"));
3102 exit(EXIT_FAILURE);
3103 }
3104 (void) strcpy(&chars[charcnt], string);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003105 charcnt += i;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003106}
3107
3108static int
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003109mkdirs(char *argname)
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003110{
3111 register char * name;
3112 register char * cp;
3113
3114 if (argname == NULL || *argname == '\0')
3115 return 0;
3116 cp = name = ecpyalloc(argname);
3117 while ((cp = strchr(cp + 1, '/')) != 0) {
3118 *cp = '\0';
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003119#ifdef HAVE_DOS_FILE_NAMES
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003120 /*
3121 ** DOS drive specifier?
3122 */
3123 if (isalpha((unsigned char) name[0]) &&
3124 name[1] == ':' && name[2] == '\0') {
3125 *cp = '/';
3126 continue;
3127 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003128#endif
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003129 if (!itsdir(name)) {
3130 /*
3131 ** It doesn't seem to exist, so we try to create it.
3132 ** Creation may fail because of the directory being
3133 ** created by some other multiprocessor, so we get
3134 ** to do extra checking.
3135 */
3136 if (mkdir(name, MKDIR_UMASK) != 0) {
3137 const char *e = strerror(errno);
3138
3139 if (errno != EEXIST || !itsdir(name)) {
3140 (void) fprintf(stderr,
3141_("%s: Can't create directory %s: %s\n"),
3142 progname, name, e);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003143 free(name);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003144 return -1;
3145 }
3146 }
3147 }
3148 *cp = '/';
3149 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003150 free(name);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003151 return 0;
3152}
3153
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003154/*
3155** UNIX was a registered trademark of The Open Group in 2003.
3156*/