intl/icu/source/tools/tzcode/zic.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial