1193323Sed/* $NetBSD: zic.c,v 1.28 2011/01/15 12:31:57 martin Exp $ */ 2193323Sed/* 3193323Sed** This file is in the public domain, so clarified as of 4193323Sed** 2006-07-17 by Arthur David Olson. 5193323Sed*/ 6193323Sed 7193323Sed#if HAVE_NBTOOL_CONFIG_H 8193323Sed#include "nbtool_config.h" 9193323Sed#endif 10193323Sed 11249423Sdim#include <sys/cdefs.h> 12198090Srdivacky#ifndef lint 13234353Sdim__RCSID("$NetBSD: zic.c,v 1.28 2011/01/15 12:31:57 martin Exp $"); 14234353Sdim#endif /* !defined lint */ 15193323Sed 16193323Sedstatic char elsieid[] = "@(#)zic.c 8.25"; 17193323Sed 18193323Sed#include "private.h" 19193323Sed#include "locale.h" 20193323Sed#include "tzfile.h" 21218893Sdim 22249423Sdim#define ZIC_VERSION '2' 23198090Srdivacky 24234353Sdimtypedef int_fast64_t zic_t; 25198090Srdivacky 26198090Srdivacky#ifndef ZIC_MAX_ABBR_LEN_WO_WARN 27226633Sdim#define ZIC_MAX_ABBR_LEN_WO_WARN 6 28226633Sdim#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 29198090Srdivacky 30198090Srdivacky#if HAVE_SYS_STAT_H 31263508Sdim#include "sys/stat.h" 32198090Srdivacky#endif 33234353Sdim#ifdef S_IRUSR 34198090Srdivacky#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 35203954Srdivacky#else 36251662Sdim#define MKDIR_UMASK 0755 37198090Srdivacky#endif 38198090Srdivacky 39198090Srdivacky#include "unistd.h" 40198090Srdivacky 41198090Srdivacky/* 42239462Sdim** On some ancient hosts, predicates like `isspace(C)' are defined 43239462Sdim** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 44226633Sdim** which says they are defined only if C == ((unsigned char) C) || C == EOF. 45226633Sdim** Neither the C Standard nor Posix require that `isascii' exist. 46243830Sdim** For portability, we check both ancient and modern requirements. 47243830Sdim** If isascii is not defined, the isascii check succeeds trivially. 48193323Sed*/ 49193323Sed#include "ctype.h" 50234353Sdim#ifndef isascii 51193323Sed#define isascii(x) 1 52193323Sed#endif 53198090Srdivacky 54198090Srdivacky#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long)) 55198090Srdivacky#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */ 56198090Srdivacky 57198090Srdivacky#define end(cp) (strchr((cp), '\0')) 58249423Sdim 59249423Sdimstruct rule { 60198090Srdivacky const char * r_filename; 61198090Srdivacky int r_linenum; 62198090Srdivacky const char * r_name; 63198090Srdivacky 64263508Sdim int r_loyear; /* for example, 1986 */ 65198090Srdivacky int r_hiyear; /* for example, 1986 */ 66198090Srdivacky const char * r_yrtype; 67239462Sdim int r_lowasnum; 68239462Sdim int r_hiwasnum; 69239462Sdim 70239462Sdim int r_month; /* 0..11 */ 71234353Sdim 72239462Sdim int r_dycode; /* see below */ 73239462Sdim int r_dayofmonth; 74234353Sdim int r_wday; 75234353Sdim 76203954Srdivacky long r_tod; /* time from midnight */ 77198090Srdivacky int r_todisstd; /* above is standard time if TRUE */ 78198090Srdivacky /* or wall clock time if FALSE */ 79251662Sdim int r_todisgmt; /* above is GMT if TRUE */ 80251662Sdim /* or local time if FALSE */ 81198090Srdivacky long r_stdoff; /* offset from standard time */ 82198090Srdivacky const char * r_abbrvar; /* variable part of abbreviation */ 83218893Sdim 84198090Srdivacky int r_todo; /* a rule to do (used in outzone) */ 85218893Sdim zic_t r_temp; /* used in outzone */ 86239462Sdim}; 87239462Sdim 88226633Sdim/* 89226633Sdim** r_dycode r_dayofmonth r_wday 90243830Sdim*/ 91243830Sdim 92198090Srdivacky#define DC_DOM 0 /* 1..31 */ /* unused */ 93198090Srdivacky#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 94198090Srdivacky#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 95193323Sed 96193323Sedstruct zone { 97193323Sed const char * z_filename; 98193323Sed int z_linenum; 99193323Sed 100198090Srdivacky const char * z_name; 101221345Sdim long z_gmtoff; 102234353Sdim const char * z_rule; 103234353Sdim const char * z_format; 104243830Sdim 105243830Sdim long z_stdoff; 106263508Sdim 107193323Sed struct rule * z_rules; 108193323Sed int z_nrules; 109234353Sdim 110193323Sed struct rule z_untilrule; 111193323Sed zic_t z_untiltime; 112193323Sed}; 113193323Sed 114193323Sedextern int getopt(int argc, char * const argv[], 115193323Sed const char * options); 116194612Sedextern int link(const char * fromname, const char * toname); 117198090Srdivackyextern char * optarg; 118193323Sedextern int optind; 119193323Sed 120193323Sedstatic void addtt(zic_t starttime, int type); 121221345Sdimstatic int addtype(long gmtoff, const char * abbr, int isdst, 122226633Sdim int ttisstd, int ttisgmt); 123193323Sedstatic void leapadd(zic_t t, int positive, int rolling, int count); 124199989Srdivackystatic void adjleap(void); 125221345Sdimstatic void associate(void); 126198090Srdivackystatic int ciequal(const char * ap, const char * bp); 127198090Srdivackystatic void convert(long val, char * buf); 128195340Sedstatic void convert64(zic_t val, char * buf); 129198090Srdivackystatic void dolink(const char * fromfield, const char * tofield); 130198090Srdivackystatic void doabbr(char * abbr, const int, const char * format, 131198396Srdivacky const char * letters, int isdst, int doquotes); 132210299Sedstatic void eat(const char * name, int num); 133224145Sdimstatic void eats(const char * name, int num, 134249423Sdim const char * rname, int rnum); 135234353Sdimstatic long eitol(int i); 136239462Sdimstatic void error(const char * message); 137243830Sdimstatic char ** getfields(char * buf); 138263508Sdimstatic long gethms(const char * string, const char * errstrng, 139263508Sdim int signable); 140193323Sedstatic void infile(const char * filename); 141193323Sedstatic void inleap(char ** fields, int nfields); 142234353Sdimstatic void inlink(char ** fields, int nfields); 143193323Sedstatic void inrule(char ** fields, int nfields); 144193323Sedstatic int inzcont(char ** fields, int nfields); 145218893Sdimstatic int inzone(char ** fields, int nfields); 146218893Sdimstatic int inzsub(char ** fields, int nfields, int iscont); 147218893Sdimstatic int is32(zic_t x); 148218893Sdimstatic int itsabbr(const char * abbr, const char * word); 149234353Sdimstatic int itsdir(const char * name); 150218893Sdimstatic int lowerit(int c); 151249423Sdimint main(int, char **); 152218893Sdimstatic char * memcheck(char * tocheck); 153218893Sdimstatic int mkdirs(char * filename); 154243830Sdimstatic void newabbr(const char * abbr); 155243830Sdimstatic long oadd(long t1, long t2); 156218893Sdimstatic void outzone(const struct zone * zp, int ntzones); 157218893Sdimstatic void puttzcode(long code, FILE * fp); 158234353Sdimstatic void puttzcode64(zic_t code, FILE * fp); 159218893Sdimstatic int rcomp(const void * leftp, const void * rightp); 160218893Sdimstatic zic_t rpytime(const struct rule * rp, int wantedy); 161199481Srdivackystatic void rulesub(struct rule * rp, 162234353Sdim const char * loyearp, const char * hiyearp, 163249423Sdim const char * typep, const char * monthp, 164234353Sdim const char * dayp, const char * timep); 165234353Sdimstatic int stringoffset(char * result, long offset); 166234353Sdimstatic int stringrule(char * result, const struct rule * rp, 167234353Sdim long dstoff, long gmtoff); 168234353Sdimstatic void stringzone(char * result, const int, 169234353Sdim const struct zone * zp, int ntzones); 170234353Sdimstatic void setboundaries(void); 171234353Sdimstatic zic_t tadd(zic_t t1, long t2); 172234353Sdimstatic void usage(FILE *stream, int status); 173263508Sdimstatic void warning(const char * const); 174234353Sdimstatic void writezone(const char * name, const char * string); 175234353Sdimstatic int yearistype(int year, const char * type); 176234353Sdimstatic int atcomp(const void *avp, const void *bvp); 177234353Sdimstatic void updateminmax(int x); 178251662Sdim 179234353Sdimstatic int charcnt; 180234353Sdimstatic int errors; 181234353Sdimstatic const char * filename; 182234353Sdimstatic int leapcnt; 183234353Sdimstatic int leapseen; 184239462Sdimstatic int leapminyear; 185239462Sdimstatic int leapmaxyear; 186234353Sdimstatic int linenum; 187234353Sdimstatic int max_abbrvar_len; 188243830Sdimstatic int max_format_len; 189243830Sdimstatic zic_t max_time; 190234353Sdimstatic int max_year; 191198090Srdivackystatic zic_t min_time; 192198090Srdivackystatic int min_year; 193206083Srdivackystatic int noise; 194199481Srdivackystatic const char * rfilename; 195221345Sdimstatic int rlinenum; 196199481Srdivackystatic const char * progname; 197199481Srdivackystatic int timecnt; 198234353Sdimstatic int typecnt; 199234353Sdim 200234353Sdim/* 201234353Sdim** Line codes. 202234353Sdim*/ 203263508Sdim 204234353Sdim#define LC_RULE 0 205234353Sdim#define LC_ZONE 1 206234353Sdim#define LC_LINK 2 207234353Sdim#define LC_LEAP 3 208234353Sdim 209234353Sdim/* 210239462Sdim** Which fields are which on a Zone line. 211239462Sdim*/ 212234353Sdim 213234353Sdim#define ZF_NAME 1 214243830Sdim#define ZF_GMTOFF 2 215243830Sdim#define ZF_RULE 3 216234353Sdim#define ZF_FORMAT 4 217199481Srdivacky#define ZF_TILYEAR 5 218199481Srdivacky#define ZF_TILMONTH 6 219234353Sdim#define ZF_TILDAY 7 220234353Sdim#define ZF_TILTIME 8 221234353Sdim#define ZONE_MINFIELDS 5 222234353Sdim#define ZONE_MAXFIELDS 9 223234353Sdim 224263508Sdim/* 225234353Sdim** Which fields are which on a Zone continuation line. 226234353Sdim*/ 227263508Sdim 228249423Sdim#define ZFC_GMTOFF 0 229234353Sdim#define ZFC_RULE 1 230234353Sdim#define ZFC_FORMAT 2 231234353Sdim#define ZFC_TILYEAR 3 232234353Sdim#define ZFC_TILMONTH 4 233234353Sdim#define ZFC_TILDAY 5 234234353Sdim#define ZFC_TILTIME 6 235234353Sdim#define ZONEC_MINFIELDS 3 236234353Sdim#define ZONEC_MAXFIELDS 7 237234353Sdim 238234353Sdim/* 239234353Sdim** Which files are which on a Rule line. 240234353Sdim*/ 241234353Sdim 242251662Sdim#define RF_NAME 1 243234353Sdim#define RF_LOYEAR 2 244263508Sdim#define RF_HIYEAR 3 245234353Sdim#define RF_COMMAND 4 246234353Sdim#define RF_MONTH 5 247239462Sdim#define RF_DAY 6 248239462Sdim#define RF_TOD 7 249234353Sdim#define RF_STDOFF 8 250234353Sdim#define RF_ABBRVAR 9 251243830Sdim#define RULE_FIELDS 10 252243830Sdim 253234353Sdim/* 254234353Sdim** Which fields are which on a Link line. 255193323Sed*/ 256234353Sdim 257234353Sdim#define LF_FROM 1 258234353Sdim#define LF_TO 2 259234353Sdim#define LINK_FIELDS 3 260234353Sdim 261234353Sdim/* 262234353Sdim** Which fields are which on a Leap line. 263243830Sdim*/ 264243830Sdim 265263508Sdim#define LP_YEAR 1 266234353Sdim#define LP_MONTH 2 267212904Sdim#define LP_DAY 3 268193323Sed#define LP_TIME 4 269234353Sdim#define LP_CORR 5 270234353Sdim#define LP_ROLL 6 271234353Sdim#define LEAP_FIELDS 7 272234353Sdim 273234353Sdim/* 274234353Sdim** Year synonyms. 275234353Sdim*/ 276234353Sdim 277234353Sdim#define YR_MINIMUM 0 278234353Sdim#define YR_MAXIMUM 1 279234353Sdim#define YR_ONLY 2 280234353Sdim 281234353Sdimstatic struct rule * rules; 282234353Sdimstatic int nrules; /* number of rules */ 283234353Sdim 284234353Sdimstatic struct zone * zones; 285234353Sdimstatic int nzones; /* number of zones */ 286234353Sdim 287234353Sdimstruct link { 288234353Sdim const char * l_filename; 289249423Sdim int l_linenum; 290234353Sdim const char * l_from; 291239462Sdim const char * l_to; 292243830Sdim}; 293263508Sdim 294263508Sdimstatic struct link * links; 295234353Sdimstatic int nlinks; 296212904Sdim 297193323Sedstruct lookup { 298234353Sdim const char * l_word; 299234353Sdim const int l_value; 300234353Sdim}; 301234353Sdim 302234353Sdimstatic struct lookup const * byword(const char * string, 303249423Sdim const struct lookup * lp); 304234353Sdim 305234353Sdimstatic struct lookup const line_codes[] = { 306243830Sdim { "Rule", LC_RULE }, 307243830Sdim { "Zone", LC_ZONE }, 308234353Sdim { "Link", LC_LINK }, 309212904Sdim { "Leap", LC_LEAP }, 310193323Sed { NULL, 0} 311234353Sdim}; 312234353Sdim 313234353Sdimstatic struct lookup const mon_names[] = { 314234353Sdim { "January", TM_JANUARY }, 315234353Sdim { "February", TM_FEBRUARY }, 316234353Sdim { "March", TM_MARCH }, 317234353Sdim { "April", TM_APRIL }, 318234353Sdim { "May", TM_MAY }, 319234353Sdim { "June", TM_JUNE }, 320234353Sdim { "July", TM_JULY }, 321218893Sdim { "August", TM_AUGUST }, 322218893Sdim { "September", TM_SEPTEMBER }, 323234353Sdim { "October", TM_OCTOBER }, 324234353Sdim { "November", TM_NOVEMBER }, 325234353Sdim { "December", TM_DECEMBER }, 326234353Sdim { NULL, 0 } 327234353Sdim}; 328234353Sdim 329234353Sdimstatic struct lookup const wday_names[] = { 330234353Sdim { "Sunday", TM_SUNDAY }, 331234353Sdim { "Monday", TM_MONDAY }, 332234353Sdim { "Tuesday", TM_TUESDAY }, 333234353Sdim { "Wednesday", TM_WEDNESDAY }, 334234353Sdim { "Thursday", TM_THURSDAY }, 335234353Sdim { "Friday", TM_FRIDAY }, 336212904Sdim { "Saturday", TM_SATURDAY }, 337234353Sdim { NULL, 0 } 338234353Sdim}; 339234353Sdim 340234353Sdimstatic struct lookup const lasts[] = { 341234353Sdim { "last-Sunday", TM_SUNDAY }, 342234353Sdim { "last-Monday", TM_MONDAY }, 343234353Sdim { "last-Tuesday", TM_TUESDAY }, 344234353Sdim { "last-Wednesday", TM_WEDNESDAY }, 345234353Sdim { "last-Thursday", TM_THURSDAY }, 346234353Sdim { "last-Friday", TM_FRIDAY }, 347234353Sdim { "last-Saturday", TM_SATURDAY }, 348234353Sdim { NULL, 0 } 349234353Sdim}; 350193323Sed 351193323Sedstatic struct lookup const begin_years[] = { 352212904Sdim { "minimum", YR_MINIMUM }, 353212904Sdim { "maximum", YR_MAXIMUM }, 354212904Sdim { NULL, 0 } 355234353Sdim}; 356212904Sdim 357212904Sdimstatic struct lookup const end_years[] = { 358212904Sdim { "minimum", YR_MINIMUM }, 359212904Sdim { "maximum", YR_MAXIMUM }, 360212904Sdim { "only", YR_ONLY }, 361212904Sdim { NULL, 0 } 362212904Sdim}; 363212904Sdim 364234353Sdimstatic struct lookup const leap_types[] = { 365212904Sdim { "Rolling", TRUE }, 366212904Sdim { "Stationary", FALSE }, 367234353Sdim { NULL, 0 } 368212904Sdim}; 369212904Sdim 370234353Sdimstatic const int len_months[2][MONSPERYEAR] = { 371218893Sdim { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 372218893Sdim { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 373234353Sdim}; 374212904Sdim 375212904Sdimstatic const int len_years[2] = { 376212904Sdim DAYSPERNYEAR, DAYSPERLYEAR 377218893Sdim}; 378212904Sdim 379212904Sdimstatic struct attype { 380212904Sdim zic_t at; 381218893Sdim unsigned char type; 382212904Sdim} attypes[TZ_MAX_TIMES]; 383212904Sdimstatic long gmtoffs[TZ_MAX_TYPES]; 384212904Sdimstatic char isdsts[TZ_MAX_TYPES]; 385212904Sdimstatic unsigned char abbrinds[TZ_MAX_TYPES]; 386218893Sdimstatic char ttisstds[TZ_MAX_TYPES]; 387212904Sdimstatic char ttisgmts[TZ_MAX_TYPES]; 388212904Sdimstatic char chars[TZ_MAX_CHARS]; 389212904Sdimstatic zic_t trans[TZ_MAX_LEAPS]; 390212904Sdimstatic long corr[TZ_MAX_LEAPS]; 391212904Sdimstatic char roll[TZ_MAX_LEAPS]; 392218893Sdim 393212904Sdim/* 394212904Sdim** Memory allocation. 395212904Sdim*/ 396212904Sdim 397212904Sdimstatic char * 398212904Sdimmemcheck(ptr) 399234353Sdimchar * const ptr; 400212904Sdim{ 401234353Sdim if (ptr == NULL) { 402212904Sdim const char *e = strerror(errno); 403212904Sdim 404212904Sdim (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), 405234353Sdim progname, e); 406212904Sdim exit(EXIT_FAILURE); 407212904Sdim } 408212904Sdim return ptr; 409234353Sdim} 410212904Sdim 411212904Sdim#define emalloc(size) memcheck(imalloc(size)) 412218893Sdim#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 413234353Sdim#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 414218893Sdim#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 415218893Sdim 416212904Sdim/* 417212904Sdim** Error handling. 418212904Sdim*/ 419212904Sdim 420212904Sdimstatic void 421212904Sdimeats(name, num, rname, rnum) 422212904Sdimconst char * const name; 423212904Sdimconst int num; 424212904Sdimconst char * const rname; 425212904Sdimconst int rnum; 426212904Sdim{ 427212904Sdim filename = name; 428212904Sdim linenum = num; 429212904Sdim rfilename = rname; 430212904Sdim rlinenum = rnum; 431212904Sdim} 432212904Sdim 433212904Sdimstatic void 434234353Sdimeat(name, num) 435234353Sdimconst char * const name; 436212904Sdimconst int num; 437212904Sdim{ 438212904Sdim eats(name, num, (char *) NULL, -1); 439212904Sdim} 440212904Sdim 441212904Sdimstatic void 442212904Sdimerror(string) 443212904Sdimconst char * const string; 444212904Sdim{ 445212904Sdim /* 446212904Sdim ** Match the format of "cc" to allow sh users to 447218893Sdim ** zic ... 2>&1 | error -t "*" -v 448212904Sdim ** on BSD systems. 449212904Sdim */ 450212904Sdim (void) fprintf(stderr, _("\"%s\", line %d: %s"), 451212904Sdim filename, linenum, string); 452212904Sdim if (rfilename != NULL) 453212904Sdim (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), 454218893Sdim rfilename, rlinenum); 455218893Sdim (void) fprintf(stderr, "\n"); 456218893Sdim ++errors; 457212904Sdim} 458212904Sdim 459212904Sdimstatic void 460212904Sdimwarning(string) 461212904Sdimconst char * const string; 462212904Sdim{ 463234353Sdim char * cp; 464234353Sdim 465212904Sdim cp = ecpyalloc(_("warning: ")); 466212904Sdim cp = ecatalloc(cp, string); 467212904Sdim error(cp); 468212904Sdim ifree(cp); 469212904Sdim --errors; 470212904Sdim} 471212904Sdim 472212904Sdimstatic void 473212904Sdimusage(FILE *stream, int status) 474212904Sdim{ 475212904Sdim (void) fprintf(stream, _("%s: usage is %s \ 476212904Sdim[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\ 477212904Sdim\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\ 478212904Sdim\n\ 479212904SdimReport bugs to tz@elsie.nci.nih.gov.\n"), 480212904Sdim progname, progname); 481212904Sdim exit(status); 482212904Sdim} 483212904Sdim 484212904Sdimstatic const char * psxrules; 485212904Sdimstatic const char * lcltime; 486198090Srdivackystatic const char * directory; 487198090Srdivackystatic const char * leapsec; 488193323Sedstatic const char * yitcommand; 489193323Sed 490198090Srdivackyint 491198090Srdivackymain(argc, argv) 492198090Srdivackyint argc; 493193323Sedchar * argv[]; 494193323Sed{ 495198090Srdivacky register int i; 496198090Srdivacky register int j; 497198090Srdivacky register int c; 498198090Srdivacky 499193323Sed#ifdef _POSIX_VERSION 500193323Sed (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 501198090Srdivacky#endif /* defined _POSIX_VERSION */ 502198090Srdivacky#if HAVE_GETTEXT - 0 503198090Srdivacky (void) setlocale(LC_MESSAGES, ""); 504198090Srdivacky#ifdef TZ_DOMAINDIR 505193323Sed (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 506193323Sed#endif /* defined TEXTDOMAINDIR */ 507198090Srdivacky (void) textdomain(TZ_DOMAIN); 508198090Srdivacky#endif /* HAVE_GETTEXT */ 509198090Srdivacky progname = argv[0]; 510193323Sed if (TYPE_BIT(zic_t) < 64) { 511193323Sed (void) fprintf(stderr, "%s: %s\n", progname, 512198090Srdivacky _("wild compilation-time specification of zic_t")); 513198090Srdivacky exit(EXIT_FAILURE); 514221345Sdim } 515218893Sdim for (i = 1; i < argc; ++i) 516221345Sdim if (strcmp(argv[i], "--version") == 0) { 517221345Sdim (void) printf("%s\n", elsieid); 518221345Sdim exit(EXIT_SUCCESS); 519218893Sdim } else if (strcmp(argv[i], "--help") == 0) { 520198090Srdivacky usage(stdout, EXIT_SUCCESS); 521198090Srdivacky } 522221345Sdim while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1) 523218893Sdim switch (c) { 524198090Srdivacky default: 525193323Sed usage(stderr, EXIT_FAILURE); 526193323Sed case 'd': 527221345Sdim if (directory == NULL) 528221345Sdim directory = optarg; 529198090Srdivacky else { 530218893Sdim (void) fprintf(stderr, 531221345Sdim_("%s: More than one -d option specified\n"), 532221345Sdim progname); 533221345Sdim exit(EXIT_FAILURE); 534221345Sdim } 535218893Sdim break; 536221345Sdim case 'l': 537221345Sdim if (lcltime == NULL) 538198090Srdivacky lcltime = optarg; 539221345Sdim else { 540221345Sdim (void) fprintf(stderr, 541221345Sdim_("%s: More than one -l option specified\n"), 542221345Sdim progname); 543221345Sdim exit(EXIT_FAILURE); 544198090Srdivacky } 545221345Sdim break; 546221345Sdim case 'p': 547218893Sdim if (psxrules == NULL) 548221345Sdim psxrules = optarg; 549221345Sdim else { 550221345Sdim (void) fprintf(stderr, 551221345Sdim_("%s: More than one -p option specified\n"), 552193323Sed progname); 553193323Sed exit(EXIT_FAILURE); 554234353Sdim } 555234353Sdim break; 556234353Sdim case 'y': 557234353Sdim if (yitcommand == NULL) 558234353Sdim yitcommand = optarg; 559234353Sdim else { 560234353Sdim (void) fprintf(stderr, 561234353Sdim_("%s: More than one -y option specified\n"), 562234353Sdim progname); 563234353Sdim exit(EXIT_FAILURE); 564234353Sdim } 565234353Sdim break; 566234353Sdim case 'L': 567234353Sdim if (leapsec == NULL) 568234353Sdim leapsec = optarg; 569234353Sdim else { 570234353Sdim (void) fprintf(stderr, 571234353Sdim_("%s: More than one -L option specified\n"), 572234353Sdim progname); 573234353Sdim exit(EXIT_FAILURE); 574234353Sdim } 575234353Sdim break; 576234353Sdim case 'v': 577234353Sdim noise = TRUE; 578234353Sdim break; 579234353Sdim case 's': 580234353Sdim (void) printf("%s: -s ignored\n", progname); 581234353Sdim break; 582234353Sdim } 583234353Sdim if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 584234353Sdim usage(stderr, EXIT_FAILURE); /* usage message by request */ 585234353Sdim if (directory == NULL) 586234353Sdim directory = TZDIR; 587234353Sdim if (yitcommand == NULL) 588234353Sdim yitcommand = "yearistype"; 589234353Sdim 590234353Sdim setboundaries(); 591234353Sdim 592234353Sdim if (optind < argc && leapsec != NULL) { 593239462Sdim infile(leapsec); 594239462Sdim adjleap(); 595239462Sdim } 596239462Sdim 597239462Sdim for (i = optind; i < argc; ++i) 598239462Sdim infile(argv[i]); 599239462Sdim if (errors) 600239462Sdim exit(EXIT_FAILURE); 601239462Sdim associate(); 602239462Sdim for (i = 0; i < nzones; i = j) { 603239462Sdim /* 604239462Sdim ** Find the next non-continuation zone entry. 605239462Sdim */ 606239462Sdim for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 607239462Sdim continue; 608239462Sdim outzone(&zones[i], j - i); 609239462Sdim } 610239462Sdim /* 611239462Sdim ** Make links. 612239462Sdim */ 613239462Sdim for (i = 0; i < nlinks; ++i) { 614239462Sdim eat(links[i].l_filename, links[i].l_linenum); 615239462Sdim dolink(links[i].l_from, links[i].l_to); 616198090Srdivacky if (noise) 617234353Sdim for (j = 0; j < nlinks; ++j) 618193323Sed if (strcmp(links[i].l_to, 619193323Sed links[j].l_from) == 0) 620193323Sed warning(_("link to link")); 621193323Sed } 622193323Sed if (lcltime != NULL) { 623193323Sed eat("command line", 1); 624193323Sed dolink(lcltime, TZDEFAULT); 625193323Sed } 626193323Sed if (psxrules != NULL) { 627193323Sed eat("command line", 1); 628193323Sed dolink(psxrules, TZDEFRULES); 629193323Sed } 630193323Sed return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 631193323Sed} 632218893Sdim 633218893Sdimstatic void 634218893Sdimdolink(fromfield, tofield) 635218893Sdimconst char * const fromfield; 636199481Srdivackyconst char * const tofield; 637198090Srdivacky{ 638198090Srdivacky register char * fromname; 639198090Srdivacky register char * toname; 640198090Srdivacky 641198090Srdivacky if (fromfield[0] == '/') 642198090Srdivacky fromname = ecpyalloc(fromfield); 643198090Srdivacky else { 644198090Srdivacky fromname = ecpyalloc(directory); 645193323Sed fromname = ecatalloc(fromname, "/"); 646193323Sed fromname = ecatalloc(fromname, fromfield); 647199481Srdivacky } 648193323Sed if (tofield[0] == '/') 649193323Sed toname = ecpyalloc(tofield); 650193323Sed else { 651199481Srdivacky toname = ecpyalloc(directory); 652193323Sed toname = ecatalloc(toname, "/"); 653193323Sed toname = ecatalloc(toname, tofield); 654193323Sed } 655193323Sed /* 656193323Sed ** We get to be careful here since 657193323Sed ** there's a fair chance of root running us. 658193323Sed */ 659199481Srdivacky if (!itsdir(toname)) 660199481Srdivacky (void) remove(toname); 661193323Sed if (link(fromname, toname) != 0) { 662193323Sed int result; 663193323Sed 664199481Srdivacky if (mkdirs(toname) != 0) 665193323Sed exit(EXIT_FAILURE); 666193323Sed 667234353Sdim result = link(fromname, toname); 668234353Sdim#if HAVE_SYMLINK 669234353Sdim if (result != 0 && 670234353Sdim access(fromname, F_OK) == 0 && 671234353Sdim !itsdir(fromname)) { 672234353Sdim const char *s = tofield; 673234353Sdim register char * symlinkcontents = NULL; 674234353Sdim 675234353Sdim while ((s = strchr(s+1, '/')) != NULL) 676234353Sdim symlinkcontents = 677234353Sdim ecatalloc(symlinkcontents, 678234353Sdim "../"); 679234353Sdim symlinkcontents = 680234353Sdim ecatalloc(symlinkcontents, 681234353Sdim fromname); 682239462Sdim result = symlink(symlinkcontents, 683234353Sdim toname); 684234353Sdim if (result == 0) 685234353Sdimwarning(_("hard link failed, symbolic link used")); 686234353Sdim ifree(symlinkcontents); 687234353Sdim } 688234353Sdim#endif /* HAVE_SYMLINK */ 689234353Sdim if (result != 0) { 690243830Sdim const char *e = strerror(errno); 691234353Sdim 692234353Sdim (void) fprintf(stderr, 693249423Sdim _("%s: Can't link from %s to %s: %s\n"), 694234353Sdim progname, fromname, toname, e); 695234353Sdim exit(EXIT_FAILURE); 696239462Sdim } 697234353Sdim } 698263508Sdim ifree(fromname); 699234353Sdim ifree(toname); 700251662Sdim} 701234353Sdim 702243830Sdim#define TIME_T_BITS_IN_FILE 64 703234353Sdim 704234353Sdimstatic void 705234353Sdimsetboundaries(void) 706234353Sdim{ 707234353Sdim register int i; 708234353Sdim 709234353Sdim min_time = -1; 710234353Sdim for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) 711234353Sdim min_time *= 2; 712234353Sdim max_time = -(min_time + 1); 713234353Sdim} 714234353Sdim 715234353Sdimstatic int 716234353Sdimitsdir(name) 717234353Sdimconst char * const name; 718234353Sdim{ 719234353Sdim register char * myname; 720234353Sdim register int accres; 721234353Sdim 722234353Sdim myname = ecpyalloc(name); 723234353Sdim myname = ecatalloc(myname, "/."); 724249423Sdim accres = access(myname, F_OK); 725234353Sdim ifree(myname); 726251662Sdim return accres == 0; 727263508Sdim} 728234353Sdim 729234353Sdim/* 730234353Sdim** Associate sets of rules with zones. 731234353Sdim*/ 732243830Sdim 733234353Sdim/* 734234353Sdim** Sort by rule name. 735234353Sdim*/ 736234353Sdim 737234353Sdimstatic int 738239462Sdimrcomp(cp1, cp2) 739234353Sdimconst void * cp1; 740234353Sdimconst void * cp2; 741234353Sdim{ 742234353Sdim return strcmp(((const struct rule *) cp1)->r_name, 743234353Sdim ((const struct rule *) cp2)->r_name); 744234353Sdim} 745234353Sdim 746234353Sdimstatic void 747234353Sdimassociate(void) 748234353Sdim{ 749234353Sdim register struct zone * zp; 750234353Sdim register struct rule * rp; 751239462Sdim register int base, out; 752234353Sdim register int i, j; 753234353Sdim 754234353Sdim if (nrules != 0) { 755243830Sdim (void) qsort((void *) rules, (size_t) nrules, 756234353Sdim (size_t) sizeof *rules, rcomp); 757234353Sdim for (i = 0; i < nrules - 1; ++i) { 758234353Sdim if (strcmp(rules[i].r_name, 759234353Sdim rules[i + 1].r_name) != 0) 760234353Sdim continue; 761234353Sdim if (strcmp(rules[i].r_filename, 762234353Sdim rules[i + 1].r_filename) == 0) 763234353Sdim continue; 764234353Sdim eat(rules[i].r_filename, rules[i].r_linenum); 765234353Sdim warning(_("same rule name in multiple files")); 766234353Sdim eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 767234353Sdim warning(_("same rule name in multiple files")); 768234353Sdim for (j = i + 2; j < nrules; ++j) { 769234353Sdim if (strcmp(rules[i].r_name, 770234353Sdim rules[j].r_name) != 0) 771234353Sdim break; 772234353Sdim if (strcmp(rules[i].r_filename, 773234353Sdim rules[j].r_filename) == 0) 774234353Sdim continue; 775234353Sdim if (strcmp(rules[i + 1].r_filename, 776249423Sdim rules[j].r_filename) == 0) 777243830Sdim continue; 778234353Sdim break; 779234353Sdim } 780239462Sdim i = j - 1; 781234353Sdim } 782263508Sdim } 783234353Sdim for (i = 0; i < nzones; ++i) { 784251662Sdim zp = &zones[i]; 785234353Sdim zp->z_rules = NULL; 786234353Sdim zp->z_nrules = 0; 787234353Sdim } 788234353Sdim for (base = 0; base < nrules; base = out) { 789234353Sdim rp = &rules[base]; 790234353Sdim for (out = base + 1; out < nrules; ++out) 791239462Sdim if (strcmp(rp->r_name, rules[out].r_name) != 0) 792234353Sdim break; 793234353Sdim for (i = 0; i < nzones; ++i) { 794234353Sdim zp = &zones[i]; 795243830Sdim if (strcmp(zp->z_rule, rp->r_name) != 0) 796234353Sdim continue; 797234353Sdim zp->z_rules = rp; 798234353Sdim zp->z_nrules = out - base; 799 } 800 } 801 for (i = 0; i < nzones; ++i) { 802 zp = &zones[i]; 803 if (zp->z_nrules == 0) { 804 /* 805 ** Maybe we have a local standard time offset. 806 */ 807 eat(zp->z_filename, zp->z_linenum); 808 zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 809 TRUE); 810 /* 811 ** Note, though, that if there's no rule, 812 ** a '%s' in the format is a bad thing. 813 */ 814 if (strchr(zp->z_format, '%') != 0) 815 error(_("%s in ruleless zone")); 816 } 817 } 818 if (errors) 819 exit(EXIT_FAILURE); 820} 821 822static void 823infile(name) 824const char * name; 825{ 826 register FILE * fp; 827 register char ** fields; 828 register char * cp; 829 register const struct lookup * lp; 830 register int nfields; 831 register int wantcont; 832 register int num; 833 char buf[BUFSIZ]; 834 835 if (strcmp(name, "-") == 0) { 836 name = _("standard input"); 837 fp = stdin; 838 } else if ((fp = fopen(name, "r")) == NULL) { 839 const char *e = strerror(errno); 840 841 (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), 842 progname, name, e); 843 exit(EXIT_FAILURE); 844 } 845 wantcont = FALSE; 846 for (num = 1; ; ++num) { 847 eat(name, num); 848 if (fgets(buf, (int) sizeof buf, fp) != buf) 849 break; 850 cp = strchr(buf, '\n'); 851 if (cp == NULL) { 852 error(_("line too long")); 853 exit(EXIT_FAILURE); 854 } 855 *cp = '\0'; 856 fields = getfields(buf); 857 nfields = 0; 858 while (fields[nfields] != NULL) { 859 static char nada; 860 861 if (strcmp(fields[nfields], "-") == 0) 862 fields[nfields] = &nada; 863 ++nfields; 864 } 865 if (nfields == 0) { 866 /* nothing to do */ 867 } else if (wantcont) { 868 wantcont = inzcont(fields, nfields); 869 } else { 870 lp = byword(fields[0], line_codes); 871 if (lp == NULL) 872 error(_("input line of unknown type")); 873 else switch ((int) (lp->l_value)) { 874 case LC_RULE: 875 inrule(fields, nfields); 876 wantcont = FALSE; 877 break; 878 case LC_ZONE: 879 wantcont = inzone(fields, nfields); 880 break; 881 case LC_LINK: 882 inlink(fields, nfields); 883 wantcont = FALSE; 884 break; 885 case LC_LEAP: 886 if (name != leapsec) 887 (void) fprintf(stderr, 888_("%s: Leap line in non leap seconds file %s\n"), 889 progname, name); 890 else inleap(fields, nfields); 891 wantcont = FALSE; 892 break; 893 default: /* "cannot happen" */ 894 (void) fprintf(stderr, 895_("%s: panic: Invalid l_value %d\n"), 896 progname, lp->l_value); 897 exit(EXIT_FAILURE); 898 } 899 } 900 ifree((char *) fields); 901 } 902 if (ferror(fp)) { 903 (void) fprintf(stderr, _("%s: Error reading %s\n"), 904 progname, filename); 905 exit(EXIT_FAILURE); 906 } 907 if (fp != stdin && fclose(fp)) { 908 const char *e = strerror(errno); 909 910 (void) fprintf(stderr, _("%s: Error closing %s: %s\n"), 911 progname, filename, e); 912 exit(EXIT_FAILURE); 913 } 914 if (wantcont) 915 error(_("expected continuation line not found")); 916} 917 918/* 919** Convert a string of one of the forms 920** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 921** into a number of seconds. 922** A null string maps to zero. 923** Call error with errstring and return zero on errors. 924*/ 925 926static long 927gethms(string, errstring, signable) 928const char * string; 929const char * const errstring; 930const int signable; 931{ 932 long hh; 933 int mm, ss, sign; 934 935 if (string == NULL || *string == '\0') 936 return 0; 937 if (!signable) 938 sign = 1; 939 else if (*string == '-') { 940 sign = -1; 941 ++string; 942 } else sign = 1; 943 if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 944 mm = ss = 0; 945 else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 946 ss = 0; 947 else if (sscanf(string, scheck(string, "%ld:%d:%d"), 948 &hh, &mm, &ss) != 3) { 949 error(errstring); 950 return 0; 951 } 952 if (hh < 0 || 953 mm < 0 || mm >= MINSPERHOUR || 954 ss < 0 || ss > SECSPERMIN) { 955 error(errstring); 956 return 0; 957 } 958 if (LONG_MAX / SECSPERHOUR < hh) { 959 error(_("time overflow")); 960 return 0; 961 } 962 if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 963 warning(_("24:00 not handled by pre-1998 versions of zic")); 964 if (noise && (hh > HOURSPERDAY || 965 (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 966warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 967 return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 968 eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); 969} 970 971static void 972inrule(fields, nfields) 973register char ** const fields; 974const int nfields; 975{ 976 static struct rule r; 977 978 if (nfields != RULE_FIELDS) { 979 error(_("wrong number of fields on Rule line")); 980 return; 981 } 982 if (*fields[RF_NAME] == '\0') { 983 error(_("nameless rule")); 984 return; 985 } 986 r.r_filename = filename; 987 r.r_linenum = linenum; 988 r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); 989 rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 990 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 991 r.r_name = ecpyalloc(fields[RF_NAME]); 992 r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 993 if (max_abbrvar_len < strlen(r.r_abbrvar)) 994 max_abbrvar_len = strlen(r.r_abbrvar); 995 rules = (struct rule *) (void *) erealloc((char *) rules, 996 (int) ((nrules + 1) * sizeof *rules)); 997 rules[nrules++] = r; 998} 999 1000static int 1001inzone(fields, nfields) 1002register char ** const fields; 1003const int nfields; 1004{ 1005 register int i; 1006 static char * buf; 1007 1008 if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1009 error(_("wrong number of fields on Zone line")); 1010 return FALSE; 1011 } 1012 if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 1013 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); 1014 (void)sprintf(buf, /* XXX: sprintf is safe */ 1015_("\"Zone %s\" line and -l option are mutually exclusive"), 1016 TZDEFAULT); 1017 error(buf); 1018 return FALSE; 1019 } 1020 if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 1021 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); 1022 (void)sprintf(buf, /* XXX: sprintf is safe */ 1023_("\"Zone %s\" line and -p option are mutually exclusive"), 1024 TZDEFRULES); 1025 error(buf); 1026 return FALSE; 1027 } 1028 for (i = 0; i < nzones; ++i) 1029 if (zones[i].z_name != NULL && 1030 strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1031 buf = erealloc(buf, (int) (132 + 1032 strlen(fields[ZF_NAME]) + 1033 strlen(zones[i].z_filename))); 1034 (void)sprintf(buf, /* XXX: sprintf is safe */ 1035_("duplicate zone name %s (file \"%s\", line %d)"), 1036 fields[ZF_NAME], 1037 zones[i].z_filename, 1038 zones[i].z_linenum); 1039 error(buf); 1040 return FALSE; 1041 } 1042 return inzsub(fields, nfields, FALSE); 1043} 1044 1045static int 1046inzcont(fields, nfields) 1047register char ** const fields; 1048const int nfields; 1049{ 1050 if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1051 error(_("wrong number of fields on Zone continuation line")); 1052 return FALSE; 1053 } 1054 return inzsub(fields, nfields, TRUE); 1055} 1056 1057static int 1058inzsub(fields, nfields, iscont) 1059register char ** const fields; 1060const int nfields; 1061const int iscont; 1062{ 1063 register char * cp; 1064 static struct zone z; 1065 register int i_gmtoff, i_rule, i_format; 1066 register int i_untilyear, i_untilmonth; 1067 register int i_untilday, i_untiltime; 1068 register int hasuntil; 1069 1070 if (iscont) { 1071 i_gmtoff = ZFC_GMTOFF; 1072 i_rule = ZFC_RULE; 1073 i_format = ZFC_FORMAT; 1074 i_untilyear = ZFC_TILYEAR; 1075 i_untilmonth = ZFC_TILMONTH; 1076 i_untilday = ZFC_TILDAY; 1077 i_untiltime = ZFC_TILTIME; 1078 z.z_name = NULL; 1079 } else { 1080 i_gmtoff = ZF_GMTOFF; 1081 i_rule = ZF_RULE; 1082 i_format = ZF_FORMAT; 1083 i_untilyear = ZF_TILYEAR; 1084 i_untilmonth = ZF_TILMONTH; 1085 i_untilday = ZF_TILDAY; 1086 i_untiltime = ZF_TILTIME; 1087 z.z_name = ecpyalloc(fields[ZF_NAME]); 1088 } 1089 z.z_filename = filename; 1090 z.z_linenum = linenum; 1091 z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); 1092 if ((cp = strchr(fields[i_format], '%')) != 0) { 1093 if (*++cp != 's' || strchr(cp, '%') != 0) { 1094 error(_("invalid abbreviation format")); 1095 return FALSE; 1096 } 1097 } 1098 z.z_rule = ecpyalloc(fields[i_rule]); 1099 z.z_format = ecpyalloc(fields[i_format]); 1100 if (max_format_len < strlen(z.z_format)) 1101 max_format_len = strlen(z.z_format); 1102 hasuntil = nfields > i_untilyear; 1103 if (hasuntil) { 1104 z.z_untilrule.r_filename = filename; 1105 z.z_untilrule.r_linenum = linenum; 1106 rulesub(&z.z_untilrule, 1107 fields[i_untilyear], 1108 "only", 1109 "", 1110 (nfields > i_untilmonth) ? 1111 fields[i_untilmonth] : "Jan", 1112 (nfields > i_untilday) ? fields[i_untilday] : "1", 1113 (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1114 z.z_untiltime = rpytime(&z.z_untilrule, 1115 z.z_untilrule.r_loyear); 1116 if (iscont && nzones > 0 && 1117 z.z_untiltime > min_time && 1118 z.z_untiltime < max_time && 1119 zones[nzones - 1].z_untiltime > min_time && 1120 zones[nzones - 1].z_untiltime < max_time && 1121 zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1122 error(_( 1123"Zone continuation line end time is not after end time of previous line" 1124 )); 1125 return FALSE; 1126 } 1127 } 1128 zones = (struct zone *) (void *) erealloc((char *) zones, 1129 (int) ((nzones + 1) * sizeof *zones)); 1130 zones[nzones++] = z; 1131 /* 1132 ** If there was an UNTIL field on this line, 1133 ** there's more information about the zone on the next line. 1134 */ 1135 return hasuntil; 1136} 1137 1138static void 1139inleap(fields, nfields) 1140register char ** const fields; 1141const int nfields; 1142{ 1143 register const char * cp; 1144 register const struct lookup * lp; 1145 register int i, j; 1146 int year, month, day; 1147 long dayoff, tod; 1148 zic_t t; 1149 1150 if (nfields != LEAP_FIELDS) { 1151 error(_("wrong number of fields on Leap line")); 1152 return; 1153 } 1154 dayoff = 0; 1155 cp = fields[LP_YEAR]; 1156 if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1157 /* 1158 ** Leapin' Lizards! 1159 */ 1160 error(_("invalid leaping year")); 1161 return; 1162 } 1163 if (!leapseen || leapmaxyear < year) 1164 leapmaxyear = year; 1165 if (!leapseen || leapminyear > year) 1166 leapminyear = year; 1167 leapseen = TRUE; 1168 j = EPOCH_YEAR; 1169 while (j != year) { 1170 if (year > j) { 1171 i = len_years[isleap(j)]; 1172 ++j; 1173 } else { 1174 --j; 1175 i = -len_years[isleap(j)]; 1176 } 1177 dayoff = oadd(dayoff, eitol(i)); 1178 } 1179 if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1180 error(_("invalid month name")); 1181 return; 1182 } 1183 month = lp->l_value; 1184 j = TM_JANUARY; 1185 while (j != month) { 1186 i = len_months[isleap(year)][j]; 1187 dayoff = oadd(dayoff, eitol(i)); 1188 ++j; 1189 } 1190 cp = fields[LP_DAY]; 1191 if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1192 day <= 0 || day > len_months[isleap(year)][month]) { 1193 error(_("invalid day of month")); 1194 return; 1195 } 1196 dayoff = oadd(dayoff, eitol(day - 1)); 1197 if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 1198 error(_("time before zero")); 1199 return; 1200 } 1201 if (dayoff < min_time / SECSPERDAY) { 1202 error(_("time too small")); 1203 return; 1204 } 1205 if (dayoff > max_time / SECSPERDAY) { 1206 error(_("time too large")); 1207 return; 1208 } 1209 t = (zic_t) dayoff * SECSPERDAY; 1210 tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); 1211 cp = fields[LP_CORR]; 1212 { 1213 register int positive; 1214 int count; 1215 1216 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1217 positive = FALSE; 1218 count = 1; 1219 } else if (strcmp(cp, "--") == 0) { 1220 positive = FALSE; 1221 count = 2; 1222 } else if (strcmp(cp, "+") == 0) { 1223 positive = TRUE; 1224 count = 1; 1225 } else if (strcmp(cp, "++") == 0) { 1226 positive = TRUE; 1227 count = 2; 1228 } else { 1229 error(_("illegal CORRECTION field on Leap line")); 1230 return; 1231 } 1232 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1233 error(_( 1234 "illegal Rolling/Stationary field on Leap line" 1235 )); 1236 return; 1237 } 1238 leapadd(tadd(t, tod), positive, lp->l_value, count); 1239 } 1240} 1241 1242static void 1243inlink(fields, nfields) 1244register char ** const fields; 1245const int nfields; 1246{ 1247 struct link l; 1248 1249 if (nfields != LINK_FIELDS) { 1250 error(_("wrong number of fields on Link line")); 1251 return; 1252 } 1253 if (*fields[LF_FROM] == '\0') { 1254 error(_("blank FROM field on Link line")); 1255 return; 1256 } 1257 if (*fields[LF_TO] == '\0') { 1258 error(_("blank TO field on Link line")); 1259 return; 1260 } 1261 l.l_filename = filename; 1262 l.l_linenum = linenum; 1263 l.l_from = ecpyalloc(fields[LF_FROM]); 1264 l.l_to = ecpyalloc(fields[LF_TO]); 1265 links = (struct link *) (void *) erealloc((char *) links, 1266 (int) ((nlinks + 1) * sizeof *links)); 1267 links[nlinks++] = l; 1268} 1269 1270static void 1271rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1272register struct rule * const rp; 1273const char * const loyearp; 1274const char * const hiyearp; 1275const char * const typep; 1276const char * const monthp; 1277const char * const dayp; 1278const char * const timep; 1279{ 1280 register const struct lookup * lp; 1281 register const char * cp; 1282 register char * dp; 1283 register char * ep; 1284 1285 if ((lp = byword(monthp, mon_names)) == NULL) { 1286 error(_("invalid month name")); 1287 return; 1288 } 1289 rp->r_month = lp->l_value; 1290 rp->r_todisstd = FALSE; 1291 rp->r_todisgmt = FALSE; 1292 dp = ecpyalloc(timep); 1293 if (*dp != '\0') { 1294 ep = dp + strlen(dp) - 1; 1295 switch (lowerit(*ep)) { 1296 case 's': /* Standard */ 1297 rp->r_todisstd = TRUE; 1298 rp->r_todisgmt = FALSE; 1299 *ep = '\0'; 1300 break; 1301 case 'w': /* Wall */ 1302 rp->r_todisstd = FALSE; 1303 rp->r_todisgmt = FALSE; 1304 *ep = '\0'; 1305 break; 1306 case 'g': /* Greenwich */ 1307 case 'u': /* Universal */ 1308 case 'z': /* Zulu */ 1309 rp->r_todisstd = TRUE; 1310 rp->r_todisgmt = TRUE; 1311 *ep = '\0'; 1312 break; 1313 } 1314 } 1315 rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); 1316 ifree(dp); 1317 /* 1318 ** Year work. 1319 */ 1320 cp = loyearp; 1321 lp = byword(cp, begin_years); 1322 rp->r_lowasnum = lp == NULL; 1323 if (!rp->r_lowasnum) switch ((int) lp->l_value) { 1324 case YR_MINIMUM: 1325 rp->r_loyear = INT_MIN; 1326 break; 1327 case YR_MAXIMUM: 1328 rp->r_loyear = INT_MAX; 1329 break; 1330 default: /* "cannot happen" */ 1331 (void) fprintf(stderr, 1332 _("%s: panic: Invalid l_value %d\n"), 1333 progname, lp->l_value); 1334 exit(EXIT_FAILURE); 1335 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1336 error(_("invalid starting year")); 1337 return; 1338 } 1339 cp = hiyearp; 1340 lp = byword(cp, end_years); 1341 rp->r_hiwasnum = lp == NULL; 1342 if (!rp->r_hiwasnum) switch ((int) lp->l_value) { 1343 case YR_MINIMUM: 1344 rp->r_hiyear = INT_MIN; 1345 break; 1346 case YR_MAXIMUM: 1347 rp->r_hiyear = INT_MAX; 1348 break; 1349 case YR_ONLY: 1350 rp->r_hiyear = rp->r_loyear; 1351 break; 1352 default: /* "cannot happen" */ 1353 (void) fprintf(stderr, 1354 _("%s: panic: Invalid l_value %d\n"), 1355 progname, lp->l_value); 1356 exit(EXIT_FAILURE); 1357 } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1358 error(_("invalid ending year")); 1359 return; 1360 } 1361 if (rp->r_loyear > rp->r_hiyear) { 1362 error(_("starting year greater than ending year")); 1363 return; 1364 } 1365 if (*typep == '\0') 1366 rp->r_yrtype = NULL; 1367 else { 1368 if (rp->r_loyear == rp->r_hiyear) { 1369 error(_("typed single year")); 1370 return; 1371 } 1372 rp->r_yrtype = ecpyalloc(typep); 1373 } 1374 /* 1375 ** Day work. 1376 ** Accept things such as: 1377 ** 1 1378 ** last-Sunday 1379 ** Sun<=20 1380 ** Sun>=7 1381 */ 1382 dp = ecpyalloc(dayp); 1383 if ((lp = byword(dp, lasts)) != NULL) { 1384 rp->r_dycode = DC_DOWLEQ; 1385 rp->r_wday = lp->l_value; 1386 rp->r_dayofmonth = len_months[1][rp->r_month]; 1387 } else { 1388 if ((ep = strchr(dp, '<')) != 0) 1389 rp->r_dycode = DC_DOWLEQ; 1390 else if ((ep = strchr(dp, '>')) != 0) 1391 rp->r_dycode = DC_DOWGEQ; 1392 else { 1393 ep = dp; 1394 rp->r_dycode = DC_DOM; 1395 } 1396 if (rp->r_dycode != DC_DOM) { 1397 *ep++ = 0; 1398 if (*ep++ != '=') { 1399 error(_("invalid day of month")); 1400 ifree(dp); 1401 return; 1402 } 1403 if ((lp = byword(dp, wday_names)) == NULL) { 1404 error(_("invalid weekday name")); 1405 ifree(dp); 1406 return; 1407 } 1408 rp->r_wday = lp->l_value; 1409 } 1410 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1411 rp->r_dayofmonth <= 0 || 1412 (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1413 error(_("invalid day of month")); 1414 ifree(dp); 1415 return; 1416 } 1417 } 1418 ifree(dp); 1419} 1420 1421static void 1422convert(val, buf) 1423const long val; 1424char * const buf; 1425{ 1426 register int i; 1427 register int shift; 1428 1429 for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1430 buf[i] = val >> shift; 1431} 1432 1433static void 1434convert64(val, buf) 1435const zic_t val; 1436char * const buf; 1437{ 1438 register int i; 1439 register int shift; 1440 1441 for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1442 buf[i] = val >> shift; 1443} 1444 1445static void 1446puttzcode(val, fp) 1447const long val; 1448FILE * const fp; 1449{ 1450 char buf[4]; 1451 1452 convert(val, buf); 1453 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 1454} 1455 1456static void 1457puttzcode64(val, fp) 1458const zic_t val; 1459FILE * const fp; 1460{ 1461 char buf[8]; 1462 1463 convert64(val, buf); 1464 (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 1465} 1466 1467static int 1468atcomp(avp, bvp) 1469const void * avp; 1470const void * bvp; 1471{ 1472 const zic_t a = ((const struct attype *) avp)->at; 1473 const zic_t b = ((const struct attype *) bvp)->at; 1474 1475 return (a < b) ? -1 : (a > b); 1476} 1477 1478static int 1479is32(x) 1480const zic_t x; 1481{ 1482 return INT32_MIN <= x && x <= INT32_MAX; 1483} 1484 1485static void 1486writezone(name, string) 1487const char * const name; 1488const char * const string; 1489{ 1490 register FILE * fp; 1491 register int i, j; 1492 register int leapcnt32, leapi32; 1493 register int timecnt32, timei32; 1494 register int pass; 1495 static char * fullname; 1496 static const struct tzhead tzh0; 1497 static struct tzhead tzh; 1498 zic_t ats[TZ_MAX_TIMES]; 1499 unsigned char types[TZ_MAX_TIMES]; 1500 1501 /* 1502 ** Sort. 1503 */ 1504 if (timecnt > 1) 1505 (void) qsort((void *) attypes, (size_t) timecnt, 1506 (size_t) sizeof *attypes, atcomp); 1507 /* 1508 ** Optimize. 1509 */ 1510 { 1511 int fromi; 1512 int toi; 1513 1514 toi = 0; 1515 fromi = 0; 1516 while (fromi < timecnt && attypes[fromi].at < min_time) 1517 ++fromi; 1518 if (isdsts[0] == 0) 1519 while (fromi < timecnt && attypes[fromi].type == 0) 1520 ++fromi; /* handled by default rule */ 1521 for ( ; fromi < timecnt; ++fromi) { 1522 if (toi != 0 && ((attypes[fromi].at + 1523 gmtoffs[attypes[toi - 1].type]) <= 1524 (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 1525 : attypes[toi - 2].type]))) { 1526 attypes[toi - 1].type = 1527 attypes[fromi].type; 1528 continue; 1529 } 1530 if (toi == 0 || 1531 attypes[toi - 1].type != attypes[fromi].type) 1532 attypes[toi++] = attypes[fromi]; 1533 } 1534 timecnt = toi; 1535 } 1536 /* 1537 ** Transfer. 1538 */ 1539 for (i = 0; i < timecnt; ++i) { 1540 ats[i] = attypes[i].at; 1541 types[i] = attypes[i].type; 1542 } 1543 /* 1544 ** Correct for leap seconds. 1545 */ 1546 for (i = 0; i < timecnt; ++i) { 1547 j = leapcnt; 1548 while (--j >= 0) 1549 if (ats[i] > trans[j] - corr[j]) { 1550 ats[i] = tadd(ats[i], corr[j]); 1551 break; 1552 } 1553 } 1554 /* 1555 ** Figure out 32-bit-limited starts and counts. 1556 */ 1557 timecnt32 = timecnt; 1558 timei32 = 0; 1559 leapcnt32 = leapcnt; 1560 leapi32 = 0; 1561 while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) 1562 --timecnt32; 1563 while (timecnt32 > 0 && !is32(ats[timei32])) { 1564 --timecnt32; 1565 ++timei32; 1566 } 1567 while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) 1568 --leapcnt32; 1569 while (leapcnt32 > 0 && !is32(trans[leapi32])) { 1570 --leapcnt32; 1571 ++leapi32; 1572 } 1573 fullname = erealloc(fullname, 1574 (int) (strlen(directory) + 1 + strlen(name) + 1)); 1575 (void) sprintf(fullname, "%s/%s", directory, name); /* XXX: sprintf is safe */ 1576 /* 1577 ** Remove old file, if any, to snap links. 1578 */ 1579 if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 1580 const char *e = strerror(errno); 1581 1582 (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"), 1583 progname, fullname, e); 1584 exit(EXIT_FAILURE); 1585 } 1586 if ((fp = fopen(fullname, "wb")) == NULL) { 1587 if (mkdirs(fullname) != 0) 1588 exit(EXIT_FAILURE); 1589 if ((fp = fopen(fullname, "wb")) == NULL) { 1590 const char *e = strerror(errno); 1591 1592 (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), 1593 progname, fullname, e); 1594 exit(EXIT_FAILURE); 1595 } 1596 } 1597 for (pass = 1; pass <= 2; ++pass) { 1598 register int thistimei, thistimecnt; 1599 register int thisleapi, thisleapcnt; 1600 register int thistimelim, thisleaplim; 1601 int writetype[TZ_MAX_TIMES]; 1602 int typemap[TZ_MAX_TYPES]; 1603 register int thistypecnt; 1604 char thischars[TZ_MAX_CHARS]; 1605 char thischarcnt; 1606 int indmap[TZ_MAX_CHARS]; 1607 1608 if (pass == 1) { 1609 thistimei = timei32; 1610 thistimecnt = timecnt32; 1611 thisleapi = leapi32; 1612 thisleapcnt = leapcnt32; 1613 } else { 1614 thistimei = 0; 1615 thistimecnt = timecnt; 1616 thisleapi = 0; 1617 thisleapcnt = leapcnt; 1618 } 1619 thistimelim = thistimei + thistimecnt; 1620 thisleaplim = thisleapi + thisleapcnt; 1621 for (i = 0; i < typecnt; ++i) 1622 writetype[i] = thistimecnt == timecnt; 1623 if (thistimecnt == 0) { 1624 /* 1625 ** No transition times fall in the current 1626 ** (32- or 64-bit) window. 1627 */ 1628 if (typecnt != 0) 1629 writetype[typecnt - 1] = TRUE; 1630 } else { 1631 for (i = thistimei - 1; i < thistimelim; ++i) 1632 if (i >= 0) 1633 writetype[types[i]] = TRUE; 1634 /* 1635 ** For America/Godthab and Antarctica/Palmer 1636 */ 1637 if (thistimei == 0) 1638 writetype[0] = TRUE; 1639 } 1640#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 1641 /* 1642 ** For some pre-2011 systems: if the last-to-be-written 1643 ** standard (or daylight) type has an offset different from the 1644 ** most recently used offset, 1645 ** append an (unused) copy of the most recently used type 1646 ** (to help get global "altzone" and "timezone" variables 1647 ** set correctly). 1648 */ 1649 { 1650 register int mrudst, mrustd, hidst, histd, type; 1651 1652 hidst = histd = mrudst = mrustd = -1; 1653 for (i = thistimei; i < thistimelim; ++i) 1654 if (isdsts[types[i]]) 1655 mrudst = types[i]; 1656 else mrustd = types[i]; 1657 for (i = 0; i < typecnt; ++i) 1658 if (writetype[i]) { 1659 if (isdsts[i]) 1660 hidst = i; 1661 else histd = i; 1662 } 1663 if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 1664 gmtoffs[hidst] != gmtoffs[mrudst]) { 1665 isdsts[mrudst] = -1; 1666 type = addtype(gmtoffs[mrudst], 1667 &chars[abbrinds[mrudst]], 1668 TRUE, 1669 ttisstds[mrudst], 1670 ttisgmts[mrudst]); 1671 isdsts[mrudst] = TRUE; 1672 writetype[type] = TRUE; 1673 } 1674 if (histd >= 0 && mrustd >= 0 && histd != mrustd && 1675 gmtoffs[histd] != gmtoffs[mrustd]) { 1676 isdsts[mrustd] = -1; 1677 type = addtype(gmtoffs[mrustd], 1678 &chars[abbrinds[mrustd]], 1679 FALSE, 1680 ttisstds[mrustd], 1681 ttisgmts[mrustd]); 1682 isdsts[mrustd] = FALSE; 1683 writetype[type] = TRUE; 1684 } 1685 } 1686#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 1687 thistypecnt = 0; 1688 for (i = 0; i < typecnt; ++i) 1689 typemap[i] = writetype[i] ? thistypecnt++ : -1; 1690 for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) 1691 indmap[i] = -1; 1692 thischarcnt = 0; 1693 for (i = 0; i < typecnt; ++i) { 1694 register char * thisabbr; 1695 1696 if (!writetype[i]) 1697 continue; 1698 if (indmap[abbrinds[i]] >= 0) 1699 continue; 1700 thisabbr = &chars[abbrinds[i]]; 1701 for (j = 0; j < thischarcnt; ++j) 1702 if (strcmp(&thischars[j], thisabbr) == 0) 1703 break; 1704 if (j == thischarcnt) { 1705 (void) strcpy(&thischars[(int) thischarcnt], 1706 thisabbr); 1707 thischarcnt += strlen(thisabbr) + 1; 1708 } 1709 indmap[abbrinds[i]] = j; 1710 } 1711#define DO(field) (void) fwrite((void *) tzh.field, \ 1712 (size_t) sizeof tzh.field, (size_t) 1, fp) 1713 tzh = tzh0; 1714 (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 1715 tzh.tzh_version[0] = ZIC_VERSION; 1716 convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt); 1717 convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt); 1718 convert(eitol(thisleapcnt), tzh.tzh_leapcnt); 1719 convert(eitol(thistimecnt), tzh.tzh_timecnt); 1720 convert(eitol(thistypecnt), tzh.tzh_typecnt); 1721 convert(eitol(thischarcnt), tzh.tzh_charcnt); 1722 DO(tzh_magic); 1723 DO(tzh_version); 1724 DO(tzh_reserved); 1725 DO(tzh_ttisgmtcnt); 1726 DO(tzh_ttisstdcnt); 1727 DO(tzh_leapcnt); 1728 DO(tzh_timecnt); 1729 DO(tzh_typecnt); 1730 DO(tzh_charcnt); 1731#undef DO 1732 for (i = thistimei; i < thistimelim; ++i) 1733 if (pass == 1) 1734 puttzcode((long) ats[i], fp); 1735 else puttzcode64(ats[i], fp); 1736 for (i = thistimei; i < thistimelim; ++i) { 1737 unsigned char uc; 1738 1739 uc = typemap[types[i]]; 1740 (void) fwrite((void *) &uc, 1741 (size_t) sizeof uc, 1742 (size_t) 1, 1743 fp); 1744 } 1745 for (i = 0; i < typecnt; ++i) 1746 if (writetype[i]) { 1747 puttzcode(gmtoffs[i], fp); 1748 (void) putc(isdsts[i], fp); 1749 (void) putc((unsigned char) indmap[abbrinds[i]], fp); 1750 } 1751 if (thischarcnt != 0) 1752 (void) fwrite((void *) thischars, 1753 (size_t) sizeof thischars[0], 1754 (size_t) thischarcnt, fp); 1755 for (i = thisleapi; i < thisleaplim; ++i) { 1756 register zic_t todo; 1757 1758 if (roll[i]) { 1759 if (timecnt == 0 || trans[i] < ats[0]) { 1760 j = 0; 1761 while (isdsts[j]) 1762 if (++j >= typecnt) { 1763 j = 0; 1764 break; 1765 } 1766 } else { 1767 j = 1; 1768 while (j < timecnt && 1769 trans[i] >= ats[j]) 1770 ++j; 1771 j = types[j - 1]; 1772 } 1773 todo = tadd(trans[i], -gmtoffs[j]); 1774 } else todo = trans[i]; 1775 if (pass == 1) 1776 puttzcode((long) todo, fp); 1777 else puttzcode64(todo, fp); 1778 puttzcode(corr[i], fp); 1779 } 1780 for (i = 0; i < typecnt; ++i) 1781 if (writetype[i]) 1782 (void) putc(ttisstds[i], fp); 1783 for (i = 0; i < typecnt; ++i) 1784 if (writetype[i]) 1785 (void) putc(ttisgmts[i], fp); 1786 } 1787 (void) fprintf(fp, "\n%s\n", string); 1788 if (ferror(fp) || fclose(fp)) { 1789 (void) fprintf(stderr, _("%s: Error writing %s\n"), 1790 progname, fullname); 1791 exit(EXIT_FAILURE); 1792 } 1793} 1794 1795static void 1796doabbr(abbr, abbrlen, format, letters, isdst, doquotes) 1797char * const abbr; 1798const int abbrlen; 1799const char * const format; 1800const char * const letters; 1801const int isdst; 1802const int doquotes; 1803{ 1804 register char * cp; 1805 register char * slashp; 1806 register int len; 1807 1808 slashp = strchr(format, '/'); 1809 if (slashp == NULL) { 1810 if (letters == NULL) 1811 (void) strlcpy(abbr, format, abbrlen); 1812 else (void) snprintf(abbr, abbrlen, format, letters); 1813 } else if (isdst) { 1814 (void) strlcpy(abbr, slashp + 1, abbrlen); 1815 } else { 1816 if (slashp > format) 1817 (void) strncpy(abbr, format, 1818 (unsigned) (slashp - format)); 1819 abbr[slashp - format] = '\0'; 1820 } 1821 if (!doquotes) 1822 return; 1823 for (cp = abbr; *cp != '\0'; ++cp) 1824 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL && 1825 strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL) 1826 break; 1827 len = strlen(abbr); 1828 if (len > 0 && *cp == '\0') 1829 return; 1830 abbr[len + 2] = '\0'; 1831 abbr[len + 1] = '>'; 1832 for ( ; len > 0; --len) 1833 abbr[len] = abbr[len - 1]; 1834 abbr[0] = '<'; 1835} 1836 1837static void 1838updateminmax(x) 1839const int x; 1840{ 1841 if (min_year > x) 1842 min_year = x; 1843 if (max_year < x) 1844 max_year = x; 1845} 1846 1847static int 1848stringoffset(result, offset) 1849char * result; 1850long offset; 1851{ 1852 register int hours; 1853 register int minutes; 1854 register int seconds; 1855 1856 result[0] = '\0'; 1857 if (offset < 0) { 1858 (void) strcpy(result, "-"); 1859 offset = -offset; 1860 } 1861 seconds = offset % SECSPERMIN; 1862 offset /= SECSPERMIN; 1863 minutes = offset % MINSPERHOUR; 1864 offset /= MINSPERHOUR; 1865 hours = offset; 1866 if (hours >= HOURSPERDAY) { 1867 result[0] = '\0'; 1868 return -1; 1869 } 1870 (void) sprintf(end(result), "%d", hours); 1871 if (minutes != 0 || seconds != 0) { 1872 (void) sprintf(end(result), ":%02d", minutes); 1873 if (seconds != 0) 1874 (void) sprintf(end(result), ":%02d", seconds); 1875 } 1876 return 0; 1877} 1878 1879static int 1880stringrule(result, rp, dstoff, gmtoff) 1881char * result; 1882const struct rule * const rp; 1883const long dstoff; 1884const long gmtoff; 1885{ 1886 register long tod; 1887 1888 result = end(result); 1889 if (rp->r_dycode == DC_DOM) { 1890 register int month, total; 1891 1892 if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 1893 return -1; 1894 total = 0; 1895 for (month = 0; month < rp->r_month; ++month) 1896 total += len_months[0][month]; 1897 (void) sprintf(result, "J%d", total + rp->r_dayofmonth); 1898 } else { 1899 register int week; 1900 1901 if (rp->r_dycode == DC_DOWGEQ) { 1902 if ((rp->r_dayofmonth % DAYSPERWEEK) != 1) 1903 return -1; 1904 week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1905 } else if (rp->r_dycode == DC_DOWLEQ) { 1906 if (rp->r_dayofmonth == len_months[1][rp->r_month]) 1907 week = 5; 1908 else { 1909 if ((rp->r_dayofmonth % DAYSPERWEEK) != 0) 1910 return -1; 1911 week = rp->r_dayofmonth / DAYSPERWEEK; 1912 } 1913 } else return -1; /* "cannot happen" */ 1914 (void) sprintf(result, "M%d.%d.%d", 1915 rp->r_month + 1, week, rp->r_wday); 1916 } 1917 tod = rp->r_tod; 1918 if (rp->r_todisgmt) 1919 tod += gmtoff; 1920 if (rp->r_todisstd && rp->r_stdoff == 0) 1921 tod += dstoff; 1922 if (tod < 0) { 1923 result[0] = '\0'; 1924 return -1; 1925 } 1926 if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 1927 (void) strcat(result, "/"); 1928 if (stringoffset(end(result), tod) != 0) 1929 return -1; 1930 } 1931 return 0; 1932} 1933 1934static void 1935stringzone(result, resultlen, zpfirst, zonecount) 1936char * result; 1937const int resultlen; 1938const struct zone * const zpfirst; 1939const int zonecount; 1940{ 1941 register const struct zone * zp; 1942 register struct rule * rp; 1943 register struct rule * stdrp; 1944 register struct rule * dstrp; 1945 register int i; 1946 register const char * abbrvar; 1947 1948 result[0] = '\0'; 1949 zp = zpfirst + zonecount - 1; 1950 stdrp = dstrp = NULL; 1951 for (i = 0; i < zp->z_nrules; ++i) { 1952 rp = &zp->z_rules[i]; 1953 if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX) 1954 continue; 1955 if (rp->r_yrtype != NULL) 1956 continue; 1957 if (rp->r_stdoff == 0) { 1958 if (stdrp == NULL) 1959 stdrp = rp; 1960 else return; 1961 } else { 1962 if (dstrp == NULL) 1963 dstrp = rp; 1964 else return; 1965 } 1966 } 1967 if (stdrp == NULL && dstrp == NULL) { 1968 /* 1969 ** There are no rules running through "max". 1970 ** Let's find the latest rule. 1971 */ 1972 for (i = 0; i < zp->z_nrules; ++i) { 1973 rp = &zp->z_rules[i]; 1974 if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || 1975 (rp->r_hiyear == stdrp->r_hiyear && 1976 rp->r_month > stdrp->r_month)) 1977 stdrp = rp; 1978 } 1979 if (stdrp != NULL && stdrp->r_stdoff != 0) 1980 return; /* We end up in DST (a POSIX no-no). */ 1981 /* 1982 ** Horrid special case: if year is 2037, 1983 ** presume this is a zone handled on a year-by-year basis; 1984 ** do not try to apply a rule to the zone. 1985 */ 1986 if (stdrp != NULL && stdrp->r_hiyear == 2037) 1987 return; 1988 } 1989 if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) 1990 return; 1991 abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 1992 doabbr(result, resultlen, zp->z_format, abbrvar, FALSE, TRUE); 1993 if (stringoffset(end(result), -zp->z_gmtoff) != 0) { 1994 result[0] = '\0'; 1995 return; 1996 } 1997 if (dstrp == NULL) 1998 return; 1999 doabbr(end(result), resultlen - strlen(result), 2000 zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); 2001 if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) 2002 if (stringoffset(end(result), 2003 -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { 2004 result[0] = '\0'; 2005 return; 2006 } 2007 (void) strcat(result, ","); 2008 if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 2009 result[0] = '\0'; 2010 return; 2011 } 2012 (void) strcat(result, ","); 2013 if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 2014 result[0] = '\0'; 2015 return; 2016 } 2017} 2018 2019static void 2020outzone(zpfirst, zonecount) 2021const struct zone * const zpfirst; 2022const int zonecount; 2023{ 2024 register const struct zone * zp; 2025 register struct rule * rp; 2026 register int i, j; 2027 register int usestart, useuntil; 2028 register zic_t starttime, untiltime; 2029 register long gmtoff; 2030 register long stdoff; 2031 register int year; 2032 register long startoff; 2033 register int startttisstd; 2034 register int startttisgmt; 2035 register int type; 2036 register char * startbuf; 2037 register char * ab; 2038 register char * envvar; 2039 register int max_abbr_len; 2040 register int max_envvar_len; 2041 register int prodstic; /* all rules are min to max */ 2042 2043 max_abbr_len = 2 + max_format_len + max_abbrvar_len; 2044 max_envvar_len = 2 * max_abbr_len + 5 * 9; 2045 startbuf = emalloc(max_abbr_len + 1); 2046 ab = emalloc(max_abbr_len + 1); 2047 envvar = emalloc(max_envvar_len + 1); 2048 INITIALIZE(untiltime); 2049 INITIALIZE(starttime); 2050 /* 2051 ** Now. . .finally. . .generate some useful data! 2052 */ 2053 timecnt = 0; 2054 typecnt = 0; 2055 charcnt = 0; 2056 prodstic = zonecount == 1; 2057 /* 2058 ** Thanks to Earl Chew 2059 ** for noting the need to unconditionally initialize startttisstd. 2060 */ 2061 startttisstd = FALSE; 2062 startttisgmt = FALSE; 2063 min_year = max_year = EPOCH_YEAR; 2064 if (leapseen) { 2065 updateminmax(leapminyear); 2066 updateminmax(leapmaxyear + (leapmaxyear < INT_MAX)); 2067 } 2068 for (i = 0; i < zonecount; ++i) { 2069 zp = &zpfirst[i]; 2070 if (i < zonecount - 1) 2071 updateminmax(zp->z_untilrule.r_loyear); 2072 for (j = 0; j < zp->z_nrules; ++j) { 2073 rp = &zp->z_rules[j]; 2074 if (rp->r_lowasnum) 2075 updateminmax(rp->r_loyear); 2076 if (rp->r_hiwasnum) 2077 updateminmax(rp->r_hiyear); 2078 } 2079 } 2080 /* 2081 ** Generate lots of data if a rule can't cover all future times. 2082 */ 2083 stringzone(envvar, max_envvar_len+1, zpfirst, zonecount); 2084 if (noise && envvar[0] == '\0') { 2085 register char * wp; 2086 2087wp = ecpyalloc(_("no POSIX environment variable for zone")); 2088 wp = ecatalloc(wp, " "); 2089 wp = ecatalloc(wp, zpfirst->z_name); 2090 warning(wp); 2091 ifree(wp); 2092 } 2093 if (envvar[0] == '\0') { 2094 if (min_year >= INT_MIN + YEARSPERREPEAT) 2095 min_year -= YEARSPERREPEAT; 2096 else min_year = INT_MIN; 2097 if (max_year <= INT_MAX - YEARSPERREPEAT) 2098 max_year += YEARSPERREPEAT; 2099 else max_year = INT_MAX; 2100 /* 2101 ** Regardless of any of the above, 2102 ** for a "proDSTic" zone which specifies that its rules 2103 ** always have and always will be in effect, 2104 ** we only need one cycle to define the zone. 2105 */ 2106 if (prodstic) { 2107 min_year = 1900; 2108 max_year = min_year + YEARSPERREPEAT; 2109 } 2110 } 2111 /* 2112 ** For the benefit of older systems, 2113 ** generate data from 1900 through 2037. 2114 */ 2115 if (min_year > 1900) 2116 min_year = 1900; 2117 if (max_year < 2037) 2118 max_year = 2037; 2119 for (i = 0; i < zonecount; ++i) { 2120 /* 2121 ** A guess that may well be corrected later. 2122 */ 2123 stdoff = 0; 2124 zp = &zpfirst[i]; 2125 usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 2126 useuntil = i < (zonecount - 1); 2127 if (useuntil && zp->z_untiltime <= min_time) 2128 continue; 2129 gmtoff = zp->z_gmtoff; 2130 eat(zp->z_filename, zp->z_linenum); 2131 *startbuf = '\0'; 2132 startoff = zp->z_gmtoff; 2133 if (zp->z_nrules == 0) { 2134 stdoff = zp->z_stdoff; 2135 doabbr(startbuf, max_abbr_len + 1, zp->z_format, 2136 (char *) NULL, stdoff != 0, FALSE); 2137 type = addtype(oadd(zp->z_gmtoff, stdoff), 2138 startbuf, stdoff != 0, startttisstd, 2139 startttisgmt); 2140 if (usestart) { 2141 addtt(starttime, type); 2142 usestart = FALSE; 2143 } else if (stdoff != 0) 2144 addtt(min_time, type); 2145 } else for (year = min_year; year <= max_year; ++year) { 2146 if (useuntil && year > zp->z_untilrule.r_hiyear) 2147 break; 2148 /* 2149 ** Mark which rules to do in the current year. 2150 ** For those to do, calculate rpytime(rp, year); 2151 */ 2152 for (j = 0; j < zp->z_nrules; ++j) { 2153 rp = &zp->z_rules[j]; 2154 eats(zp->z_filename, zp->z_linenum, 2155 rp->r_filename, rp->r_linenum); 2156 rp->r_todo = year >= rp->r_loyear && 2157 year <= rp->r_hiyear && 2158 yearistype(year, rp->r_yrtype); 2159 if (rp->r_todo) 2160 rp->r_temp = rpytime(rp, year); 2161 } 2162 for ( ; ; ) { 2163 register int k; 2164 register zic_t jtime, ktime; 2165 register long offset; 2166 2167 INITIALIZE(ktime); 2168 if (useuntil) { 2169 /* 2170 ** Turn untiltime into UTC 2171 ** assuming the current gmtoff and 2172 ** stdoff values. 2173 */ 2174 untiltime = zp->z_untiltime; 2175 if (!zp->z_untilrule.r_todisgmt) 2176 untiltime = tadd(untiltime, 2177 -gmtoff); 2178 if (!zp->z_untilrule.r_todisstd) 2179 untiltime = tadd(untiltime, 2180 -stdoff); 2181 } 2182 /* 2183 ** Find the rule (of those to do, if any) 2184 ** that takes effect earliest in the year. 2185 */ 2186 k = -1; 2187 for (j = 0; j < zp->z_nrules; ++j) { 2188 rp = &zp->z_rules[j]; 2189 if (!rp->r_todo) 2190 continue; 2191 eats(zp->z_filename, zp->z_linenum, 2192 rp->r_filename, rp->r_linenum); 2193 offset = rp->r_todisgmt ? 0 : gmtoff; 2194 if (!rp->r_todisstd) 2195 offset = oadd(offset, stdoff); 2196 jtime = rp->r_temp; 2197 if (jtime == min_time || 2198 jtime == max_time) 2199 continue; 2200 jtime = tadd(jtime, -offset); 2201 if (k < 0 || jtime < ktime) { 2202 k = j; 2203 ktime = jtime; 2204 } 2205 } 2206 if (k < 0) 2207 break; /* go on to next year */ 2208 rp = &zp->z_rules[k]; 2209 rp->r_todo = FALSE; 2210 if (useuntil && ktime >= untiltime) 2211 break; 2212 stdoff = rp->r_stdoff; 2213 if (usestart && ktime == starttime) 2214 usestart = FALSE; 2215 if (usestart) { 2216 if (ktime < starttime) { 2217 startoff = oadd(zp->z_gmtoff, 2218 stdoff); 2219 doabbr(startbuf, 2220 max_abbr_len + 1, 2221 zp->z_format, 2222 rp->r_abbrvar, 2223 rp->r_stdoff != 0, 2224 FALSE); 2225 continue; 2226 } 2227 if (*startbuf == '\0' && 2228 startoff == oadd(zp->z_gmtoff, 2229 stdoff)) { 2230 doabbr(startbuf, 2231 max_abbr_len + 1, 2232 zp->z_format, 2233 rp->r_abbrvar, 2234 rp->r_stdoff != 2235 0, 2236 FALSE); 2237 } 2238 } 2239 eats(zp->z_filename, zp->z_linenum, 2240 rp->r_filename, rp->r_linenum); 2241 doabbr(ab, max_abbr_len+1, zp->z_format, rp->r_abbrvar, 2242 rp->r_stdoff != 0, FALSE); 2243 offset = oadd(zp->z_gmtoff, rp->r_stdoff); 2244 type = addtype(offset, ab, rp->r_stdoff != 0, 2245 rp->r_todisstd, rp->r_todisgmt); 2246 addtt(ktime, type); 2247 } 2248 } 2249 if (usestart) { 2250 if (*startbuf == '\0' && 2251 zp->z_format != NULL && 2252 strchr(zp->z_format, '%') == NULL && 2253 strchr(zp->z_format, '/') == NULL) 2254 (void)strncpy(startbuf, zp->z_format, 2255 max_abbr_len + 1 - 1); 2256 eat(zp->z_filename, zp->z_linenum); 2257 if (*startbuf == '\0') 2258error(_("can't determine time zone abbreviation to use just after until time")); 2259 else addtt(starttime, 2260 addtype(startoff, startbuf, 2261 startoff != zp->z_gmtoff, 2262 startttisstd, 2263 startttisgmt)); 2264 } 2265 /* 2266 ** Now we may get to set starttime for the next zone line. 2267 */ 2268 if (useuntil) { 2269 startttisstd = zp->z_untilrule.r_todisstd; 2270 startttisgmt = zp->z_untilrule.r_todisgmt; 2271 starttime = zp->z_untiltime; 2272 if (!startttisstd) 2273 starttime = tadd(starttime, -stdoff); 2274 if (!startttisgmt) 2275 starttime = tadd(starttime, -gmtoff); 2276 } 2277 } 2278 writezone(zpfirst->z_name, envvar); 2279 ifree(startbuf); 2280 ifree(ab); 2281 ifree(envvar); 2282} 2283 2284static void 2285addtt(starttime, type) 2286const zic_t starttime; 2287int type; 2288{ 2289 if (starttime <= min_time || 2290 (timecnt == 1 && attypes[0].at < min_time)) { 2291 gmtoffs[0] = gmtoffs[type]; 2292 isdsts[0] = isdsts[type]; 2293 ttisstds[0] = ttisstds[type]; 2294 ttisgmts[0] = ttisgmts[type]; 2295 if (abbrinds[type] != 0) 2296 (void) strcpy(chars, &chars[abbrinds[type]]); 2297 abbrinds[0] = 0; 2298 charcnt = strlen(chars) + 1; 2299 typecnt = 1; 2300 timecnt = 0; 2301 type = 0; 2302 } 2303 if (timecnt >= TZ_MAX_TIMES) { 2304 error(_("too many transitions?!")); 2305 exit(EXIT_FAILURE); 2306 } 2307 attypes[timecnt].at = starttime; 2308 attypes[timecnt].type = type; 2309 ++timecnt; 2310} 2311 2312static int 2313addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 2314const long gmtoff; 2315const char * const abbr; 2316const int isdst; 2317const int ttisstd; 2318const int ttisgmt; 2319{ 2320 register int i, j; 2321 2322 if (isdst != TRUE && isdst != FALSE) { 2323 error(_("internal error - addtype called with bad isdst")); 2324 exit(EXIT_FAILURE); 2325 } 2326 if (ttisstd != TRUE && ttisstd != FALSE) { 2327 error(_("internal error - addtype called with bad ttisstd")); 2328 exit(EXIT_FAILURE); 2329 } 2330 if (ttisgmt != TRUE && ttisgmt != FALSE) { 2331 error(_("internal error - addtype called with bad ttisgmt")); 2332 exit(EXIT_FAILURE); 2333 } 2334 /* 2335 ** See if there's already an entry for this zone type. 2336 ** If so, just return its index. 2337 */ 2338 for (i = 0; i < typecnt; ++i) { 2339 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 2340 strcmp(abbr, &chars[abbrinds[i]]) == 0 && 2341 ttisstd == ttisstds[i] && 2342 ttisgmt == ttisgmts[i]) 2343 return i; 2344 } 2345 /* 2346 ** There isn't one; add a new one, unless there are already too 2347 ** many. 2348 */ 2349 if (typecnt >= TZ_MAX_TYPES) { 2350 error(_("too many local time types")); 2351 exit(EXIT_FAILURE); 2352 } 2353 if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 2354 error(_("UTC offset out of range")); 2355 exit(EXIT_FAILURE); 2356 } 2357 gmtoffs[i] = gmtoff; 2358 isdsts[i] = isdst; 2359 ttisstds[i] = ttisstd; 2360 ttisgmts[i] = ttisgmt; 2361 2362 for (j = 0; j < charcnt; ++j) 2363 if (strcmp(&chars[j], abbr) == 0) 2364 break; 2365 if (j == charcnt) 2366 newabbr(abbr); 2367 abbrinds[i] = j; 2368 ++typecnt; 2369 return i; 2370} 2371 2372static void 2373leapadd(t, positive, rolling, count) 2374const zic_t t; 2375const int positive; 2376const int rolling; 2377int count; 2378{ 2379 register int i, j; 2380 2381 if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 2382 error(_("too many leap seconds")); 2383 exit(EXIT_FAILURE); 2384 } 2385 for (i = 0; i < leapcnt; ++i) 2386 if (t <= trans[i]) { 2387 if (t == trans[i]) { 2388 error(_("repeated leap second moment")); 2389 exit(EXIT_FAILURE); 2390 } 2391 break; 2392 } 2393 do { 2394 for (j = leapcnt; j > i; --j) { 2395 trans[j] = trans[j - 1]; 2396 corr[j] = corr[j - 1]; 2397 roll[j] = roll[j - 1]; 2398 } 2399 trans[i] = t; 2400 corr[i] = positive ? 1L : eitol(-count); 2401 roll[i] = rolling; 2402 ++leapcnt; 2403 } while (positive && --count != 0); 2404} 2405 2406static void 2407adjleap(void) 2408{ 2409 register int i; 2410 register long last = 0; 2411 2412 /* 2413 ** propagate leap seconds forward 2414 */ 2415 for (i = 0; i < leapcnt; ++i) { 2416 trans[i] = tadd(trans[i], last); 2417 last = corr[i] += last; 2418 } 2419} 2420 2421static int 2422yearistype(year, type) 2423const int year; 2424const char * const type; 2425{ 2426 static char * buf; 2427 int result; 2428 2429 if (type == NULL || *type == '\0') 2430 return TRUE; 2431 buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 2432 (void)sprintf(buf, "%s %d %s", yitcommand, year, type); /* XXX: sprintf is safe */ 2433 result = system(buf); 2434 if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { 2435 case 0: 2436 return TRUE; 2437 case 1: 2438 return FALSE; 2439 } 2440 error(_("Wild result from command execution")); 2441 (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), 2442 progname, buf, result); 2443 for ( ; ; ) 2444 exit(EXIT_FAILURE); 2445} 2446 2447static int 2448lowerit(a) 2449int a; 2450{ 2451 a = (unsigned char) a; 2452 return (isascii(a) && isupper(a)) ? tolower(a) : a; 2453} 2454 2455static int 2456ciequal(ap, bp) /* case-insensitive equality */ 2457register const char * ap; 2458register const char * bp; 2459{ 2460 while (lowerit(*ap) == lowerit(*bp++)) 2461 if (*ap++ == '\0') 2462 return TRUE; 2463 return FALSE; 2464} 2465 2466static int 2467itsabbr(abbr, word) 2468register const char * abbr; 2469register const char * word; 2470{ 2471 if (lowerit(*abbr) != lowerit(*word)) 2472 return FALSE; 2473 ++word; 2474 while (*++abbr != '\0') 2475 do { 2476 if (*word == '\0') 2477 return FALSE; 2478 } while (lowerit(*word++) != lowerit(*abbr)); 2479 return TRUE; 2480} 2481 2482static const struct lookup * 2483byword(word, table) 2484register const char * const word; 2485register const struct lookup * const table; 2486{ 2487 register const struct lookup * foundlp; 2488 register const struct lookup * lp; 2489 2490 if (word == NULL || table == NULL) 2491 return NULL; 2492 /* 2493 ** Look for exact match. 2494 */ 2495 for (lp = table; lp->l_word != NULL; ++lp) 2496 if (ciequal(word, lp->l_word)) 2497 return lp; 2498 /* 2499 ** Look for inexact match. 2500 */ 2501 foundlp = NULL; 2502 for (lp = table; lp->l_word != NULL; ++lp) 2503 if (itsabbr(word, lp->l_word)) { 2504 if (foundlp == NULL) 2505 foundlp = lp; 2506 else return NULL; /* multiple inexact matches */ 2507 } 2508 return foundlp; 2509} 2510 2511static char ** 2512getfields(cp) 2513register char * cp; 2514{ 2515 register char * dp; 2516 register char ** array; 2517 register int nsubs; 2518 2519 if (cp == NULL) 2520 return NULL; 2521 array = (char **) (void *) 2522 emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 2523 nsubs = 0; 2524 for ( ; ; ) { 2525 while (isascii((unsigned char) *cp) && 2526 isspace((unsigned char) *cp)) 2527 ++cp; 2528 if (*cp == '\0' || *cp == '#') 2529 break; 2530 array[nsubs++] = dp = cp; 2531 do { 2532 if ((*dp = *cp++) != '"') 2533 ++dp; 2534 else while ((*dp = *cp++) != '"') 2535 if (*dp != '\0') 2536 ++dp; 2537 else { 2538 error(_( 2539 "Odd number of quotation marks" 2540 )); 2541 exit(1); 2542 } 2543 } while (*cp != '\0' && *cp != '#' && 2544 (!isascii(*cp) || !isspace((unsigned char) *cp))); 2545 if (isascii(*cp) && isspace((unsigned char) *cp)) 2546 ++cp; 2547 *dp = '\0'; 2548 } 2549 array[nsubs] = NULL; 2550 return array; 2551} 2552 2553static long 2554oadd(t1, t2) 2555const long t1; 2556const long t2; 2557{ 2558 register long t; 2559 2560 t = t1 + t2; 2561 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2562 error(_("time overflow")); 2563 exit(EXIT_FAILURE); 2564 } 2565 return t; 2566} 2567 2568static zic_t 2569tadd(t1, t2) 2570const zic_t t1; 2571const long t2; 2572{ 2573 register zic_t t; 2574 2575 if (t1 == max_time && t2 > 0) 2576 return max_time; 2577 if (t1 == min_time && t2 < 0) 2578 return min_time; 2579 t = t1 + t2; 2580 if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2581 error(_("time overflow")); 2582 exit(EXIT_FAILURE); 2583 } 2584 return t; 2585} 2586 2587/* 2588** Given a rule, and a year, compute the date - in seconds since January 1, 2589** 1970, 00:00 LOCAL time - in that year that the rule refers to. 2590*/ 2591 2592static zic_t 2593rpytime(rp, wantedy) 2594register const struct rule * const rp; 2595register const int wantedy; 2596{ 2597 register int y, m, i; 2598 register long dayoff; /* with a nod to Margaret O. */ 2599 register zic_t t; 2600 2601 if (wantedy == INT_MIN) 2602 return min_time; 2603 if (wantedy == INT_MAX) 2604 return max_time; 2605 dayoff = 0; 2606 m = TM_JANUARY; 2607 y = EPOCH_YEAR; 2608 while (wantedy != y) { 2609 if (wantedy > y) { 2610 i = len_years[isleap(y)]; 2611 ++y; 2612 } else { 2613 --y; 2614 i = -len_years[isleap(y)]; 2615 } 2616 dayoff = oadd(dayoff, eitol(i)); 2617 } 2618 while (m != rp->r_month) { 2619 i = len_months[isleap(y)][m]; 2620 dayoff = oadd(dayoff, eitol(i)); 2621 ++m; 2622 } 2623 i = rp->r_dayofmonth; 2624 if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2625 if (rp->r_dycode == DC_DOWLEQ) 2626 --i; 2627 else { 2628 error(_("use of 2/29 in non leap-year")); 2629 exit(EXIT_FAILURE); 2630 } 2631 } 2632 --i; 2633 dayoff = oadd(dayoff, eitol(i)); 2634 if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2635 register long wday; 2636 2637#define LDAYSPERWEEK ((long) DAYSPERWEEK) 2638 wday = eitol(EPOCH_WDAY); 2639 /* 2640 ** Don't trust mod of negative numbers. 2641 */ 2642 if (dayoff >= 0) 2643 wday = (wday + dayoff) % LDAYSPERWEEK; 2644 else { 2645 wday -= ((-dayoff) % LDAYSPERWEEK); 2646 if (wday < 0) 2647 wday += LDAYSPERWEEK; 2648 } 2649 while (wday != eitol(rp->r_wday)) 2650 if (rp->r_dycode == DC_DOWGEQ) { 2651 dayoff = oadd(dayoff, (long) 1); 2652 if (++wday >= LDAYSPERWEEK) 2653 wday = 0; 2654 ++i; 2655 } else { 2656 dayoff = oadd(dayoff, (long) -1); 2657 if (--wday < 0) 2658 wday = LDAYSPERWEEK - 1; 2659 --i; 2660 } 2661 if (i < 0 || i >= len_months[isleap(y)][m]) { 2662 if (noise) 2663 warning(_("rule goes past start/end of month--\ 2664will not work with pre-2004 versions of zic")); 2665 } 2666 } 2667 if (dayoff < min_time / SECSPERDAY) 2668 return min_time; 2669 if (dayoff > max_time / SECSPERDAY) 2670 return max_time; 2671 t = (zic_t) dayoff * SECSPERDAY; 2672 return tadd(t, rp->r_tod); 2673} 2674 2675static void 2676newabbr(string) 2677const char * const string; 2678{ 2679 register int i; 2680 2681 if (strcmp(string, GRANDPARENTED) != 0) { 2682 register const char * cp; 2683 register char * wp; 2684 2685 /* 2686 ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics 2687 ** optionally followed by a + or - and a number from 1 to 14. 2688 */ 2689 cp = string; 2690 wp = NULL; 2691 while (isascii((unsigned char) *cp) && 2692 isalpha((unsigned char) *cp)) 2693 ++cp; 2694 if (cp - string == 0) 2695wp = _("time zone abbreviation lacks alphabetic at start"); 2696 if (noise && cp - string > 3) 2697wp = _("time zone abbreviation has more than 3 alphabetics"); 2698 if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2699wp = _("time zone abbreviation has too many alphabetics"); 2700 if (wp == NULL && (*cp == '+' || *cp == '-')) { 2701 ++cp; 2702 if (isascii((unsigned char) *cp) && 2703 isdigit((unsigned char) *cp)) 2704 if (*cp++ == '1' && 2705 *cp >= '0' && *cp <= '4') 2706 ++cp; 2707 } 2708 if (*cp != '\0') 2709wp = _("time zone abbreviation differs from POSIX standard"); 2710 if (wp != NULL) { 2711 wp = ecpyalloc(wp); 2712 wp = ecatalloc(wp, " ("); 2713 wp = ecatalloc(wp, string); 2714 wp = ecatalloc(wp, ")"); 2715 warning(wp); 2716 ifree(wp); 2717 } 2718 } 2719 i = strlen(string) + 1; 2720 if (charcnt + i > TZ_MAX_CHARS) { 2721 error(_("too many, or too long, time zone abbreviations")); 2722 exit(EXIT_FAILURE); 2723 } 2724 (void)strncpy(&chars[charcnt], string, sizeof(chars) - charcnt - 1); 2725 charcnt += eitol(i); 2726} 2727 2728static int 2729mkdirs(argname) 2730char * argname; 2731{ 2732 register char * name; 2733 register char * cp; 2734 2735 if (argname == NULL || *argname == '\0') 2736 return 0; 2737 cp = name = ecpyalloc(argname); 2738 while ((cp = strchr(cp + 1, '/')) != 0) { 2739 *cp = '\0'; 2740#ifndef __NetBSD__ 2741 /* 2742 ** DOS drive specifier? 2743 */ 2744 if (isalpha((unsigned char) name[0]) && 2745 name[1] == ':' && name[2] == '\0') { 2746 *cp = '/'; 2747 continue; 2748 } 2749#endif /* !defined __NetBSD__ */ 2750 if (!itsdir(name)) { 2751 /* 2752 ** It doesn't seem to exist, so we try to create it. 2753 ** Creation may fail because of the directory being 2754 ** created by some other multiprocessor, so we get 2755 ** to do extra checking. 2756 */ 2757 if (mkdir(name, MKDIR_UMASK) != 0) { 2758 const char *e = strerror(errno); 2759 2760 if (errno != EEXIST || !itsdir(name)) { 2761 (void) fprintf(stderr, 2762_("%s: Can't create directory %s: %s\n"), 2763 progname, name, e); 2764 ifree(name); 2765 return -1; 2766 } 2767 } 2768 } 2769 *cp = '/'; 2770 } 2771 ifree(name); 2772 return 0; 2773} 2774 2775static long 2776eitol(i) 2777const int i; 2778{ 2779 long l; 2780 2781 l = i; 2782 if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2783 (void) fprintf(stderr, 2784 _("%s: %d did not sign extend correctly\n"), 2785 progname, i); 2786 exit(EXIT_FAILURE); 2787 } 2788 return l; 2789} 2790 2791/* 2792** UNIX was a registered trademark of The Open Group in 2003. 2793*/ 2794