1bc421551SDag-Erling Smørgrav /* Compile .zi time zone data into TZif binary files. */ 2bc421551SDag-Erling Smørgrav 3bc421551SDag-Erling Smørgrav /* 4bc421551SDag-Erling Smørgrav ** This file is in the public domain, so clarified as of 5bc421551SDag-Erling Smørgrav ** 2006-07-17 by Arthur David Olson. 6bc421551SDag-Erling Smørgrav */ 7bc421551SDag-Erling Smørgrav 8bc421551SDag-Erling Smørgrav /* Use the system 'time' function, instead of any private replacement. 9bc421551SDag-Erling Smørgrav This avoids creating an unnecessary dependency on localtime.c. */ 10bc421551SDag-Erling Smørgrav #undef EPOCH_LOCAL 11bc421551SDag-Erling Smørgrav #undef EPOCH_OFFSET 12bc421551SDag-Erling Smørgrav #undef RESERVE_STD_EXT_IDS 13bc421551SDag-Erling Smørgrav #undef time_tz 14bc421551SDag-Erling Smørgrav 15bc421551SDag-Erling Smørgrav #include "version.h" 16bc421551SDag-Erling Smørgrav #include "private.h" 1746c59934SDag-Erling Smørgrav #include "tzdir.h" 18bc421551SDag-Erling Smørgrav #include "tzfile.h" 19bc421551SDag-Erling Smørgrav 20bc421551SDag-Erling Smørgrav #include <fcntl.h> 21bc421551SDag-Erling Smørgrav #include <locale.h> 22bc421551SDag-Erling Smørgrav #include <signal.h> 23bc421551SDag-Erling Smørgrav #include <stdarg.h> 24bc421551SDag-Erling Smørgrav #include <stdio.h> 25bc421551SDag-Erling Smørgrav 26bc421551SDag-Erling Smørgrav typedef int_fast64_t zic_t; 27bc421551SDag-Erling Smørgrav static zic_t const 28bc421551SDag-Erling Smørgrav ZIC_MIN = INT_FAST64_MIN, 29bc421551SDag-Erling Smørgrav ZIC_MAX = INT_FAST64_MAX, 30bc421551SDag-Erling Smørgrav ZIC32_MIN = -1 - (zic_t) 0x7fffffff, 31bc421551SDag-Erling Smørgrav ZIC32_MAX = 0x7fffffff; 32bc421551SDag-Erling Smørgrav #define SCNdZIC SCNdFAST64 33bc421551SDag-Erling Smørgrav 34bc421551SDag-Erling Smørgrav #ifndef ZIC_MAX_ABBR_LEN_WO_WARN 35bc421551SDag-Erling Smørgrav # define ZIC_MAX_ABBR_LEN_WO_WARN 6 36bc421551SDag-Erling Smørgrav #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 37bc421551SDag-Erling Smørgrav 3846c59934SDag-Erling Smørgrav /* Minimum and maximum years, assuming signed 32-bit time_t. */ 3946c59934SDag-Erling Smørgrav enum { YEAR_32BIT_MIN = 1901, YEAR_32BIT_MAX = 2038 }; 4046c59934SDag-Erling Smørgrav 41bc421551SDag-Erling Smørgrav /* An upper bound on how much a format might grow due to concatenation. */ 42bc421551SDag-Erling Smørgrav enum { FORMAT_LEN_GROWTH_BOUND = 5 }; 43bc421551SDag-Erling Smørgrav 44bc421551SDag-Erling Smørgrav #ifdef HAVE_DIRECT_H 45bc421551SDag-Erling Smørgrav # include <direct.h> 46bc421551SDag-Erling Smørgrav # include <io.h> 47bc421551SDag-Erling Smørgrav # undef mkdir 48bc421551SDag-Erling Smørgrav # define mkdir(name, mode) _mkdir(name) 49bc421551SDag-Erling Smørgrav #endif 50bc421551SDag-Erling Smørgrav 51bc421551SDag-Erling Smørgrav #ifndef HAVE_GETRANDOM 52bc421551SDag-Erling Smørgrav # ifdef __has_include 53bc421551SDag-Erling Smørgrav # if __has_include(<sys/random.h>) 54bc421551SDag-Erling Smørgrav # include <sys/random.h> 55bc421551SDag-Erling Smørgrav # endif 56bc421551SDag-Erling Smørgrav # elif 2 < __GLIBC__ + (25 <= __GLIBC_MINOR__) 57bc421551SDag-Erling Smørgrav # include <sys/random.h> 58bc421551SDag-Erling Smørgrav # endif 59bc421551SDag-Erling Smørgrav # define HAVE_GETRANDOM GRND_RANDOM 60bc421551SDag-Erling Smørgrav #elif HAVE_GETRANDOM 61bc421551SDag-Erling Smørgrav # include <sys/random.h> 62bc421551SDag-Erling Smørgrav #endif 63bc421551SDag-Erling Smørgrav 64bc421551SDag-Erling Smørgrav #if HAVE_SYS_STAT_H 65bc421551SDag-Erling Smørgrav # include <sys/stat.h> 66bc421551SDag-Erling Smørgrav #endif 67bc421551SDag-Erling Smørgrav #ifdef S_IRUSR 68bc421551SDag-Erling Smørgrav # define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 69bc421551SDag-Erling Smørgrav #else 70bc421551SDag-Erling Smørgrav # define MKDIR_UMASK 0755 71bc421551SDag-Erling Smørgrav #endif 72bc421551SDag-Erling Smørgrav 7375411d15SDag-Erling Smørgrav /* The minimum alignment of a type, for pre-C23 platforms. 7475411d15SDag-Erling Smørgrav The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks 7575411d15SDag-Erling Smørgrav <stdalign.h> even though __STDC_VERSION__ == 201112. */ 7675411d15SDag-Erling Smørgrav #if __STDC_VERSION__ < 201112 || defined __SUNPRO_C 77bc421551SDag-Erling Smørgrav # define alignof(type) offsetof(struct { char a; type b; }, b) 78bc421551SDag-Erling Smørgrav #elif __STDC_VERSION__ < 202311 79bc421551SDag-Erling Smørgrav # include <stdalign.h> 80bc421551SDag-Erling Smørgrav #endif 81bc421551SDag-Erling Smørgrav 82bc421551SDag-Erling Smørgrav /* The maximum length of a text line, including the trailing newline. */ 83bc421551SDag-Erling Smørgrav #ifndef _POSIX2_LINE_MAX 84bc421551SDag-Erling Smørgrav # define _POSIX2_LINE_MAX 2048 85bc421551SDag-Erling Smørgrav #endif 86bc421551SDag-Erling Smørgrav 87bc421551SDag-Erling Smørgrav /* The type for line numbers. Use PRIdMAX to format them; formerly 88bc421551SDag-Erling Smørgrav there was also "#define PRIdLINENO PRIdMAX" and formats used 89bc421551SDag-Erling Smørgrav PRIdLINENO, but xgettext cannot grok that. */ 90bc421551SDag-Erling Smørgrav typedef intmax_t lineno; 91bc421551SDag-Erling Smørgrav 92bc421551SDag-Erling Smørgrav struct rule { 93bc421551SDag-Erling Smørgrav int r_filenum; 94bc421551SDag-Erling Smørgrav lineno r_linenum; 95bc421551SDag-Erling Smørgrav const char * r_name; 96bc421551SDag-Erling Smørgrav 97bc421551SDag-Erling Smørgrav zic_t r_loyear; /* for example, 1986 */ 98bc421551SDag-Erling Smørgrav zic_t r_hiyear; /* for example, 1986 */ 99bc421551SDag-Erling Smørgrav bool r_hiwasnum; 100bc421551SDag-Erling Smørgrav 101bc421551SDag-Erling Smørgrav int r_month; /* 0..11 */ 102bc421551SDag-Erling Smørgrav 103bc421551SDag-Erling Smørgrav int r_dycode; /* see below */ 104bc421551SDag-Erling Smørgrav int r_dayofmonth; 105bc421551SDag-Erling Smørgrav int r_wday; 106bc421551SDag-Erling Smørgrav 107bc421551SDag-Erling Smørgrav zic_t r_tod; /* time from midnight */ 108bc421551SDag-Erling Smørgrav bool r_todisstd; /* is r_tod standard time? */ 109bc421551SDag-Erling Smørgrav bool r_todisut; /* is r_tod UT? */ 110bc421551SDag-Erling Smørgrav bool r_isdst; /* is this daylight saving time? */ 111bc421551SDag-Erling Smørgrav zic_t r_save; /* offset from standard time */ 112bc421551SDag-Erling Smørgrav const char * r_abbrvar; /* variable part of abbreviation */ 113bc421551SDag-Erling Smørgrav 114bc421551SDag-Erling Smørgrav bool r_todo; /* a rule to do (used in outzone) */ 115bc421551SDag-Erling Smørgrav zic_t r_temp; /* used in outzone */ 116bc421551SDag-Erling Smørgrav }; 117bc421551SDag-Erling Smørgrav 118bc421551SDag-Erling Smørgrav /* 119bc421551SDag-Erling Smørgrav ** r_dycode r_dayofmonth r_wday 120bc421551SDag-Erling Smørgrav */ 121bc421551SDag-Erling Smørgrav enum { 122bc421551SDag-Erling Smørgrav DC_DOM, /* 1..31 */ /* unused */ 123bc421551SDag-Erling Smørgrav DC_DOWGEQ, /* 1..31 */ /* 0..6 (Sun..Sat) */ 124bc421551SDag-Erling Smørgrav DC_DOWLEQ /* 1..31 */ /* 0..6 (Sun..Sat) */ 125bc421551SDag-Erling Smørgrav }; 126bc421551SDag-Erling Smørgrav 127bc421551SDag-Erling Smørgrav struct zone { 128bc421551SDag-Erling Smørgrav int z_filenum; 129bc421551SDag-Erling Smørgrav lineno z_linenum; 130bc421551SDag-Erling Smørgrav 131bc421551SDag-Erling Smørgrav const char * z_name; 132bc421551SDag-Erling Smørgrav zic_t z_stdoff; 133bc421551SDag-Erling Smørgrav char * z_rule; 134bc421551SDag-Erling Smørgrav const char * z_format; 135bc421551SDag-Erling Smørgrav char z_format_specifier; 136bc421551SDag-Erling Smørgrav 137bc421551SDag-Erling Smørgrav bool z_isdst; 138bc421551SDag-Erling Smørgrav zic_t z_save; 139bc421551SDag-Erling Smørgrav 140bc421551SDag-Erling Smørgrav struct rule * z_rules; 141bc421551SDag-Erling Smørgrav ptrdiff_t z_nrules; 142bc421551SDag-Erling Smørgrav 143bc421551SDag-Erling Smørgrav struct rule z_untilrule; 144bc421551SDag-Erling Smørgrav zic_t z_untiltime; 145bc421551SDag-Erling Smørgrav }; 146bc421551SDag-Erling Smørgrav 147bc421551SDag-Erling Smørgrav #if !HAVE_POSIX_DECLS 148bc421551SDag-Erling Smørgrav extern int getopt(int argc, char * const argv[], 149bc421551SDag-Erling Smørgrav const char * options); 150bc421551SDag-Erling Smørgrav extern int link(const char * target, const char * linkname); 151bc421551SDag-Erling Smørgrav extern char * optarg; 152bc421551SDag-Erling Smørgrav extern int optind; 153bc421551SDag-Erling Smørgrav #endif 154bc421551SDag-Erling Smørgrav 155bc421551SDag-Erling Smørgrav #if ! HAVE_SYMLINK 156bc421551SDag-Erling Smørgrav static ssize_t 157bc421551SDag-Erling Smørgrav readlink(char const *restrict file, char *restrict buf, size_t size) 158bc421551SDag-Erling Smørgrav { 159bc421551SDag-Erling Smørgrav errno = ENOTSUP; 160bc421551SDag-Erling Smørgrav return -1; 161bc421551SDag-Erling Smørgrav } 162bc421551SDag-Erling Smørgrav static int 163bc421551SDag-Erling Smørgrav symlink(char const *target, char const *linkname) 164bc421551SDag-Erling Smørgrav { 165bc421551SDag-Erling Smørgrav errno = ENOTSUP; 166bc421551SDag-Erling Smørgrav return -1; 167bc421551SDag-Erling Smørgrav } 168bc421551SDag-Erling Smørgrav #endif 169bc421551SDag-Erling Smørgrav #ifndef AT_SYMLINK_FOLLOW 170bc421551SDag-Erling Smørgrav # define linkat(targetdir, target, linknamedir, linkname, flag) \ 171bc421551SDag-Erling Smørgrav (errno = ENOTSUP, -1) 172bc421551SDag-Erling Smørgrav #endif 173bc421551SDag-Erling Smørgrav 174bc421551SDag-Erling Smørgrav static void addtt(zic_t starttime, int type); 175bc421551SDag-Erling Smørgrav static int addtype(zic_t, char const *, bool, bool, bool); 176bc421551SDag-Erling Smørgrav static void leapadd(zic_t, int, int); 177bc421551SDag-Erling Smørgrav static void adjleap(void); 178bc421551SDag-Erling Smørgrav static void associate(void); 179bc421551SDag-Erling Smørgrav static void dolink(const char *, const char *, bool); 180bc421551SDag-Erling Smørgrav static int getfields(char *, char **, int); 181bc421551SDag-Erling Smørgrav static zic_t gethms(const char * string, const char * errstring); 182bc421551SDag-Erling Smørgrav static zic_t getsave(char *, bool *); 183bc421551SDag-Erling Smørgrav static void inexpires(char **, int); 184bc421551SDag-Erling Smørgrav static void infile(int, char const *); 185bc421551SDag-Erling Smørgrav static void inleap(char ** fields, int nfields); 186bc421551SDag-Erling Smørgrav static void inlink(char ** fields, int nfields); 187bc421551SDag-Erling Smørgrav static void inrule(char ** fields, int nfields); 188bc421551SDag-Erling Smørgrav static bool inzcont(char ** fields, int nfields); 189bc421551SDag-Erling Smørgrav static bool inzone(char ** fields, int nfields); 190bc421551SDag-Erling Smørgrav static bool inzsub(char **, int, bool); 19146c59934SDag-Erling Smørgrav static int itssymlink(char const *, int *); 192bc421551SDag-Erling Smørgrav static bool is_alpha(char a); 193bc421551SDag-Erling Smørgrav static char lowerit(char); 194bc421551SDag-Erling Smørgrav static void mkdirs(char const *, bool); 195bc421551SDag-Erling Smørgrav static void newabbr(const char * abbr); 196bc421551SDag-Erling Smørgrav static zic_t oadd(zic_t t1, zic_t t2); 197bc421551SDag-Erling Smørgrav static void outzone(const struct zone * zp, ptrdiff_t ntzones); 198bc421551SDag-Erling Smørgrav static zic_t rpytime(const struct rule * rp, zic_t wantedy); 199bc421551SDag-Erling Smørgrav static bool rulesub(struct rule * rp, 200bc421551SDag-Erling Smørgrav const char * loyearp, const char * hiyearp, 201bc421551SDag-Erling Smørgrav const char * typep, const char * monthp, 202bc421551SDag-Erling Smørgrav const char * dayp, const char * timep); 203bc421551SDag-Erling Smørgrav static void setgroup(gid_t *flag, const char *name); 204bc421551SDag-Erling Smørgrav static void setuser(uid_t *flag, const char *name); 205bc421551SDag-Erling Smørgrav static zic_t tadd(zic_t t1, zic_t t2); 206bc421551SDag-Erling Smørgrav 207bc421551SDag-Erling Smørgrav /* Bound on length of what %z can expand to. */ 208bc421551SDag-Erling Smørgrav enum { PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1 }; 209bc421551SDag-Erling Smørgrav 210bc421551SDag-Erling Smørgrav static int charcnt; 211bc421551SDag-Erling Smørgrav static bool errors; 212bc421551SDag-Erling Smørgrav static bool warnings; 213bc421551SDag-Erling Smørgrav static int filenum; 214bc421551SDag-Erling Smørgrav static int leapcnt; 215bc421551SDag-Erling Smørgrav static bool leapseen; 216bc421551SDag-Erling Smørgrav static zic_t leapminyear; 217bc421551SDag-Erling Smørgrav static zic_t leapmaxyear; 218bc421551SDag-Erling Smørgrav static lineno linenum; 219bc421551SDag-Erling Smørgrav static size_t max_abbrvar_len = PERCENT_Z_LEN_BOUND; 220bc421551SDag-Erling Smørgrav static int max_format_len; 221bc421551SDag-Erling Smørgrav static zic_t max_year; 222bc421551SDag-Erling Smørgrav static zic_t min_year; 223bc421551SDag-Erling Smørgrav static bool noise; 224bc421551SDag-Erling Smørgrav static int rfilenum; 225bc421551SDag-Erling Smørgrav static lineno rlinenum; 226bc421551SDag-Erling Smørgrav static const char * progname; 227bc421551SDag-Erling Smørgrav static char const * leapsec; 228bc421551SDag-Erling Smørgrav static char *const * main_argv; 229bc421551SDag-Erling Smørgrav static ptrdiff_t timecnt; 230bc421551SDag-Erling Smørgrav static ptrdiff_t timecnt_alloc; 231bc421551SDag-Erling Smørgrav static int typecnt; 232bc421551SDag-Erling Smørgrav static int unspecifiedtype; 233bc421551SDag-Erling Smørgrav 234bc421551SDag-Erling Smørgrav /* 235bc421551SDag-Erling Smørgrav ** Line codes. 236bc421551SDag-Erling Smørgrav */ 237bc421551SDag-Erling Smørgrav 238bc421551SDag-Erling Smørgrav enum { 239bc421551SDag-Erling Smørgrav LC_RULE, 240bc421551SDag-Erling Smørgrav LC_ZONE, 241bc421551SDag-Erling Smørgrav LC_LINK, 242bc421551SDag-Erling Smørgrav LC_LEAP, 243bc421551SDag-Erling Smørgrav LC_EXPIRES 244bc421551SDag-Erling Smørgrav }; 245bc421551SDag-Erling Smørgrav 246bc421551SDag-Erling Smørgrav /* 247bc421551SDag-Erling Smørgrav ** Which fields are which on a Zone line. 248bc421551SDag-Erling Smørgrav */ 249bc421551SDag-Erling Smørgrav 250bc421551SDag-Erling Smørgrav enum { 251bc421551SDag-Erling Smørgrav ZF_NAME = 1, 252bc421551SDag-Erling Smørgrav ZF_STDOFF, 253bc421551SDag-Erling Smørgrav ZF_RULE, 254bc421551SDag-Erling Smørgrav ZF_FORMAT, 255bc421551SDag-Erling Smørgrav ZF_TILYEAR, 256bc421551SDag-Erling Smørgrav ZF_TILMONTH, 257bc421551SDag-Erling Smørgrav ZF_TILDAY, 258bc421551SDag-Erling Smørgrav ZF_TILTIME, 259bc421551SDag-Erling Smørgrav ZONE_MAXFIELDS, 260bc421551SDag-Erling Smørgrav ZONE_MINFIELDS = ZF_TILYEAR 261bc421551SDag-Erling Smørgrav }; 262bc421551SDag-Erling Smørgrav 263bc421551SDag-Erling Smørgrav /* 264bc421551SDag-Erling Smørgrav ** Which fields are which on a Zone continuation line. 265bc421551SDag-Erling Smørgrav */ 266bc421551SDag-Erling Smørgrav 267bc421551SDag-Erling Smørgrav enum { 268bc421551SDag-Erling Smørgrav ZFC_STDOFF, 269bc421551SDag-Erling Smørgrav ZFC_RULE, 270bc421551SDag-Erling Smørgrav ZFC_FORMAT, 271bc421551SDag-Erling Smørgrav ZFC_TILYEAR, 272bc421551SDag-Erling Smørgrav ZFC_TILMONTH, 273bc421551SDag-Erling Smørgrav ZFC_TILDAY, 274bc421551SDag-Erling Smørgrav ZFC_TILTIME, 275bc421551SDag-Erling Smørgrav ZONEC_MAXFIELDS, 276bc421551SDag-Erling Smørgrav ZONEC_MINFIELDS = ZFC_TILYEAR 277bc421551SDag-Erling Smørgrav }; 278bc421551SDag-Erling Smørgrav 279bc421551SDag-Erling Smørgrav /* 280bc421551SDag-Erling Smørgrav ** Which files are which on a Rule line. 281bc421551SDag-Erling Smørgrav */ 282bc421551SDag-Erling Smørgrav 283bc421551SDag-Erling Smørgrav enum { 284bc421551SDag-Erling Smørgrav RF_NAME = 1, 285bc421551SDag-Erling Smørgrav RF_LOYEAR, 286bc421551SDag-Erling Smørgrav RF_HIYEAR, 287bc421551SDag-Erling Smørgrav RF_COMMAND, 288bc421551SDag-Erling Smørgrav RF_MONTH, 289bc421551SDag-Erling Smørgrav RF_DAY, 290bc421551SDag-Erling Smørgrav RF_TOD, 291bc421551SDag-Erling Smørgrav RF_SAVE, 292bc421551SDag-Erling Smørgrav RF_ABBRVAR, 293bc421551SDag-Erling Smørgrav RULE_FIELDS 294bc421551SDag-Erling Smørgrav }; 295bc421551SDag-Erling Smørgrav 296bc421551SDag-Erling Smørgrav /* 297bc421551SDag-Erling Smørgrav ** Which fields are which on a Link line. 298bc421551SDag-Erling Smørgrav */ 299bc421551SDag-Erling Smørgrav 300bc421551SDag-Erling Smørgrav enum { 301bc421551SDag-Erling Smørgrav LF_TARGET = 1, 302bc421551SDag-Erling Smørgrav LF_LINKNAME, 303bc421551SDag-Erling Smørgrav LINK_FIELDS 304bc421551SDag-Erling Smørgrav }; 305bc421551SDag-Erling Smørgrav 306bc421551SDag-Erling Smørgrav /* 307bc421551SDag-Erling Smørgrav ** Which fields are which on a Leap line. 308bc421551SDag-Erling Smørgrav */ 309bc421551SDag-Erling Smørgrav 310bc421551SDag-Erling Smørgrav enum { 311bc421551SDag-Erling Smørgrav LP_YEAR = 1, 312bc421551SDag-Erling Smørgrav LP_MONTH, 313bc421551SDag-Erling Smørgrav LP_DAY, 314bc421551SDag-Erling Smørgrav LP_TIME, 315bc421551SDag-Erling Smørgrav LP_CORR, 316bc421551SDag-Erling Smørgrav LP_ROLL, 317bc421551SDag-Erling Smørgrav LEAP_FIELDS, 318bc421551SDag-Erling Smørgrav 319bc421551SDag-Erling Smørgrav /* Expires lines are like Leap lines, except without CORR and ROLL fields. */ 320bc421551SDag-Erling Smørgrav EXPIRES_FIELDS = LP_TIME + 1 321bc421551SDag-Erling Smørgrav }; 322bc421551SDag-Erling Smørgrav 323bc421551SDag-Erling Smørgrav /* The maximum number of fields on any of the above lines. 324bc421551SDag-Erling Smørgrav (The "+"s pacify gcc -Wenum-compare.) */ 325bc421551SDag-Erling Smørgrav enum { 326bc421551SDag-Erling Smørgrav MAX_FIELDS = max(max(+RULE_FIELDS, +LINK_FIELDS), 327bc421551SDag-Erling Smørgrav max(+LEAP_FIELDS, +EXPIRES_FIELDS)) 328bc421551SDag-Erling Smørgrav }; 329bc421551SDag-Erling Smørgrav 330bc421551SDag-Erling Smørgrav /* 331bc421551SDag-Erling Smørgrav ** Year synonyms. 332bc421551SDag-Erling Smørgrav */ 333bc421551SDag-Erling Smørgrav 334bc421551SDag-Erling Smørgrav enum { 33546c59934SDag-Erling Smørgrav YR_MINIMUM, /* "minimum" is for backward compatibility only */ 336bc421551SDag-Erling Smørgrav YR_MAXIMUM, 337bc421551SDag-Erling Smørgrav YR_ONLY 338bc421551SDag-Erling Smørgrav }; 339bc421551SDag-Erling Smørgrav 340bc421551SDag-Erling Smørgrav static struct rule * rules; 341bc421551SDag-Erling Smørgrav static ptrdiff_t nrules; /* number of rules */ 342bc421551SDag-Erling Smørgrav static ptrdiff_t nrules_alloc; 343bc421551SDag-Erling Smørgrav 344bc421551SDag-Erling Smørgrav static struct zone * zones; 345bc421551SDag-Erling Smørgrav static ptrdiff_t nzones; /* number of zones */ 346bc421551SDag-Erling Smørgrav static ptrdiff_t nzones_alloc; 347bc421551SDag-Erling Smørgrav 348bc421551SDag-Erling Smørgrav struct link { 349bc421551SDag-Erling Smørgrav int l_filenum; 350bc421551SDag-Erling Smørgrav lineno l_linenum; 351bc421551SDag-Erling Smørgrav const char * l_target; 352bc421551SDag-Erling Smørgrav const char * l_linkname; 353bc421551SDag-Erling Smørgrav }; 354bc421551SDag-Erling Smørgrav 355bc421551SDag-Erling Smørgrav static struct link * links; 356bc421551SDag-Erling Smørgrav static ptrdiff_t nlinks; 357bc421551SDag-Erling Smørgrav static ptrdiff_t nlinks_alloc; 358bc421551SDag-Erling Smørgrav 359bc421551SDag-Erling Smørgrav struct lookup { 360bc421551SDag-Erling Smørgrav const char * l_word; 361bc421551SDag-Erling Smørgrav const int l_value; 362bc421551SDag-Erling Smørgrav }; 363bc421551SDag-Erling Smørgrav 364bc421551SDag-Erling Smørgrav static struct lookup const * byword(const char * string, 365bc421551SDag-Erling Smørgrav const struct lookup * lp); 366bc421551SDag-Erling Smørgrav 367bc421551SDag-Erling Smørgrav static struct lookup const zi_line_codes[] = { 368bc421551SDag-Erling Smørgrav { "Rule", LC_RULE }, 369bc421551SDag-Erling Smørgrav { "Zone", LC_ZONE }, 370bc421551SDag-Erling Smørgrav { "Link", LC_LINK }, 371bc421551SDag-Erling Smørgrav { NULL, 0 } 372bc421551SDag-Erling Smørgrav }; 373bc421551SDag-Erling Smørgrav static struct lookup const leap_line_codes[] = { 374bc421551SDag-Erling Smørgrav { "Leap", LC_LEAP }, 375bc421551SDag-Erling Smørgrav { "Expires", LC_EXPIRES }, 376bc421551SDag-Erling Smørgrav { NULL, 0} 377bc421551SDag-Erling Smørgrav }; 378bc421551SDag-Erling Smørgrav 379bc421551SDag-Erling Smørgrav static struct lookup const mon_names[] = { 380bc421551SDag-Erling Smørgrav { "January", TM_JANUARY }, 381bc421551SDag-Erling Smørgrav { "February", TM_FEBRUARY }, 382bc421551SDag-Erling Smørgrav { "March", TM_MARCH }, 383bc421551SDag-Erling Smørgrav { "April", TM_APRIL }, 384bc421551SDag-Erling Smørgrav { "May", TM_MAY }, 385bc421551SDag-Erling Smørgrav { "June", TM_JUNE }, 386bc421551SDag-Erling Smørgrav { "July", TM_JULY }, 387bc421551SDag-Erling Smørgrav { "August", TM_AUGUST }, 388bc421551SDag-Erling Smørgrav { "September", TM_SEPTEMBER }, 389bc421551SDag-Erling Smørgrav { "October", TM_OCTOBER }, 390bc421551SDag-Erling Smørgrav { "November", TM_NOVEMBER }, 391bc421551SDag-Erling Smørgrav { "December", TM_DECEMBER }, 392bc421551SDag-Erling Smørgrav { NULL, 0 } 393bc421551SDag-Erling Smørgrav }; 394bc421551SDag-Erling Smørgrav 395bc421551SDag-Erling Smørgrav static struct lookup const wday_names[] = { 396bc421551SDag-Erling Smørgrav { "Sunday", TM_SUNDAY }, 397bc421551SDag-Erling Smørgrav { "Monday", TM_MONDAY }, 398bc421551SDag-Erling Smørgrav { "Tuesday", TM_TUESDAY }, 399bc421551SDag-Erling Smørgrav { "Wednesday", TM_WEDNESDAY }, 400bc421551SDag-Erling Smørgrav { "Thursday", TM_THURSDAY }, 401bc421551SDag-Erling Smørgrav { "Friday", TM_FRIDAY }, 402bc421551SDag-Erling Smørgrav { "Saturday", TM_SATURDAY }, 403bc421551SDag-Erling Smørgrav { NULL, 0 } 404bc421551SDag-Erling Smørgrav }; 405bc421551SDag-Erling Smørgrav 406bc421551SDag-Erling Smørgrav static struct lookup const lasts[] = { 407bc421551SDag-Erling Smørgrav { "last-Sunday", TM_SUNDAY }, 408bc421551SDag-Erling Smørgrav { "last-Monday", TM_MONDAY }, 409bc421551SDag-Erling Smørgrav { "last-Tuesday", TM_TUESDAY }, 410bc421551SDag-Erling Smørgrav { "last-Wednesday", TM_WEDNESDAY }, 411bc421551SDag-Erling Smørgrav { "last-Thursday", TM_THURSDAY }, 412bc421551SDag-Erling Smørgrav { "last-Friday", TM_FRIDAY }, 413bc421551SDag-Erling Smørgrav { "last-Saturday", TM_SATURDAY }, 414bc421551SDag-Erling Smørgrav { NULL, 0 } 415bc421551SDag-Erling Smørgrav }; 416bc421551SDag-Erling Smørgrav 417bc421551SDag-Erling Smørgrav static struct lookup const begin_years[] = { 418bc421551SDag-Erling Smørgrav { "minimum", YR_MINIMUM }, 419bc421551SDag-Erling Smørgrav { NULL, 0 } 420bc421551SDag-Erling Smørgrav }; 421bc421551SDag-Erling Smørgrav 422bc421551SDag-Erling Smørgrav static struct lookup const end_years[] = { 423bc421551SDag-Erling Smørgrav { "maximum", YR_MAXIMUM }, 424bc421551SDag-Erling Smørgrav { "only", YR_ONLY }, 425bc421551SDag-Erling Smørgrav { NULL, 0 } 426bc421551SDag-Erling Smørgrav }; 427bc421551SDag-Erling Smørgrav 428bc421551SDag-Erling Smørgrav static struct lookup const leap_types[] = { 429bc421551SDag-Erling Smørgrav { "Rolling", true }, 430bc421551SDag-Erling Smørgrav { "Stationary", false }, 431bc421551SDag-Erling Smørgrav { NULL, 0 } 432bc421551SDag-Erling Smørgrav }; 433bc421551SDag-Erling Smørgrav 434bc421551SDag-Erling Smørgrav static const int len_months[2][MONSPERYEAR] = { 435bc421551SDag-Erling Smørgrav { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 436bc421551SDag-Erling Smørgrav { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 437bc421551SDag-Erling Smørgrav }; 438bc421551SDag-Erling Smørgrav 439bc421551SDag-Erling Smørgrav static const int len_years[2] = { 440bc421551SDag-Erling Smørgrav DAYSPERNYEAR, DAYSPERLYEAR 441bc421551SDag-Erling Smørgrav }; 442bc421551SDag-Erling Smørgrav 443bc421551SDag-Erling Smørgrav static struct attype { 444bc421551SDag-Erling Smørgrav zic_t at; 445bc421551SDag-Erling Smørgrav bool dontmerge; 446bc421551SDag-Erling Smørgrav unsigned char type; 447bc421551SDag-Erling Smørgrav } * attypes; 448bc421551SDag-Erling Smørgrav static zic_t utoffs[TZ_MAX_TYPES]; 449bc421551SDag-Erling Smørgrav static char isdsts[TZ_MAX_TYPES]; 450bc421551SDag-Erling Smørgrav static unsigned char desigidx[TZ_MAX_TYPES]; 451bc421551SDag-Erling Smørgrav static bool ttisstds[TZ_MAX_TYPES]; 452bc421551SDag-Erling Smørgrav static bool ttisuts[TZ_MAX_TYPES]; 453bc421551SDag-Erling Smørgrav static char chars[TZ_MAX_CHARS]; 454bc421551SDag-Erling Smørgrav static zic_t trans[TZ_MAX_LEAPS]; 455bc421551SDag-Erling Smørgrav static zic_t corr[TZ_MAX_LEAPS]; 456bc421551SDag-Erling Smørgrav static char roll[TZ_MAX_LEAPS]; 457bc421551SDag-Erling Smørgrav 458bc421551SDag-Erling Smørgrav /* 459bc421551SDag-Erling Smørgrav ** Memory allocation. 460bc421551SDag-Erling Smørgrav */ 461bc421551SDag-Erling Smørgrav 46275411d15SDag-Erling Smørgrav ATTRIBUTE_NORETURN static void 463bc421551SDag-Erling Smørgrav memory_exhausted(const char *msg) 464bc421551SDag-Erling Smørgrav { 465bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); 466bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 467bc421551SDag-Erling Smørgrav } 468bc421551SDag-Erling Smørgrav 46975411d15SDag-Erling Smørgrav ATTRIBUTE_NORETURN static void 470bc421551SDag-Erling Smørgrav size_overflow(void) 471bc421551SDag-Erling Smørgrav { 472bc421551SDag-Erling Smørgrav memory_exhausted(_("size overflow")); 473bc421551SDag-Erling Smørgrav } 474bc421551SDag-Erling Smørgrav 475*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static ptrdiff_t 476bc421551SDag-Erling Smørgrav size_sum(size_t a, size_t b) 477bc421551SDag-Erling Smørgrav { 478bc421551SDag-Erling Smørgrav #ifdef ckd_add 47975411d15SDag-Erling Smørgrav ptrdiff_t sum; 48075411d15SDag-Erling Smørgrav if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX) 481bc421551SDag-Erling Smørgrav return sum; 482bc421551SDag-Erling Smørgrav #else 48375411d15SDag-Erling Smørgrav if (a <= INDEX_MAX && b <= INDEX_MAX - a) 484bc421551SDag-Erling Smørgrav return a + b; 485bc421551SDag-Erling Smørgrav #endif 486bc421551SDag-Erling Smørgrav size_overflow(); 487bc421551SDag-Erling Smørgrav } 488bc421551SDag-Erling Smørgrav 489*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static ptrdiff_t 49075411d15SDag-Erling Smørgrav size_product(ptrdiff_t nitems, ptrdiff_t itemsize) 491bc421551SDag-Erling Smørgrav { 492bc421551SDag-Erling Smørgrav #ifdef ckd_mul 49375411d15SDag-Erling Smørgrav ptrdiff_t product; 49475411d15SDag-Erling Smørgrav if (!ckd_mul(&product, nitems, itemsize) && product <= INDEX_MAX) 495bc421551SDag-Erling Smørgrav return product; 496bc421551SDag-Erling Smørgrav #else 49775411d15SDag-Erling Smørgrav ptrdiff_t nitems_max = INDEX_MAX / itemsize; 49875411d15SDag-Erling Smørgrav if (nitems <= nitems_max) 499bc421551SDag-Erling Smørgrav return nitems * itemsize; 500bc421551SDag-Erling Smørgrav #endif 501bc421551SDag-Erling Smørgrav size_overflow(); 502bc421551SDag-Erling Smørgrav } 503bc421551SDag-Erling Smørgrav 504*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static ptrdiff_t 50575411d15SDag-Erling Smørgrav align_to(ptrdiff_t size, ptrdiff_t alignment) 506bc421551SDag-Erling Smørgrav { 507d5c85ac6SDag-Erling Smørgrav size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); 508bc421551SDag-Erling Smørgrav return sum & ~lo_bits; 509bc421551SDag-Erling Smørgrav } 510bc421551SDag-Erling Smørgrav 511bc421551SDag-Erling Smørgrav #if !HAVE_STRDUP 512bc421551SDag-Erling Smørgrav static char * 513bc421551SDag-Erling Smørgrav strdup(char const *str) 514bc421551SDag-Erling Smørgrav { 515bc421551SDag-Erling Smørgrav char *result = malloc(strlen(str) + 1); 516bc421551SDag-Erling Smørgrav return result ? strcpy(result, str) : result; 517bc421551SDag-Erling Smørgrav } 518bc421551SDag-Erling Smørgrav #endif 519bc421551SDag-Erling Smørgrav 520bc421551SDag-Erling Smørgrav static void * 521bc421551SDag-Erling Smørgrav memcheck(void *ptr) 522bc421551SDag-Erling Smørgrav { 523bc421551SDag-Erling Smørgrav if (ptr == NULL) 524bc421551SDag-Erling Smørgrav memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM)); 525bc421551SDag-Erling Smørgrav return ptr; 526bc421551SDag-Erling Smørgrav } 527bc421551SDag-Erling Smørgrav 528*a979394aSDag-Erling Smørgrav static void * 529bc421551SDag-Erling Smørgrav emalloc(size_t size) 530bc421551SDag-Erling Smørgrav { 531bc421551SDag-Erling Smørgrav return memcheck(malloc(size)); 532bc421551SDag-Erling Smørgrav } 533bc421551SDag-Erling Smørgrav 534bc421551SDag-Erling Smørgrav static void * 535bc421551SDag-Erling Smørgrav erealloc(void *ptr, size_t size) 536bc421551SDag-Erling Smørgrav { 537bc421551SDag-Erling Smørgrav return memcheck(realloc(ptr, size)); 538bc421551SDag-Erling Smørgrav } 539bc421551SDag-Erling Smørgrav 540*a979394aSDag-Erling Smørgrav static char * 541bc421551SDag-Erling Smørgrav estrdup(char const *str) 542bc421551SDag-Erling Smørgrav { 543bc421551SDag-Erling Smørgrav return memcheck(strdup(str)); 544bc421551SDag-Erling Smørgrav } 545bc421551SDag-Erling Smørgrav 546bc421551SDag-Erling Smørgrav static ptrdiff_t 547bc421551SDag-Erling Smørgrav grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) 548bc421551SDag-Erling Smørgrav { 549bc421551SDag-Erling Smørgrav ptrdiff_t addend = (*nitems_alloc >> 1) + 1; 550bc421551SDag-Erling Smørgrav #if defined ckd_add && defined ckd_mul 551bc421551SDag-Erling Smørgrav ptrdiff_t product; 552bc421551SDag-Erling Smørgrav if (!ckd_add(nitems_alloc, *nitems_alloc, addend) 55375411d15SDag-Erling Smørgrav && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= INDEX_MAX) 554bc421551SDag-Erling Smørgrav return product; 555bc421551SDag-Erling Smørgrav #else 55675411d15SDag-Erling Smørgrav if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize) { 557bc421551SDag-Erling Smørgrav *nitems_alloc += addend; 558bc421551SDag-Erling Smørgrav return *nitems_alloc * itemsize; 559bc421551SDag-Erling Smørgrav } 560bc421551SDag-Erling Smørgrav #endif 561bc421551SDag-Erling Smørgrav memory_exhausted(_("integer overflow")); 562bc421551SDag-Erling Smørgrav } 563bc421551SDag-Erling Smørgrav 564bc421551SDag-Erling Smørgrav static void * 565bc421551SDag-Erling Smørgrav growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, 566bc421551SDag-Erling Smørgrav ptrdiff_t *nitems_alloc) 567bc421551SDag-Erling Smørgrav { 568bc421551SDag-Erling Smørgrav return (nitems < *nitems_alloc 569bc421551SDag-Erling Smørgrav ? ptr 570bc421551SDag-Erling Smørgrav : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); 571bc421551SDag-Erling Smørgrav } 572bc421551SDag-Erling Smørgrav 573bc421551SDag-Erling Smørgrav /* 574bc421551SDag-Erling Smørgrav ** Error handling. 575bc421551SDag-Erling Smørgrav */ 576bc421551SDag-Erling Smørgrav 577bc421551SDag-Erling Smørgrav /* In most of the code, an input file name is represented by its index 578bc421551SDag-Erling Smørgrav into the main argument vector, except that LEAPSEC_FILENUM stands 579bc421551SDag-Erling Smørgrav for leapsec and COMMAND_LINE_FILENUM stands for the command line. */ 580bc421551SDag-Erling Smørgrav enum { LEAPSEC_FILENUM = -2, COMMAND_LINE_FILENUM = -1 }; 581bc421551SDag-Erling Smørgrav 582bc421551SDag-Erling Smørgrav /* Return the name of the Ith input file, for diagnostics. */ 583bc421551SDag-Erling Smørgrav static char const * 584bc421551SDag-Erling Smørgrav filename(int i) 585bc421551SDag-Erling Smørgrav { 586bc421551SDag-Erling Smørgrav if (i == COMMAND_LINE_FILENUM) 587bc421551SDag-Erling Smørgrav return _("command line"); 588bc421551SDag-Erling Smørgrav else { 589bc421551SDag-Erling Smørgrav char const *fname = i == LEAPSEC_FILENUM ? leapsec : main_argv[i]; 590bc421551SDag-Erling Smørgrav return strcmp(fname, "-") == 0 ? _("standard input") : fname; 591bc421551SDag-Erling Smørgrav } 592bc421551SDag-Erling Smørgrav } 593bc421551SDag-Erling Smørgrav 594bc421551SDag-Erling Smørgrav static void 595bc421551SDag-Erling Smørgrav eats(int fnum, lineno num, int rfnum, lineno rnum) 596bc421551SDag-Erling Smørgrav { 597bc421551SDag-Erling Smørgrav filenum = fnum; 598bc421551SDag-Erling Smørgrav linenum = num; 599bc421551SDag-Erling Smørgrav rfilenum = rfnum; 600bc421551SDag-Erling Smørgrav rlinenum = rnum; 601bc421551SDag-Erling Smørgrav } 602bc421551SDag-Erling Smørgrav 603bc421551SDag-Erling Smørgrav static void 604bc421551SDag-Erling Smørgrav eat(int fnum, lineno num) 605bc421551SDag-Erling Smørgrav { 606bc421551SDag-Erling Smørgrav eats(fnum, num, 0, -1); 607bc421551SDag-Erling Smørgrav } 608bc421551SDag-Erling Smørgrav 60975411d15SDag-Erling Smørgrav ATTRIBUTE_FORMAT((printf, 1, 0)) static void 610bc421551SDag-Erling Smørgrav verror(const char *const string, va_list args) 611bc421551SDag-Erling Smørgrav { 612bc421551SDag-Erling Smørgrav /* 613bc421551SDag-Erling Smørgrav ** Match the format of "cc" to allow sh users to 614bc421551SDag-Erling Smørgrav ** zic ... 2>&1 | error -t "*" -v 615bc421551SDag-Erling Smørgrav ** on BSD systems. 616bc421551SDag-Erling Smørgrav */ 617bc421551SDag-Erling Smørgrav if (filenum) 618bc421551SDag-Erling Smørgrav fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), 619bc421551SDag-Erling Smørgrav filename(filenum), linenum); 620bc421551SDag-Erling Smørgrav vfprintf(stderr, string, args); 621bc421551SDag-Erling Smørgrav if (rfilenum) 622bc421551SDag-Erling Smørgrav fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"), 623bc421551SDag-Erling Smørgrav filename(rfilenum), rlinenum); 624bc421551SDag-Erling Smørgrav fprintf(stderr, "\n"); 625bc421551SDag-Erling Smørgrav } 626bc421551SDag-Erling Smørgrav 62775411d15SDag-Erling Smørgrav ATTRIBUTE_FORMAT((printf, 1, 2)) static void 628bc421551SDag-Erling Smørgrav error(const char *const string, ...) 629bc421551SDag-Erling Smørgrav { 630bc421551SDag-Erling Smørgrav va_list args; 631bc421551SDag-Erling Smørgrav va_start(args, string); 632bc421551SDag-Erling Smørgrav verror(string, args); 633bc421551SDag-Erling Smørgrav va_end(args); 634bc421551SDag-Erling Smørgrav errors = true; 635bc421551SDag-Erling Smørgrav } 636bc421551SDag-Erling Smørgrav 63775411d15SDag-Erling Smørgrav ATTRIBUTE_FORMAT((printf, 1, 2)) static void 638bc421551SDag-Erling Smørgrav warning(const char *const string, ...) 639bc421551SDag-Erling Smørgrav { 640bc421551SDag-Erling Smørgrav va_list args; 641bc421551SDag-Erling Smørgrav fprintf(stderr, _("warning: ")); 642bc421551SDag-Erling Smørgrav va_start(args, string); 643bc421551SDag-Erling Smørgrav verror(string, args); 644bc421551SDag-Erling Smørgrav va_end(args); 645bc421551SDag-Erling Smørgrav warnings = true; 646bc421551SDag-Erling Smørgrav } 647bc421551SDag-Erling Smørgrav 648bc421551SDag-Erling Smørgrav /* Close STREAM. If it had an I/O error, report it against DIR/NAME, 649bc421551SDag-Erling Smørgrav remove TEMPNAME if nonnull, and then exit. */ 650bc421551SDag-Erling Smørgrav static void 651bc421551SDag-Erling Smørgrav close_file(FILE *stream, char const *dir, char const *name, 652bc421551SDag-Erling Smørgrav char const *tempname) 653bc421551SDag-Erling Smørgrav { 654bc421551SDag-Erling Smørgrav char const *e = (ferror(stream) ? _("I/O error") 655bc421551SDag-Erling Smørgrav : fclose(stream) != 0 ? strerror(errno) : NULL); 656bc421551SDag-Erling Smørgrav if (e) { 657bc421551SDag-Erling Smørgrav fprintf(stderr, "%s: %s%s%s%s%s\n", progname, 658bc421551SDag-Erling Smørgrav dir ? dir : "", dir ? "/" : "", 659bc421551SDag-Erling Smørgrav name ? name : "", name ? ": " : "", 660bc421551SDag-Erling Smørgrav e); 661bc421551SDag-Erling Smørgrav if (tempname) 6622aad7570SDag-Erling Smørgrav (void)remove(tempname); 663bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 664bc421551SDag-Erling Smørgrav } 665bc421551SDag-Erling Smørgrav } 666bc421551SDag-Erling Smørgrav 66775411d15SDag-Erling Smørgrav ATTRIBUTE_NORETURN static void 668bc421551SDag-Erling Smørgrav usage(FILE *stream, int status) 669bc421551SDag-Erling Smørgrav { 670bc421551SDag-Erling Smørgrav fprintf(stream, 671bc421551SDag-Erling Smørgrav _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" 672bc421551SDag-Erling Smørgrav "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" 673bc421551SDag-Erling Smørgrav " [ -L leapseconds ] \\\n" 674bc421551SDag-Erling Smørgrav "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n" 675bc421551SDag-Erling Smørgrav "\t[ -t localtime-link ] [ -D ] [ -g gid ] [ -u uid ] \\\n" 676bc421551SDag-Erling Smørgrav "\t[ filename ... ]\n\n" 677bc421551SDag-Erling Smørgrav "Report bugs to %s.\n"), 678bc421551SDag-Erling Smørgrav progname, progname, REPORT_BUGS_TO); 679bc421551SDag-Erling Smørgrav if (status == EXIT_SUCCESS) 680bc421551SDag-Erling Smørgrav close_file(stream, NULL, NULL, NULL); 681bc421551SDag-Erling Smørgrav exit(status); 682bc421551SDag-Erling Smørgrav } 683bc421551SDag-Erling Smørgrav 684bc421551SDag-Erling Smørgrav /* Change the working directory to DIR, possibly creating DIR and its 685bc421551SDag-Erling Smørgrav ancestors. After this is done, all files are accessed with names 686bc421551SDag-Erling Smørgrav relative to DIR. */ 687bc421551SDag-Erling Smørgrav static void 688bc421551SDag-Erling Smørgrav change_directory(char const *dir) 689bc421551SDag-Erling Smørgrav { 690bc421551SDag-Erling Smørgrav if (chdir(dir) != 0) { 691bc421551SDag-Erling Smørgrav int chdir_errno = errno; 692bc421551SDag-Erling Smørgrav if (chdir_errno == ENOENT) { 693bc421551SDag-Erling Smørgrav mkdirs(dir, false); 694bc421551SDag-Erling Smørgrav chdir_errno = chdir(dir) == 0 ? 0 : errno; 695bc421551SDag-Erling Smørgrav } 696bc421551SDag-Erling Smørgrav if (chdir_errno != 0) { 697bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't chdir to %s: %s\n"), 698bc421551SDag-Erling Smørgrav progname, dir, strerror(chdir_errno)); 699bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 700bc421551SDag-Erling Smørgrav } 701bc421551SDag-Erling Smørgrav } 702bc421551SDag-Erling Smørgrav } 703bc421551SDag-Erling Smørgrav 704bc421551SDag-Erling Smørgrav /* Compare the two links A and B, for a stable sort by link name. */ 705bc421551SDag-Erling Smørgrav static int 706bc421551SDag-Erling Smørgrav qsort_linkcmp(void const *a, void const *b) 707bc421551SDag-Erling Smørgrav { 708bc421551SDag-Erling Smørgrav struct link const *l = a; 709bc421551SDag-Erling Smørgrav struct link const *m = b; 710bc421551SDag-Erling Smørgrav int cmp = strcmp(l->l_linkname, m->l_linkname); 711bc421551SDag-Erling Smørgrav if (cmp) 712bc421551SDag-Erling Smørgrav return cmp; 713bc421551SDag-Erling Smørgrav 714bc421551SDag-Erling Smørgrav /* The link names are the same. Make the sort stable by comparing 715bc421551SDag-Erling Smørgrav file numbers (where subtraction cannot overflow) and possibly 716bc421551SDag-Erling Smørgrav line numbers (where it can). */ 717bc421551SDag-Erling Smørgrav cmp = l->l_filenum - m->l_filenum; 718bc421551SDag-Erling Smørgrav if (cmp) 719bc421551SDag-Erling Smørgrav return cmp; 720bc421551SDag-Erling Smørgrav return (l->l_linenum > m->l_linenum) - (l->l_linenum < m->l_linenum); 721bc421551SDag-Erling Smørgrav } 722bc421551SDag-Erling Smørgrav 723bc421551SDag-Erling Smørgrav /* Compare the string KEY to the link B, for bsearch. */ 724bc421551SDag-Erling Smørgrav static int 725bc421551SDag-Erling Smørgrav bsearch_linkcmp(void const *key, void const *b) 726bc421551SDag-Erling Smørgrav { 727bc421551SDag-Erling Smørgrav struct link const *m = b; 728bc421551SDag-Erling Smørgrav return strcmp(key, m->l_linkname); 729bc421551SDag-Erling Smørgrav } 730bc421551SDag-Erling Smørgrav 731bc421551SDag-Erling Smørgrav /* Make the links specified by the Link lines. */ 732bc421551SDag-Erling Smørgrav static void 733bc421551SDag-Erling Smørgrav make_links(void) 734bc421551SDag-Erling Smørgrav { 735bc421551SDag-Erling Smørgrav ptrdiff_t i, j, nalinks, pass_size; 736bc421551SDag-Erling Smørgrav if (1 < nlinks) 737bc421551SDag-Erling Smørgrav qsort(links, nlinks, sizeof *links, qsort_linkcmp); 738bc421551SDag-Erling Smørgrav 739bc421551SDag-Erling Smørgrav /* Ignore each link superseded by a later link with the same name. */ 740bc421551SDag-Erling Smørgrav j = 0; 741bc421551SDag-Erling Smørgrav for (i = 0; i < nlinks; i++) { 742bc421551SDag-Erling Smørgrav while (i + 1 < nlinks 743bc421551SDag-Erling Smørgrav && strcmp(links[i].l_linkname, links[i + 1].l_linkname) == 0) 744bc421551SDag-Erling Smørgrav i++; 745bc421551SDag-Erling Smørgrav links[j++] = links[i]; 746bc421551SDag-Erling Smørgrav } 747bc421551SDag-Erling Smørgrav nlinks = pass_size = j; 748bc421551SDag-Erling Smørgrav 749bc421551SDag-Erling Smørgrav /* Walk through the link array making links. However, 750bc421551SDag-Erling Smørgrav if a link's target has not been made yet, append a copy to the 751bc421551SDag-Erling Smørgrav end of the array. The end of the array will gradually fill 752bc421551SDag-Erling Smørgrav up with a small sorted subsequence of not-yet-made links. 753bc421551SDag-Erling Smørgrav nalinks counts all the links in the array, including copies. 754bc421551SDag-Erling Smørgrav When we reach the copied subsequence, it may still contain 755bc421551SDag-Erling Smørgrav a link to a not-yet-made link, so the process repeats. 756bc421551SDag-Erling Smørgrav At any given point in time, the link array consists of the 757bc421551SDag-Erling Smørgrav following subregions, where 0 <= i <= j <= nalinks and 758bc421551SDag-Erling Smørgrav 0 <= nlinks <= nalinks: 759bc421551SDag-Erling Smørgrav 760bc421551SDag-Erling Smørgrav 0 .. (i - 1): 761bc421551SDag-Erling Smørgrav links that either have been made, or have been copied to a 762bc421551SDag-Erling Smørgrav later point point in the array (this later point can be in 763bc421551SDag-Erling Smørgrav any of the three subregions) 764bc421551SDag-Erling Smørgrav i .. (j - 1): 765bc421551SDag-Erling Smørgrav not-yet-made links for this pass 766bc421551SDag-Erling Smørgrav j .. (nalinks - 1): 767bc421551SDag-Erling Smørgrav not-yet-made links that this pass has skipped because 768bc421551SDag-Erling Smørgrav they were links to not-yet-made links 769bc421551SDag-Erling Smørgrav 770bc421551SDag-Erling Smørgrav The first subregion might not be sorted if nlinks < i; 771bc421551SDag-Erling Smørgrav the other two subregions are sorted. This algorithm does 772bc421551SDag-Erling Smørgrav not alter entries 0 .. (nlinks - 1), which remain sorted. 773bc421551SDag-Erling Smørgrav 774bc421551SDag-Erling Smørgrav If there are L links, this algorithm is O(C*L*log(L)) where 775bc421551SDag-Erling Smørgrav C is the length of the longest link chain. Usually C is 776bc421551SDag-Erling Smørgrav short (e.g., 3) though its worst-case value is L. */ 777bc421551SDag-Erling Smørgrav 778bc421551SDag-Erling Smørgrav j = nalinks = nlinks; 779bc421551SDag-Erling Smørgrav 780bc421551SDag-Erling Smørgrav for (i = 0; i < nalinks; i++) { 781bc421551SDag-Erling Smørgrav struct link *l; 782bc421551SDag-Erling Smørgrav 783bc421551SDag-Erling Smørgrav eat(links[i].l_filenum, links[i].l_linenum); 784bc421551SDag-Erling Smørgrav 785bc421551SDag-Erling Smørgrav /* If this pass examined all its links, start the next pass. */ 786bc421551SDag-Erling Smørgrav if (i == j) { 787bc421551SDag-Erling Smørgrav if (nalinks - i == pass_size) { 788bc421551SDag-Erling Smørgrav error(_("\"Link %s %s\" is part of a link cycle"), 789bc421551SDag-Erling Smørgrav links[i].l_target, links[i].l_linkname); 790bc421551SDag-Erling Smørgrav break; 791bc421551SDag-Erling Smørgrav } 792bc421551SDag-Erling Smørgrav j = nalinks; 793bc421551SDag-Erling Smørgrav pass_size = nalinks - i; 794bc421551SDag-Erling Smørgrav } 795bc421551SDag-Erling Smørgrav 796bc421551SDag-Erling Smørgrav /* Diagnose self links, which the cycle detection algorithm would not 797bc421551SDag-Erling Smørgrav otherwise catch. */ 798bc421551SDag-Erling Smørgrav if (strcmp(links[i].l_target, links[i].l_linkname) == 0) { 799bc421551SDag-Erling Smørgrav error(_("link %s targets itself"), links[i].l_target); 800bc421551SDag-Erling Smørgrav continue; 801bc421551SDag-Erling Smørgrav } 802bc421551SDag-Erling Smørgrav 803bc421551SDag-Erling Smørgrav /* Make this link unless its target has not been made yet. */ 804bc421551SDag-Erling Smørgrav l = bsearch(links[i].l_target, &links[i + 1], j - (i + 1), 805bc421551SDag-Erling Smørgrav sizeof *links, bsearch_linkcmp); 806bc421551SDag-Erling Smørgrav if (!l) 807bc421551SDag-Erling Smørgrav l = bsearch(links[i].l_target, &links[j], nalinks - j, 808bc421551SDag-Erling Smørgrav sizeof *links, bsearch_linkcmp); 809bc421551SDag-Erling Smørgrav if (!l) 810bc421551SDag-Erling Smørgrav dolink(links[i].l_target, links[i].l_linkname, false); 811bc421551SDag-Erling Smørgrav else { 812bc421551SDag-Erling Smørgrav /* The link target has not been made yet; copy the link to the end. */ 813bc421551SDag-Erling Smørgrav links = growalloc(links, sizeof *links, nalinks, &nlinks_alloc); 814bc421551SDag-Erling Smørgrav links[nalinks++] = links[i]; 815bc421551SDag-Erling Smørgrav } 816bc421551SDag-Erling Smørgrav 817bc421551SDag-Erling Smørgrav if (noise && i < nlinks) { 818bc421551SDag-Erling Smørgrav if (l) 819bc421551SDag-Erling Smørgrav warning(_("link %s targeting link %s mishandled by pre-2023 zic"), 820bc421551SDag-Erling Smørgrav links[i].l_linkname, links[i].l_target); 821bc421551SDag-Erling Smørgrav else if (bsearch(links[i].l_target, links, nlinks, sizeof *links, 822bc421551SDag-Erling Smørgrav bsearch_linkcmp)) 823bc421551SDag-Erling Smørgrav warning(_("link %s targeting link %s"), 824bc421551SDag-Erling Smørgrav links[i].l_linkname, links[i].l_target); 825bc421551SDag-Erling Smørgrav } 826bc421551SDag-Erling Smørgrav } 827bc421551SDag-Erling Smørgrav } 828bc421551SDag-Erling Smørgrav 829bc421551SDag-Erling Smørgrav /* Simple signal handling: just set a flag that is checked 830bc421551SDag-Erling Smørgrav periodically outside critical sections. To set up the handler, 831bc421551SDag-Erling Smørgrav prefer sigaction if available to close a signal race. */ 832bc421551SDag-Erling Smørgrav 833bc421551SDag-Erling Smørgrav static sig_atomic_t got_signal; 834bc421551SDag-Erling Smørgrav 835bc421551SDag-Erling Smørgrav static void 836bc421551SDag-Erling Smørgrav signal_handler(int sig) 837bc421551SDag-Erling Smørgrav { 838bc421551SDag-Erling Smørgrav #ifndef SA_SIGINFO 839bc421551SDag-Erling Smørgrav signal(sig, signal_handler); 840bc421551SDag-Erling Smørgrav #endif 841bc421551SDag-Erling Smørgrav got_signal = sig; 842bc421551SDag-Erling Smørgrav } 843bc421551SDag-Erling Smørgrav 844bc421551SDag-Erling Smørgrav /* Arrange for SIGINT etc. to be caught by the handler. */ 845bc421551SDag-Erling Smørgrav static void 846bc421551SDag-Erling Smørgrav catch_signals(void) 847bc421551SDag-Erling Smørgrav { 848bc421551SDag-Erling Smørgrav static int const signals[] = { 849bc421551SDag-Erling Smørgrav #ifdef SIGHUP 850bc421551SDag-Erling Smørgrav SIGHUP, 851bc421551SDag-Erling Smørgrav #endif 852bc421551SDag-Erling Smørgrav SIGINT, 853bc421551SDag-Erling Smørgrav #ifdef SIGPIPE 854bc421551SDag-Erling Smørgrav SIGPIPE, 855bc421551SDag-Erling Smørgrav #endif 856bc421551SDag-Erling Smørgrav SIGTERM 857bc421551SDag-Erling Smørgrav }; 858bc421551SDag-Erling Smørgrav size_t i; 859bc421551SDag-Erling Smørgrav for (i = 0; i < sizeof signals / sizeof signals[0]; i++) { 860bc421551SDag-Erling Smørgrav #ifdef SA_SIGINFO 861bc421551SDag-Erling Smørgrav struct sigaction act0, act; 862bc421551SDag-Erling Smørgrav act.sa_handler = signal_handler; 863bc421551SDag-Erling Smørgrav sigemptyset(&act.sa_mask); 864bc421551SDag-Erling Smørgrav act.sa_flags = 0; 865bc421551SDag-Erling Smørgrav if (sigaction(signals[i], &act, &act0) == 0 866bc421551SDag-Erling Smørgrav && ! (act0.sa_flags & SA_SIGINFO) && act0.sa_handler == SIG_IGN) { 867bc421551SDag-Erling Smørgrav sigaction(signals[i], &act0, NULL); 868bc421551SDag-Erling Smørgrav got_signal = 0; 869bc421551SDag-Erling Smørgrav } 870bc421551SDag-Erling Smørgrav #else 871bc421551SDag-Erling Smørgrav if (signal(signals[i], signal_handler) == SIG_IGN) { 872bc421551SDag-Erling Smørgrav signal(signals[i], SIG_IGN); 873bc421551SDag-Erling Smørgrav got_signal = 0; 874bc421551SDag-Erling Smørgrav } 875bc421551SDag-Erling Smørgrav #endif 876bc421551SDag-Erling Smørgrav } 877bc421551SDag-Erling Smørgrav } 878bc421551SDag-Erling Smørgrav 879bc421551SDag-Erling Smørgrav /* If a signal has arrived, terminate zic with appropriate status. */ 880bc421551SDag-Erling Smørgrav static void 881bc421551SDag-Erling Smørgrav check_for_signal(void) 882bc421551SDag-Erling Smørgrav { 883bc421551SDag-Erling Smørgrav int sig = got_signal; 884bc421551SDag-Erling Smørgrav if (sig) { 885bc421551SDag-Erling Smørgrav signal(sig, SIG_DFL); 886bc421551SDag-Erling Smørgrav raise(sig); 887bc421551SDag-Erling Smørgrav abort(); /* A bug in 'raise'. */ 888bc421551SDag-Erling Smørgrav } 889bc421551SDag-Erling Smørgrav } 890bc421551SDag-Erling Smørgrav 891bc421551SDag-Erling Smørgrav enum { TIME_T_BITS_IN_FILE = 64 }; 892bc421551SDag-Erling Smørgrav 893bc421551SDag-Erling Smørgrav /* The minimum and maximum values representable in a TZif file. */ 894bc421551SDag-Erling Smørgrav static zic_t const min_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); 895bc421551SDag-Erling Smørgrav static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); 896bc421551SDag-Erling Smørgrav 897bc421551SDag-Erling Smørgrav /* The minimum, and one less than the maximum, values specified by 898bc421551SDag-Erling Smørgrav the -r option. These default to MIN_TIME and MAX_TIME. */ 899bc421551SDag-Erling Smørgrav static zic_t lo_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); 900bc421551SDag-Erling Smørgrav static zic_t hi_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE); 901bc421551SDag-Erling Smørgrav 90246c59934SDag-Erling Smørgrav /* The time specified by the -R option, defaulting to MIN_TIME; 90346c59934SDag-Erling Smørgrav or lo_time, whichever is greater. */ 904bc421551SDag-Erling Smørgrav static zic_t redundant_time = MINVAL(zic_t, TIME_T_BITS_IN_FILE); 905bc421551SDag-Erling Smørgrav 906bc421551SDag-Erling Smørgrav /* The time specified by an Expires line, or negative if no such line. */ 907bc421551SDag-Erling Smørgrav static zic_t leapexpires = -1; 908bc421551SDag-Erling Smørgrav 909bc421551SDag-Erling Smørgrav /* Set the time range of the output to TIMERANGE. 910bc421551SDag-Erling Smørgrav Return true if successful. */ 911bc421551SDag-Erling Smørgrav static bool 912bc421551SDag-Erling Smørgrav timerange_option(char *timerange) 913bc421551SDag-Erling Smørgrav { 914bc421551SDag-Erling Smørgrav intmax_t lo = min_time, hi = max_time; 915bc421551SDag-Erling Smørgrav char *lo_end = timerange, *hi_end; 916bc421551SDag-Erling Smørgrav if (*timerange == '@') { 917bc421551SDag-Erling Smørgrav errno = 0; 918bc421551SDag-Erling Smørgrav lo = strtoimax(timerange + 1, &lo_end, 10); 919bc421551SDag-Erling Smørgrav if (lo_end == timerange + 1 || (lo == INTMAX_MAX && errno == ERANGE)) 920bc421551SDag-Erling Smørgrav return false; 921bc421551SDag-Erling Smørgrav } 922bc421551SDag-Erling Smørgrav hi_end = lo_end; 923bc421551SDag-Erling Smørgrav if (lo_end[0] == '/' && lo_end[1] == '@') { 924bc421551SDag-Erling Smørgrav errno = 0; 925bc421551SDag-Erling Smørgrav hi = strtoimax(lo_end + 2, &hi_end, 10); 926bc421551SDag-Erling Smørgrav if (hi_end == lo_end + 2 || hi == INTMAX_MIN) 927bc421551SDag-Erling Smørgrav return false; 928bc421551SDag-Erling Smørgrav hi -= ! (hi == INTMAX_MAX && errno == ERANGE); 929bc421551SDag-Erling Smørgrav } 930bc421551SDag-Erling Smørgrav if (*hi_end || hi < lo || max_time < lo || hi < min_time) 931bc421551SDag-Erling Smørgrav return false; 932bc421551SDag-Erling Smørgrav lo_time = max(lo, min_time); 933bc421551SDag-Erling Smørgrav hi_time = min(hi, max_time); 934bc421551SDag-Erling Smørgrav return true; 935bc421551SDag-Erling Smørgrav } 936bc421551SDag-Erling Smørgrav 937bc421551SDag-Erling Smørgrav /* Generate redundant time stamps up to OPT. Return true if successful. */ 938bc421551SDag-Erling Smørgrav static bool 939bc421551SDag-Erling Smørgrav redundant_time_option(char *opt) 940bc421551SDag-Erling Smørgrav { 941bc421551SDag-Erling Smørgrav if (*opt == '@') { 942bc421551SDag-Erling Smørgrav intmax_t redundant; 943bc421551SDag-Erling Smørgrav char *opt_end; 944bc421551SDag-Erling Smørgrav redundant = strtoimax(opt + 1, &opt_end, 10); 945bc421551SDag-Erling Smørgrav if (opt_end != opt + 1 && !*opt_end) { 946bc421551SDag-Erling Smørgrav redundant_time = max(redundant_time, redundant); 947bc421551SDag-Erling Smørgrav return true; 948bc421551SDag-Erling Smørgrav } 949bc421551SDag-Erling Smørgrav } 950bc421551SDag-Erling Smørgrav return false; 951bc421551SDag-Erling Smørgrav } 952bc421551SDag-Erling Smørgrav 953bc421551SDag-Erling Smørgrav static const char * psxrules; 954bc421551SDag-Erling Smørgrav static const char * lcltime; 955bc421551SDag-Erling Smørgrav static const char * directory; 956bc421551SDag-Erling Smørgrav static const char * leapsec; 957bc421551SDag-Erling Smørgrav static int Dflag; 958bc421551SDag-Erling Smørgrav static uid_t uflag = (uid_t)-1; 959bc421551SDag-Erling Smørgrav static gid_t gflag = (gid_t)-1; 960bc421551SDag-Erling Smørgrav static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH 961bc421551SDag-Erling Smørgrav | S_IWUSR); 962bc421551SDag-Erling Smørgrav static const char * tzdefault; 963bc421551SDag-Erling Smørgrav 964bc421551SDag-Erling Smørgrav /* -1 if the TZif output file should be slim, 0 if default, 1 if the 965bc421551SDag-Erling Smørgrav output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT 966bc421551SDag-Erling Smørgrav determines the default. */ 967bc421551SDag-Erling Smørgrav static int bloat; 968bc421551SDag-Erling Smørgrav 969bc421551SDag-Erling Smørgrav static bool 970bc421551SDag-Erling Smørgrav want_bloat(void) 971bc421551SDag-Erling Smørgrav { 972bc421551SDag-Erling Smørgrav return 0 <= bloat; 973bc421551SDag-Erling Smørgrav } 974bc421551SDag-Erling Smørgrav 975bc421551SDag-Erling Smørgrav #ifndef ZIC_BLOAT_DEFAULT 976bc421551SDag-Erling Smørgrav # define ZIC_BLOAT_DEFAULT "slim" 977bc421551SDag-Erling Smørgrav #endif 978bc421551SDag-Erling Smørgrav 979bc421551SDag-Erling Smørgrav int 980bc421551SDag-Erling Smørgrav main(int argc, char **argv) 981bc421551SDag-Erling Smørgrav { 982bc421551SDag-Erling Smørgrav register int c, k; 983bc421551SDag-Erling Smørgrav register ptrdiff_t i, j; 984bc421551SDag-Erling Smørgrav bool timerange_given = false; 985bc421551SDag-Erling Smørgrav 986bc421551SDag-Erling Smørgrav #ifdef S_IWGRP 987bc421551SDag-Erling Smørgrav umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 988bc421551SDag-Erling Smørgrav #endif 989bc421551SDag-Erling Smørgrav #if HAVE_GETTEXT 990bc421551SDag-Erling Smørgrav setlocale(LC_ALL, ""); 991bc421551SDag-Erling Smørgrav # ifdef TZ_DOMAINDIR 992bc421551SDag-Erling Smørgrav bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 993bc421551SDag-Erling Smørgrav # endif /* defined TEXTDOMAINDIR */ 994bc421551SDag-Erling Smørgrav textdomain(TZ_DOMAIN); 995bc421551SDag-Erling Smørgrav #endif /* HAVE_GETTEXT */ 996bc421551SDag-Erling Smørgrav main_argv = argv; 997bc421551SDag-Erling Smørgrav progname = /* argv[0] ? argv[0] : */ "zic"; 998bc421551SDag-Erling Smørgrav if (TYPE_BIT(zic_t) < 64) { 999bc421551SDag-Erling Smørgrav fprintf(stderr, "%s: %s\n", progname, 1000bc421551SDag-Erling Smørgrav _("wild compilation-time specification of zic_t")); 1001bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1002bc421551SDag-Erling Smørgrav } 1003bc421551SDag-Erling Smørgrav for (k = 1; k < argc; k++) 1004bc421551SDag-Erling Smørgrav if (strcmp(argv[k], "--version") == 0) { 1005bc421551SDag-Erling Smørgrav printf("zic %s%s\n", PKGVERSION, TZVERSION); 1006bc421551SDag-Erling Smørgrav close_file(stdout, NULL, NULL, NULL); 1007bc421551SDag-Erling Smørgrav return EXIT_SUCCESS; 1008bc421551SDag-Erling Smørgrav } else if (strcmp(argv[k], "--help") == 0) { 1009bc421551SDag-Erling Smørgrav usage(stdout, EXIT_SUCCESS); 1010bc421551SDag-Erling Smørgrav } 1011bc421551SDag-Erling Smørgrav while ((c = getopt(argc, argv, "Db:d:g:l:L:m:p:r:R:st:u:vy:")) != EOF 1012bc421551SDag-Erling Smørgrav && c != -1) 1013bc421551SDag-Erling Smørgrav switch (c) { 1014bc421551SDag-Erling Smørgrav default: 1015bc421551SDag-Erling Smørgrav usage(stderr, EXIT_FAILURE); 1016bc421551SDag-Erling Smørgrav case 'D': 1017bc421551SDag-Erling Smørgrav Dflag = 1; 1018bc421551SDag-Erling Smørgrav break; 1019bc421551SDag-Erling Smørgrav case 'b': 1020bc421551SDag-Erling Smørgrav if (strcmp(optarg, "slim") == 0) { 1021bc421551SDag-Erling Smørgrav if (0 < bloat) 1022bc421551SDag-Erling Smørgrav error(_("incompatible -b options")); 1023bc421551SDag-Erling Smørgrav bloat = -1; 1024bc421551SDag-Erling Smørgrav } else if (strcmp(optarg, "fat") == 0) { 1025bc421551SDag-Erling Smørgrav if (bloat < 0) 1026bc421551SDag-Erling Smørgrav error(_("incompatible -b options")); 1027bc421551SDag-Erling Smørgrav bloat = 1; 1028bc421551SDag-Erling Smørgrav } else 1029bc421551SDag-Erling Smørgrav error(_("invalid option: -b '%s'"), optarg); 1030bc421551SDag-Erling Smørgrav break; 1031bc421551SDag-Erling Smørgrav case 'd': 1032bc421551SDag-Erling Smørgrav if (directory == NULL) 1033bc421551SDag-Erling Smørgrav directory = optarg; 1034bc421551SDag-Erling Smørgrav else { 1035bc421551SDag-Erling Smørgrav fprintf(stderr, 103646c59934SDag-Erling Smørgrav _("%s: More than one -d option" 103746c59934SDag-Erling Smørgrav " specified\n"), 1038bc421551SDag-Erling Smørgrav progname); 1039bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1040bc421551SDag-Erling Smørgrav } 1041bc421551SDag-Erling Smørgrav break; 1042bc421551SDag-Erling Smørgrav case 'g': 1043bc421551SDag-Erling Smørgrav setgroup(&gflag, optarg); 1044bc421551SDag-Erling Smørgrav break; 1045bc421551SDag-Erling Smørgrav case 'l': 1046bc421551SDag-Erling Smørgrav if (lcltime == NULL) 1047bc421551SDag-Erling Smørgrav lcltime = optarg; 1048bc421551SDag-Erling Smørgrav else { 1049bc421551SDag-Erling Smørgrav fprintf(stderr, 105046c59934SDag-Erling Smørgrav _("%s: More than one -l option" 105146c59934SDag-Erling Smørgrav " specified\n"), 1052bc421551SDag-Erling Smørgrav progname); 1053bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1054bc421551SDag-Erling Smørgrav } 1055bc421551SDag-Erling Smørgrav break; 1056bc421551SDag-Erling Smørgrav case 'm': 1057bc421551SDag-Erling Smørgrav { 1058bc421551SDag-Erling Smørgrav void *set = setmode(optarg); 1059bc421551SDag-Erling Smørgrav if (set == NULL) { 1060bc421551SDag-Erling Smørgrav fprintf(stderr, 1061bc421551SDag-Erling Smørgrav _("invalid file mode")); 1062bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1063bc421551SDag-Erling Smørgrav } 1064bc421551SDag-Erling Smørgrav mflag = getmode(set, mflag); 1065bc421551SDag-Erling Smørgrav free(set); 1066bc421551SDag-Erling Smørgrav break; 1067bc421551SDag-Erling Smørgrav } 1068bc421551SDag-Erling Smørgrav case 'p': 1069bc421551SDag-Erling Smørgrav if (psxrules == NULL) 1070bc421551SDag-Erling Smørgrav psxrules = optarg; 1071bc421551SDag-Erling Smørgrav else { 1072bc421551SDag-Erling Smørgrav fprintf(stderr, 107346c59934SDag-Erling Smørgrav _("%s: More than one -p option" 107446c59934SDag-Erling Smørgrav " specified\n"), 1075bc421551SDag-Erling Smørgrav progname); 1076bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1077bc421551SDag-Erling Smørgrav } 1078bc421551SDag-Erling Smørgrav break; 1079bc421551SDag-Erling Smørgrav case 't': 1080bc421551SDag-Erling Smørgrav if (tzdefault != NULL) { 1081bc421551SDag-Erling Smørgrav fprintf(stderr, 1082bc421551SDag-Erling Smørgrav _("%s: More than one -t option" 1083bc421551SDag-Erling Smørgrav " specified\n"), 1084bc421551SDag-Erling Smørgrav progname); 1085bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1086bc421551SDag-Erling Smørgrav } 1087bc421551SDag-Erling Smørgrav tzdefault = optarg; 1088bc421551SDag-Erling Smørgrav break; 1089bc421551SDag-Erling Smørgrav case 'u': 1090bc421551SDag-Erling Smørgrav setuser(&uflag, optarg); 1091bc421551SDag-Erling Smørgrav break; 1092bc421551SDag-Erling Smørgrav case 'y': 1093bc421551SDag-Erling Smørgrav warning(_("-y ignored")); 1094bc421551SDag-Erling Smørgrav break; 1095bc421551SDag-Erling Smørgrav case 'L': 1096bc421551SDag-Erling Smørgrav if (leapsec == NULL) 1097bc421551SDag-Erling Smørgrav leapsec = optarg; 1098bc421551SDag-Erling Smørgrav else { 1099bc421551SDag-Erling Smørgrav fprintf(stderr, 110046c59934SDag-Erling Smørgrav _("%s: More than one -L option" 110146c59934SDag-Erling Smørgrav " specified\n"), 1102bc421551SDag-Erling Smørgrav progname); 1103bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1104bc421551SDag-Erling Smørgrav } 1105bc421551SDag-Erling Smørgrav break; 1106bc421551SDag-Erling Smørgrav case 'v': 1107bc421551SDag-Erling Smørgrav noise = true; 1108bc421551SDag-Erling Smørgrav break; 1109bc421551SDag-Erling Smørgrav case 'r': 1110bc421551SDag-Erling Smørgrav if (timerange_given) { 1111bc421551SDag-Erling Smørgrav fprintf(stderr, 111246c59934SDag-Erling Smørgrav _("%s: More than one -r option" 111346c59934SDag-Erling Smørgrav " specified\n"), 1114bc421551SDag-Erling Smørgrav progname); 1115bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1116bc421551SDag-Erling Smørgrav } 1117bc421551SDag-Erling Smørgrav if (! timerange_option(optarg)) { 1118bc421551SDag-Erling Smørgrav fprintf(stderr, 1119bc421551SDag-Erling Smørgrav _("%s: invalid time range: %s\n"), 1120bc421551SDag-Erling Smørgrav progname, optarg); 1121bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1122bc421551SDag-Erling Smørgrav } 1123bc421551SDag-Erling Smørgrav timerange_given = true; 1124bc421551SDag-Erling Smørgrav break; 1125bc421551SDag-Erling Smørgrav case 'R': 1126bc421551SDag-Erling Smørgrav if (! redundant_time_option(optarg)) { 1127bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: invalid time: %s\n"), 1128bc421551SDag-Erling Smørgrav progname, optarg); 1129bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1130bc421551SDag-Erling Smørgrav } 1131bc421551SDag-Erling Smørgrav break; 1132bc421551SDag-Erling Smørgrav case 's': 1133bc421551SDag-Erling Smørgrav warning(_("-s ignored")); 1134bc421551SDag-Erling Smørgrav break; 1135bc421551SDag-Erling Smørgrav } 1136bc421551SDag-Erling Smørgrav if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 1137bc421551SDag-Erling Smørgrav usage(stderr, EXIT_FAILURE); /* usage message by request */ 1138bc421551SDag-Erling Smørgrav if (hi_time + (hi_time < ZIC_MAX) < redundant_time) { 1139bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: -R time exceeds -r cutoff\n"), progname); 1140bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1141bc421551SDag-Erling Smørgrav } 114246c59934SDag-Erling Smørgrav if (redundant_time < lo_time) 114346c59934SDag-Erling Smørgrav redundant_time = lo_time; 1144bc421551SDag-Erling Smørgrav if (bloat == 0) { 1145bc421551SDag-Erling Smørgrav static char const bloat_default[] = ZIC_BLOAT_DEFAULT; 1146bc421551SDag-Erling Smørgrav if (strcmp(bloat_default, "slim") == 0) 1147bc421551SDag-Erling Smørgrav bloat = -1; 1148bc421551SDag-Erling Smørgrav else if (strcmp(bloat_default, "fat") == 0) 1149bc421551SDag-Erling Smørgrav bloat = 1; 1150bc421551SDag-Erling Smørgrav else 1151bc421551SDag-Erling Smørgrav abort(); /* Configuration error. */ 1152bc421551SDag-Erling Smørgrav } 1153bc421551SDag-Erling Smørgrav if (directory == NULL) 1154bc421551SDag-Erling Smørgrav directory = TZDIR; 1155bc421551SDag-Erling Smørgrav if (tzdefault == NULL) 1156bc421551SDag-Erling Smørgrav tzdefault = TZDEFAULT; 1157bc421551SDag-Erling Smørgrav 1158bc421551SDag-Erling Smørgrav if (optind < argc && leapsec != NULL) { 1159bc421551SDag-Erling Smørgrav infile(LEAPSEC_FILENUM, leapsec); 1160bc421551SDag-Erling Smørgrav adjleap(); 1161bc421551SDag-Erling Smørgrav } 1162bc421551SDag-Erling Smørgrav 1163bc421551SDag-Erling Smørgrav for (k = optind; k < argc; k++) 1164bc421551SDag-Erling Smørgrav infile(k, argv[k]); 1165bc421551SDag-Erling Smørgrav if (errors) 1166bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1167bc421551SDag-Erling Smørgrav associate(); 1168bc421551SDag-Erling Smørgrav change_directory(directory); 1169bc421551SDag-Erling Smørgrav catch_signals(); 1170bc421551SDag-Erling Smørgrav for (i = 0; i < nzones; i = j) { 1171bc421551SDag-Erling Smørgrav /* 1172bc421551SDag-Erling Smørgrav ** Find the next non-continuation zone entry. 1173bc421551SDag-Erling Smørgrav */ 1174bc421551SDag-Erling Smørgrav for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 1175bc421551SDag-Erling Smørgrav continue; 1176bc421551SDag-Erling Smørgrav outzone(&zones[i], j - i); 1177bc421551SDag-Erling Smørgrav } 1178bc421551SDag-Erling Smørgrav make_links(); 1179bc421551SDag-Erling Smørgrav if (lcltime != NULL) { 1180bc421551SDag-Erling Smørgrav eat(COMMAND_LINE_FILENUM, 1); 1181bc421551SDag-Erling Smørgrav dolink(lcltime, tzdefault, true); 1182bc421551SDag-Erling Smørgrav } 1183bc421551SDag-Erling Smørgrav if (psxrules != NULL) { 1184bc421551SDag-Erling Smørgrav eat(COMMAND_LINE_FILENUM, 1); 1185bc421551SDag-Erling Smørgrav dolink(psxrules, TZDEFRULES, true); 1186bc421551SDag-Erling Smørgrav } 1187bc421551SDag-Erling Smørgrav if (warnings && (ferror(stderr) || fclose(stderr) != 0)) 1188bc421551SDag-Erling Smørgrav return EXIT_FAILURE; 1189bc421551SDag-Erling Smørgrav return errors ? EXIT_FAILURE : EXIT_SUCCESS; 1190bc421551SDag-Erling Smørgrav } 1191bc421551SDag-Erling Smørgrav 1192bc421551SDag-Erling Smørgrav static bool 1193bc421551SDag-Erling Smørgrav componentcheck(char const *name, char const *component, 1194bc421551SDag-Erling Smørgrav char const *component_end) 1195bc421551SDag-Erling Smørgrav { 1196bc421551SDag-Erling Smørgrav enum { component_len_max = 14 }; 1197bc421551SDag-Erling Smørgrav ptrdiff_t component_len = component_end - component; 1198bc421551SDag-Erling Smørgrav if (component_len == 0) { 1199bc421551SDag-Erling Smørgrav if (!*name) 1200bc421551SDag-Erling Smørgrav error(_("empty file name")); 1201bc421551SDag-Erling Smørgrav else 1202bc421551SDag-Erling Smørgrav error(_(component == name 1203bc421551SDag-Erling Smørgrav ? "file name '%s' begins with '/'" 1204bc421551SDag-Erling Smørgrav : *component_end 1205bc421551SDag-Erling Smørgrav ? "file name '%s' contains '//'" 1206bc421551SDag-Erling Smørgrav : "file name '%s' ends with '/'"), 1207bc421551SDag-Erling Smørgrav name); 1208bc421551SDag-Erling Smørgrav return false; 1209bc421551SDag-Erling Smørgrav } 1210bc421551SDag-Erling Smørgrav if (0 < component_len && component_len <= 2 1211bc421551SDag-Erling Smørgrav && component[0] == '.' && component_end[-1] == '.') { 1212bc421551SDag-Erling Smørgrav int len = component_len; 1213bc421551SDag-Erling Smørgrav error(_("file name '%s' contains '%.*s' component"), 1214bc421551SDag-Erling Smørgrav name, len, component); 1215bc421551SDag-Erling Smørgrav return false; 1216bc421551SDag-Erling Smørgrav } 1217bc421551SDag-Erling Smørgrav if (noise) { 1218bc421551SDag-Erling Smørgrav if (0 < component_len && component[0] == '-') 1219bc421551SDag-Erling Smørgrav warning(_("file name '%s' component contains leading '-'"), 1220bc421551SDag-Erling Smørgrav name); 1221bc421551SDag-Erling Smørgrav if (component_len_max < component_len) 1222bc421551SDag-Erling Smørgrav warning(_("file name '%s' contains overlength component" 1223bc421551SDag-Erling Smørgrav " '%.*s...'"), 1224bc421551SDag-Erling Smørgrav name, component_len_max, component); 1225bc421551SDag-Erling Smørgrav } 1226bc421551SDag-Erling Smørgrav return true; 1227bc421551SDag-Erling Smørgrav } 1228bc421551SDag-Erling Smørgrav 1229bc421551SDag-Erling Smørgrav static bool 1230bc421551SDag-Erling Smørgrav namecheck(const char *name) 1231bc421551SDag-Erling Smørgrav { 1232bc421551SDag-Erling Smørgrav register char const *cp; 1233bc421551SDag-Erling Smørgrav 1234bc421551SDag-Erling Smørgrav /* Benign characters in a portable file name. */ 1235bc421551SDag-Erling Smørgrav static char const benign[] = 1236bc421551SDag-Erling Smørgrav "-/_" 1237bc421551SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyz" 1238bc421551SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 1239bc421551SDag-Erling Smørgrav 1240bc421551SDag-Erling Smørgrav /* Non-control chars in the POSIX portable character set, 1241bc421551SDag-Erling Smørgrav excluding the benign characters. */ 1242bc421551SDag-Erling Smørgrav static char const printable_and_not_benign[] = 1243bc421551SDag-Erling Smørgrav " !\"#$%&'()*+,.0123456789:;<=>?@[\\]^`{|}~"; 1244bc421551SDag-Erling Smørgrav 1245bc421551SDag-Erling Smørgrav register char const *component = name; 1246bc421551SDag-Erling Smørgrav for (cp = name; *cp; cp++) { 1247bc421551SDag-Erling Smørgrav unsigned char c = *cp; 1248bc421551SDag-Erling Smørgrav if (noise && !strchr(benign, c)) { 1249bc421551SDag-Erling Smørgrav warning((strchr(printable_and_not_benign, c) 1250bc421551SDag-Erling Smørgrav ? _("file name '%s' contains byte '%c'") 1251bc421551SDag-Erling Smørgrav : _("file name '%s' contains byte '\\%o'")), 1252bc421551SDag-Erling Smørgrav name, c); 1253bc421551SDag-Erling Smørgrav } 1254bc421551SDag-Erling Smørgrav if (c == '/') { 1255bc421551SDag-Erling Smørgrav if (!componentcheck(name, component, cp)) 1256bc421551SDag-Erling Smørgrav return false; 1257bc421551SDag-Erling Smørgrav component = cp + 1; 1258bc421551SDag-Erling Smørgrav } 1259bc421551SDag-Erling Smørgrav } 1260bc421551SDag-Erling Smørgrav return componentcheck(name, component, cp); 1261bc421551SDag-Erling Smørgrav } 1262bc421551SDag-Erling Smørgrav 1263bc421551SDag-Erling Smørgrav /* Return a random uint_fast64_t. */ 1264bc421551SDag-Erling Smørgrav static uint_fast64_t 1265bc421551SDag-Erling Smørgrav get_rand_u64(void) 1266bc421551SDag-Erling Smørgrav { 1267bc421551SDag-Erling Smørgrav #if HAVE_GETRANDOM 1268bc421551SDag-Erling Smørgrav static uint_fast64_t entropy_buffer[max(1, 256 / sizeof(uint_fast64_t))]; 1269bc421551SDag-Erling Smørgrav static int nwords; 1270bc421551SDag-Erling Smørgrav if (!nwords) { 1271bc421551SDag-Erling Smørgrav ssize_t s; 1272bc421551SDag-Erling Smørgrav do 1273bc421551SDag-Erling Smørgrav s = getrandom(entropy_buffer, sizeof entropy_buffer, 0); 1274bc421551SDag-Erling Smørgrav while (s < 0 && errno == EINTR); 1275bc421551SDag-Erling Smørgrav 1276d5c85ac6SDag-Erling Smørgrav if (s < 0) 1277d5c85ac6SDag-Erling Smørgrav nwords = -1; 1278d5c85ac6SDag-Erling Smørgrav else 1279d5c85ac6SDag-Erling Smørgrav nwords = s / sizeof *entropy_buffer; 1280bc421551SDag-Erling Smørgrav } 1281bc421551SDag-Erling Smørgrav if (0 < nwords) 1282bc421551SDag-Erling Smørgrav return entropy_buffer[--nwords]; 1283bc421551SDag-Erling Smørgrav #endif 1284bc421551SDag-Erling Smørgrav 1285bc421551SDag-Erling Smørgrav /* getrandom didn't work, so fall back on portable code that is 1286bc421551SDag-Erling Smørgrav not the best because the seed isn't cryptographically random and 1287bc421551SDag-Erling Smørgrav 'rand' might not be cryptographically secure. */ 1288bc421551SDag-Erling Smørgrav { 1289bc421551SDag-Erling Smørgrav static bool initialized; 1290bc421551SDag-Erling Smørgrav if (!initialized) { 1291bc421551SDag-Erling Smørgrav srand(time(NULL)); 1292bc421551SDag-Erling Smørgrav initialized = true; 1293bc421551SDag-Erling Smørgrav } 1294bc421551SDag-Erling Smørgrav } 1295bc421551SDag-Erling Smørgrav 1296bc421551SDag-Erling Smørgrav /* Return a random number if rand() yields a random number and in 1297bc421551SDag-Erling Smørgrav the typical case where RAND_MAX is one less than a power of two. 1298bc421551SDag-Erling Smørgrav In other cases this code yields a sort-of-random number. */ 1299bc421551SDag-Erling Smørgrav { 1300bc421551SDag-Erling Smørgrav uint_fast64_t rand_max = RAND_MAX, 1301bc421551SDag-Erling Smørgrav nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0, 1302bc421551SDag-Erling Smørgrav rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1, 1303bc421551SDag-Erling Smørgrav r = 0, rmax = 0; 1304bc421551SDag-Erling Smørgrav 1305bc421551SDag-Erling Smørgrav do { 1306bc421551SDag-Erling Smørgrav uint_fast64_t rmax1 = rmax; 1307bc421551SDag-Erling Smørgrav if (rmod) { 1308bc421551SDag-Erling Smørgrav /* Avoid signed integer overflow on theoretical platforms 1309bc421551SDag-Erling Smørgrav where uint_fast64_t promotes to int. */ 1310bc421551SDag-Erling Smørgrav rmax1 %= rmod; 1311bc421551SDag-Erling Smørgrav r %= rmod; 1312bc421551SDag-Erling Smørgrav } 1313bc421551SDag-Erling Smørgrav rmax1 = nrand * rmax1 + rand_max; 1314bc421551SDag-Erling Smørgrav r = nrand * r + rand(); 1315bc421551SDag-Erling Smørgrav rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX; 1316bc421551SDag-Erling Smørgrav } while (rmax < UINT_FAST64_MAX); 1317bc421551SDag-Erling Smørgrav 1318bc421551SDag-Erling Smørgrav return r; 1319bc421551SDag-Erling Smørgrav } 1320bc421551SDag-Erling Smørgrav } 1321bc421551SDag-Erling Smørgrav 1322bc421551SDag-Erling Smørgrav /* Generate a randomish name in the same directory as *NAME. If 1323bc421551SDag-Erling Smørgrav *NAMEALLOC, put the name into *NAMEALLOC which is assumed to be 1324bc421551SDag-Erling Smørgrav that returned by a previous call and is thus already almost set up 1325bc421551SDag-Erling Smørgrav and equal to *NAME; otherwise, allocate a new name and put its 1326bc421551SDag-Erling Smørgrav address into both *NAMEALLOC and *NAME. */ 1327bc421551SDag-Erling Smørgrav static void 1328bc421551SDag-Erling Smørgrav random_dirent(char const **name, char **namealloc) 1329bc421551SDag-Erling Smørgrav { 1330bc421551SDag-Erling Smørgrav char const *src = *name; 1331bc421551SDag-Erling Smørgrav char *dst = *namealloc; 1332bc421551SDag-Erling Smørgrav static char const prefix[] = ".zic"; 1333bc421551SDag-Erling Smørgrav static char const alphabet[] = 1334bc421551SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyz" 1335bc421551SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1336bc421551SDag-Erling Smørgrav "0123456789"; 1337bc421551SDag-Erling Smørgrav enum { prefixlen = sizeof prefix - 1, alphabetlen = sizeof alphabet - 1 }; 1338bc421551SDag-Erling Smørgrav int suffixlen = 6; 1339bc421551SDag-Erling Smørgrav char const *lastslash = strrchr(src, '/'); 1340bc421551SDag-Erling Smørgrav ptrdiff_t dirlen = lastslash ? lastslash + 1 - src : 0; 1341bc421551SDag-Erling Smørgrav int i; 1342bc421551SDag-Erling Smørgrav uint_fast64_t r; 1343bc421551SDag-Erling Smørgrav uint_fast64_t base = alphabetlen; 1344bc421551SDag-Erling Smørgrav 1345bc421551SDag-Erling Smørgrav /* BASE**6 */ 1346bc421551SDag-Erling Smørgrav uint_fast64_t base__6 = base * base * base * base * base * base; 1347bc421551SDag-Erling Smørgrav 1348bc421551SDag-Erling Smørgrav /* The largest uintmax_t that is a multiple of BASE**6. Any random 1349bc421551SDag-Erling Smørgrav uintmax_t value that is this value or greater, yields a biased 1350bc421551SDag-Erling Smørgrav remainder when divided by BASE**6. UNFAIR_MIN equals the 1351bc421551SDag-Erling Smørgrav mathematical value of ((UINTMAX_MAX + 1) - (UINTMAX_MAX + 1) % BASE**6) 1352bc421551SDag-Erling Smørgrav computed without overflow. */ 1353bc421551SDag-Erling Smørgrav uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); 1354bc421551SDag-Erling Smørgrav 1355bc421551SDag-Erling Smørgrav if (!dst) { 1356bc421551SDag-Erling Smørgrav dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); 1357bc421551SDag-Erling Smørgrav memcpy(dst, src, dirlen); 1358bc421551SDag-Erling Smørgrav memcpy(dst + dirlen, prefix, prefixlen); 1359bc421551SDag-Erling Smørgrav dst[dirlen + prefixlen + suffixlen] = '\0'; 1360bc421551SDag-Erling Smørgrav *name = *namealloc = dst; 1361bc421551SDag-Erling Smørgrav } 1362bc421551SDag-Erling Smørgrav 1363bc421551SDag-Erling Smørgrav do 1364bc421551SDag-Erling Smørgrav r = get_rand_u64(); 1365bc421551SDag-Erling Smørgrav while (unfair_min <= r); 1366bc421551SDag-Erling Smørgrav 1367bc421551SDag-Erling Smørgrav for (i = 0; i < suffixlen; i++) { 1368bc421551SDag-Erling Smørgrav dst[dirlen + prefixlen + i] = alphabet[r % alphabetlen]; 1369bc421551SDag-Erling Smørgrav r /= alphabetlen; 1370bc421551SDag-Erling Smørgrav } 1371bc421551SDag-Erling Smørgrav } 1372bc421551SDag-Erling Smørgrav 1373bc421551SDag-Erling Smørgrav /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the 1374bc421551SDag-Erling Smørgrav name of the temporary file that will eventually be renamed to 1375bc421551SDag-Erling Smørgrav *OUTNAME. Assign the temporary file's name to both *OUTNAME and 1376bc421551SDag-Erling Smørgrav *TEMPNAME. If *TEMPNAME is null, allocate the name of any such 1377bc421551SDag-Erling Smørgrav temporary file; otherwise, reuse *TEMPNAME's storage, which is 1378bc421551SDag-Erling Smørgrav already set up and only needs its trailing suffix updated. */ 1379bc421551SDag-Erling Smørgrav static FILE * 1380bc421551SDag-Erling Smørgrav open_outfile(char const **outname, char **tempname) 1381bc421551SDag-Erling Smørgrav { 1382bc421551SDag-Erling Smørgrav #if __STDC_VERSION__ < 201112 1383bc421551SDag-Erling Smørgrav static char const fopen_mode[] = "wb"; 1384bc421551SDag-Erling Smørgrav #else 1385bc421551SDag-Erling Smørgrav static char const fopen_mode[] = "wbx"; 1386bc421551SDag-Erling Smørgrav #endif 1387bc421551SDag-Erling Smørgrav 1388bc421551SDag-Erling Smørgrav FILE *fp; 1389bc421551SDag-Erling Smørgrav bool dirs_made = false; 1390bc421551SDag-Erling Smørgrav if (!*tempname) 1391bc421551SDag-Erling Smørgrav random_dirent(outname, tempname); 1392bc421551SDag-Erling Smørgrav 1393bc421551SDag-Erling Smørgrav /* 1394bc421551SDag-Erling Smørgrav * Remove old file, if any, to snap links. 1395bc421551SDag-Erling Smørgrav */ 1396bc421551SDag-Erling Smørgrav if (remove(*outname) != 0 && errno != ENOENT && errno != EISDIR) { 1397bc421551SDag-Erling Smørgrav fprintf(stderr, _("can't remove %s"), *outname); 1398bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1399bc421551SDag-Erling Smørgrav } 1400bc421551SDag-Erling Smørgrav 1401bc421551SDag-Erling Smørgrav while (! (fp = fopen(*outname, fopen_mode))) { 1402bc421551SDag-Erling Smørgrav int fopen_errno = errno; 1403bc421551SDag-Erling Smørgrav if (fopen_errno == ENOENT && !dirs_made) { 1404bc421551SDag-Erling Smørgrav mkdirs(*outname, true); 1405bc421551SDag-Erling Smørgrav dirs_made = true; 1406bc421551SDag-Erling Smørgrav } else if (fopen_errno == EEXIST) 1407bc421551SDag-Erling Smørgrav random_dirent(outname, tempname); 1408bc421551SDag-Erling Smørgrav else { 1409bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), 1410bc421551SDag-Erling Smørgrav progname, directory, *outname, strerror(fopen_errno)); 1411bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1412bc421551SDag-Erling Smørgrav } 1413bc421551SDag-Erling Smørgrav } 1414bc421551SDag-Erling Smørgrav 1415bc421551SDag-Erling Smørgrav return fp; 1416bc421551SDag-Erling Smørgrav } 1417bc421551SDag-Erling Smørgrav 1418bc421551SDag-Erling Smørgrav /* If TEMPNAME, the result is in the temporary file TEMPNAME even 1419bc421551SDag-Erling Smørgrav though the user wanted it in NAME, so rename TEMPNAME to NAME. 1420bc421551SDag-Erling Smørgrav Report an error and exit if there is trouble. Also, free TEMPNAME. */ 1421bc421551SDag-Erling Smørgrav static void 1422bc421551SDag-Erling Smørgrav rename_dest(char *tempname, char const *name) 1423bc421551SDag-Erling Smørgrav { 1424bc421551SDag-Erling Smørgrav if (tempname) { 1425bc421551SDag-Erling Smørgrav if (rename(tempname, name) != 0) { 1426bc421551SDag-Erling Smørgrav int rename_errno = errno; 14272aad7570SDag-Erling Smørgrav (void)remove(tempname); 1428bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: rename to %s/%s: %s\n"), 1429bc421551SDag-Erling Smørgrav progname, directory, name, strerror(rename_errno)); 1430bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1431bc421551SDag-Erling Smørgrav } 1432bc421551SDag-Erling Smørgrav free(tempname); 1433bc421551SDag-Erling Smørgrav } 1434bc421551SDag-Erling Smørgrav } 1435bc421551SDag-Erling Smørgrav 143646c59934SDag-Erling Smørgrav /* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a 143746c59934SDag-Erling Smørgrav freshly allocated string. TARGET should be a relative file name, and 143846c59934SDag-Erling Smørgrav is relative to the global variable DIRECTORY. LINKNAME can be either 1439bc421551SDag-Erling Smørgrav relative or absolute. */ 1440bc421551SDag-Erling Smørgrav static char * 1441bc421551SDag-Erling Smørgrav relname(char const *target, char const *linkname) 1442bc421551SDag-Erling Smørgrav { 1443bc421551SDag-Erling Smørgrav size_t i, taillen, dir_len = 0, dotdots = 0; 144475411d15SDag-Erling Smørgrav ptrdiff_t dotdotetcsize, linksize = INDEX_MAX; 1445bc421551SDag-Erling Smørgrav char const *f = target; 1446bc421551SDag-Erling Smørgrav char *result = NULL; 1447bc421551SDag-Erling Smørgrav if (*linkname == '/') { 1448bc421551SDag-Erling Smørgrav /* Make F absolute too. */ 1449bc421551SDag-Erling Smørgrav size_t len = strlen(directory); 1450bc421551SDag-Erling Smørgrav size_t lenslash = len + (len && directory[len - 1] != '/'); 1451bc421551SDag-Erling Smørgrav size_t targetsize = strlen(target) + 1; 1452bc421551SDag-Erling Smørgrav linksize = size_sum(lenslash, targetsize); 1453bc421551SDag-Erling Smørgrav f = result = emalloc(linksize); 1454bc421551SDag-Erling Smørgrav memcpy(result, directory, len); 1455bc421551SDag-Erling Smørgrav result[len] = '/'; 1456bc421551SDag-Erling Smørgrav memcpy(result + lenslash, target, targetsize); 1457bc421551SDag-Erling Smørgrav } 1458bc421551SDag-Erling Smørgrav for (i = 0; f[i] && f[i] == linkname[i]; i++) 1459bc421551SDag-Erling Smørgrav if (f[i] == '/') 1460bc421551SDag-Erling Smørgrav dir_len = i + 1; 1461bc421551SDag-Erling Smørgrav for (; linkname[i]; i++) 1462bc421551SDag-Erling Smørgrav dotdots += linkname[i] == '/' && linkname[i - 1] != '/'; 1463bc421551SDag-Erling Smørgrav taillen = strlen(f + dir_len); 1464bc421551SDag-Erling Smørgrav dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); 1465bc421551SDag-Erling Smørgrav if (dotdotetcsize <= linksize) { 1466bc421551SDag-Erling Smørgrav if (!result) 1467bc421551SDag-Erling Smørgrav result = emalloc(dotdotetcsize); 1468bc421551SDag-Erling Smørgrav for (i = 0; i < dotdots; i++) 1469bc421551SDag-Erling Smørgrav memcpy(result + 3 * i, "../", 3); 1470bc421551SDag-Erling Smørgrav memmove(result + 3 * dotdots, f + dir_len, taillen + 1); 1471bc421551SDag-Erling Smørgrav } 1472bc421551SDag-Erling Smørgrav return result; 1473bc421551SDag-Erling Smørgrav } 1474bc421551SDag-Erling Smørgrav 147546c59934SDag-Erling Smørgrav /* Return true if A and B must have the same parent dir if A and B exist. 147646c59934SDag-Erling Smørgrav Return false if this is not necessarily true (though it might be true). 147746c59934SDag-Erling Smørgrav Keep it simple, and do not inspect the file system. */ 1478*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static bool 147946c59934SDag-Erling Smørgrav same_parent_dirs(char const *a, char const *b) 148046c59934SDag-Erling Smørgrav { 148146c59934SDag-Erling Smørgrav for (; *a == *b; a++, b++) 148246c59934SDag-Erling Smørgrav if (!*a) 148346c59934SDag-Erling Smørgrav return true; 148446c59934SDag-Erling Smørgrav return ! (strchr(a, '/') || strchr(b, '/')); 148546c59934SDag-Erling Smørgrav } 148646c59934SDag-Erling Smørgrav 1487bc421551SDag-Erling Smørgrav static void 1488bc421551SDag-Erling Smørgrav dolink(char const *target, char const *linkname, bool staysymlink) 1489bc421551SDag-Erling Smørgrav { 1490bc421551SDag-Erling Smørgrav bool linkdirs_made = false; 1491bc421551SDag-Erling Smørgrav int link_errno; 1492bc421551SDag-Erling Smørgrav char *tempname = NULL; 1493bc421551SDag-Erling Smørgrav char const *outname = linkname; 149446c59934SDag-Erling Smørgrav int targetissym = -2, linknameissym = -2; 1495bc421551SDag-Erling Smørgrav 1496bc421551SDag-Erling Smørgrav check_for_signal(); 1497bc421551SDag-Erling Smørgrav 1498bc421551SDag-Erling Smørgrav if (strcmp(target, "-") == 0) { 1499bc421551SDag-Erling Smørgrav if (remove(linkname) == 0 || errno == ENOENT || errno == ENOTDIR) 1500bc421551SDag-Erling Smørgrav return; 1501bc421551SDag-Erling Smørgrav else { 1502bc421551SDag-Erling Smørgrav char const *e = strerror(errno); 1503bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), 1504bc421551SDag-Erling Smørgrav progname, directory, linkname, e); 1505bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1506bc421551SDag-Erling Smørgrav } 1507bc421551SDag-Erling Smørgrav } 1508bc421551SDag-Erling Smørgrav 1509bc421551SDag-Erling Smørgrav while (true) { 1510bc421551SDag-Erling Smørgrav if (linkat(AT_FDCWD, target, AT_FDCWD, outname, AT_SYMLINK_FOLLOW) 1511bc421551SDag-Erling Smørgrav == 0) { 1512bc421551SDag-Erling Smørgrav link_errno = 0; 1513bc421551SDag-Erling Smørgrav break; 1514bc421551SDag-Erling Smørgrav } 1515bc421551SDag-Erling Smørgrav link_errno = errno; 151646c59934SDag-Erling Smørgrav /* Linux 2.6.16 and 2.6.17 mishandle AT_SYMLINK_FOLLOW. */ 151746c59934SDag-Erling Smørgrav if (link_errno == EINVAL) 151846c59934SDag-Erling Smørgrav link_errno = ENOTSUP; 151946c59934SDag-Erling Smørgrav #if HAVE_LINK 152046c59934SDag-Erling Smørgrav /* If linkat is not supported, fall back on link(A, B). 152146c59934SDag-Erling Smørgrav However, skip this if A is a relative symlink 152246c59934SDag-Erling Smørgrav and A and B might not have the same parent directory. 152346c59934SDag-Erling Smørgrav On some platforms link(A, B) does not follow a symlink A, 152446c59934SDag-Erling Smørgrav and if A is relative it might misbehave elsewhere. */ 152546c59934SDag-Erling Smørgrav if (link_errno == ENOTSUP 152646c59934SDag-Erling Smørgrav && (same_parent_dirs(target, outname) 152746c59934SDag-Erling Smørgrav || 0 <= itssymlink(target, &targetissym))) { 152846c59934SDag-Erling Smørgrav if (link(target, outname) == 0) { 152946c59934SDag-Erling Smørgrav link_errno = 0; 153046c59934SDag-Erling Smørgrav break; 153146c59934SDag-Erling Smørgrav } 153246c59934SDag-Erling Smørgrav link_errno = errno; 153346c59934SDag-Erling Smørgrav } 153446c59934SDag-Erling Smørgrav #endif 1535bc421551SDag-Erling Smørgrav if (link_errno == EXDEV || link_errno == ENOTSUP) 1536bc421551SDag-Erling Smørgrav break; 1537bc421551SDag-Erling Smørgrav 1538bc421551SDag-Erling Smørgrav if (link_errno == EEXIST) { 1539bc421551SDag-Erling Smørgrav staysymlink &= !tempname; 1540bc421551SDag-Erling Smørgrav random_dirent(&outname, &tempname); 154146c59934SDag-Erling Smørgrav if (staysymlink && itssymlink(linkname, &linknameissym)) 1542bc421551SDag-Erling Smørgrav break; 1543bc421551SDag-Erling Smørgrav } else if (link_errno == ENOENT && !linkdirs_made) { 1544bc421551SDag-Erling Smørgrav mkdirs(linkname, true); 1545bc421551SDag-Erling Smørgrav linkdirs_made = true; 1546bc421551SDag-Erling Smørgrav } else { 1547bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), 1548bc421551SDag-Erling Smørgrav progname, directory, target, directory, outname, 1549bc421551SDag-Erling Smørgrav strerror(link_errno)); 1550bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1551bc421551SDag-Erling Smørgrav } 1552bc421551SDag-Erling Smørgrav } 1553bc421551SDag-Erling Smørgrav if (link_errno != 0) { 1554bc421551SDag-Erling Smørgrav bool absolute = *target == '/'; 1555bc421551SDag-Erling Smørgrav char *linkalloc = absolute ? NULL : relname(target, linkname); 1556bc421551SDag-Erling Smørgrav char const *contents = absolute ? target : linkalloc; 1557bc421551SDag-Erling Smørgrav int symlink_errno; 1558bc421551SDag-Erling Smørgrav 1559bc421551SDag-Erling Smørgrav while (true) { 1560bc421551SDag-Erling Smørgrav if (symlink(contents, outname) == 0) { 1561bc421551SDag-Erling Smørgrav symlink_errno = 0; 1562bc421551SDag-Erling Smørgrav break; 1563bc421551SDag-Erling Smørgrav } 1564bc421551SDag-Erling Smørgrav symlink_errno = errno; 1565bc421551SDag-Erling Smørgrav if (symlink_errno == EEXIST) 1566bc421551SDag-Erling Smørgrav random_dirent(&outname, &tempname); 1567bc421551SDag-Erling Smørgrav else if (symlink_errno == ENOENT && !linkdirs_made) { 1568bc421551SDag-Erling Smørgrav mkdirs(linkname, true); 1569bc421551SDag-Erling Smørgrav linkdirs_made = true; 1570bc421551SDag-Erling Smørgrav } else 1571bc421551SDag-Erling Smørgrav break; 1572bc421551SDag-Erling Smørgrav } 1573bc421551SDag-Erling Smørgrav free(linkalloc); 1574bc421551SDag-Erling Smørgrav if (symlink_errno == 0) { 1575bc421551SDag-Erling Smørgrav if (link_errno != ENOTSUP && link_errno != EEXIST) 1576bc421551SDag-Erling Smørgrav warning(_("symbolic link used because hard link failed: %s"), 1577bc421551SDag-Erling Smørgrav strerror(link_errno)); 1578bc421551SDag-Erling Smørgrav } else { 1579bc421551SDag-Erling Smørgrav FILE *fp, *tp; 1580bc421551SDag-Erling Smørgrav int c; 1581bc421551SDag-Erling Smørgrav fp = fopen(target, "rb"); 1582bc421551SDag-Erling Smørgrav if (!fp) { 1583bc421551SDag-Erling Smørgrav char const *e = strerror(errno); 1584bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), 1585bc421551SDag-Erling Smørgrav progname, directory, target, e); 1586bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1587bc421551SDag-Erling Smørgrav } 1588bc421551SDag-Erling Smørgrav tp = open_outfile(&outname, &tempname); 1589bc421551SDag-Erling Smørgrav while ((c = getc(fp)) != EOF) 1590bc421551SDag-Erling Smørgrav putc(c, tp); 1591bc421551SDag-Erling Smørgrav close_file(tp, directory, linkname, tempname); 1592bc421551SDag-Erling Smørgrav close_file(fp, directory, target, NULL); 1593bc421551SDag-Erling Smørgrav if (link_errno != ENOTSUP) 1594bc421551SDag-Erling Smørgrav warning(_("copy used because hard link failed: %s"), 1595bc421551SDag-Erling Smørgrav strerror(link_errno)); 1596bc421551SDag-Erling Smørgrav else if (symlink_errno != ENOTSUP) 1597bc421551SDag-Erling Smørgrav warning(_("copy used because symbolic link failed: %s"), 1598bc421551SDag-Erling Smørgrav strerror(symlink_errno)); 1599bc421551SDag-Erling Smørgrav } 1600bc421551SDag-Erling Smørgrav } 1601bc421551SDag-Erling Smørgrav rename_dest(tempname, linkname); 1602bc421551SDag-Erling Smørgrav } 1603bc421551SDag-Erling Smørgrav 160446c59934SDag-Erling Smørgrav /* Return 1 if NAME is an absolute symbolic link, -1 if it is relative, 160546c59934SDag-Erling Smørgrav 0 if it is not a symbolic link. If *CACHE is not -2, it is the 160646c59934SDag-Erling Smørgrav cached result of a previous call to this function with the same NAME. */ 160746c59934SDag-Erling Smørgrav static int 160846c59934SDag-Erling Smørgrav itssymlink(char const *name, int *cache) 1609bc421551SDag-Erling Smørgrav { 161046c59934SDag-Erling Smørgrav if (*cache == -2) { 161146c59934SDag-Erling Smørgrav char c = '\0'; 161246c59934SDag-Erling Smørgrav *cache = readlink(name, &c, 1) < 0 ? 0 : c == '/' ? 1 : -1; 161346c59934SDag-Erling Smørgrav } 161446c59934SDag-Erling Smørgrav return *cache; 1615bc421551SDag-Erling Smørgrav } 1616bc421551SDag-Erling Smørgrav 1617bc421551SDag-Erling Smørgrav /* 1618bc421551SDag-Erling Smørgrav ** Associate sets of rules with zones. 1619bc421551SDag-Erling Smørgrav */ 1620bc421551SDag-Erling Smørgrav 1621bc421551SDag-Erling Smørgrav /* 1622bc421551SDag-Erling Smørgrav ** Sort by rule name. 1623bc421551SDag-Erling Smørgrav */ 1624bc421551SDag-Erling Smørgrav 1625bc421551SDag-Erling Smørgrav static int 1626bc421551SDag-Erling Smørgrav rcomp(const void *cp1, const void *cp2) 1627bc421551SDag-Erling Smørgrav { 1628bc421551SDag-Erling Smørgrav struct rule const *r1 = cp1, *r2 = cp2; 1629bc421551SDag-Erling Smørgrav return strcmp(r1->r_name, r2->r_name); 1630bc421551SDag-Erling Smørgrav } 1631bc421551SDag-Erling Smørgrav 1632bc421551SDag-Erling Smørgrav static void 1633bc421551SDag-Erling Smørgrav associate(void) 1634bc421551SDag-Erling Smørgrav { 1635bc421551SDag-Erling Smørgrav register struct zone * zp; 1636bc421551SDag-Erling Smørgrav register struct rule * rp; 1637bc421551SDag-Erling Smørgrav register ptrdiff_t i, j, base, out; 1638bc421551SDag-Erling Smørgrav 1639bc421551SDag-Erling Smørgrav if (1 < nrules) { 1640bc421551SDag-Erling Smørgrav qsort(rules, nrules, sizeof *rules, rcomp); 1641bc421551SDag-Erling Smørgrav for (i = 0; i < nrules - 1; ++i) { 1642bc421551SDag-Erling Smørgrav if (strcmp(rules[i].r_name, 1643bc421551SDag-Erling Smørgrav rules[i + 1].r_name) != 0) 1644bc421551SDag-Erling Smørgrav continue; 1645bc421551SDag-Erling Smørgrav if (rules[i].r_filenum == rules[i + 1].r_filenum) 1646bc421551SDag-Erling Smørgrav continue; 1647bc421551SDag-Erling Smørgrav eat(rules[i].r_filenum, rules[i].r_linenum); 1648bc421551SDag-Erling Smørgrav warning(_("same rule name in multiple files")); 1649bc421551SDag-Erling Smørgrav eat(rules[i + 1].r_filenum, rules[i + 1].r_linenum); 1650bc421551SDag-Erling Smørgrav warning(_("same rule name in multiple files")); 1651bc421551SDag-Erling Smørgrav for (j = i + 2; j < nrules; ++j) { 1652bc421551SDag-Erling Smørgrav if (strcmp(rules[i].r_name, 1653bc421551SDag-Erling Smørgrav rules[j].r_name) != 0) 1654bc421551SDag-Erling Smørgrav break; 1655bc421551SDag-Erling Smørgrav if (rules[i].r_filenum == rules[j].r_filenum) 1656bc421551SDag-Erling Smørgrav continue; 1657bc421551SDag-Erling Smørgrav if (rules[i + 1].r_filenum 1658bc421551SDag-Erling Smørgrav == rules[j].r_filenum) 1659bc421551SDag-Erling Smørgrav continue; 1660bc421551SDag-Erling Smørgrav break; 1661bc421551SDag-Erling Smørgrav } 1662bc421551SDag-Erling Smørgrav i = j - 1; 1663bc421551SDag-Erling Smørgrav } 1664bc421551SDag-Erling Smørgrav } 1665bc421551SDag-Erling Smørgrav for (i = 0; i < nzones; ++i) { 1666bc421551SDag-Erling Smørgrav zp = &zones[i]; 1667bc421551SDag-Erling Smørgrav zp->z_rules = NULL; 1668bc421551SDag-Erling Smørgrav zp->z_nrules = 0; 1669bc421551SDag-Erling Smørgrav } 1670bc421551SDag-Erling Smørgrav for (base = 0; base < nrules; base = out) { 1671bc421551SDag-Erling Smørgrav rp = &rules[base]; 1672bc421551SDag-Erling Smørgrav for (out = base + 1; out < nrules; ++out) 1673bc421551SDag-Erling Smørgrav if (strcmp(rp->r_name, rules[out].r_name) != 0) 1674bc421551SDag-Erling Smørgrav break; 1675bc421551SDag-Erling Smørgrav for (i = 0; i < nzones; ++i) { 1676bc421551SDag-Erling Smørgrav zp = &zones[i]; 1677bc421551SDag-Erling Smørgrav if (strcmp(zp->z_rule, rp->r_name) != 0) 1678bc421551SDag-Erling Smørgrav continue; 1679bc421551SDag-Erling Smørgrav zp->z_rules = rp; 1680bc421551SDag-Erling Smørgrav zp->z_nrules = out - base; 1681bc421551SDag-Erling Smørgrav } 1682bc421551SDag-Erling Smørgrav } 1683bc421551SDag-Erling Smørgrav for (i = 0; i < nzones; ++i) { 1684bc421551SDag-Erling Smørgrav zp = &zones[i]; 1685bc421551SDag-Erling Smørgrav if (zp->z_nrules == 0) { 1686bc421551SDag-Erling Smørgrav /* 1687bc421551SDag-Erling Smørgrav ** Maybe we have a local standard time offset. 1688bc421551SDag-Erling Smørgrav */ 1689bc421551SDag-Erling Smørgrav eat(zp->z_filenum, zp->z_linenum); 1690bc421551SDag-Erling Smørgrav zp->z_save = getsave(zp->z_rule, &zp->z_isdst); 1691bc421551SDag-Erling Smørgrav /* 1692bc421551SDag-Erling Smørgrav ** Note, though, that if there's no rule, 1693bc421551SDag-Erling Smørgrav ** a '%s' in the format is a bad thing. 1694bc421551SDag-Erling Smørgrav */ 1695bc421551SDag-Erling Smørgrav if (zp->z_format_specifier == 's') 1696bc421551SDag-Erling Smørgrav error("%s", _("%s in ruleless zone")); 1697bc421551SDag-Erling Smørgrav } 1698bc421551SDag-Erling Smørgrav } 1699bc421551SDag-Erling Smørgrav if (errors) 1700bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1701bc421551SDag-Erling Smørgrav } 1702bc421551SDag-Erling Smørgrav 1703bc421551SDag-Erling Smørgrav /* Read a text line from FP into BUF, which is of size BUFSIZE. 1704bc421551SDag-Erling Smørgrav Terminate it with a NUL byte instead of a newline. 1705bc421551SDag-Erling Smørgrav Return true if successful, false if EOF. 1706bc421551SDag-Erling Smørgrav On error, report the error and exit. */ 1707bc421551SDag-Erling Smørgrav static bool 1708bc421551SDag-Erling Smørgrav inputline(FILE *fp, char *buf, ptrdiff_t bufsize) 1709bc421551SDag-Erling Smørgrav { 1710bc421551SDag-Erling Smørgrav ptrdiff_t linelen = 0, ch; 1711bc421551SDag-Erling Smørgrav while ((ch = getc(fp)) != '\n') { 1712bc421551SDag-Erling Smørgrav if (ch < 0) { 1713bc421551SDag-Erling Smørgrav if (ferror(fp)) { 1714bc421551SDag-Erling Smørgrav error(_("input error")); 1715bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1716bc421551SDag-Erling Smørgrav } 1717bc421551SDag-Erling Smørgrav if (linelen == 0) 1718bc421551SDag-Erling Smørgrav return false; 1719bc421551SDag-Erling Smørgrav error(_("unterminated line")); 1720bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1721bc421551SDag-Erling Smørgrav } 1722bc421551SDag-Erling Smørgrav if (!ch) { 1723bc421551SDag-Erling Smørgrav error(_("NUL input byte")); 1724bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1725bc421551SDag-Erling Smørgrav } 1726bc421551SDag-Erling Smørgrav buf[linelen++] = ch; 1727bc421551SDag-Erling Smørgrav if (linelen == bufsize) { 1728bc421551SDag-Erling Smørgrav error(_("line too long")); 1729bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1730bc421551SDag-Erling Smørgrav } 1731bc421551SDag-Erling Smørgrav } 1732bc421551SDag-Erling Smørgrav buf[linelen] = '\0'; 1733bc421551SDag-Erling Smørgrav return true; 1734bc421551SDag-Erling Smørgrav } 1735bc421551SDag-Erling Smørgrav 1736bc421551SDag-Erling Smørgrav static void 1737bc421551SDag-Erling Smørgrav infile(int fnum, char const *name) 1738bc421551SDag-Erling Smørgrav { 1739bc421551SDag-Erling Smørgrav register FILE * fp; 1740bc421551SDag-Erling Smørgrav register const struct lookup * lp; 1741bc421551SDag-Erling Smørgrav register bool wantcont; 1742bc421551SDag-Erling Smørgrav register lineno num; 1743bc421551SDag-Erling Smørgrav 1744bc421551SDag-Erling Smørgrav if (strcmp(name, "-") == 0) { 1745bc421551SDag-Erling Smørgrav fp = stdin; 1746bc421551SDag-Erling Smørgrav } else if ((fp = fopen(name, "r")) == NULL) { 1747bc421551SDag-Erling Smørgrav const char *e = strerror(errno); 1748bc421551SDag-Erling Smørgrav 1749bc421551SDag-Erling Smørgrav fprintf(stderr, _("%s: Can't open %s: %s\n"), 1750bc421551SDag-Erling Smørgrav progname, name, e); 1751bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 1752bc421551SDag-Erling Smørgrav } 1753bc421551SDag-Erling Smørgrav wantcont = false; 1754bc421551SDag-Erling Smørgrav for (num = 1; ; ++num) { 1755bc421551SDag-Erling Smørgrav enum { bufsize_bound 175675411d15SDag-Erling Smørgrav = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND) }; 1757bc421551SDag-Erling Smørgrav char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; 1758bc421551SDag-Erling Smørgrav int nfields; 1759bc421551SDag-Erling Smørgrav char *fields[MAX_FIELDS]; 1760bc421551SDag-Erling Smørgrav eat(fnum, num); 1761bc421551SDag-Erling Smørgrav if (!inputline(fp, buf, sizeof buf)) 1762bc421551SDag-Erling Smørgrav break; 1763bc421551SDag-Erling Smørgrav nfields = getfields(buf, fields, 1764bc421551SDag-Erling Smørgrav sizeof fields / sizeof *fields); 1765bc421551SDag-Erling Smørgrav if (nfields == 0) { 1766bc421551SDag-Erling Smørgrav /* nothing to do */ 1767bc421551SDag-Erling Smørgrav } else if (wantcont) { 1768bc421551SDag-Erling Smørgrav wantcont = inzcont(fields, nfields); 1769bc421551SDag-Erling Smørgrav } else { 1770bc421551SDag-Erling Smørgrav struct lookup const *line_codes 1771bc421551SDag-Erling Smørgrav = fnum < 0 ? leap_line_codes : zi_line_codes; 1772bc421551SDag-Erling Smørgrav lp = byword(fields[0], line_codes); 1773bc421551SDag-Erling Smørgrav if (lp == NULL) 1774bc421551SDag-Erling Smørgrav error(_("input line of unknown type")); 1775bc421551SDag-Erling Smørgrav else switch (lp->l_value) { 1776bc421551SDag-Erling Smørgrav case LC_RULE: 1777bc421551SDag-Erling Smørgrav inrule(fields, nfields); 1778bc421551SDag-Erling Smørgrav wantcont = false; 1779bc421551SDag-Erling Smørgrav break; 1780bc421551SDag-Erling Smørgrav case LC_ZONE: 1781bc421551SDag-Erling Smørgrav wantcont = inzone(fields, nfields); 1782bc421551SDag-Erling Smørgrav break; 1783bc421551SDag-Erling Smørgrav case LC_LINK: 1784bc421551SDag-Erling Smørgrav inlink(fields, nfields); 1785bc421551SDag-Erling Smørgrav wantcont = false; 1786bc421551SDag-Erling Smørgrav break; 1787bc421551SDag-Erling Smørgrav case LC_LEAP: 1788bc421551SDag-Erling Smørgrav inleap(fields, nfields); 1789bc421551SDag-Erling Smørgrav wantcont = false; 1790bc421551SDag-Erling Smørgrav break; 1791bc421551SDag-Erling Smørgrav case LC_EXPIRES: 1792bc421551SDag-Erling Smørgrav inexpires(fields, nfields); 1793bc421551SDag-Erling Smørgrav wantcont = false; 1794bc421551SDag-Erling Smørgrav break; 1795bc421551SDag-Erling Smørgrav default: unreachable(); 1796bc421551SDag-Erling Smørgrav } 1797bc421551SDag-Erling Smørgrav } 1798bc421551SDag-Erling Smørgrav } 1799bc421551SDag-Erling Smørgrav close_file(fp, NULL, filename(fnum), NULL); 1800bc421551SDag-Erling Smørgrav if (wantcont) 1801bc421551SDag-Erling Smørgrav error(_("expected continuation line not found")); 1802bc421551SDag-Erling Smørgrav } 1803bc421551SDag-Erling Smørgrav 1804bc421551SDag-Erling Smørgrav /* 1805bc421551SDag-Erling Smørgrav ** Convert a string of one of the forms 1806bc421551SDag-Erling Smørgrav ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 1807bc421551SDag-Erling Smørgrav ** into a number of seconds. 1808bc421551SDag-Erling Smørgrav ** A null string maps to zero. 1809bc421551SDag-Erling Smørgrav ** Call error with errstring and return zero on errors. 1810bc421551SDag-Erling Smørgrav */ 1811bc421551SDag-Erling Smørgrav 1812bc421551SDag-Erling Smørgrav static zic_t 1813bc421551SDag-Erling Smørgrav gethms(char const *string, char const *errstring) 1814bc421551SDag-Erling Smørgrav { 1815bc421551SDag-Erling Smørgrav zic_t hh; 1816bc421551SDag-Erling Smørgrav int sign, mm = 0, ss = 0; 1817bc421551SDag-Erling Smørgrav char hhx, mmx, ssx, xr = '0', xs; 1818bc421551SDag-Erling Smørgrav int tenths = 0; 1819bc421551SDag-Erling Smørgrav bool ok = true; 1820bc421551SDag-Erling Smørgrav 1821bc421551SDag-Erling Smørgrav if (string == NULL || *string == '\0') 1822bc421551SDag-Erling Smørgrav return 0; 1823bc421551SDag-Erling Smørgrav if (*string == '-') { 1824bc421551SDag-Erling Smørgrav sign = -1; 1825bc421551SDag-Erling Smørgrav ++string; 1826bc421551SDag-Erling Smørgrav } else sign = 1; 1827bc421551SDag-Erling Smørgrav switch (sscanf(string, 1828bc421551SDag-Erling Smørgrav "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c", 1829bc421551SDag-Erling Smørgrav &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { 1830bc421551SDag-Erling Smørgrav default: ok = false; break; 1831bc421551SDag-Erling Smørgrav case 8: 1832bc421551SDag-Erling Smørgrav ok = '0' <= xr && xr <= '9'; 1833bc421551SDag-Erling Smørgrav ATTRIBUTE_FALLTHROUGH; 1834bc421551SDag-Erling Smørgrav case 7: 1835bc421551SDag-Erling Smørgrav ok &= ssx == '.'; 1836bc421551SDag-Erling Smørgrav if (ok && noise) 1837bc421551SDag-Erling Smørgrav warning(_("fractional seconds rejected by" 1838bc421551SDag-Erling Smørgrav " pre-2018 versions of zic")); 1839bc421551SDag-Erling Smørgrav ATTRIBUTE_FALLTHROUGH; 1840bc421551SDag-Erling Smørgrav case 5: ok &= mmx == ':'; ATTRIBUTE_FALLTHROUGH; 1841bc421551SDag-Erling Smørgrav case 3: ok &= hhx == ':'; ATTRIBUTE_FALLTHROUGH; 1842bc421551SDag-Erling Smørgrav case 1: break; 1843bc421551SDag-Erling Smørgrav } 1844bc421551SDag-Erling Smørgrav if (!ok) { 1845bc421551SDag-Erling Smørgrav error("%s", errstring); 1846bc421551SDag-Erling Smørgrav return 0; 1847bc421551SDag-Erling Smørgrav } 1848bc421551SDag-Erling Smørgrav if (hh < 0 || 1849bc421551SDag-Erling Smørgrav mm < 0 || mm >= MINSPERHOUR || 1850bc421551SDag-Erling Smørgrav ss < 0 || ss > SECSPERMIN) { 1851bc421551SDag-Erling Smørgrav error("%s", errstring); 1852bc421551SDag-Erling Smørgrav return 0; 1853bc421551SDag-Erling Smørgrav } 1854bc421551SDag-Erling Smørgrav if (ZIC_MAX / SECSPERHOUR < hh) { 1855bc421551SDag-Erling Smørgrav error(_("time overflow")); 1856bc421551SDag-Erling Smørgrav return 0; 1857bc421551SDag-Erling Smørgrav } 1858bc421551SDag-Erling Smørgrav ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */ 1859bc421551SDag-Erling Smørgrav if (noise && (hh > HOURSPERDAY || 1860bc421551SDag-Erling Smørgrav (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 1861bc421551SDag-Erling Smørgrav warning(_("values over 24 hours not handled by pre-2007 versions of zic")); 1862bc421551SDag-Erling Smørgrav return oadd(sign * hh * SECSPERHOUR, 1863bc421551SDag-Erling Smørgrav sign * (mm * SECSPERMIN + ss)); 1864bc421551SDag-Erling Smørgrav } 1865bc421551SDag-Erling Smørgrav 1866bc421551SDag-Erling Smørgrav static zic_t 1867bc421551SDag-Erling Smørgrav getsave(char *field, bool *isdst) 1868bc421551SDag-Erling Smørgrav { 1869bc421551SDag-Erling Smørgrav int dst = -1; 1870bc421551SDag-Erling Smørgrav zic_t save; 1871bc421551SDag-Erling Smørgrav ptrdiff_t fieldlen = strlen(field); 1872bc421551SDag-Erling Smørgrav if (fieldlen != 0) { 1873bc421551SDag-Erling Smørgrav char *ep = field + fieldlen - 1; 1874bc421551SDag-Erling Smørgrav switch (*ep) { 1875bc421551SDag-Erling Smørgrav case 'd': dst = 1; *ep = '\0'; break; 1876bc421551SDag-Erling Smørgrav case 's': dst = 0; *ep = '\0'; break; 1877bc421551SDag-Erling Smørgrav } 1878bc421551SDag-Erling Smørgrav } 1879bc421551SDag-Erling Smørgrav save = gethms(field, _("invalid saved time")); 1880bc421551SDag-Erling Smørgrav *isdst = dst < 0 ? save != 0 : dst; 1881bc421551SDag-Erling Smørgrav return save; 1882bc421551SDag-Erling Smørgrav } 1883bc421551SDag-Erling Smørgrav 1884bc421551SDag-Erling Smørgrav static void 1885bc421551SDag-Erling Smørgrav inrule(char **fields, int nfields) 1886bc421551SDag-Erling Smørgrav { 188755572cffSDag-Erling Smørgrav struct rule r = { 0 }; 1888bc421551SDag-Erling Smørgrav 1889bc421551SDag-Erling Smørgrav if (nfields != RULE_FIELDS) { 1890bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Rule line")); 1891bc421551SDag-Erling Smørgrav return; 1892bc421551SDag-Erling Smørgrav } 1893bc421551SDag-Erling Smørgrav switch (*fields[RF_NAME]) { 1894bc421551SDag-Erling Smørgrav case '\0': 1895bc421551SDag-Erling Smørgrav case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 1896bc421551SDag-Erling Smørgrav case '+': case '-': 1897bc421551SDag-Erling Smørgrav case '0': case '1': case '2': case '3': case '4': 1898bc421551SDag-Erling Smørgrav case '5': case '6': case '7': case '8': case '9': 1899bc421551SDag-Erling Smørgrav error(_("Invalid rule name \"%s\""), fields[RF_NAME]); 1900bc421551SDag-Erling Smørgrav return; 1901bc421551SDag-Erling Smørgrav } 1902bc421551SDag-Erling Smørgrav r.r_filenum = filenum; 1903bc421551SDag-Erling Smørgrav r.r_linenum = linenum; 1904bc421551SDag-Erling Smørgrav r.r_save = getsave(fields[RF_SAVE], &r.r_isdst); 1905bc421551SDag-Erling Smørgrav if (!rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], 1906bc421551SDag-Erling Smørgrav fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], 1907bc421551SDag-Erling Smørgrav fields[RF_TOD])) 1908bc421551SDag-Erling Smørgrav return; 1909bc421551SDag-Erling Smørgrav r.r_name = estrdup(fields[RF_NAME]); 1910bc421551SDag-Erling Smørgrav r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); 1911bc421551SDag-Erling Smørgrav if (max_abbrvar_len < strlen(r.r_abbrvar)) 1912bc421551SDag-Erling Smørgrav max_abbrvar_len = strlen(r.r_abbrvar); 1913bc421551SDag-Erling Smørgrav rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); 1914bc421551SDag-Erling Smørgrav rules[nrules++] = r; 1915bc421551SDag-Erling Smørgrav } 1916bc421551SDag-Erling Smørgrav 1917bc421551SDag-Erling Smørgrav static bool 1918bc421551SDag-Erling Smørgrav inzone(char **fields, int nfields) 1919bc421551SDag-Erling Smørgrav { 1920bc421551SDag-Erling Smørgrav register ptrdiff_t i; 1921bc421551SDag-Erling Smørgrav 1922bc421551SDag-Erling Smørgrav if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 1923bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Zone line")); 1924bc421551SDag-Erling Smørgrav return false; 1925bc421551SDag-Erling Smørgrav } 1926bc421551SDag-Erling Smørgrav if (lcltime != NULL && strcmp(fields[ZF_NAME], tzdefault) == 0) { 192746c59934SDag-Erling Smørgrav error(_("\"Zone %s\" line and -l option are mutually exclusive"), 1928bc421551SDag-Erling Smørgrav tzdefault); 1929bc421551SDag-Erling Smørgrav return false; 1930bc421551SDag-Erling Smørgrav } 1931bc421551SDag-Erling Smørgrav if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 193246c59934SDag-Erling Smørgrav error(_("\"Zone %s\" line and -p option are mutually exclusive"), 1933bc421551SDag-Erling Smørgrav TZDEFRULES); 1934bc421551SDag-Erling Smørgrav return false; 1935bc421551SDag-Erling Smørgrav } 1936bc421551SDag-Erling Smørgrav for (i = 0; i < nzones; ++i) 1937bc421551SDag-Erling Smørgrav if (zones[i].z_name != NULL && 1938bc421551SDag-Erling Smørgrav strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 1939bc421551SDag-Erling Smørgrav error(_("duplicate zone name %s" 1940bc421551SDag-Erling Smørgrav " (file \"%s\", line %"PRIdMAX")"), 1941bc421551SDag-Erling Smørgrav fields[ZF_NAME], 1942bc421551SDag-Erling Smørgrav filename(zones[i].z_filenum), 1943bc421551SDag-Erling Smørgrav zones[i].z_linenum); 1944bc421551SDag-Erling Smørgrav return false; 1945bc421551SDag-Erling Smørgrav } 1946bc421551SDag-Erling Smørgrav return inzsub(fields, nfields, false); 1947bc421551SDag-Erling Smørgrav } 1948bc421551SDag-Erling Smørgrav 1949bc421551SDag-Erling Smørgrav static bool 1950bc421551SDag-Erling Smørgrav inzcont(char **fields, int nfields) 1951bc421551SDag-Erling Smørgrav { 1952bc421551SDag-Erling Smørgrav if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1953bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Zone continuation line")); 1954bc421551SDag-Erling Smørgrav return false; 1955bc421551SDag-Erling Smørgrav } 1956bc421551SDag-Erling Smørgrav return inzsub(fields, nfields, true); 1957bc421551SDag-Erling Smørgrav } 1958bc421551SDag-Erling Smørgrav 1959bc421551SDag-Erling Smørgrav static bool 1960bc421551SDag-Erling Smørgrav inzsub(char **fields, int nfields, bool iscont) 1961bc421551SDag-Erling Smørgrav { 1962bc421551SDag-Erling Smørgrav register char * cp; 1963bc421551SDag-Erling Smørgrav char * cp1; 196455572cffSDag-Erling Smørgrav struct zone z = { 0 }; 1965bc421551SDag-Erling Smørgrav int format_len; 1966bc421551SDag-Erling Smørgrav register int i_stdoff, i_rule, i_format; 1967bc421551SDag-Erling Smørgrav register int i_untilyear, i_untilmonth; 1968bc421551SDag-Erling Smørgrav register int i_untilday, i_untiltime; 1969bc421551SDag-Erling Smørgrav register bool hasuntil; 1970bc421551SDag-Erling Smørgrav 1971bc421551SDag-Erling Smørgrav if (iscont) { 1972bc421551SDag-Erling Smørgrav i_stdoff = ZFC_STDOFF; 1973bc421551SDag-Erling Smørgrav i_rule = ZFC_RULE; 1974bc421551SDag-Erling Smørgrav i_format = ZFC_FORMAT; 1975bc421551SDag-Erling Smørgrav i_untilyear = ZFC_TILYEAR; 1976bc421551SDag-Erling Smørgrav i_untilmonth = ZFC_TILMONTH; 1977bc421551SDag-Erling Smørgrav i_untilday = ZFC_TILDAY; 1978bc421551SDag-Erling Smørgrav i_untiltime = ZFC_TILTIME; 1979bc421551SDag-Erling Smørgrav } else if (!namecheck(fields[ZF_NAME])) 1980bc421551SDag-Erling Smørgrav return false; 1981bc421551SDag-Erling Smørgrav else { 1982bc421551SDag-Erling Smørgrav i_stdoff = ZF_STDOFF; 1983bc421551SDag-Erling Smørgrav i_rule = ZF_RULE; 1984bc421551SDag-Erling Smørgrav i_format = ZF_FORMAT; 1985bc421551SDag-Erling Smørgrav i_untilyear = ZF_TILYEAR; 1986bc421551SDag-Erling Smørgrav i_untilmonth = ZF_TILMONTH; 1987bc421551SDag-Erling Smørgrav i_untilday = ZF_TILDAY; 1988bc421551SDag-Erling Smørgrav i_untiltime = ZF_TILTIME; 1989bc421551SDag-Erling Smørgrav } 1990bc421551SDag-Erling Smørgrav z.z_filenum = filenum; 1991bc421551SDag-Erling Smørgrav z.z_linenum = linenum; 1992bc421551SDag-Erling Smørgrav z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); 1993bc421551SDag-Erling Smørgrav if ((cp = strchr(fields[i_format], '%')) != 0) { 1994bc421551SDag-Erling Smørgrav if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') 1995bc421551SDag-Erling Smørgrav || strchr(fields[i_format], '/')) { 1996bc421551SDag-Erling Smørgrav error(_("invalid abbreviation format")); 1997bc421551SDag-Erling Smørgrav return false; 1998bc421551SDag-Erling Smørgrav } 1999bc421551SDag-Erling Smørgrav } 2000bc421551SDag-Erling Smørgrav z.z_format_specifier = cp ? *cp : '\0'; 2001bc421551SDag-Erling Smørgrav format_len = strlen(fields[i_format]); 2002bc421551SDag-Erling Smørgrav if (max_format_len < format_len) 2003bc421551SDag-Erling Smørgrav max_format_len = format_len; 2004bc421551SDag-Erling Smørgrav hasuntil = nfields > i_untilyear; 2005bc421551SDag-Erling Smørgrav if (hasuntil) { 2006bc421551SDag-Erling Smørgrav z.z_untilrule.r_filenum = filenum; 2007bc421551SDag-Erling Smørgrav z.z_untilrule.r_linenum = linenum; 2008bc421551SDag-Erling Smørgrav if (!rulesub( 2009bc421551SDag-Erling Smørgrav &z.z_untilrule, 2010bc421551SDag-Erling Smørgrav fields[i_untilyear], 2011bc421551SDag-Erling Smørgrav "only", 2012bc421551SDag-Erling Smørgrav "", 2013bc421551SDag-Erling Smørgrav (nfields > i_untilmonth) ? 2014bc421551SDag-Erling Smørgrav fields[i_untilmonth] : "Jan", 2015bc421551SDag-Erling Smørgrav (nfields > i_untilday) ? fields[i_untilday] : "1", 2016bc421551SDag-Erling Smørgrav (nfields > i_untiltime) ? fields[i_untiltime] : "0")) 2017bc421551SDag-Erling Smørgrav return false; 2018bc421551SDag-Erling Smørgrav z.z_untiltime = rpytime(&z.z_untilrule, 2019bc421551SDag-Erling Smørgrav z.z_untilrule.r_loyear); 2020bc421551SDag-Erling Smørgrav if (iscont && nzones > 0 && 2021bc421551SDag-Erling Smørgrav z.z_untiltime > min_time && 2022bc421551SDag-Erling Smørgrav z.z_untiltime < max_time && 2023bc421551SDag-Erling Smørgrav zones[nzones - 1].z_untiltime > min_time && 2024bc421551SDag-Erling Smørgrav zones[nzones - 1].z_untiltime < max_time && 2025bc421551SDag-Erling Smørgrav zones[nzones - 1].z_untiltime >= z.z_untiltime) { 202646c59934SDag-Erling Smørgrav error(_("Zone continuation line end time is" 202746c59934SDag-Erling Smørgrav " not after end time of previous line")); 2028bc421551SDag-Erling Smørgrav return false; 2029bc421551SDag-Erling Smørgrav } 2030bc421551SDag-Erling Smørgrav } 2031bc421551SDag-Erling Smørgrav z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); 2032bc421551SDag-Erling Smørgrav z.z_rule = estrdup(fields[i_rule]); 2033bc421551SDag-Erling Smørgrav z.z_format = cp1 = estrdup(fields[i_format]); 2034bc421551SDag-Erling Smørgrav if (z.z_format_specifier == 'z') { 2035bc421551SDag-Erling Smørgrav cp1[cp - fields[i_format]] = 's'; 2036bc421551SDag-Erling Smørgrav if (noise) 2037bc421551SDag-Erling Smørgrav warning(_("format '%s' not handled by pre-2015 versions of zic"), 2038bc421551SDag-Erling Smørgrav fields[i_format]); 2039bc421551SDag-Erling Smørgrav } 2040bc421551SDag-Erling Smørgrav zones = growalloc(zones, sizeof *zones, nzones, &nzones_alloc); 2041bc421551SDag-Erling Smørgrav zones[nzones++] = z; 2042bc421551SDag-Erling Smørgrav /* 2043bc421551SDag-Erling Smørgrav ** If there was an UNTIL field on this line, 2044bc421551SDag-Erling Smørgrav ** there's more information about the zone on the next line. 2045bc421551SDag-Erling Smørgrav */ 2046bc421551SDag-Erling Smørgrav return hasuntil; 2047bc421551SDag-Erling Smørgrav } 2048bc421551SDag-Erling Smørgrav 2049bc421551SDag-Erling Smørgrav static zic_t 2050bc421551SDag-Erling Smørgrav getleapdatetime(char **fields, bool expire_line) 2051bc421551SDag-Erling Smørgrav { 2052bc421551SDag-Erling Smørgrav register const char * cp; 2053bc421551SDag-Erling Smørgrav register const struct lookup * lp; 2054bc421551SDag-Erling Smørgrav register zic_t i, j; 2055bc421551SDag-Erling Smørgrav zic_t year; 2056bc421551SDag-Erling Smørgrav int month, day; 2057bc421551SDag-Erling Smørgrav zic_t dayoff, tod; 2058bc421551SDag-Erling Smørgrav zic_t t; 2059bc421551SDag-Erling Smørgrav char xs; 2060bc421551SDag-Erling Smørgrav 2061bc421551SDag-Erling Smørgrav dayoff = 0; 2062bc421551SDag-Erling Smørgrav cp = fields[LP_YEAR]; 2063bc421551SDag-Erling Smørgrav if (sscanf(cp, "%"SCNdZIC"%c", &year, &xs) != 1) { 2064bc421551SDag-Erling Smørgrav /* 2065bc421551SDag-Erling Smørgrav ** Leapin' Lizards! 2066bc421551SDag-Erling Smørgrav */ 2067bc421551SDag-Erling Smørgrav error(_("invalid leaping year")); 2068bc421551SDag-Erling Smørgrav return -1; 2069bc421551SDag-Erling Smørgrav } 2070bc421551SDag-Erling Smørgrav if (!expire_line) { 2071bc421551SDag-Erling Smørgrav if (!leapseen || leapmaxyear < year) 2072bc421551SDag-Erling Smørgrav leapmaxyear = year; 2073bc421551SDag-Erling Smørgrav if (!leapseen || leapminyear > year) 2074bc421551SDag-Erling Smørgrav leapminyear = year; 2075bc421551SDag-Erling Smørgrav leapseen = true; 2076bc421551SDag-Erling Smørgrav } 2077bc421551SDag-Erling Smørgrav j = EPOCH_YEAR; 2078bc421551SDag-Erling Smørgrav while (j != year) { 2079bc421551SDag-Erling Smørgrav if (year > j) { 2080bc421551SDag-Erling Smørgrav i = len_years[isleap(j)]; 2081bc421551SDag-Erling Smørgrav ++j; 2082bc421551SDag-Erling Smørgrav } else { 2083bc421551SDag-Erling Smørgrav --j; 2084bc421551SDag-Erling Smørgrav i = -len_years[isleap(j)]; 2085bc421551SDag-Erling Smørgrav } 2086bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, i); 2087bc421551SDag-Erling Smørgrav } 2088bc421551SDag-Erling Smørgrav if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 2089bc421551SDag-Erling Smørgrav error(_("invalid month name")); 2090bc421551SDag-Erling Smørgrav return -1; 2091bc421551SDag-Erling Smørgrav } 2092bc421551SDag-Erling Smørgrav month = lp->l_value; 2093bc421551SDag-Erling Smørgrav j = TM_JANUARY; 2094bc421551SDag-Erling Smørgrav while (j != month) { 2095bc421551SDag-Erling Smørgrav i = len_months[isleap(year)][j]; 2096bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, i); 2097bc421551SDag-Erling Smørgrav ++j; 2098bc421551SDag-Erling Smørgrav } 2099bc421551SDag-Erling Smørgrav cp = fields[LP_DAY]; 2100bc421551SDag-Erling Smørgrav if (sscanf(cp, "%d%c", &day, &xs) != 1 || 2101bc421551SDag-Erling Smørgrav day <= 0 || day > len_months[isleap(year)][month]) { 2102bc421551SDag-Erling Smørgrav error(_("invalid day of month")); 2103bc421551SDag-Erling Smørgrav return -1; 2104bc421551SDag-Erling Smørgrav } 2105bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, day - 1); 2106bc421551SDag-Erling Smørgrav if (dayoff < min_time / SECSPERDAY) { 2107bc421551SDag-Erling Smørgrav error(_("time too small")); 2108bc421551SDag-Erling Smørgrav return -1; 2109bc421551SDag-Erling Smørgrav } 2110bc421551SDag-Erling Smørgrav if (dayoff > max_time / SECSPERDAY) { 2111bc421551SDag-Erling Smørgrav error(_("time too large")); 2112bc421551SDag-Erling Smørgrav return -1; 2113bc421551SDag-Erling Smørgrav } 2114bc421551SDag-Erling Smørgrav t = dayoff * SECSPERDAY; 2115bc421551SDag-Erling Smørgrav tod = gethms(fields[LP_TIME], _("invalid time of day")); 2116bc421551SDag-Erling Smørgrav t = tadd(t, tod); 2117bc421551SDag-Erling Smørgrav if (t < 0) 2118bc421551SDag-Erling Smørgrav error(_("leap second precedes Epoch")); 2119bc421551SDag-Erling Smørgrav return t; 2120bc421551SDag-Erling Smørgrav } 2121bc421551SDag-Erling Smørgrav 2122bc421551SDag-Erling Smørgrav static void 2123bc421551SDag-Erling Smørgrav inleap(char **fields, int nfields) 2124bc421551SDag-Erling Smørgrav { 2125bc421551SDag-Erling Smørgrav if (nfields != LEAP_FIELDS) 2126bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Leap line")); 2127bc421551SDag-Erling Smørgrav else { 2128bc421551SDag-Erling Smørgrav zic_t t = getleapdatetime(fields, false); 2129bc421551SDag-Erling Smørgrav if (0 <= t) { 2130bc421551SDag-Erling Smørgrav struct lookup const *lp = byword(fields[LP_ROLL], leap_types); 2131bc421551SDag-Erling Smørgrav if (!lp) 2132bc421551SDag-Erling Smørgrav error(_("invalid Rolling/Stationary field on Leap line")); 2133bc421551SDag-Erling Smørgrav else { 2134bc421551SDag-Erling Smørgrav int correction = 0; 2135bc421551SDag-Erling Smørgrav if (!fields[LP_CORR][0]) /* infile() turns "-" into "". */ 2136bc421551SDag-Erling Smørgrav correction = -1; 2137bc421551SDag-Erling Smørgrav else if (strcmp(fields[LP_CORR], "+") == 0) 2138bc421551SDag-Erling Smørgrav correction = 1; 2139bc421551SDag-Erling Smørgrav else 2140bc421551SDag-Erling Smørgrav error(_("invalid CORRECTION field on Leap line")); 2141bc421551SDag-Erling Smørgrav if (correction) 2142bc421551SDag-Erling Smørgrav leapadd(t, correction, lp->l_value); 2143bc421551SDag-Erling Smørgrav } 2144bc421551SDag-Erling Smørgrav } 2145bc421551SDag-Erling Smørgrav } 2146bc421551SDag-Erling Smørgrav } 2147bc421551SDag-Erling Smørgrav 2148bc421551SDag-Erling Smørgrav static void 2149bc421551SDag-Erling Smørgrav inexpires(char **fields, int nfields) 2150bc421551SDag-Erling Smørgrav { 2151bc421551SDag-Erling Smørgrav if (nfields != EXPIRES_FIELDS) 2152bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Expires line")); 2153bc421551SDag-Erling Smørgrav else if (0 <= leapexpires) 2154bc421551SDag-Erling Smørgrav error(_("multiple Expires lines")); 2155bc421551SDag-Erling Smørgrav else 2156bc421551SDag-Erling Smørgrav leapexpires = getleapdatetime(fields, true); 2157bc421551SDag-Erling Smørgrav } 2158bc421551SDag-Erling Smørgrav 2159bc421551SDag-Erling Smørgrav static void 2160bc421551SDag-Erling Smørgrav inlink(char **fields, int nfields) 2161bc421551SDag-Erling Smørgrav { 2162bc421551SDag-Erling Smørgrav struct link l; 2163bc421551SDag-Erling Smørgrav 2164bc421551SDag-Erling Smørgrav if (nfields != LINK_FIELDS) { 2165bc421551SDag-Erling Smørgrav error(_("wrong number of fields on Link line")); 2166bc421551SDag-Erling Smørgrav return; 2167bc421551SDag-Erling Smørgrav } 2168bc421551SDag-Erling Smørgrav if (*fields[LF_TARGET] == '\0') { 2169bc421551SDag-Erling Smørgrav error(_("blank TARGET field on Link line")); 2170bc421551SDag-Erling Smørgrav return; 2171bc421551SDag-Erling Smørgrav } 2172bc421551SDag-Erling Smørgrav if (! namecheck(fields[LF_LINKNAME])) 2173bc421551SDag-Erling Smørgrav return; 2174bc421551SDag-Erling Smørgrav l.l_filenum = filenum; 2175bc421551SDag-Erling Smørgrav l.l_linenum = linenum; 2176bc421551SDag-Erling Smørgrav l.l_target = estrdup(fields[LF_TARGET]); 2177bc421551SDag-Erling Smørgrav l.l_linkname = estrdup(fields[LF_LINKNAME]); 2178bc421551SDag-Erling Smørgrav links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); 2179bc421551SDag-Erling Smørgrav links[nlinks++] = l; 2180bc421551SDag-Erling Smørgrav } 2181bc421551SDag-Erling Smørgrav 2182bc421551SDag-Erling Smørgrav static bool 2183bc421551SDag-Erling Smørgrav rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, 2184bc421551SDag-Erling Smørgrav const char *typep, const char *monthp, const char *dayp, 2185bc421551SDag-Erling Smørgrav const char *timep) 2186bc421551SDag-Erling Smørgrav { 2187bc421551SDag-Erling Smørgrav register const struct lookup * lp; 2188bc421551SDag-Erling Smørgrav register const char * cp; 2189bc421551SDag-Erling Smørgrav register char * dp; 2190bc421551SDag-Erling Smørgrav register char * ep; 2191bc421551SDag-Erling Smørgrav char xs; 2192bc421551SDag-Erling Smørgrav 2193bc421551SDag-Erling Smørgrav if ((lp = byword(monthp, mon_names)) == NULL) { 2194bc421551SDag-Erling Smørgrav error(_("invalid month name")); 2195bc421551SDag-Erling Smørgrav return false; 2196bc421551SDag-Erling Smørgrav } 2197bc421551SDag-Erling Smørgrav rp->r_month = lp->l_value; 2198bc421551SDag-Erling Smørgrav rp->r_todisstd = false; 2199bc421551SDag-Erling Smørgrav rp->r_todisut = false; 2200bc421551SDag-Erling Smørgrav dp = estrdup(timep); 2201bc421551SDag-Erling Smørgrav if (*dp != '\0') { 2202bc421551SDag-Erling Smørgrav ep = dp + strlen(dp) - 1; 2203bc421551SDag-Erling Smørgrav switch (lowerit(*ep)) { 2204bc421551SDag-Erling Smørgrav case 's': /* Standard */ 2205bc421551SDag-Erling Smørgrav rp->r_todisstd = true; 2206bc421551SDag-Erling Smørgrav rp->r_todisut = false; 2207bc421551SDag-Erling Smørgrav *ep = '\0'; 2208bc421551SDag-Erling Smørgrav break; 2209bc421551SDag-Erling Smørgrav case 'w': /* Wall */ 2210bc421551SDag-Erling Smørgrav rp->r_todisstd = false; 2211bc421551SDag-Erling Smørgrav rp->r_todisut = false; 2212bc421551SDag-Erling Smørgrav *ep = '\0'; 2213bc421551SDag-Erling Smørgrav break; 2214bc421551SDag-Erling Smørgrav case 'g': /* Greenwich */ 2215bc421551SDag-Erling Smørgrav case 'u': /* Universal */ 2216bc421551SDag-Erling Smørgrav case 'z': /* Zulu */ 2217bc421551SDag-Erling Smørgrav rp->r_todisstd = true; 2218bc421551SDag-Erling Smørgrav rp->r_todisut = true; 2219bc421551SDag-Erling Smørgrav *ep = '\0'; 2220bc421551SDag-Erling Smørgrav break; 2221bc421551SDag-Erling Smørgrav } 2222bc421551SDag-Erling Smørgrav } 2223bc421551SDag-Erling Smørgrav rp->r_tod = gethms(dp, _("invalid time of day")); 2224bc421551SDag-Erling Smørgrav free(dp); 2225bc421551SDag-Erling Smørgrav /* 2226bc421551SDag-Erling Smørgrav ** Year work. 2227bc421551SDag-Erling Smørgrav */ 2228bc421551SDag-Erling Smørgrav cp = loyearp; 2229bc421551SDag-Erling Smørgrav lp = byword(cp, begin_years); 223046c59934SDag-Erling Smørgrav if (lp) switch (lp->l_value) { 2231bc421551SDag-Erling Smørgrav case YR_MINIMUM: 223246c59934SDag-Erling Smørgrav warning(_("FROM year \"%s\" is obsolete;" 223346c59934SDag-Erling Smørgrav " treated as %d"), 223446c59934SDag-Erling Smørgrav cp, YEAR_32BIT_MIN - 1); 223546c59934SDag-Erling Smørgrav rp->r_loyear = YEAR_32BIT_MIN - 1; 2236bc421551SDag-Erling Smørgrav break; 2237bc421551SDag-Erling Smørgrav default: unreachable(); 2238bc421551SDag-Erling Smørgrav } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_loyear, &xs) != 1) { 2239bc421551SDag-Erling Smørgrav error(_("invalid starting year")); 2240bc421551SDag-Erling Smørgrav return false; 2241bc421551SDag-Erling Smørgrav } 2242bc421551SDag-Erling Smørgrav cp = hiyearp; 2243bc421551SDag-Erling Smørgrav lp = byword(cp, end_years); 2244bc421551SDag-Erling Smørgrav rp->r_hiwasnum = lp == NULL; 2245bc421551SDag-Erling Smørgrav if (!rp->r_hiwasnum) switch (lp->l_value) { 2246bc421551SDag-Erling Smørgrav case YR_MAXIMUM: 2247bc421551SDag-Erling Smørgrav rp->r_hiyear = ZIC_MAX; 2248bc421551SDag-Erling Smørgrav break; 2249bc421551SDag-Erling Smørgrav case YR_ONLY: 2250bc421551SDag-Erling Smørgrav rp->r_hiyear = rp->r_loyear; 2251bc421551SDag-Erling Smørgrav break; 2252bc421551SDag-Erling Smørgrav default: unreachable(); 2253bc421551SDag-Erling Smørgrav } else if (sscanf(cp, "%"SCNdZIC"%c", &rp->r_hiyear, &xs) != 1) { 2254bc421551SDag-Erling Smørgrav error(_("invalid ending year")); 2255bc421551SDag-Erling Smørgrav return false; 2256bc421551SDag-Erling Smørgrav } 2257bc421551SDag-Erling Smørgrav if (rp->r_loyear > rp->r_hiyear) { 2258bc421551SDag-Erling Smørgrav error(_("starting year greater than ending year")); 2259bc421551SDag-Erling Smørgrav return false; 2260bc421551SDag-Erling Smørgrav } 2261bc421551SDag-Erling Smørgrav if (*typep != '\0') { 2262bc421551SDag-Erling Smørgrav error(_("year type \"%s\" is unsupported; use \"-\" instead"), 2263bc421551SDag-Erling Smørgrav typep); 2264bc421551SDag-Erling Smørgrav return false; 2265bc421551SDag-Erling Smørgrav } 2266bc421551SDag-Erling Smørgrav /* 2267bc421551SDag-Erling Smørgrav ** Day work. 2268bc421551SDag-Erling Smørgrav ** Accept things such as: 2269bc421551SDag-Erling Smørgrav ** 1 2270bc421551SDag-Erling Smørgrav ** lastSunday 2271bc421551SDag-Erling Smørgrav ** last-Sunday (undocumented; warn about this) 2272bc421551SDag-Erling Smørgrav ** Sun<=20 2273bc421551SDag-Erling Smørgrav ** Sun>=7 2274bc421551SDag-Erling Smørgrav */ 2275bc421551SDag-Erling Smørgrav dp = estrdup(dayp); 2276bc421551SDag-Erling Smørgrav if ((lp = byword(dp, lasts)) != NULL) { 2277bc421551SDag-Erling Smørgrav rp->r_dycode = DC_DOWLEQ; 2278bc421551SDag-Erling Smørgrav rp->r_wday = lp->l_value; 2279bc421551SDag-Erling Smørgrav rp->r_dayofmonth = len_months[1][rp->r_month]; 2280bc421551SDag-Erling Smørgrav } else { 2281bc421551SDag-Erling Smørgrav if ((ep = strchr(dp, '<')) != 0) 2282bc421551SDag-Erling Smørgrav rp->r_dycode = DC_DOWLEQ; 2283bc421551SDag-Erling Smørgrav else if ((ep = strchr(dp, '>')) != 0) 2284bc421551SDag-Erling Smørgrav rp->r_dycode = DC_DOWGEQ; 2285bc421551SDag-Erling Smørgrav else { 2286bc421551SDag-Erling Smørgrav ep = dp; 2287bc421551SDag-Erling Smørgrav rp->r_dycode = DC_DOM; 2288bc421551SDag-Erling Smørgrav } 2289bc421551SDag-Erling Smørgrav if (rp->r_dycode != DC_DOM) { 2290bc421551SDag-Erling Smørgrav *ep++ = 0; 2291bc421551SDag-Erling Smørgrav if (*ep++ != '=') { 2292bc421551SDag-Erling Smørgrav error(_("invalid day of month")); 2293bc421551SDag-Erling Smørgrav free(dp); 2294bc421551SDag-Erling Smørgrav return false; 2295bc421551SDag-Erling Smørgrav } 2296bc421551SDag-Erling Smørgrav if ((lp = byword(dp, wday_names)) == NULL) { 2297bc421551SDag-Erling Smørgrav error(_("invalid weekday name")); 2298bc421551SDag-Erling Smørgrav free(dp); 2299bc421551SDag-Erling Smørgrav return false; 2300bc421551SDag-Erling Smørgrav } 2301bc421551SDag-Erling Smørgrav rp->r_wday = lp->l_value; 2302bc421551SDag-Erling Smørgrav } 2303bc421551SDag-Erling Smørgrav if (sscanf(ep, "%d%c", &rp->r_dayofmonth, &xs) != 1 || 2304bc421551SDag-Erling Smørgrav rp->r_dayofmonth <= 0 || 2305bc421551SDag-Erling Smørgrav (rp->r_dayofmonth > len_months[1][rp->r_month])) { 2306bc421551SDag-Erling Smørgrav error(_("invalid day of month")); 2307bc421551SDag-Erling Smørgrav free(dp); 2308bc421551SDag-Erling Smørgrav return false; 2309bc421551SDag-Erling Smørgrav } 2310bc421551SDag-Erling Smørgrav } 2311bc421551SDag-Erling Smørgrav free(dp); 2312bc421551SDag-Erling Smørgrav return true; 2313bc421551SDag-Erling Smørgrav } 2314bc421551SDag-Erling Smørgrav 2315bc421551SDag-Erling Smørgrav static void 2316bc421551SDag-Erling Smørgrav convert(uint_fast32_t val, char *buf) 2317bc421551SDag-Erling Smørgrav { 2318bc421551SDag-Erling Smørgrav register int i; 2319bc421551SDag-Erling Smørgrav register int shift; 2320bc421551SDag-Erling Smørgrav unsigned char *const b = (unsigned char *) buf; 2321bc421551SDag-Erling Smørgrav 2322bc421551SDag-Erling Smørgrav for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 2323bc421551SDag-Erling Smørgrav b[i] = (val >> shift) & 0xff; 2324bc421551SDag-Erling Smørgrav } 2325bc421551SDag-Erling Smørgrav 2326bc421551SDag-Erling Smørgrav static void 2327bc421551SDag-Erling Smørgrav convert64(uint_fast64_t val, char *buf) 2328bc421551SDag-Erling Smørgrav { 2329bc421551SDag-Erling Smørgrav register int i; 2330bc421551SDag-Erling Smørgrav register int shift; 2331bc421551SDag-Erling Smørgrav unsigned char *const b = (unsigned char *) buf; 2332bc421551SDag-Erling Smørgrav 2333bc421551SDag-Erling Smørgrav for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 2334bc421551SDag-Erling Smørgrav b[i] = (val >> shift) & 0xff; 2335bc421551SDag-Erling Smørgrav } 2336bc421551SDag-Erling Smørgrav 2337bc421551SDag-Erling Smørgrav static void 2338bc421551SDag-Erling Smørgrav puttzcode(zic_t val, FILE *fp) 2339bc421551SDag-Erling Smørgrav { 2340bc421551SDag-Erling Smørgrav char buf[4]; 2341bc421551SDag-Erling Smørgrav 2342bc421551SDag-Erling Smørgrav convert(val, buf); 2343bc421551SDag-Erling Smørgrav fwrite(buf, sizeof buf, 1, fp); 2344bc421551SDag-Erling Smørgrav } 2345bc421551SDag-Erling Smørgrav 2346bc421551SDag-Erling Smørgrav static void 2347bc421551SDag-Erling Smørgrav puttzcodepass(zic_t val, FILE *fp, int pass) 2348bc421551SDag-Erling Smørgrav { 2349bc421551SDag-Erling Smørgrav if (pass == 1) 2350bc421551SDag-Erling Smørgrav puttzcode(val, fp); 2351bc421551SDag-Erling Smørgrav else { 2352bc421551SDag-Erling Smørgrav char buf[8]; 2353bc421551SDag-Erling Smørgrav 2354bc421551SDag-Erling Smørgrav convert64(val, buf); 2355bc421551SDag-Erling Smørgrav fwrite(buf, sizeof buf, 1, fp); 2356bc421551SDag-Erling Smørgrav } 2357bc421551SDag-Erling Smørgrav } 2358bc421551SDag-Erling Smørgrav 2359bc421551SDag-Erling Smørgrav static int 2360bc421551SDag-Erling Smørgrav atcomp(const void *avp, const void *bvp) 2361bc421551SDag-Erling Smørgrav { 2362bc421551SDag-Erling Smørgrav struct attype const *ap = avp, *bp = bvp; 2363bc421551SDag-Erling Smørgrav zic_t a = ap->at, b = bp->at; 2364bc421551SDag-Erling Smørgrav return a < b ? -1 : a > b; 2365bc421551SDag-Erling Smørgrav } 2366bc421551SDag-Erling Smørgrav 2367bc421551SDag-Erling Smørgrav struct timerange { 2368bc421551SDag-Erling Smørgrav int defaulttype; 2369bc421551SDag-Erling Smørgrav ptrdiff_t base, count; 2370bc421551SDag-Erling Smørgrav int leapbase, leapcount; 2371bc421551SDag-Erling Smørgrav bool leapexpiry; 2372bc421551SDag-Erling Smørgrav }; 2373bc421551SDag-Erling Smørgrav 2374bc421551SDag-Erling Smørgrav static struct timerange 2375bc421551SDag-Erling Smørgrav limitrange(struct timerange r, zic_t lo, zic_t hi, 2376bc421551SDag-Erling Smørgrav zic_t const *ats, unsigned char const *types) 2377bc421551SDag-Erling Smørgrav { 2378bc421551SDag-Erling Smørgrav /* Omit ordinary transitions < LO. */ 2379bc421551SDag-Erling Smørgrav while (0 < r.count && ats[r.base] < lo) { 2380bc421551SDag-Erling Smørgrav r.defaulttype = types[r.base]; 2381bc421551SDag-Erling Smørgrav r.count--; 2382bc421551SDag-Erling Smørgrav r.base++; 2383bc421551SDag-Erling Smørgrav } 2384bc421551SDag-Erling Smørgrav 2385bc421551SDag-Erling Smørgrav /* Omit as many initial leap seconds as possible, such that the 2386bc421551SDag-Erling Smørgrav first leap second in the truncated list is <= LO, and is a 2387bc421551SDag-Erling Smørgrav positive leap second if and only if it has a positive correction. 2388bc421551SDag-Erling Smørgrav This supports common TZif readers that assume that the first leap 2389bc421551SDag-Erling Smørgrav second is positive if and only if its correction is positive. */ 2390bc421551SDag-Erling Smørgrav while (1 < r.leapcount && trans[r.leapbase + 1] <= lo) { 2391bc421551SDag-Erling Smørgrav r.leapcount--; 2392bc421551SDag-Erling Smørgrav r.leapbase++; 2393bc421551SDag-Erling Smørgrav } 2394bc421551SDag-Erling Smørgrav while (0 < r.leapbase 2395bc421551SDag-Erling Smørgrav && ((corr[r.leapbase - 1] < corr[r.leapbase]) 2396bc421551SDag-Erling Smørgrav != (0 < corr[r.leapbase]))) { 2397bc421551SDag-Erling Smørgrav r.leapcount++; 2398bc421551SDag-Erling Smørgrav r.leapbase--; 2399bc421551SDag-Erling Smørgrav } 2400bc421551SDag-Erling Smørgrav 2401bc421551SDag-Erling Smørgrav 2402bc421551SDag-Erling Smørgrav /* Omit ordinary and leap second transitions greater than HI + 1. */ 2403bc421551SDag-Erling Smørgrav if (hi < max_time) { 2404bc421551SDag-Erling Smørgrav while (0 < r.count && hi + 1 < ats[r.base + r.count - 1]) 2405bc421551SDag-Erling Smørgrav r.count--; 2406bc421551SDag-Erling Smørgrav while (0 < r.leapcount && hi + 1 < trans[r.leapbase + r.leapcount - 1]) 2407bc421551SDag-Erling Smørgrav r.leapcount--; 2408bc421551SDag-Erling Smørgrav } 2409bc421551SDag-Erling Smørgrav 2410bc421551SDag-Erling Smørgrav /* Determine whether to append an expiration to the leap second table. */ 2411bc421551SDag-Erling Smørgrav r.leapexpiry = 0 <= leapexpires && leapexpires - 1 <= hi; 2412bc421551SDag-Erling Smørgrav 2413bc421551SDag-Erling Smørgrav return r; 2414bc421551SDag-Erling Smørgrav } 2415bc421551SDag-Erling Smørgrav 2416bc421551SDag-Erling Smørgrav static void 2417bc421551SDag-Erling Smørgrav writezone(const char *const name, const char *const string, char version, 2418bc421551SDag-Erling Smørgrav int defaulttype) 2419bc421551SDag-Erling Smørgrav { 2420bc421551SDag-Erling Smørgrav register FILE * fp; 2421bc421551SDag-Erling Smørgrav register ptrdiff_t i, j; 2422bc421551SDag-Erling Smørgrav register size_t u; 2423bc421551SDag-Erling Smørgrav register int pass; 2424bc421551SDag-Erling Smørgrav char *tempname = NULL; 2425bc421551SDag-Erling Smørgrav char const *outname = name; 2426bc421551SDag-Erling Smørgrav 2427bc421551SDag-Erling Smørgrav /* Allocate the ATS and TYPES arrays via a single malloc, 2428bc421551SDag-Erling Smørgrav as this is a bit faster. Do not malloc(0) if !timecnt, 2429bc421551SDag-Erling Smørgrav as that might return NULL even on success. */ 2430bc421551SDag-Erling Smørgrav zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, 2431bc421551SDag-Erling Smørgrav sizeof *ats + 1), 2432bc421551SDag-Erling Smørgrav alignof(zic_t))); 2433bc421551SDag-Erling Smørgrav void *typesptr = ats + timecnt; 2434bc421551SDag-Erling Smørgrav unsigned char *types = typesptr; 2435bc421551SDag-Erling Smørgrav struct timerange rangeall = {0}, range32, range64; 2436bc421551SDag-Erling Smørgrav 2437bc421551SDag-Erling Smørgrav /* 2438bc421551SDag-Erling Smørgrav ** Sort. 2439bc421551SDag-Erling Smørgrav */ 2440bc421551SDag-Erling Smørgrav if (timecnt > 1) 2441bc421551SDag-Erling Smørgrav qsort(attypes, timecnt, sizeof *attypes, atcomp); 2442bc421551SDag-Erling Smørgrav /* 2443bc421551SDag-Erling Smørgrav ** Optimize. 2444bc421551SDag-Erling Smørgrav */ 2445bc421551SDag-Erling Smørgrav { 2446bc421551SDag-Erling Smørgrav ptrdiff_t fromi, toi; 2447bc421551SDag-Erling Smørgrav 2448bc421551SDag-Erling Smørgrav toi = 0; 2449bc421551SDag-Erling Smørgrav fromi = 0; 2450bc421551SDag-Erling Smørgrav for ( ; fromi < timecnt; ++fromi) { 2451bc421551SDag-Erling Smørgrav if (toi != 0 2452bc421551SDag-Erling Smørgrav && ((attypes[fromi].at 2453bc421551SDag-Erling Smørgrav + utoffs[attypes[toi - 1].type]) 2454bc421551SDag-Erling Smørgrav <= (attypes[toi - 1].at 2455bc421551SDag-Erling Smørgrav + utoffs[toi == 1 ? 0 2456bc421551SDag-Erling Smørgrav : attypes[toi - 2].type]))) { 2457bc421551SDag-Erling Smørgrav attypes[toi - 1].type = 2458bc421551SDag-Erling Smørgrav attypes[fromi].type; 2459bc421551SDag-Erling Smørgrav continue; 2460bc421551SDag-Erling Smørgrav } 2461bc421551SDag-Erling Smørgrav if (toi == 0 2462bc421551SDag-Erling Smørgrav || attypes[fromi].dontmerge 2463bc421551SDag-Erling Smørgrav || (utoffs[attypes[toi - 1].type] 2464bc421551SDag-Erling Smørgrav != utoffs[attypes[fromi].type]) 2465bc421551SDag-Erling Smørgrav || (isdsts[attypes[toi - 1].type] 2466bc421551SDag-Erling Smørgrav != isdsts[attypes[fromi].type]) 2467bc421551SDag-Erling Smørgrav || (desigidx[attypes[toi - 1].type] 2468bc421551SDag-Erling Smørgrav != desigidx[attypes[fromi].type])) 2469bc421551SDag-Erling Smørgrav attypes[toi++] = attypes[fromi]; 2470bc421551SDag-Erling Smørgrav } 2471bc421551SDag-Erling Smørgrav timecnt = toi; 2472bc421551SDag-Erling Smørgrav } 2473bc421551SDag-Erling Smørgrav 2474bc421551SDag-Erling Smørgrav if (noise && timecnt > 1200) { 2475bc421551SDag-Erling Smørgrav if (timecnt > TZ_MAX_TIMES) 2476bc421551SDag-Erling Smørgrav warning(_("reference clients mishandle" 2477bc421551SDag-Erling Smørgrav " more than %d transition times"), 2478bc421551SDag-Erling Smørgrav TZ_MAX_TIMES); 2479bc421551SDag-Erling Smørgrav else 2480bc421551SDag-Erling Smørgrav warning(_("pre-2014 clients may mishandle" 2481bc421551SDag-Erling Smørgrav " more than 1200 transition times")); 2482bc421551SDag-Erling Smørgrav } 2483bc421551SDag-Erling Smørgrav /* 2484bc421551SDag-Erling Smørgrav ** Transfer. 2485bc421551SDag-Erling Smørgrav */ 2486bc421551SDag-Erling Smørgrav for (i = 0; i < timecnt; ++i) { 2487bc421551SDag-Erling Smørgrav ats[i] = attypes[i].at; 2488bc421551SDag-Erling Smørgrav types[i] = attypes[i].type; 2489bc421551SDag-Erling Smørgrav } 2490bc421551SDag-Erling Smørgrav 2491bc421551SDag-Erling Smørgrav /* 2492bc421551SDag-Erling Smørgrav ** Correct for leap seconds. 2493bc421551SDag-Erling Smørgrav */ 2494bc421551SDag-Erling Smørgrav for (i = 0; i < timecnt; ++i) { 2495bc421551SDag-Erling Smørgrav j = leapcnt; 2496bc421551SDag-Erling Smørgrav while (--j >= 0) 2497bc421551SDag-Erling Smørgrav if (ats[i] > trans[j] - corr[j]) { 2498bc421551SDag-Erling Smørgrav ats[i] = tadd(ats[i], corr[j]); 2499bc421551SDag-Erling Smørgrav break; 2500bc421551SDag-Erling Smørgrav } 2501bc421551SDag-Erling Smørgrav } 2502bc421551SDag-Erling Smørgrav 2503bc421551SDag-Erling Smørgrav rangeall.defaulttype = defaulttype; 2504bc421551SDag-Erling Smørgrav rangeall.count = timecnt; 2505bc421551SDag-Erling Smørgrav rangeall.leapcount = leapcnt; 2506bc421551SDag-Erling Smørgrav range64 = limitrange(rangeall, lo_time, 2507bc421551SDag-Erling Smørgrav max(hi_time, 2508bc421551SDag-Erling Smørgrav redundant_time - (ZIC_MIN < redundant_time)), 2509bc421551SDag-Erling Smørgrav ats, types); 2510bc421551SDag-Erling Smørgrav range32 = limitrange(range64, ZIC32_MIN, ZIC32_MAX, ats, types); 2511bc421551SDag-Erling Smørgrav 2512bc421551SDag-Erling Smørgrav /* TZif version 4 is needed if a no-op transition is appended to 2513bc421551SDag-Erling Smørgrav indicate the expiration of the leap second table, or if the first 2514bc421551SDag-Erling Smørgrav leap second transition is not to a +1 or -1 correction. */ 2515bc421551SDag-Erling Smørgrav for (pass = 1; pass <= 2; pass++) { 2516bc421551SDag-Erling Smørgrav struct timerange const *r = pass == 1 ? &range32 : &range64; 2517bc421551SDag-Erling Smørgrav if (pass == 1 && !want_bloat()) 2518bc421551SDag-Erling Smørgrav continue; 2519bc421551SDag-Erling Smørgrav if (r->leapexpiry) { 2520bc421551SDag-Erling Smørgrav if (noise) 2521bc421551SDag-Erling Smørgrav warning(_("%s: pre-2021b clients may mishandle" 2522bc421551SDag-Erling Smørgrav " leap second expiry"), 2523bc421551SDag-Erling Smørgrav name); 2524bc421551SDag-Erling Smørgrav version = '4'; 2525bc421551SDag-Erling Smørgrav } 2526bc421551SDag-Erling Smørgrav if (0 < r->leapcount 2527bc421551SDag-Erling Smørgrav && corr[r->leapbase] != 1 && corr[r->leapbase] != -1) { 2528bc421551SDag-Erling Smørgrav if (noise) 2529bc421551SDag-Erling Smørgrav warning(_("%s: pre-2021b clients may mishandle" 2530bc421551SDag-Erling Smørgrav " leap second table truncation"), 2531bc421551SDag-Erling Smørgrav name); 2532bc421551SDag-Erling Smørgrav version = '4'; 2533bc421551SDag-Erling Smørgrav } 2534bc421551SDag-Erling Smørgrav if (version == '4') 2535bc421551SDag-Erling Smørgrav break; 2536bc421551SDag-Erling Smørgrav } 2537bc421551SDag-Erling Smørgrav 2538bc421551SDag-Erling Smørgrav fp = open_outfile(&outname, &tempname); 2539bc421551SDag-Erling Smørgrav 2540bc421551SDag-Erling Smørgrav for (pass = 1; pass <= 2; ++pass) { 2541bc421551SDag-Erling Smørgrav register ptrdiff_t thistimei, thistimecnt, thistimelim; 2542bc421551SDag-Erling Smørgrav register int thisleapi, thisleapcnt, thisleaplim; 2543bc421551SDag-Erling Smørgrav struct tzhead tzh; 2544bc421551SDag-Erling Smørgrav int pretranstype = -1, thisdefaulttype; 2545bc421551SDag-Erling Smørgrav bool locut, hicut, thisleapexpiry; 2546bc421551SDag-Erling Smørgrav zic_t lo, thismin, thismax; 2547bc421551SDag-Erling Smørgrav int old0; 2548bc421551SDag-Erling Smørgrav char omittype[TZ_MAX_TYPES]; 2549bc421551SDag-Erling Smørgrav int typemap[TZ_MAX_TYPES]; 2550bc421551SDag-Erling Smørgrav int thistypecnt, stdcnt, utcnt; 2551bc421551SDag-Erling Smørgrav char thischars[TZ_MAX_CHARS]; 2552bc421551SDag-Erling Smørgrav int thischarcnt; 2553bc421551SDag-Erling Smørgrav bool toomanytimes; 2554bc421551SDag-Erling Smørgrav int indmap[TZ_MAX_CHARS]; 2555bc421551SDag-Erling Smørgrav 2556bc421551SDag-Erling Smørgrav if (pass == 1) { 2557bc421551SDag-Erling Smørgrav thisdefaulttype = range32.defaulttype; 2558bc421551SDag-Erling Smørgrav thistimei = range32.base; 2559bc421551SDag-Erling Smørgrav thistimecnt = range32.count; 2560bc421551SDag-Erling Smørgrav toomanytimes = thistimecnt >> 31 >> 1 != 0; 2561bc421551SDag-Erling Smørgrav thisleapi = range32.leapbase; 2562bc421551SDag-Erling Smørgrav thisleapcnt = range32.leapcount; 2563bc421551SDag-Erling Smørgrav thisleapexpiry = range32.leapexpiry; 2564bc421551SDag-Erling Smørgrav thismin = ZIC32_MIN; 2565bc421551SDag-Erling Smørgrav thismax = ZIC32_MAX; 2566bc421551SDag-Erling Smørgrav } else { 2567bc421551SDag-Erling Smørgrav thisdefaulttype = range64.defaulttype; 2568bc421551SDag-Erling Smørgrav thistimei = range64.base; 2569bc421551SDag-Erling Smørgrav thistimecnt = range64.count; 2570bc421551SDag-Erling Smørgrav toomanytimes = thistimecnt >> 31 >> 31 >> 2 != 0; 2571bc421551SDag-Erling Smørgrav thisleapi = range64.leapbase; 2572bc421551SDag-Erling Smørgrav thisleapcnt = range64.leapcount; 2573bc421551SDag-Erling Smørgrav thisleapexpiry = range64.leapexpiry; 2574bc421551SDag-Erling Smørgrav thismin = min_time; 2575bc421551SDag-Erling Smørgrav thismax = max_time; 2576bc421551SDag-Erling Smørgrav } 2577bc421551SDag-Erling Smørgrav if (toomanytimes) 2578bc421551SDag-Erling Smørgrav error(_("too many transition times")); 2579bc421551SDag-Erling Smørgrav 2580bc421551SDag-Erling Smørgrav locut = thismin < lo_time && lo_time <= thismax; 2581bc421551SDag-Erling Smørgrav hicut = thismin <= hi_time && hi_time < thismax; 2582bc421551SDag-Erling Smørgrav thistimelim = thistimei + thistimecnt; 2583bc421551SDag-Erling Smørgrav memset(omittype, true, typecnt); 2584bc421551SDag-Erling Smørgrav 2585bc421551SDag-Erling Smørgrav /* Determine whether to output a transition before the first 2586bc421551SDag-Erling Smørgrav transition in range. This is needed when the output is 2587bc421551SDag-Erling Smørgrav truncated at the start, and is also useful when catering to 2588bc421551SDag-Erling Smørgrav buggy 32-bit clients that do not use time type 0 for 2589bc421551SDag-Erling Smørgrav timestamps before the first transition. */ 2590bc421551SDag-Erling Smørgrav if ((locut || (pass == 1 && thistimei)) 2591bc421551SDag-Erling Smørgrav && ! (thistimecnt && ats[thistimei] == lo_time)) { 2592bc421551SDag-Erling Smørgrav pretranstype = thisdefaulttype; 2593bc421551SDag-Erling Smørgrav omittype[pretranstype] = false; 2594bc421551SDag-Erling Smørgrav } 2595bc421551SDag-Erling Smørgrav 2596bc421551SDag-Erling Smørgrav /* Arguably the default time type in the 32-bit data 2597bc421551SDag-Erling Smørgrav should be range32.defaulttype, which is suited for 2598bc421551SDag-Erling Smørgrav timestamps just before ZIC32_MIN. However, zic 2599bc421551SDag-Erling Smørgrav traditionally used the time type of the indefinite 2600bc421551SDag-Erling Smørgrav past instead. Internet RFC 8532 says readers should 2601bc421551SDag-Erling Smørgrav ignore 32-bit data, so this discrepancy matters only 2602bc421551SDag-Erling Smørgrav to obsolete readers where the traditional type might 2603bc421551SDag-Erling Smørgrav be more appropriate even if it's "wrong". So, use 2604bc421551SDag-Erling Smørgrav the historical zic value, unless -r specifies a low 2605bc421551SDag-Erling Smørgrav cutoff that excludes some 32-bit timestamps. */ 2606bc421551SDag-Erling Smørgrav if (pass == 1 && lo_time <= thismin) 2607bc421551SDag-Erling Smørgrav thisdefaulttype = range64.defaulttype; 2608bc421551SDag-Erling Smørgrav 2609bc421551SDag-Erling Smørgrav if (locut) 2610bc421551SDag-Erling Smørgrav thisdefaulttype = unspecifiedtype; 2611bc421551SDag-Erling Smørgrav omittype[thisdefaulttype] = false; 2612bc421551SDag-Erling Smørgrav for (i = thistimei; i < thistimelim; i++) 2613bc421551SDag-Erling Smørgrav omittype[types[i]] = false; 2614bc421551SDag-Erling Smørgrav if (hicut) 2615bc421551SDag-Erling Smørgrav omittype[unspecifiedtype] = false; 2616bc421551SDag-Erling Smørgrav 2617bc421551SDag-Erling Smørgrav /* Reorder types to make THISDEFAULTTYPE type 0. 2618bc421551SDag-Erling Smørgrav Use TYPEMAP to swap OLD0 and THISDEFAULTTYPE so that 2619bc421551SDag-Erling Smørgrav THISDEFAULTTYPE appears as type 0 in the output instead 2620bc421551SDag-Erling Smørgrav of OLD0. TYPEMAP also omits unused types. */ 2621bc421551SDag-Erling Smørgrav old0 = strlen(omittype); 2622bc421551SDag-Erling Smørgrav 2623bc421551SDag-Erling Smørgrav #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 2624bc421551SDag-Erling Smørgrav /* 2625bc421551SDag-Erling Smørgrav ** For some pre-2011 systems: if the last-to-be-written 2626bc421551SDag-Erling Smørgrav ** standard (or daylight) type has an offset different from the 2627bc421551SDag-Erling Smørgrav ** most recently used offset, 2628bc421551SDag-Erling Smørgrav ** append an (unused) copy of the most recently used type 2629bc421551SDag-Erling Smørgrav ** (to help get global "altzone" and "timezone" variables 2630bc421551SDag-Erling Smørgrav ** set correctly). 2631bc421551SDag-Erling Smørgrav */ 2632bc421551SDag-Erling Smørgrav if (want_bloat()) { 2633bc421551SDag-Erling Smørgrav register int mrudst, mrustd, hidst, histd, type; 2634bc421551SDag-Erling Smørgrav 2635bc421551SDag-Erling Smørgrav hidst = histd = mrudst = mrustd = -1; 2636bc421551SDag-Erling Smørgrav if (0 <= pretranstype) { 2637bc421551SDag-Erling Smørgrav if (isdsts[pretranstype]) 2638bc421551SDag-Erling Smørgrav mrudst = pretranstype; 2639bc421551SDag-Erling Smørgrav else 2640bc421551SDag-Erling Smørgrav mrustd = pretranstype; 2641bc421551SDag-Erling Smørgrav } 2642bc421551SDag-Erling Smørgrav for (i = thistimei; i < thistimelim; i++) 2643bc421551SDag-Erling Smørgrav if (isdsts[types[i]]) 2644bc421551SDag-Erling Smørgrav mrudst = types[i]; 2645bc421551SDag-Erling Smørgrav else mrustd = types[i]; 2646bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) { 2647bc421551SDag-Erling Smørgrav int h = (i == old0 ? thisdefaulttype 2648bc421551SDag-Erling Smørgrav : i == thisdefaulttype ? old0 : i); 2649bc421551SDag-Erling Smørgrav if (!omittype[h]) { 2650bc421551SDag-Erling Smørgrav if (isdsts[h]) 2651bc421551SDag-Erling Smørgrav hidst = i; 2652bc421551SDag-Erling Smørgrav else 2653bc421551SDag-Erling Smørgrav histd = i; 2654bc421551SDag-Erling Smørgrav } 2655bc421551SDag-Erling Smørgrav } 2656bc421551SDag-Erling Smørgrav if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 2657bc421551SDag-Erling Smørgrav utoffs[hidst] != utoffs[mrudst]) { 2658bc421551SDag-Erling Smørgrav isdsts[mrudst] = -1; 2659bc421551SDag-Erling Smørgrav type = addtype(utoffs[mrudst], 2660bc421551SDag-Erling Smørgrav &chars[desigidx[mrudst]], 2661bc421551SDag-Erling Smørgrav true, 2662bc421551SDag-Erling Smørgrav ttisstds[mrudst], 2663bc421551SDag-Erling Smørgrav ttisuts[mrudst]); 2664bc421551SDag-Erling Smørgrav isdsts[mrudst] = 1; 2665bc421551SDag-Erling Smørgrav omittype[type] = false; 2666bc421551SDag-Erling Smørgrav } 2667bc421551SDag-Erling Smørgrav if (histd >= 0 && mrustd >= 0 && histd != mrustd && 2668bc421551SDag-Erling Smørgrav utoffs[histd] != utoffs[mrustd]) { 2669bc421551SDag-Erling Smørgrav isdsts[mrustd] = -1; 2670bc421551SDag-Erling Smørgrav type = addtype(utoffs[mrustd], 2671bc421551SDag-Erling Smørgrav &chars[desigidx[mrustd]], 2672bc421551SDag-Erling Smørgrav false, 2673bc421551SDag-Erling Smørgrav ttisstds[mrustd], 2674bc421551SDag-Erling Smørgrav ttisuts[mrustd]); 2675bc421551SDag-Erling Smørgrav isdsts[mrustd] = 0; 2676bc421551SDag-Erling Smørgrav omittype[type] = false; 2677bc421551SDag-Erling Smørgrav } 2678bc421551SDag-Erling Smørgrav } 2679bc421551SDag-Erling Smørgrav #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 2680bc421551SDag-Erling Smørgrav thistypecnt = 0; 2681bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) 2682bc421551SDag-Erling Smørgrav if (!omittype[i]) 2683bc421551SDag-Erling Smørgrav typemap[i == old0 ? thisdefaulttype 2684bc421551SDag-Erling Smørgrav : i == thisdefaulttype ? old0 : i] 2685bc421551SDag-Erling Smørgrav = thistypecnt++; 2686bc421551SDag-Erling Smørgrav 2687bc421551SDag-Erling Smørgrav for (u = 0; u < sizeof indmap / sizeof indmap[0]; ++u) 2688bc421551SDag-Erling Smørgrav indmap[u] = -1; 2689bc421551SDag-Erling Smørgrav thischarcnt = stdcnt = utcnt = 0; 2690bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) { 2691bc421551SDag-Erling Smørgrav register char * thisabbr; 2692bc421551SDag-Erling Smørgrav 2693bc421551SDag-Erling Smørgrav if (omittype[i]) 2694bc421551SDag-Erling Smørgrav continue; 2695bc421551SDag-Erling Smørgrav if (ttisstds[i]) 2696bc421551SDag-Erling Smørgrav stdcnt = thistypecnt; 2697bc421551SDag-Erling Smørgrav if (ttisuts[i]) 2698bc421551SDag-Erling Smørgrav utcnt = thistypecnt; 2699bc421551SDag-Erling Smørgrav if (indmap[desigidx[i]] >= 0) 2700bc421551SDag-Erling Smørgrav continue; 2701bc421551SDag-Erling Smørgrav thisabbr = &chars[desigidx[i]]; 2702bc421551SDag-Erling Smørgrav for (j = 0; j < thischarcnt; ++j) 2703bc421551SDag-Erling Smørgrav if (strcmp(&thischars[j], thisabbr) == 0) 2704bc421551SDag-Erling Smørgrav break; 2705bc421551SDag-Erling Smørgrav if (j == thischarcnt) { 2706bc421551SDag-Erling Smørgrav strcpy(&thischars[thischarcnt], thisabbr); 2707bc421551SDag-Erling Smørgrav thischarcnt += strlen(thisabbr) + 1; 2708bc421551SDag-Erling Smørgrav } 2709bc421551SDag-Erling Smørgrav indmap[desigidx[i]] = j; 2710bc421551SDag-Erling Smørgrav } 2711bc421551SDag-Erling Smørgrav if (pass == 1 && !want_bloat()) { 2712bc421551SDag-Erling Smørgrav hicut = thisleapexpiry = false; 2713bc421551SDag-Erling Smørgrav pretranstype = -1; 2714bc421551SDag-Erling Smørgrav thistimecnt = thisleapcnt = 0; 2715bc421551SDag-Erling Smørgrav thistypecnt = thischarcnt = 1; 2716bc421551SDag-Erling Smørgrav } 2717bc421551SDag-Erling Smørgrav #define DO(field) fwrite(tzh.field, sizeof tzh.field, 1, fp) 2718bc421551SDag-Erling Smørgrav memset(&tzh, 0, sizeof tzh); 2719bc421551SDag-Erling Smørgrav memcpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 2720bc421551SDag-Erling Smørgrav tzh.tzh_version[0] = version; 2721bc421551SDag-Erling Smørgrav convert(utcnt, tzh.tzh_ttisutcnt); 2722bc421551SDag-Erling Smørgrav convert(stdcnt, tzh.tzh_ttisstdcnt); 2723bc421551SDag-Erling Smørgrav convert(thisleapcnt + thisleapexpiry, tzh.tzh_leapcnt); 2724bc421551SDag-Erling Smørgrav convert((0 <= pretranstype) + thistimecnt + hicut, 2725bc421551SDag-Erling Smørgrav tzh.tzh_timecnt); 2726bc421551SDag-Erling Smørgrav convert(thistypecnt, tzh.tzh_typecnt); 2727bc421551SDag-Erling Smørgrav convert(thischarcnt, tzh.tzh_charcnt); 2728bc421551SDag-Erling Smørgrav DO(tzh_magic); 2729bc421551SDag-Erling Smørgrav DO(tzh_version); 2730bc421551SDag-Erling Smørgrav DO(tzh_reserved); 2731bc421551SDag-Erling Smørgrav DO(tzh_ttisutcnt); 2732bc421551SDag-Erling Smørgrav DO(tzh_ttisstdcnt); 2733bc421551SDag-Erling Smørgrav DO(tzh_leapcnt); 2734bc421551SDag-Erling Smørgrav DO(tzh_timecnt); 2735bc421551SDag-Erling Smørgrav DO(tzh_typecnt); 2736bc421551SDag-Erling Smørgrav DO(tzh_charcnt); 2737bc421551SDag-Erling Smørgrav #undef DO 2738bc421551SDag-Erling Smørgrav if (pass == 1 && !want_bloat()) { 2739bc421551SDag-Erling Smørgrav /* Output a minimal data block with just one time type. */ 2740bc421551SDag-Erling Smørgrav puttzcode(0, fp); /* utoff */ 2741bc421551SDag-Erling Smørgrav putc(0, fp); /* dst */ 2742bc421551SDag-Erling Smørgrav putc(0, fp); /* index of abbreviation */ 2743bc421551SDag-Erling Smørgrav putc(0, fp); /* empty-string abbreviation */ 2744bc421551SDag-Erling Smørgrav continue; 2745bc421551SDag-Erling Smørgrav } 2746bc421551SDag-Erling Smørgrav 2747bc421551SDag-Erling Smørgrav /* Output a LO_TIME transition if needed; see limitrange. 2748bc421551SDag-Erling Smørgrav But do not go below the minimum representable value 2749bc421551SDag-Erling Smørgrav for this pass. */ 2750bc421551SDag-Erling Smørgrav lo = pass == 1 && lo_time < ZIC32_MIN ? ZIC32_MIN : lo_time; 2751bc421551SDag-Erling Smørgrav 2752bc421551SDag-Erling Smørgrav if (0 <= pretranstype) 2753bc421551SDag-Erling Smørgrav puttzcodepass(lo, fp, pass); 2754bc421551SDag-Erling Smørgrav for (i = thistimei; i < thistimelim; ++i) { 2755bc421551SDag-Erling Smørgrav puttzcodepass(ats[i], fp, pass); 2756bc421551SDag-Erling Smørgrav } 2757bc421551SDag-Erling Smørgrav if (hicut) 2758bc421551SDag-Erling Smørgrav puttzcodepass(hi_time + 1, fp, pass); 2759bc421551SDag-Erling Smørgrav if (0 <= pretranstype) 2760bc421551SDag-Erling Smørgrav putc(typemap[pretranstype], fp); 2761bc421551SDag-Erling Smørgrav for (i = thistimei; i < thistimelim; i++) 2762bc421551SDag-Erling Smørgrav putc(typemap[types[i]], fp); 2763bc421551SDag-Erling Smørgrav if (hicut) 2764bc421551SDag-Erling Smørgrav putc(typemap[unspecifiedtype], fp); 2765bc421551SDag-Erling Smørgrav 2766bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) { 2767bc421551SDag-Erling Smørgrav int h = (i == old0 ? thisdefaulttype 2768bc421551SDag-Erling Smørgrav : i == thisdefaulttype ? old0 : i); 2769bc421551SDag-Erling Smørgrav if (!omittype[h]) { 2770bc421551SDag-Erling Smørgrav puttzcode(utoffs[h], fp); 2771bc421551SDag-Erling Smørgrav putc(isdsts[h], fp); 2772bc421551SDag-Erling Smørgrav putc(indmap[desigidx[h]], fp); 2773bc421551SDag-Erling Smørgrav } 2774bc421551SDag-Erling Smørgrav } 2775bc421551SDag-Erling Smørgrav if (thischarcnt != 0) 2776bc421551SDag-Erling Smørgrav fwrite(thischars, sizeof thischars[0], 2777bc421551SDag-Erling Smørgrav thischarcnt, fp); 2778bc421551SDag-Erling Smørgrav thisleaplim = thisleapi + thisleapcnt; 2779bc421551SDag-Erling Smørgrav for (i = thisleapi; i < thisleaplim; ++i) { 2780bc421551SDag-Erling Smørgrav register zic_t todo; 2781bc421551SDag-Erling Smørgrav 2782bc421551SDag-Erling Smørgrav if (roll[i]) { 2783bc421551SDag-Erling Smørgrav if (timecnt == 0 || trans[i] < ats[0]) { 2784bc421551SDag-Erling Smørgrav j = 0; 2785bc421551SDag-Erling Smørgrav while (isdsts[j]) 2786bc421551SDag-Erling Smørgrav if (++j >= typecnt) { 2787bc421551SDag-Erling Smørgrav j = 0; 2788bc421551SDag-Erling Smørgrav break; 2789bc421551SDag-Erling Smørgrav } 2790bc421551SDag-Erling Smørgrav } else { 2791bc421551SDag-Erling Smørgrav j = 1; 2792bc421551SDag-Erling Smørgrav while (j < timecnt && 2793bc421551SDag-Erling Smørgrav trans[i] >= ats[j]) 2794bc421551SDag-Erling Smørgrav ++j; 2795bc421551SDag-Erling Smørgrav j = types[j - 1]; 2796bc421551SDag-Erling Smørgrav } 2797bc421551SDag-Erling Smørgrav todo = tadd(trans[i], -utoffs[j]); 2798bc421551SDag-Erling Smørgrav } else todo = trans[i]; 2799bc421551SDag-Erling Smørgrav puttzcodepass(todo, fp, pass); 2800bc421551SDag-Erling Smørgrav puttzcode(corr[i], fp); 2801bc421551SDag-Erling Smørgrav } 2802bc421551SDag-Erling Smørgrav if (thisleapexpiry) { 2803bc421551SDag-Erling Smørgrav /* Append a no-op leap correction indicating when the leap 2804bc421551SDag-Erling Smørgrav second table expires. Although this does not conform to 2805bc421551SDag-Erling Smørgrav Internet RFC 8536, most clients seem to accept this and 2806bc421551SDag-Erling Smørgrav the plan is to amend the RFC to allow this in version 4 2807bc421551SDag-Erling Smørgrav TZif files. */ 2808bc421551SDag-Erling Smørgrav puttzcodepass(leapexpires, fp, pass); 2809bc421551SDag-Erling Smørgrav puttzcode(thisleaplim ? corr[thisleaplim - 1] : 0, fp); 2810bc421551SDag-Erling Smørgrav } 2811bc421551SDag-Erling Smørgrav if (stdcnt != 0) 2812bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) 2813bc421551SDag-Erling Smørgrav if (!omittype[i]) 2814bc421551SDag-Erling Smørgrav putc(ttisstds[i], fp); 2815bc421551SDag-Erling Smørgrav if (utcnt != 0) 2816bc421551SDag-Erling Smørgrav for (i = old0; i < typecnt; i++) 2817bc421551SDag-Erling Smørgrav if (!omittype[i]) 2818bc421551SDag-Erling Smørgrav putc(ttisuts[i], fp); 2819bc421551SDag-Erling Smørgrav } 2820bc421551SDag-Erling Smørgrav fprintf(fp, "\n%s\n", string); 2821bc421551SDag-Erling Smørgrav close_file(fp, directory, name, tempname); 2822bc421551SDag-Erling Smørgrav if (chmod(tempname, mflag) < 0) { 2823bc421551SDag-Erling Smørgrav fprintf(stderr, _("cannot change mode of %s to %03o"), 2824bc421551SDag-Erling Smørgrav tempname, (unsigned)mflag); 2825bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 2826bc421551SDag-Erling Smørgrav } 2827bc421551SDag-Erling Smørgrav if ((uflag != (uid_t)-1 || gflag != (gid_t)-1) 2828bc421551SDag-Erling Smørgrav && chown(tempname, uflag, gflag) < 0) { 2829bc421551SDag-Erling Smørgrav fprintf(stderr, _("cannot change ownership of %s"), 2830bc421551SDag-Erling Smørgrav tempname); 2831bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 2832bc421551SDag-Erling Smørgrav } 2833bc421551SDag-Erling Smørgrav rename_dest(tempname, name); 2834bc421551SDag-Erling Smørgrav free(ats); 2835bc421551SDag-Erling Smørgrav } 2836bc421551SDag-Erling Smørgrav 2837bc421551SDag-Erling Smørgrav static char const * 2838bc421551SDag-Erling Smørgrav abbroffset(char *buf, zic_t offset) 2839bc421551SDag-Erling Smørgrav { 2840bc421551SDag-Erling Smørgrav char sign = '+'; 2841bc421551SDag-Erling Smørgrav int seconds, minutes; 2842bc421551SDag-Erling Smørgrav 2843bc421551SDag-Erling Smørgrav if (offset < 0) { 2844bc421551SDag-Erling Smørgrav offset = -offset; 2845bc421551SDag-Erling Smørgrav sign = '-'; 2846bc421551SDag-Erling Smørgrav } 2847bc421551SDag-Erling Smørgrav 2848bc421551SDag-Erling Smørgrav seconds = offset % SECSPERMIN; 2849bc421551SDag-Erling Smørgrav offset /= SECSPERMIN; 2850bc421551SDag-Erling Smørgrav minutes = offset % MINSPERHOUR; 2851bc421551SDag-Erling Smørgrav offset /= MINSPERHOUR; 2852bc421551SDag-Erling Smørgrav if (100 <= offset) { 2853bc421551SDag-Erling Smørgrav error(_("%%z UT offset magnitude exceeds 99:59:59")); 2854bc421551SDag-Erling Smørgrav return "%z"; 2855bc421551SDag-Erling Smørgrav } else { 2856bc421551SDag-Erling Smørgrav char *p = buf; 2857bc421551SDag-Erling Smørgrav *p++ = sign; 2858bc421551SDag-Erling Smørgrav *p++ = '0' + offset / 10; 2859bc421551SDag-Erling Smørgrav *p++ = '0' + offset % 10; 2860bc421551SDag-Erling Smørgrav if (minutes | seconds) { 2861bc421551SDag-Erling Smørgrav *p++ = '0' + minutes / 10; 2862bc421551SDag-Erling Smørgrav *p++ = '0' + minutes % 10; 2863bc421551SDag-Erling Smørgrav if (seconds) { 2864bc421551SDag-Erling Smørgrav *p++ = '0' + seconds / 10; 2865bc421551SDag-Erling Smørgrav *p++ = '0' + seconds % 10; 2866bc421551SDag-Erling Smørgrav } 2867bc421551SDag-Erling Smørgrav } 2868bc421551SDag-Erling Smørgrav *p = '\0'; 2869bc421551SDag-Erling Smørgrav return buf; 2870bc421551SDag-Erling Smørgrav } 2871bc421551SDag-Erling Smørgrav } 2872bc421551SDag-Erling Smørgrav 2873bc421551SDag-Erling Smørgrav static char const disable_percent_s[] = ""; 2874bc421551SDag-Erling Smørgrav 2875bc421551SDag-Erling Smørgrav static ptrdiff_t 2876bc421551SDag-Erling Smørgrav doabbr(char *abbr, struct zone const *zp, char const *letters, 2877bc421551SDag-Erling Smørgrav bool isdst, zic_t save, bool doquotes) 2878bc421551SDag-Erling Smørgrav { 2879bc421551SDag-Erling Smørgrav register char * cp; 2880bc421551SDag-Erling Smørgrav register char * slashp; 2881bc421551SDag-Erling Smørgrav ptrdiff_t len; 2882bc421551SDag-Erling Smørgrav char const *format = zp->z_format; 2883bc421551SDag-Erling Smørgrav 2884bc421551SDag-Erling Smørgrav slashp = strchr(format, '/'); 2885bc421551SDag-Erling Smørgrav if (slashp == NULL) { 2886bc421551SDag-Erling Smørgrav char letterbuf[PERCENT_Z_LEN_BOUND + 1]; 2887bc421551SDag-Erling Smørgrav if (zp->z_format_specifier == 'z') 2888bc421551SDag-Erling Smørgrav letters = abbroffset(letterbuf, zp->z_stdoff + save); 2889bc421551SDag-Erling Smørgrav else if (!letters) 2890bc421551SDag-Erling Smørgrav letters = "%s"; 2891bc421551SDag-Erling Smørgrav else if (letters == disable_percent_s) 2892bc421551SDag-Erling Smørgrav return 0; 2893bc421551SDag-Erling Smørgrav sprintf(abbr, format, letters); 2894bc421551SDag-Erling Smørgrav } else if (isdst) { 2895bc421551SDag-Erling Smørgrav strcpy(abbr, slashp + 1); 2896bc421551SDag-Erling Smørgrav } else { 2897bc421551SDag-Erling Smørgrav memcpy(abbr, format, slashp - format); 2898bc421551SDag-Erling Smørgrav abbr[slashp - format] = '\0'; 2899bc421551SDag-Erling Smørgrav } 2900bc421551SDag-Erling Smørgrav len = strlen(abbr); 2901bc421551SDag-Erling Smørgrav if (!doquotes) 2902bc421551SDag-Erling Smørgrav return len; 2903bc421551SDag-Erling Smørgrav for (cp = abbr; is_alpha(*cp); cp++) 2904bc421551SDag-Erling Smørgrav continue; 2905bc421551SDag-Erling Smørgrav if (len > 0 && *cp == '\0') 2906bc421551SDag-Erling Smørgrav return len; 2907bc421551SDag-Erling Smørgrav abbr[len + 2] = '\0'; 2908bc421551SDag-Erling Smørgrav abbr[len + 1] = '>'; 2909bc421551SDag-Erling Smørgrav memmove(abbr + 1, abbr, len); 2910bc421551SDag-Erling Smørgrav abbr[0] = '<'; 2911bc421551SDag-Erling Smørgrav return len + 2; 2912bc421551SDag-Erling Smørgrav } 2913bc421551SDag-Erling Smørgrav 2914bc421551SDag-Erling Smørgrav static void 2915bc421551SDag-Erling Smørgrav updateminmax(const zic_t x) 2916bc421551SDag-Erling Smørgrav { 2917bc421551SDag-Erling Smørgrav if (min_year > x) 2918bc421551SDag-Erling Smørgrav min_year = x; 2919bc421551SDag-Erling Smørgrav if (max_year < x) 2920bc421551SDag-Erling Smørgrav max_year = x; 2921bc421551SDag-Erling Smørgrav } 2922bc421551SDag-Erling Smørgrav 2923bc421551SDag-Erling Smørgrav static int 2924bc421551SDag-Erling Smørgrav stringoffset(char *result, zic_t offset) 2925bc421551SDag-Erling Smørgrav { 2926bc421551SDag-Erling Smørgrav register int hours; 2927bc421551SDag-Erling Smørgrav register int minutes; 2928bc421551SDag-Erling Smørgrav register int seconds; 2929bc421551SDag-Erling Smørgrav bool negative = offset < 0; 2930bc421551SDag-Erling Smørgrav int len = negative; 2931bc421551SDag-Erling Smørgrav 2932bc421551SDag-Erling Smørgrav if (negative) { 2933bc421551SDag-Erling Smørgrav offset = -offset; 2934bc421551SDag-Erling Smørgrav result[0] = '-'; 2935bc421551SDag-Erling Smørgrav } 2936bc421551SDag-Erling Smørgrav seconds = offset % SECSPERMIN; 2937bc421551SDag-Erling Smørgrav offset /= SECSPERMIN; 2938bc421551SDag-Erling Smørgrav minutes = offset % MINSPERHOUR; 2939bc421551SDag-Erling Smørgrav offset /= MINSPERHOUR; 2940bc421551SDag-Erling Smørgrav hours = offset; 2941bc421551SDag-Erling Smørgrav if (hours >= HOURSPERDAY * DAYSPERWEEK) { 2942bc421551SDag-Erling Smørgrav result[0] = '\0'; 2943bc421551SDag-Erling Smørgrav return 0; 2944bc421551SDag-Erling Smørgrav } 2945bc421551SDag-Erling Smørgrav len += sprintf(result + len, "%d", hours); 2946bc421551SDag-Erling Smørgrav if (minutes != 0 || seconds != 0) { 2947bc421551SDag-Erling Smørgrav len += sprintf(result + len, ":%02d", minutes); 2948bc421551SDag-Erling Smørgrav if (seconds != 0) 2949bc421551SDag-Erling Smørgrav len += sprintf(result + len, ":%02d", seconds); 2950bc421551SDag-Erling Smørgrav } 2951bc421551SDag-Erling Smørgrav return len; 2952bc421551SDag-Erling Smørgrav } 2953bc421551SDag-Erling Smørgrav 2954bc421551SDag-Erling Smørgrav static int 2955bc421551SDag-Erling Smørgrav stringrule(char *result, struct rule *const rp, zic_t save, zic_t stdoff) 2956bc421551SDag-Erling Smørgrav { 2957bc421551SDag-Erling Smørgrav register zic_t tod = rp->r_tod; 2958bc421551SDag-Erling Smørgrav register int compat = 0; 2959bc421551SDag-Erling Smørgrav 2960bc421551SDag-Erling Smørgrav if (rp->r_dycode == DC_DOM) { 2961bc421551SDag-Erling Smørgrav register int month, total; 2962bc421551SDag-Erling Smørgrav 2963bc421551SDag-Erling Smørgrav if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 2964bc421551SDag-Erling Smørgrav return -1; 2965bc421551SDag-Erling Smørgrav total = 0; 2966bc421551SDag-Erling Smørgrav for (month = 0; month < rp->r_month; ++month) 2967bc421551SDag-Erling Smørgrav total += len_months[0][month]; 2968bc421551SDag-Erling Smørgrav /* Omit the "J" in Jan and Feb, as that's shorter. */ 2969bc421551SDag-Erling Smørgrav if (rp->r_month <= 1) 2970bc421551SDag-Erling Smørgrav result += sprintf(result, "%d", total + rp->r_dayofmonth - 1); 2971bc421551SDag-Erling Smørgrav else 2972bc421551SDag-Erling Smørgrav result += sprintf(result, "J%d", total + rp->r_dayofmonth); 2973bc421551SDag-Erling Smørgrav } else { 2974bc421551SDag-Erling Smørgrav register int week; 2975bc421551SDag-Erling Smørgrav register int wday = rp->r_wday; 2976bc421551SDag-Erling Smørgrav register int wdayoff; 2977bc421551SDag-Erling Smørgrav 2978bc421551SDag-Erling Smørgrav if (rp->r_dycode == DC_DOWGEQ) { 2979bc421551SDag-Erling Smørgrav wdayoff = (rp->r_dayofmonth - 1) % DAYSPERWEEK; 2980bc421551SDag-Erling Smørgrav if (wdayoff) 2981bc421551SDag-Erling Smørgrav compat = 2013; 2982bc421551SDag-Erling Smørgrav wday -= wdayoff; 2983bc421551SDag-Erling Smørgrav tod += wdayoff * SECSPERDAY; 2984bc421551SDag-Erling Smørgrav week = 1 + (rp->r_dayofmonth - 1) / DAYSPERWEEK; 2985bc421551SDag-Erling Smørgrav } else if (rp->r_dycode == DC_DOWLEQ) { 2986bc421551SDag-Erling Smørgrav if (rp->r_dayofmonth == len_months[1][rp->r_month]) 2987bc421551SDag-Erling Smørgrav week = 5; 2988bc421551SDag-Erling Smørgrav else { 2989bc421551SDag-Erling Smørgrav wdayoff = rp->r_dayofmonth % DAYSPERWEEK; 2990bc421551SDag-Erling Smørgrav if (wdayoff) 2991bc421551SDag-Erling Smørgrav compat = 2013; 2992bc421551SDag-Erling Smørgrav wday -= wdayoff; 2993bc421551SDag-Erling Smørgrav tod += wdayoff * SECSPERDAY; 2994bc421551SDag-Erling Smørgrav week = rp->r_dayofmonth / DAYSPERWEEK; 2995bc421551SDag-Erling Smørgrav } 2996bc421551SDag-Erling Smørgrav } else return -1; /* "cannot happen" */ 2997bc421551SDag-Erling Smørgrav if (wday < 0) 2998bc421551SDag-Erling Smørgrav wday += DAYSPERWEEK; 2999bc421551SDag-Erling Smørgrav result += sprintf(result, "M%d.%d.%d", 3000bc421551SDag-Erling Smørgrav rp->r_month + 1, week, wday); 3001bc421551SDag-Erling Smørgrav } 3002bc421551SDag-Erling Smørgrav if (rp->r_todisut) 3003bc421551SDag-Erling Smørgrav tod += stdoff; 3004bc421551SDag-Erling Smørgrav if (rp->r_todisstd && !rp->r_isdst) 3005bc421551SDag-Erling Smørgrav tod += save; 3006bc421551SDag-Erling Smørgrav if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 3007bc421551SDag-Erling Smørgrav *result++ = '/'; 3008bc421551SDag-Erling Smørgrav if (! stringoffset(result, tod)) 3009bc421551SDag-Erling Smørgrav return -1; 3010bc421551SDag-Erling Smørgrav if (tod < 0) { 3011bc421551SDag-Erling Smørgrav if (compat < 2013) 3012bc421551SDag-Erling Smørgrav compat = 2013; 3013bc421551SDag-Erling Smørgrav } else if (SECSPERDAY <= tod) { 3014bc421551SDag-Erling Smørgrav if (compat < 1994) 3015bc421551SDag-Erling Smørgrav compat = 1994; 3016bc421551SDag-Erling Smørgrav } 3017bc421551SDag-Erling Smørgrav } 3018bc421551SDag-Erling Smørgrav return compat; 3019bc421551SDag-Erling Smørgrav } 3020bc421551SDag-Erling Smørgrav 3021bc421551SDag-Erling Smørgrav static int 3022bc421551SDag-Erling Smørgrav rule_cmp(struct rule const *a, struct rule const *b) 3023bc421551SDag-Erling Smørgrav { 3024bc421551SDag-Erling Smørgrav if (!a) 3025bc421551SDag-Erling Smørgrav return -!!b; 3026bc421551SDag-Erling Smørgrav if (!b) 3027bc421551SDag-Erling Smørgrav return 1; 3028bc421551SDag-Erling Smørgrav if (a->r_hiyear != b->r_hiyear) 3029bc421551SDag-Erling Smørgrav return a->r_hiyear < b->r_hiyear ? -1 : 1; 3030bc421551SDag-Erling Smørgrav if (a->r_hiyear == ZIC_MAX) 3031bc421551SDag-Erling Smørgrav return 0; 3032bc421551SDag-Erling Smørgrav if (a->r_month - b->r_month != 0) 3033bc421551SDag-Erling Smørgrav return a->r_month - b->r_month; 3034bc421551SDag-Erling Smørgrav return a->r_dayofmonth - b->r_dayofmonth; 3035bc421551SDag-Erling Smørgrav } 3036bc421551SDag-Erling Smørgrav 3037*a979394aSDag-Erling Smørgrav /* Store into RESULT a proleptic TZ string that represent the future 303846c59934SDag-Erling Smørgrav predictions for the zone ZPFIRST with ZONECOUNT entries. Return a 303946c59934SDag-Erling Smørgrav compatibility indicator (a TZDB release year) if successful, a 3040*a979394aSDag-Erling Smørgrav negative integer if no such TZ string exists. */ 3041bc421551SDag-Erling Smørgrav static int 3042bc421551SDag-Erling Smørgrav stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) 3043bc421551SDag-Erling Smørgrav { 3044bc421551SDag-Erling Smørgrav register const struct zone * zp; 3045bc421551SDag-Erling Smørgrav register struct rule * rp; 3046bc421551SDag-Erling Smørgrav register struct rule * stdrp; 3047bc421551SDag-Erling Smørgrav register struct rule * dstrp; 3048bc421551SDag-Erling Smørgrav register ptrdiff_t i; 3049bc421551SDag-Erling Smørgrav register int compat = 0; 3050bc421551SDag-Erling Smørgrav register int c; 3051bc421551SDag-Erling Smørgrav int offsetlen; 3052bc421551SDag-Erling Smørgrav struct rule stdr, dstr; 3053bc421551SDag-Erling Smørgrav ptrdiff_t len; 3054bc421551SDag-Erling Smørgrav int dstcmp; 3055bc421551SDag-Erling Smørgrav struct rule *lastrp[2] = { NULL, NULL }; 3056bc421551SDag-Erling Smørgrav struct zone zstr[2]; 3057bc421551SDag-Erling Smørgrav struct zone const *stdzp; 3058bc421551SDag-Erling Smørgrav struct zone const *dstzp; 3059bc421551SDag-Erling Smørgrav 3060bc421551SDag-Erling Smørgrav result[0] = '\0'; 3061bc421551SDag-Erling Smørgrav 3062bc421551SDag-Erling Smørgrav /* Internet RFC 8536 section 5.1 says to use an empty TZ string if 3063bc421551SDag-Erling Smørgrav future timestamps are truncated. */ 3064bc421551SDag-Erling Smørgrav if (hi_time < max_time) 3065bc421551SDag-Erling Smørgrav return -1; 3066bc421551SDag-Erling Smørgrav 3067bc421551SDag-Erling Smørgrav zp = zpfirst + zonecount - 1; 3068bc421551SDag-Erling Smørgrav for (i = 0; i < zp->z_nrules; ++i) { 3069bc421551SDag-Erling Smørgrav struct rule **last; 3070bc421551SDag-Erling Smørgrav int cmp; 3071bc421551SDag-Erling Smørgrav rp = &zp->z_rules[i]; 3072bc421551SDag-Erling Smørgrav last = &lastrp[rp->r_isdst]; 3073bc421551SDag-Erling Smørgrav cmp = rule_cmp(*last, rp); 3074bc421551SDag-Erling Smørgrav if (cmp < 0) 3075bc421551SDag-Erling Smørgrav *last = rp; 3076bc421551SDag-Erling Smørgrav else if (cmp == 0) 3077bc421551SDag-Erling Smørgrav return -1; 3078bc421551SDag-Erling Smørgrav } 3079bc421551SDag-Erling Smørgrav stdrp = lastrp[false]; 3080bc421551SDag-Erling Smørgrav dstrp = lastrp[true]; 3081bc421551SDag-Erling Smørgrav dstcmp = zp->z_nrules ? rule_cmp(dstrp, stdrp) : zp->z_isdst ? 1 : -1; 3082bc421551SDag-Erling Smørgrav stdzp = dstzp = zp; 3083bc421551SDag-Erling Smørgrav 3084bc421551SDag-Erling Smørgrav if (dstcmp < 0) { 3085bc421551SDag-Erling Smørgrav /* Standard time all year. */ 3086bc421551SDag-Erling Smørgrav dstrp = NULL; 3087bc421551SDag-Erling Smørgrav } else if (0 < dstcmp) { 3088bc421551SDag-Erling Smørgrav /* DST all year. Use an abbreviation like 3089bc421551SDag-Erling Smørgrav "XXX3EDT4,0/0,J365/23" for EDT (-04) all year. */ 3090bc421551SDag-Erling Smørgrav zic_t save = dstrp ? dstrp->r_save : zp->z_save; 3091bc421551SDag-Erling Smørgrav if (0 <= save) 3092bc421551SDag-Erling Smørgrav { 3093bc421551SDag-Erling Smørgrav /* Positive DST, the typical case for all-year DST. 3094bc421551SDag-Erling Smørgrav Fake a timezone with negative DST. */ 3095bc421551SDag-Erling Smørgrav stdzp = &zstr[0]; 3096bc421551SDag-Erling Smørgrav dstzp = &zstr[1]; 3097bc421551SDag-Erling Smørgrav zstr[0].z_stdoff = zp->z_stdoff + 2 * save; 3098bc421551SDag-Erling Smørgrav zstr[0].z_format = "XXX"; /* Any 3 letters will do. */ 3099bc421551SDag-Erling Smørgrav zstr[0].z_format_specifier = 0; 3100bc421551SDag-Erling Smørgrav zstr[1].z_stdoff = zstr[0].z_stdoff; 3101bc421551SDag-Erling Smørgrav zstr[1].z_format = zp->z_format; 3102bc421551SDag-Erling Smørgrav zstr[1].z_format_specifier = zp->z_format_specifier; 3103bc421551SDag-Erling Smørgrav } 3104bc421551SDag-Erling Smørgrav dstr.r_month = TM_JANUARY; 3105bc421551SDag-Erling Smørgrav dstr.r_dycode = DC_DOM; 3106bc421551SDag-Erling Smørgrav dstr.r_dayofmonth = 1; 3107bc421551SDag-Erling Smørgrav dstr.r_tod = 0; 3108bc421551SDag-Erling Smørgrav dstr.r_todisstd = dstr.r_todisut = false; 3109bc421551SDag-Erling Smørgrav dstr.r_isdst = true; 3110bc421551SDag-Erling Smørgrav dstr.r_save = save < 0 ? save : -save; 3111bc421551SDag-Erling Smørgrav dstr.r_abbrvar = dstrp ? dstrp->r_abbrvar : NULL; 3112bc421551SDag-Erling Smørgrav stdr.r_month = TM_DECEMBER; 3113bc421551SDag-Erling Smørgrav stdr.r_dycode = DC_DOM; 3114bc421551SDag-Erling Smørgrav stdr.r_dayofmonth = 31; 3115bc421551SDag-Erling Smørgrav stdr.r_tod = SECSPERDAY + dstr.r_save; 3116bc421551SDag-Erling Smørgrav stdr.r_todisstd = stdr.r_todisut = false; 3117bc421551SDag-Erling Smørgrav stdr.r_isdst = false; 3118bc421551SDag-Erling Smørgrav stdr.r_save = 0; 3119bc421551SDag-Erling Smørgrav stdr.r_abbrvar = save < 0 && stdrp ? stdrp->r_abbrvar : NULL; 3120bc421551SDag-Erling Smørgrav dstrp = &dstr; 3121bc421551SDag-Erling Smørgrav stdrp = &stdr; 3122bc421551SDag-Erling Smørgrav } 3123bc421551SDag-Erling Smørgrav len = doabbr(result, stdzp, stdrp ? stdrp->r_abbrvar : NULL, 3124bc421551SDag-Erling Smørgrav false, 0, true); 3125bc421551SDag-Erling Smørgrav offsetlen = stringoffset(result + len, - stdzp->z_stdoff); 3126bc421551SDag-Erling Smørgrav if (! offsetlen) { 3127bc421551SDag-Erling Smørgrav result[0] = '\0'; 3128bc421551SDag-Erling Smørgrav return -1; 3129bc421551SDag-Erling Smørgrav } 3130bc421551SDag-Erling Smørgrav len += offsetlen; 3131bc421551SDag-Erling Smørgrav if (dstrp == NULL) 3132bc421551SDag-Erling Smørgrav return compat; 3133bc421551SDag-Erling Smørgrav len += doabbr(result + len, dstzp, dstrp->r_abbrvar, 3134bc421551SDag-Erling Smørgrav dstrp->r_isdst, dstrp->r_save, true); 3135bc421551SDag-Erling Smørgrav if (dstrp->r_save != SECSPERMIN * MINSPERHOUR) { 3136bc421551SDag-Erling Smørgrav offsetlen = stringoffset(result + len, 3137bc421551SDag-Erling Smørgrav - (dstzp->z_stdoff + dstrp->r_save)); 3138bc421551SDag-Erling Smørgrav if (! offsetlen) { 3139bc421551SDag-Erling Smørgrav result[0] = '\0'; 3140bc421551SDag-Erling Smørgrav return -1; 3141bc421551SDag-Erling Smørgrav } 3142bc421551SDag-Erling Smørgrav len += offsetlen; 3143bc421551SDag-Erling Smørgrav } 3144bc421551SDag-Erling Smørgrav result[len++] = ','; 3145bc421551SDag-Erling Smørgrav c = stringrule(result + len, dstrp, dstrp->r_save, stdzp->z_stdoff); 3146bc421551SDag-Erling Smørgrav if (c < 0) { 3147bc421551SDag-Erling Smørgrav result[0] = '\0'; 3148bc421551SDag-Erling Smørgrav return -1; 3149bc421551SDag-Erling Smørgrav } 3150bc421551SDag-Erling Smørgrav if (compat < c) 3151bc421551SDag-Erling Smørgrav compat = c; 3152bc421551SDag-Erling Smørgrav len += strlen(result + len); 3153bc421551SDag-Erling Smørgrav result[len++] = ','; 3154bc421551SDag-Erling Smørgrav c = stringrule(result + len, stdrp, dstrp->r_save, stdzp->z_stdoff); 3155bc421551SDag-Erling Smørgrav if (c < 0) { 3156bc421551SDag-Erling Smørgrav result[0] = '\0'; 3157bc421551SDag-Erling Smørgrav return -1; 3158bc421551SDag-Erling Smørgrav } 3159bc421551SDag-Erling Smørgrav if (compat < c) 3160bc421551SDag-Erling Smørgrav compat = c; 3161bc421551SDag-Erling Smørgrav return compat; 3162bc421551SDag-Erling Smørgrav } 3163bc421551SDag-Erling Smørgrav 3164bc421551SDag-Erling Smørgrav static void 3165bc421551SDag-Erling Smørgrav outzone(const struct zone *zpfirst, ptrdiff_t zonecount) 3166bc421551SDag-Erling Smørgrav { 3167bc421551SDag-Erling Smørgrav register ptrdiff_t i, j; 3168bc421551SDag-Erling Smørgrav register zic_t starttime, untiltime; 3169bc421551SDag-Erling Smørgrav register bool startttisstd; 3170bc421551SDag-Erling Smørgrav register bool startttisut; 3171bc421551SDag-Erling Smørgrav register char * startbuf; 3172bc421551SDag-Erling Smørgrav register char * ab; 3173bc421551SDag-Erling Smørgrav register char * envvar; 3174bc421551SDag-Erling Smørgrav register int max_abbr_len; 3175bc421551SDag-Erling Smørgrav register int max_envvar_len; 3176bc421551SDag-Erling Smørgrav register int compat; 3177bc421551SDag-Erling Smørgrav register bool do_extend; 3178bc421551SDag-Erling Smørgrav register char version; 317946c59934SDag-Erling Smørgrav zic_t nonTZlimtime = ZIC_MIN; 318046c59934SDag-Erling Smørgrav int nonTZlimtype = -1; 3181bc421551SDag-Erling Smørgrav zic_t max_year0; 3182bc421551SDag-Erling Smørgrav int defaulttype = -1; 3183bc421551SDag-Erling Smørgrav 3184bc421551SDag-Erling Smørgrav check_for_signal(); 3185bc421551SDag-Erling Smørgrav 3186bc421551SDag-Erling Smørgrav /* This cannot overflow; see FORMAT_LEN_GROWTH_BOUND. */ 3187bc421551SDag-Erling Smørgrav max_abbr_len = 2 + max_format_len + max_abbrvar_len; 3188bc421551SDag-Erling Smørgrav max_envvar_len = 2 * max_abbr_len + 5 * 9; 3189bc421551SDag-Erling Smørgrav 3190bc421551SDag-Erling Smørgrav startbuf = emalloc(max_abbr_len + 1); 3191bc421551SDag-Erling Smørgrav ab = emalloc(max_abbr_len + 1); 3192bc421551SDag-Erling Smørgrav envvar = emalloc(max_envvar_len + 1); 3193bc421551SDag-Erling Smørgrav INITIALIZE(untiltime); 3194bc421551SDag-Erling Smørgrav INITIALIZE(starttime); 3195bc421551SDag-Erling Smørgrav /* 3196bc421551SDag-Erling Smørgrav ** Now. . .finally. . .generate some useful data! 3197bc421551SDag-Erling Smørgrav */ 3198bc421551SDag-Erling Smørgrav timecnt = 0; 3199bc421551SDag-Erling Smørgrav typecnt = 0; 3200bc421551SDag-Erling Smørgrav charcnt = 0; 3201bc421551SDag-Erling Smørgrav /* 3202bc421551SDag-Erling Smørgrav ** Thanks to Earl Chew 3203bc421551SDag-Erling Smørgrav ** for noting the need to unconditionally initialize startttisstd. 3204bc421551SDag-Erling Smørgrav */ 3205bc421551SDag-Erling Smørgrav startttisstd = false; 3206bc421551SDag-Erling Smørgrav startttisut = false; 3207bc421551SDag-Erling Smørgrav min_year = max_year = EPOCH_YEAR; 3208bc421551SDag-Erling Smørgrav if (leapseen) { 3209bc421551SDag-Erling Smørgrav updateminmax(leapminyear); 3210bc421551SDag-Erling Smørgrav updateminmax(leapmaxyear + (leapmaxyear < ZIC_MAX)); 3211bc421551SDag-Erling Smørgrav } 3212bc421551SDag-Erling Smørgrav for (i = 0; i < zonecount; ++i) { 3213bc421551SDag-Erling Smørgrav struct zone const *zp = &zpfirst[i]; 3214bc421551SDag-Erling Smørgrav if (i < zonecount - 1) 3215bc421551SDag-Erling Smørgrav updateminmax(zp->z_untilrule.r_loyear); 3216bc421551SDag-Erling Smørgrav for (j = 0; j < zp->z_nrules; ++j) { 3217bc421551SDag-Erling Smørgrav struct rule *rp = &zp->z_rules[j]; 3218bc421551SDag-Erling Smørgrav updateminmax(rp->r_loyear); 3219bc421551SDag-Erling Smørgrav if (rp->r_hiwasnum) 3220bc421551SDag-Erling Smørgrav updateminmax(rp->r_hiyear); 3221bc421551SDag-Erling Smørgrav } 3222bc421551SDag-Erling Smørgrav } 3223bc421551SDag-Erling Smørgrav /* 3224bc421551SDag-Erling Smørgrav ** Generate lots of data if a rule can't cover all future times. 3225bc421551SDag-Erling Smørgrav */ 3226bc421551SDag-Erling Smørgrav compat = stringzone(envvar, zpfirst, zonecount); 3227bc421551SDag-Erling Smørgrav version = compat < 2013 ? '2' : '3'; 3228bc421551SDag-Erling Smørgrav do_extend = compat < 0; 3229bc421551SDag-Erling Smørgrav if (noise) { 3230bc421551SDag-Erling Smørgrav if (!*envvar) 3231bc421551SDag-Erling Smørgrav warning("%s %s", 3232*a979394aSDag-Erling Smørgrav _("no proleptic TZ string for zone"), 3233bc421551SDag-Erling Smørgrav zpfirst->z_name); 3234bc421551SDag-Erling Smørgrav else if (compat != 0) { 3235bc421551SDag-Erling Smørgrav /* Circa-COMPAT clients, and earlier clients, might 3236bc421551SDag-Erling Smørgrav not work for this zone when given dates before 3237bc421551SDag-Erling Smørgrav 1970 or after 2038. */ 3238bc421551SDag-Erling Smørgrav warning(_("%s: pre-%d clients may mishandle" 3239bc421551SDag-Erling Smørgrav " distant timestamps"), 3240bc421551SDag-Erling Smørgrav zpfirst->z_name, compat); 3241bc421551SDag-Erling Smørgrav } 3242bc421551SDag-Erling Smørgrav } 3243bc421551SDag-Erling Smørgrav if (do_extend) { 3244bc421551SDag-Erling Smørgrav if (min_year >= ZIC_MIN + years_of_observations) 3245bc421551SDag-Erling Smørgrav min_year -= years_of_observations; 3246bc421551SDag-Erling Smørgrav else min_year = ZIC_MIN; 3247bc421551SDag-Erling Smørgrav if (max_year <= ZIC_MAX - years_of_observations) 3248bc421551SDag-Erling Smørgrav max_year += years_of_observations; 3249bc421551SDag-Erling Smørgrav else max_year = ZIC_MAX; 3250bc421551SDag-Erling Smørgrav } 3251bc421551SDag-Erling Smørgrav max_year = max(max_year, (redundant_time / (SECSPERDAY * DAYSPERNYEAR) 3252bc421551SDag-Erling Smørgrav + EPOCH_YEAR + 1)); 3253bc421551SDag-Erling Smørgrav max_year0 = max_year; 3254bc421551SDag-Erling Smørgrav if (want_bloat()) { 3255bc421551SDag-Erling Smørgrav /* For the benefit of older systems, 3256bc421551SDag-Erling Smørgrav generate data from 1900 through 2038. */ 325746c59934SDag-Erling Smørgrav if (min_year > YEAR_32BIT_MIN - 1) 325846c59934SDag-Erling Smørgrav min_year = YEAR_32BIT_MIN - 1; 325946c59934SDag-Erling Smørgrav if (max_year < YEAR_32BIT_MAX) 326046c59934SDag-Erling Smørgrav max_year = YEAR_32BIT_MAX; 3261bc421551SDag-Erling Smørgrav } 3262bc421551SDag-Erling Smørgrav 3263bc421551SDag-Erling Smørgrav if (min_time < lo_time || hi_time < max_time) 3264bc421551SDag-Erling Smørgrav unspecifiedtype = addtype(0, "-00", false, false, false); 3265bc421551SDag-Erling Smørgrav 3266bc421551SDag-Erling Smørgrav for (i = 0; i < zonecount; ++i) { 3267bc421551SDag-Erling Smørgrav /* 3268bc421551SDag-Erling Smørgrav ** A guess that may well be corrected later. 3269bc421551SDag-Erling Smørgrav */ 3270bc421551SDag-Erling Smørgrav zic_t save = 0; 3271bc421551SDag-Erling Smørgrav struct zone const *zp = &zpfirst[i]; 3272bc421551SDag-Erling Smørgrav bool usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 3273bc421551SDag-Erling Smørgrav bool useuntil = i < (zonecount - 1); 3274bc421551SDag-Erling Smørgrav zic_t stdoff = zp->z_stdoff; 3275bc421551SDag-Erling Smørgrav zic_t startoff = stdoff; 3276bc421551SDag-Erling Smørgrav if (useuntil && zp->z_untiltime <= min_time) 3277bc421551SDag-Erling Smørgrav continue; 3278bc421551SDag-Erling Smørgrav eat(zp->z_filenum, zp->z_linenum); 3279bc421551SDag-Erling Smørgrav *startbuf = '\0'; 3280bc421551SDag-Erling Smørgrav if (zp->z_nrules == 0) { 3281bc421551SDag-Erling Smørgrav int type; 3282bc421551SDag-Erling Smørgrav save = zp->z_save; 3283bc421551SDag-Erling Smørgrav doabbr(startbuf, zp, NULL, zp->z_isdst, save, false); 3284bc421551SDag-Erling Smørgrav type = addtype(oadd(zp->z_stdoff, save), 3285bc421551SDag-Erling Smørgrav startbuf, zp->z_isdst, startttisstd, 3286bc421551SDag-Erling Smørgrav startttisut); 3287bc421551SDag-Erling Smørgrav if (usestart) { 3288bc421551SDag-Erling Smørgrav addtt(starttime, type); 328946c59934SDag-Erling Smørgrav if (useuntil && nonTZlimtime < starttime) { 329046c59934SDag-Erling Smørgrav nonTZlimtime = starttime; 329146c59934SDag-Erling Smørgrav nonTZlimtype = type; 329246c59934SDag-Erling Smørgrav } 3293bc421551SDag-Erling Smørgrav usestart = false; 3294bc421551SDag-Erling Smørgrav } else 3295bc421551SDag-Erling Smørgrav defaulttype = type; 3296bc421551SDag-Erling Smørgrav } else { 3297bc421551SDag-Erling Smørgrav zic_t year; 3298bc421551SDag-Erling Smørgrav for (year = min_year; year <= max_year; ++year) { 3299bc421551SDag-Erling Smørgrav if (useuntil && year > zp->z_untilrule.r_hiyear) 3300bc421551SDag-Erling Smørgrav break; 3301bc421551SDag-Erling Smørgrav /* 3302bc421551SDag-Erling Smørgrav ** Mark which rules to do in the current year. 3303bc421551SDag-Erling Smørgrav ** For those to do, calculate rpytime(rp, year); 3304bc421551SDag-Erling Smørgrav ** The former TYPE field was also considered here. 3305bc421551SDag-Erling Smørgrav */ 3306bc421551SDag-Erling Smørgrav for (j = 0; j < zp->z_nrules; ++j) { 3307bc421551SDag-Erling Smørgrav zic_t one = 1; 3308bc421551SDag-Erling Smørgrav zic_t y2038_boundary = one << 31; 3309bc421551SDag-Erling Smørgrav struct rule *rp = &zp->z_rules[j]; 3310bc421551SDag-Erling Smørgrav eats(zp->z_filenum, zp->z_linenum, 3311bc421551SDag-Erling Smørgrav rp->r_filenum, rp->r_linenum); 3312bc421551SDag-Erling Smørgrav rp->r_todo = year >= rp->r_loyear && 3313bc421551SDag-Erling Smørgrav year <= rp->r_hiyear; 3314bc421551SDag-Erling Smørgrav if (rp->r_todo) { 3315bc421551SDag-Erling Smørgrav rp->r_temp = rpytime(rp, year); 3316bc421551SDag-Erling Smørgrav rp->r_todo 3317bc421551SDag-Erling Smørgrav = (rp->r_temp < y2038_boundary 3318bc421551SDag-Erling Smørgrav || year <= max_year0); 3319bc421551SDag-Erling Smørgrav } 3320bc421551SDag-Erling Smørgrav } 3321bc421551SDag-Erling Smørgrav for ( ; ; ) { 3322bc421551SDag-Erling Smørgrav register ptrdiff_t k; 3323bc421551SDag-Erling Smørgrav register zic_t jtime, ktime; 3324bc421551SDag-Erling Smørgrav register zic_t offset; 3325bc421551SDag-Erling Smørgrav struct rule *rp; 3326bc421551SDag-Erling Smørgrav int type; 3327bc421551SDag-Erling Smørgrav 3328bc421551SDag-Erling Smørgrav INITIALIZE(ktime); 3329bc421551SDag-Erling Smørgrav if (useuntil) { 3330bc421551SDag-Erling Smørgrav /* 3331bc421551SDag-Erling Smørgrav ** Turn untiltime into UT 3332bc421551SDag-Erling Smørgrav ** assuming the current stdoff and 3333bc421551SDag-Erling Smørgrav ** save values. 3334bc421551SDag-Erling Smørgrav */ 3335bc421551SDag-Erling Smørgrav untiltime = zp->z_untiltime; 3336bc421551SDag-Erling Smørgrav if (!zp->z_untilrule.r_todisut) 3337bc421551SDag-Erling Smørgrav untiltime = tadd(untiltime, 3338bc421551SDag-Erling Smørgrav -stdoff); 3339bc421551SDag-Erling Smørgrav if (!zp->z_untilrule.r_todisstd) 3340bc421551SDag-Erling Smørgrav untiltime = tadd(untiltime, 3341bc421551SDag-Erling Smørgrav -save); 3342bc421551SDag-Erling Smørgrav } 3343bc421551SDag-Erling Smørgrav /* 3344bc421551SDag-Erling Smørgrav ** Find the rule (of those to do, if any) 3345bc421551SDag-Erling Smørgrav ** that takes effect earliest in the year. 3346bc421551SDag-Erling Smørgrav */ 3347bc421551SDag-Erling Smørgrav k = -1; 3348bc421551SDag-Erling Smørgrav for (j = 0; j < zp->z_nrules; ++j) { 3349bc421551SDag-Erling Smørgrav struct rule *r = &zp->z_rules[j]; 3350bc421551SDag-Erling Smørgrav if (!r->r_todo) 3351bc421551SDag-Erling Smørgrav continue; 3352bc421551SDag-Erling Smørgrav eats(zp->z_filenum, zp->z_linenum, 3353bc421551SDag-Erling Smørgrav r->r_filenum, r->r_linenum); 3354bc421551SDag-Erling Smørgrav offset = r->r_todisut ? 0 : stdoff; 3355bc421551SDag-Erling Smørgrav if (!r->r_todisstd) 3356bc421551SDag-Erling Smørgrav offset = oadd(offset, save); 3357bc421551SDag-Erling Smørgrav jtime = r->r_temp; 3358bc421551SDag-Erling Smørgrav if (jtime == min_time || 3359bc421551SDag-Erling Smørgrav jtime == max_time) 3360bc421551SDag-Erling Smørgrav continue; 3361bc421551SDag-Erling Smørgrav jtime = tadd(jtime, -offset); 3362bc421551SDag-Erling Smørgrav if (k < 0 || jtime < ktime) { 3363bc421551SDag-Erling Smørgrav k = j; 3364bc421551SDag-Erling Smørgrav ktime = jtime; 3365bc421551SDag-Erling Smørgrav } else if (jtime == ktime) { 3366bc421551SDag-Erling Smørgrav char const *dup_rules_msg = 3367bc421551SDag-Erling Smørgrav _("two rules for same instant"); 3368bc421551SDag-Erling Smørgrav eats(zp->z_filenum, zp->z_linenum, 3369bc421551SDag-Erling Smørgrav r->r_filenum, r->r_linenum); 3370bc421551SDag-Erling Smørgrav warning("%s", dup_rules_msg); 3371bc421551SDag-Erling Smørgrav r = &zp->z_rules[k]; 3372bc421551SDag-Erling Smørgrav eats(zp->z_filenum, zp->z_linenum, 3373bc421551SDag-Erling Smørgrav r->r_filenum, r->r_linenum); 3374bc421551SDag-Erling Smørgrav error("%s", dup_rules_msg); 3375bc421551SDag-Erling Smørgrav } 3376bc421551SDag-Erling Smørgrav } 3377bc421551SDag-Erling Smørgrav if (k < 0) 3378bc421551SDag-Erling Smørgrav break; /* go on to next year */ 3379bc421551SDag-Erling Smørgrav rp = &zp->z_rules[k]; 3380bc421551SDag-Erling Smørgrav rp->r_todo = false; 3381bc421551SDag-Erling Smørgrav if (useuntil && ktime >= untiltime) { 3382bc421551SDag-Erling Smørgrav if (!*startbuf 3383bc421551SDag-Erling Smørgrav && (oadd(zp->z_stdoff, rp->r_save) 3384bc421551SDag-Erling Smørgrav == startoff)) 3385bc421551SDag-Erling Smørgrav doabbr(startbuf, zp, rp->r_abbrvar, 3386bc421551SDag-Erling Smørgrav rp->r_isdst, rp->r_save, 3387bc421551SDag-Erling Smørgrav false); 3388bc421551SDag-Erling Smørgrav break; 3389bc421551SDag-Erling Smørgrav } 3390bc421551SDag-Erling Smørgrav save = rp->r_save; 3391bc421551SDag-Erling Smørgrav if (usestart && ktime == starttime) 3392bc421551SDag-Erling Smørgrav usestart = false; 3393bc421551SDag-Erling Smørgrav if (usestart) { 3394bc421551SDag-Erling Smørgrav if (ktime < starttime) { 3395bc421551SDag-Erling Smørgrav startoff = oadd(zp->z_stdoff, 3396bc421551SDag-Erling Smørgrav save); 3397bc421551SDag-Erling Smørgrav doabbr(startbuf, zp, 3398bc421551SDag-Erling Smørgrav rp->r_abbrvar, 3399bc421551SDag-Erling Smørgrav rp->r_isdst, 3400bc421551SDag-Erling Smørgrav rp->r_save, 3401bc421551SDag-Erling Smørgrav false); 3402bc421551SDag-Erling Smørgrav continue; 3403bc421551SDag-Erling Smørgrav } 3404bc421551SDag-Erling Smørgrav if (*startbuf == '\0' 3405bc421551SDag-Erling Smørgrav && startoff == oadd(zp->z_stdoff, 3406bc421551SDag-Erling Smørgrav save)) { 3407bc421551SDag-Erling Smørgrav doabbr(startbuf, 3408bc421551SDag-Erling Smørgrav zp, 3409bc421551SDag-Erling Smørgrav rp->r_abbrvar, 3410bc421551SDag-Erling Smørgrav rp->r_isdst, 3411bc421551SDag-Erling Smørgrav rp->r_save, 3412bc421551SDag-Erling Smørgrav false); 3413bc421551SDag-Erling Smørgrav } 3414bc421551SDag-Erling Smørgrav } 3415bc421551SDag-Erling Smørgrav eats(zp->z_filenum, zp->z_linenum, 3416bc421551SDag-Erling Smørgrav rp->r_filenum, rp->r_linenum); 3417bc421551SDag-Erling Smørgrav doabbr(ab, zp, rp->r_abbrvar, 3418bc421551SDag-Erling Smørgrav rp->r_isdst, rp->r_save, false); 3419bc421551SDag-Erling Smørgrav offset = oadd(zp->z_stdoff, rp->r_save); 3420bc421551SDag-Erling Smørgrav type = addtype(offset, ab, rp->r_isdst, 3421bc421551SDag-Erling Smørgrav rp->r_todisstd, rp->r_todisut); 3422bc421551SDag-Erling Smørgrav if (defaulttype < 0 && !rp->r_isdst) 3423bc421551SDag-Erling Smørgrav defaulttype = type; 3424bc421551SDag-Erling Smørgrav addtt(ktime, type); 342546c59934SDag-Erling Smørgrav if (nonTZlimtime < ktime 342646c59934SDag-Erling Smørgrav && (useuntil || rp->r_hiyear != ZIC_MAX)) { 342746c59934SDag-Erling Smørgrav nonTZlimtime = ktime; 342846c59934SDag-Erling Smørgrav nonTZlimtype = type; 342946c59934SDag-Erling Smørgrav } 3430bc421551SDag-Erling Smørgrav } 3431bc421551SDag-Erling Smørgrav } 3432bc421551SDag-Erling Smørgrav } 3433bc421551SDag-Erling Smørgrav if (usestart) { 3434bc421551SDag-Erling Smørgrav bool isdst = startoff != zp->z_stdoff; 3435bc421551SDag-Erling Smørgrav if (*startbuf == '\0' && zp->z_format) 3436bc421551SDag-Erling Smørgrav doabbr(startbuf, zp, disable_percent_s, 3437bc421551SDag-Erling Smørgrav isdst, save, false); 3438bc421551SDag-Erling Smørgrav eat(zp->z_filenum, zp->z_linenum); 3439bc421551SDag-Erling Smørgrav if (*startbuf == '\0') 344046c59934SDag-Erling Smørgrav error(_("can't determine time zone abbreviation" 344146c59934SDag-Erling Smørgrav " to use just after until time")); 3442bc421551SDag-Erling Smørgrav else { 3443bc421551SDag-Erling Smørgrav int type = addtype(startoff, startbuf, isdst, 3444bc421551SDag-Erling Smørgrav startttisstd, startttisut); 3445bc421551SDag-Erling Smørgrav if (defaulttype < 0 && !isdst) 3446bc421551SDag-Erling Smørgrav defaulttype = type; 3447bc421551SDag-Erling Smørgrav addtt(starttime, type); 3448bc421551SDag-Erling Smørgrav } 3449bc421551SDag-Erling Smørgrav } 3450bc421551SDag-Erling Smørgrav /* 3451bc421551SDag-Erling Smørgrav ** Now we may get to set starttime for the next zone line. 3452bc421551SDag-Erling Smørgrav */ 3453bc421551SDag-Erling Smørgrav if (useuntil) { 3454bc421551SDag-Erling Smørgrav startttisstd = zp->z_untilrule.r_todisstd; 3455bc421551SDag-Erling Smørgrav startttisut = zp->z_untilrule.r_todisut; 3456bc421551SDag-Erling Smørgrav starttime = zp->z_untiltime; 3457bc421551SDag-Erling Smørgrav if (!startttisstd) 3458bc421551SDag-Erling Smørgrav starttime = tadd(starttime, -save); 3459bc421551SDag-Erling Smørgrav if (!startttisut) 3460bc421551SDag-Erling Smørgrav starttime = tadd(starttime, -stdoff); 3461bc421551SDag-Erling Smørgrav } 3462bc421551SDag-Erling Smørgrav } 3463bc421551SDag-Erling Smørgrav if (defaulttype < 0) 3464bc421551SDag-Erling Smørgrav defaulttype = 0; 346546c59934SDag-Erling Smørgrav if (!do_extend && !want_bloat()) { 346646c59934SDag-Erling Smørgrav /* Keep trailing transitions that are no greater than this. */ 346746c59934SDag-Erling Smørgrav zic_t keep_at_max; 346846c59934SDag-Erling Smørgrav 346946c59934SDag-Erling Smørgrav /* The earliest transition into a time governed by the TZ string. */ 347046c59934SDag-Erling Smørgrav zic_t TZstarttime = ZIC_MAX; 347146c59934SDag-Erling Smørgrav for (i = 0; i < timecnt; i++) { 347246c59934SDag-Erling Smørgrav zic_t at = attypes[i].at; 347346c59934SDag-Erling Smørgrav if (nonTZlimtime < at && at < TZstarttime) 347446c59934SDag-Erling Smørgrav TZstarttime = at; 347546c59934SDag-Erling Smørgrav } 347646c59934SDag-Erling Smørgrav if (TZstarttime == ZIC_MAX) 347746c59934SDag-Erling Smørgrav TZstarttime = nonTZlimtime; 347846c59934SDag-Erling Smørgrav 347946c59934SDag-Erling Smørgrav /* Omit trailing transitions deducible from the TZ string, 348046c59934SDag-Erling Smørgrav and not needed for -r or -R. */ 348146c59934SDag-Erling Smørgrav keep_at_max = max(TZstarttime, redundant_time); 348246c59934SDag-Erling Smørgrav for (i = j = 0; i < timecnt; i++) 348346c59934SDag-Erling Smørgrav if (attypes[i].at <= keep_at_max) { 348446c59934SDag-Erling Smørgrav attypes[j].at = attypes[i].at; 348546c59934SDag-Erling Smørgrav attypes[j].dontmerge = (attypes[i].at == TZstarttime 348646c59934SDag-Erling Smørgrav && (nonTZlimtype != attypes[i].type 348746c59934SDag-Erling Smørgrav || strchr(envvar, ','))); 348846c59934SDag-Erling Smørgrav attypes[j].type = attypes[i].type; 348946c59934SDag-Erling Smørgrav j++; 349046c59934SDag-Erling Smørgrav } 349146c59934SDag-Erling Smørgrav timecnt = j; 349246c59934SDag-Erling Smørgrav } 3493bc421551SDag-Erling Smørgrav if (do_extend) { 3494bc421551SDag-Erling Smørgrav /* 349546c59934SDag-Erling Smørgrav ** If we're extending the explicitly listed observations for 3496*a979394aSDag-Erling Smørgrav ** 400 years because we can't fill the proleptic TZ field, 3497bc421551SDag-Erling Smørgrav ** check whether we actually ended up explicitly listing 3498bc421551SDag-Erling Smørgrav ** observations through that period. If there aren't any 3499bc421551SDag-Erling Smørgrav ** near the end of the 400-year period, add a redundant 3500bc421551SDag-Erling Smørgrav ** one at the end of the final year, to make it clear 3501bc421551SDag-Erling Smørgrav ** that we are claiming to have definite knowledge of 3502bc421551SDag-Erling Smørgrav ** the lack of transitions up to that point. 3503bc421551SDag-Erling Smørgrav */ 3504bc421551SDag-Erling Smørgrav struct rule xr; 3505bc421551SDag-Erling Smørgrav struct attype *lastat; 3506bc421551SDag-Erling Smørgrav xr.r_month = TM_JANUARY; 3507bc421551SDag-Erling Smørgrav xr.r_dycode = DC_DOM; 3508bc421551SDag-Erling Smørgrav xr.r_dayofmonth = 1; 3509bc421551SDag-Erling Smørgrav xr.r_tod = 0; 3510bc421551SDag-Erling Smørgrav for (lastat = attypes, i = 1; i < timecnt; i++) 3511bc421551SDag-Erling Smørgrav if (attypes[i].at > lastat->at) 3512bc421551SDag-Erling Smørgrav lastat = &attypes[i]; 3513bc421551SDag-Erling Smørgrav if (!lastat || lastat->at < rpytime(&xr, max_year - 1)) { 3514bc421551SDag-Erling Smørgrav addtt(rpytime(&xr, max_year + 1), 3515bc421551SDag-Erling Smørgrav lastat ? lastat->type : defaulttype); 3516bc421551SDag-Erling Smørgrav attypes[timecnt - 1].dontmerge = true; 3517bc421551SDag-Erling Smørgrav } 3518bc421551SDag-Erling Smørgrav } 3519bc421551SDag-Erling Smørgrav writezone(zpfirst->z_name, envvar, version, defaulttype); 3520bc421551SDag-Erling Smørgrav free(startbuf); 3521bc421551SDag-Erling Smørgrav free(ab); 3522bc421551SDag-Erling Smørgrav free(envvar); 3523bc421551SDag-Erling Smørgrav } 3524bc421551SDag-Erling Smørgrav 3525bc421551SDag-Erling Smørgrav static void 3526bc421551SDag-Erling Smørgrav addtt(zic_t starttime, int type) 3527bc421551SDag-Erling Smørgrav { 3528bc421551SDag-Erling Smørgrav attypes = growalloc(attypes, sizeof *attypes, timecnt, &timecnt_alloc); 3529bc421551SDag-Erling Smørgrav attypes[timecnt].at = starttime; 3530bc421551SDag-Erling Smørgrav attypes[timecnt].dontmerge = false; 3531bc421551SDag-Erling Smørgrav attypes[timecnt].type = type; 3532bc421551SDag-Erling Smørgrav ++timecnt; 3533bc421551SDag-Erling Smørgrav } 3534bc421551SDag-Erling Smørgrav 3535bc421551SDag-Erling Smørgrav static int 3536bc421551SDag-Erling Smørgrav addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut) 3537bc421551SDag-Erling Smørgrav { 3538bc421551SDag-Erling Smørgrav register int i, j; 3539bc421551SDag-Erling Smørgrav 3540bc421551SDag-Erling Smørgrav if (! (-1L - 2147483647L <= utoff && utoff <= 2147483647L)) { 3541bc421551SDag-Erling Smørgrav error(_("UT offset out of range")); 3542bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3543bc421551SDag-Erling Smørgrav } 3544bc421551SDag-Erling Smørgrav if (!want_bloat()) 3545bc421551SDag-Erling Smørgrav ttisstd = ttisut = false; 3546bc421551SDag-Erling Smørgrav 3547bc421551SDag-Erling Smørgrav for (j = 0; j < charcnt; ++j) 3548bc421551SDag-Erling Smørgrav if (strcmp(&chars[j], abbr) == 0) 3549bc421551SDag-Erling Smørgrav break; 3550bc421551SDag-Erling Smørgrav if (j == charcnt) 3551bc421551SDag-Erling Smørgrav newabbr(abbr); 3552bc421551SDag-Erling Smørgrav else { 3553bc421551SDag-Erling Smørgrav /* If there's already an entry, return its index. */ 3554bc421551SDag-Erling Smørgrav for (i = 0; i < typecnt; i++) 3555bc421551SDag-Erling Smørgrav if (utoff == utoffs[i] && isdst == isdsts[i] && j == desigidx[i] 3556bc421551SDag-Erling Smørgrav && ttisstd == ttisstds[i] && ttisut == ttisuts[i]) 3557bc421551SDag-Erling Smørgrav return i; 3558bc421551SDag-Erling Smørgrav } 3559bc421551SDag-Erling Smørgrav /* 3560bc421551SDag-Erling Smørgrav ** There isn't one; add a new one, unless there are already too 3561bc421551SDag-Erling Smørgrav ** many. 3562bc421551SDag-Erling Smørgrav */ 3563bc421551SDag-Erling Smørgrav if (typecnt >= TZ_MAX_TYPES) { 3564bc421551SDag-Erling Smørgrav error(_("too many local time types")); 3565bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3566bc421551SDag-Erling Smørgrav } 3567bc421551SDag-Erling Smørgrav i = typecnt++; 3568bc421551SDag-Erling Smørgrav utoffs[i] = utoff; 3569bc421551SDag-Erling Smørgrav isdsts[i] = isdst; 3570bc421551SDag-Erling Smørgrav ttisstds[i] = ttisstd; 3571bc421551SDag-Erling Smørgrav ttisuts[i] = ttisut; 3572bc421551SDag-Erling Smørgrav desigidx[i] = j; 3573bc421551SDag-Erling Smørgrav return i; 3574bc421551SDag-Erling Smørgrav } 3575bc421551SDag-Erling Smørgrav 3576bc421551SDag-Erling Smørgrav static void 3577bc421551SDag-Erling Smørgrav leapadd(zic_t t, int correction, int rolling) 3578bc421551SDag-Erling Smørgrav { 3579bc421551SDag-Erling Smørgrav register int i; 3580bc421551SDag-Erling Smørgrav 3581bc421551SDag-Erling Smørgrav if (TZ_MAX_LEAPS <= leapcnt) { 3582bc421551SDag-Erling Smørgrav error(_("too many leap seconds")); 3583bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3584bc421551SDag-Erling Smørgrav } 3585bc421551SDag-Erling Smørgrav if (rolling && (lo_time != min_time || hi_time != max_time)) { 3586bc421551SDag-Erling Smørgrav error(_("Rolling leap seconds not supported with -r")); 3587bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3588bc421551SDag-Erling Smørgrav } 3589bc421551SDag-Erling Smørgrav for (i = 0; i < leapcnt; ++i) 3590bc421551SDag-Erling Smørgrav if (t <= trans[i]) 3591bc421551SDag-Erling Smørgrav break; 3592bc421551SDag-Erling Smørgrav memmove(&trans[i + 1], &trans[i], (leapcnt - i) * sizeof *trans); 3593bc421551SDag-Erling Smørgrav memmove(&corr[i + 1], &corr[i], (leapcnt - i) * sizeof *corr); 3594bc421551SDag-Erling Smørgrav memmove(&roll[i + 1], &roll[i], (leapcnt - i) * sizeof *roll); 3595bc421551SDag-Erling Smørgrav trans[i] = t; 3596bc421551SDag-Erling Smørgrav corr[i] = correction; 3597bc421551SDag-Erling Smørgrav roll[i] = rolling; 3598bc421551SDag-Erling Smørgrav ++leapcnt; 3599bc421551SDag-Erling Smørgrav } 3600bc421551SDag-Erling Smørgrav 3601bc421551SDag-Erling Smørgrav static void 3602bc421551SDag-Erling Smørgrav adjleap(void) 3603bc421551SDag-Erling Smørgrav { 3604bc421551SDag-Erling Smørgrav register int i; 3605bc421551SDag-Erling Smørgrav register zic_t last = 0; 3606bc421551SDag-Erling Smørgrav register zic_t prevtrans = 0; 3607bc421551SDag-Erling Smørgrav 3608bc421551SDag-Erling Smørgrav /* 3609bc421551SDag-Erling Smørgrav ** propagate leap seconds forward 3610bc421551SDag-Erling Smørgrav */ 3611bc421551SDag-Erling Smørgrav for (i = 0; i < leapcnt; ++i) { 3612bc421551SDag-Erling Smørgrav if (trans[i] - prevtrans < 28 * SECSPERDAY) { 3613bc421551SDag-Erling Smørgrav error(_("Leap seconds too close together")); 3614bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3615bc421551SDag-Erling Smørgrav } 3616bc421551SDag-Erling Smørgrav prevtrans = trans[i]; 3617bc421551SDag-Erling Smørgrav trans[i] = tadd(trans[i], last); 3618bc421551SDag-Erling Smørgrav last = corr[i] += last; 3619bc421551SDag-Erling Smørgrav } 3620bc421551SDag-Erling Smørgrav 3621bc421551SDag-Erling Smørgrav if (0 <= leapexpires) { 3622bc421551SDag-Erling Smørgrav leapexpires = oadd(leapexpires, last); 3623bc421551SDag-Erling Smørgrav if (! (leapcnt == 0 || (trans[leapcnt - 1] < leapexpires))) { 3624bc421551SDag-Erling Smørgrav error(_("last Leap time does not precede Expires time")); 3625bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3626bc421551SDag-Erling Smørgrav } 3627bc421551SDag-Erling Smørgrav } 3628bc421551SDag-Erling Smørgrav } 3629bc421551SDag-Erling Smørgrav 3630bc421551SDag-Erling Smørgrav /* Is A a space character in the C locale? */ 3631bc421551SDag-Erling Smørgrav static bool 3632bc421551SDag-Erling Smørgrav is_space(char a) 3633bc421551SDag-Erling Smørgrav { 3634bc421551SDag-Erling Smørgrav switch (a) { 3635bc421551SDag-Erling Smørgrav default: 3636bc421551SDag-Erling Smørgrav return false; 3637bc421551SDag-Erling Smørgrav case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': 3638bc421551SDag-Erling Smørgrav return true; 3639bc421551SDag-Erling Smørgrav } 3640bc421551SDag-Erling Smørgrav } 3641bc421551SDag-Erling Smørgrav 3642bc421551SDag-Erling Smørgrav /* Is A an alphabetic character in the C locale? */ 3643bc421551SDag-Erling Smørgrav static bool 3644bc421551SDag-Erling Smørgrav is_alpha(char a) 3645bc421551SDag-Erling Smørgrav { 3646bc421551SDag-Erling Smørgrav switch (a) { 3647bc421551SDag-Erling Smørgrav default: 3648bc421551SDag-Erling Smørgrav return false; 3649bc421551SDag-Erling Smørgrav case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 3650bc421551SDag-Erling Smørgrav case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': 3651bc421551SDag-Erling Smørgrav case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': 3652bc421551SDag-Erling Smørgrav case 'V': case 'W': case 'X': case 'Y': case 'Z': 3653bc421551SDag-Erling Smørgrav case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': 3654bc421551SDag-Erling Smørgrav case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': 3655bc421551SDag-Erling Smørgrav case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': 3656bc421551SDag-Erling Smørgrav case 'v': case 'w': case 'x': case 'y': case 'z': 3657bc421551SDag-Erling Smørgrav return true; 3658bc421551SDag-Erling Smørgrav } 3659bc421551SDag-Erling Smørgrav } 3660bc421551SDag-Erling Smørgrav 3661bc421551SDag-Erling Smørgrav /* If A is an uppercase character in the C locale, return its lowercase 3662bc421551SDag-Erling Smørgrav counterpart. Otherwise, return A. */ 3663bc421551SDag-Erling Smørgrav static char 3664bc421551SDag-Erling Smørgrav lowerit(char a) 3665bc421551SDag-Erling Smørgrav { 3666bc421551SDag-Erling Smørgrav switch (a) { 3667bc421551SDag-Erling Smørgrav default: return a; 3668bc421551SDag-Erling Smørgrav case 'A': return 'a'; case 'B': return 'b'; case 'C': return 'c'; 3669bc421551SDag-Erling Smørgrav case 'D': return 'd'; case 'E': return 'e'; case 'F': return 'f'; 3670bc421551SDag-Erling Smørgrav case 'G': return 'g'; case 'H': return 'h'; case 'I': return 'i'; 3671bc421551SDag-Erling Smørgrav case 'J': return 'j'; case 'K': return 'k'; case 'L': return 'l'; 3672bc421551SDag-Erling Smørgrav case 'M': return 'm'; case 'N': return 'n'; case 'O': return 'o'; 3673bc421551SDag-Erling Smørgrav case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; 3674bc421551SDag-Erling Smørgrav case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; 3675bc421551SDag-Erling Smørgrav case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; 3676bc421551SDag-Erling Smørgrav case 'Y': return 'y'; case 'Z': return 'z'; 3677bc421551SDag-Erling Smørgrav } 3678bc421551SDag-Erling Smørgrav } 3679bc421551SDag-Erling Smørgrav 3680bc421551SDag-Erling Smørgrav /* case-insensitive equality */ 3681*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static bool 3682bc421551SDag-Erling Smørgrav ciequal(register const char *ap, register const char *bp) 3683bc421551SDag-Erling Smørgrav { 3684bc421551SDag-Erling Smørgrav while (lowerit(*ap) == lowerit(*bp++)) 3685bc421551SDag-Erling Smørgrav if (*ap++ == '\0') 3686bc421551SDag-Erling Smørgrav return true; 3687bc421551SDag-Erling Smørgrav return false; 3688bc421551SDag-Erling Smørgrav } 3689bc421551SDag-Erling Smørgrav 3690*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static bool 3691bc421551SDag-Erling Smørgrav itsabbr(register const char *abbr, register const char *word) 3692bc421551SDag-Erling Smørgrav { 3693bc421551SDag-Erling Smørgrav if (lowerit(*abbr) != lowerit(*word)) 3694bc421551SDag-Erling Smørgrav return false; 3695bc421551SDag-Erling Smørgrav ++word; 3696bc421551SDag-Erling Smørgrav while (*++abbr != '\0') 3697bc421551SDag-Erling Smørgrav do { 3698bc421551SDag-Erling Smørgrav if (*word == '\0') 3699bc421551SDag-Erling Smørgrav return false; 3700bc421551SDag-Erling Smørgrav } while (lowerit(*word++) != lowerit(*abbr)); 3701bc421551SDag-Erling Smørgrav return true; 3702bc421551SDag-Erling Smørgrav } 3703bc421551SDag-Erling Smørgrav 3704bc421551SDag-Erling Smørgrav /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ 3705bc421551SDag-Erling Smørgrav 3706*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static bool 3707bc421551SDag-Erling Smørgrav ciprefix(char const *abbr, char const *word) 3708bc421551SDag-Erling Smørgrav { 3709bc421551SDag-Erling Smørgrav do 3710bc421551SDag-Erling Smørgrav if (!*abbr) 3711bc421551SDag-Erling Smørgrav return true; 3712bc421551SDag-Erling Smørgrav while (lowerit(*abbr++) == lowerit(*word++)); 3713bc421551SDag-Erling Smørgrav 3714bc421551SDag-Erling Smørgrav return false; 3715bc421551SDag-Erling Smørgrav } 3716bc421551SDag-Erling Smørgrav 3717bc421551SDag-Erling Smørgrav static const struct lookup * 3718bc421551SDag-Erling Smørgrav byword(const char *word, const struct lookup *table) 3719bc421551SDag-Erling Smørgrav { 3720bc421551SDag-Erling Smørgrav register const struct lookup * foundlp; 3721bc421551SDag-Erling Smørgrav register const struct lookup * lp; 3722bc421551SDag-Erling Smørgrav 3723bc421551SDag-Erling Smørgrav if (word == NULL || table == NULL) 3724bc421551SDag-Erling Smørgrav return NULL; 3725bc421551SDag-Erling Smørgrav 3726bc421551SDag-Erling Smørgrav /* If TABLE is LASTS and the word starts with "last" followed 3727bc421551SDag-Erling Smørgrav by a non-'-', skip the "last" and look in WDAY_NAMES instead. 3728bc421551SDag-Erling Smørgrav Warn about any usage of the undocumented prefix "last-". */ 3729bc421551SDag-Erling Smørgrav if (table == lasts && ciprefix("last", word) && word[4]) { 3730bc421551SDag-Erling Smørgrav if (word[4] == '-') 3731bc421551SDag-Erling Smørgrav warning(_("\"%s\" is undocumented; use \"last%s\" instead"), 3732bc421551SDag-Erling Smørgrav word, word + 5); 3733bc421551SDag-Erling Smørgrav else { 3734bc421551SDag-Erling Smørgrav word += 4; 3735bc421551SDag-Erling Smørgrav table = wday_names; 3736bc421551SDag-Erling Smørgrav } 3737bc421551SDag-Erling Smørgrav } 3738bc421551SDag-Erling Smørgrav 3739bc421551SDag-Erling Smørgrav /* 3740bc421551SDag-Erling Smørgrav ** Look for exact match. 3741bc421551SDag-Erling Smørgrav */ 3742bc421551SDag-Erling Smørgrav for (lp = table; lp->l_word != NULL; ++lp) 3743bc421551SDag-Erling Smørgrav if (ciequal(word, lp->l_word)) 3744bc421551SDag-Erling Smørgrav return lp; 3745bc421551SDag-Erling Smørgrav /* 3746bc421551SDag-Erling Smørgrav ** Look for inexact match. 3747bc421551SDag-Erling Smørgrav */ 3748bc421551SDag-Erling Smørgrav foundlp = NULL; 3749bc421551SDag-Erling Smørgrav for (lp = table; lp->l_word != NULL; ++lp) 3750bc421551SDag-Erling Smørgrav if (ciprefix(word, lp->l_word)) { 3751bc421551SDag-Erling Smørgrav if (foundlp == NULL) 3752bc421551SDag-Erling Smørgrav foundlp = lp; 3753bc421551SDag-Erling Smørgrav else return NULL; /* multiple inexact matches */ 3754bc421551SDag-Erling Smørgrav } 3755bc421551SDag-Erling Smørgrav 3756bc421551SDag-Erling Smørgrav if (foundlp && noise) { 3757bc421551SDag-Erling Smørgrav /* Warn about any backward-compatibility issue with pre-2017c zic. */ 3758bc421551SDag-Erling Smørgrav bool pre_2017c_match = false; 3759bc421551SDag-Erling Smørgrav for (lp = table; lp->l_word; lp++) 3760bc421551SDag-Erling Smørgrav if (itsabbr(word, lp->l_word)) { 3761bc421551SDag-Erling Smørgrav if (pre_2017c_match) { 3762bc421551SDag-Erling Smørgrav warning(_("\"%s\" is ambiguous in pre-2017c zic"), word); 3763bc421551SDag-Erling Smørgrav break; 3764bc421551SDag-Erling Smørgrav } 3765bc421551SDag-Erling Smørgrav pre_2017c_match = true; 3766bc421551SDag-Erling Smørgrav } 3767bc421551SDag-Erling Smørgrav } 3768bc421551SDag-Erling Smørgrav 3769bc421551SDag-Erling Smørgrav return foundlp; 3770bc421551SDag-Erling Smørgrav } 3771bc421551SDag-Erling Smørgrav 3772bc421551SDag-Erling Smørgrav static int 3773bc421551SDag-Erling Smørgrav getfields(char *cp, char **array, int arrayelts) 3774bc421551SDag-Erling Smørgrav { 3775bc421551SDag-Erling Smørgrav register char * dp; 3776bc421551SDag-Erling Smørgrav register int nsubs; 3777bc421551SDag-Erling Smørgrav 3778bc421551SDag-Erling Smørgrav nsubs = 0; 3779bc421551SDag-Erling Smørgrav for ( ; ; ) { 3780bc421551SDag-Erling Smørgrav char *dstart; 3781bc421551SDag-Erling Smørgrav while (is_space(*cp)) 3782bc421551SDag-Erling Smørgrav ++cp; 3783bc421551SDag-Erling Smørgrav if (*cp == '\0' || *cp == '#') 3784bc421551SDag-Erling Smørgrav break; 3785bc421551SDag-Erling Smørgrav dstart = dp = cp; 3786bc421551SDag-Erling Smørgrav do { 3787bc421551SDag-Erling Smørgrav if ((*dp = *cp++) != '"') 3788bc421551SDag-Erling Smørgrav ++dp; 3789bc421551SDag-Erling Smørgrav else while ((*dp = *cp++) != '"') 3790bc421551SDag-Erling Smørgrav if (*dp != '\0') 3791bc421551SDag-Erling Smørgrav ++dp; 3792bc421551SDag-Erling Smørgrav else { 3793bc421551SDag-Erling Smørgrav error(_("Odd number of quotation marks")); 3794bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3795bc421551SDag-Erling Smørgrav } 3796bc421551SDag-Erling Smørgrav } while (*cp && *cp != '#' && !is_space(*cp)); 3797bc421551SDag-Erling Smørgrav if (is_space(*cp)) 3798bc421551SDag-Erling Smørgrav ++cp; 3799bc421551SDag-Erling Smørgrav *dp = '\0'; 3800bc421551SDag-Erling Smørgrav if (nsubs == arrayelts) { 3801bc421551SDag-Erling Smørgrav error(_("Too many input fields")); 3802bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3803bc421551SDag-Erling Smørgrav } 3804bc421551SDag-Erling Smørgrav array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1); 3805bc421551SDag-Erling Smørgrav } 3806bc421551SDag-Erling Smørgrav return nsubs; 3807bc421551SDag-Erling Smørgrav } 3808bc421551SDag-Erling Smørgrav 380975411d15SDag-Erling Smørgrav ATTRIBUTE_NORETURN static void 3810bc421551SDag-Erling Smørgrav time_overflow(void) 3811bc421551SDag-Erling Smørgrav { 3812bc421551SDag-Erling Smørgrav error(_("time overflow")); 3813bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3814bc421551SDag-Erling Smørgrav } 3815bc421551SDag-Erling Smørgrav 3816*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static zic_t 3817bc421551SDag-Erling Smørgrav oadd(zic_t t1, zic_t t2) 3818bc421551SDag-Erling Smørgrav { 3819bc421551SDag-Erling Smørgrav #ifdef ckd_add 3820bc421551SDag-Erling Smørgrav zic_t sum; 3821bc421551SDag-Erling Smørgrav if (!ckd_add(&sum, t1, t2)) 3822bc421551SDag-Erling Smørgrav return sum; 3823bc421551SDag-Erling Smørgrav #else 3824bc421551SDag-Erling Smørgrav if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) 3825bc421551SDag-Erling Smørgrav return t1 + t2; 3826bc421551SDag-Erling Smørgrav #endif 3827bc421551SDag-Erling Smørgrav time_overflow(); 3828bc421551SDag-Erling Smørgrav } 3829bc421551SDag-Erling Smørgrav 3830*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static zic_t 3831bc421551SDag-Erling Smørgrav tadd(zic_t t1, zic_t t2) 3832bc421551SDag-Erling Smørgrav { 3833bc421551SDag-Erling Smørgrav #ifdef ckd_add 3834bc421551SDag-Erling Smørgrav zic_t sum; 3835bc421551SDag-Erling Smørgrav if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) 3836bc421551SDag-Erling Smørgrav return sum; 3837bc421551SDag-Erling Smørgrav #else 3838bc421551SDag-Erling Smørgrav if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) 3839bc421551SDag-Erling Smørgrav return t1 + t2; 3840bc421551SDag-Erling Smørgrav #endif 3841bc421551SDag-Erling Smørgrav if (t1 == min_time || t1 == max_time) 3842bc421551SDag-Erling Smørgrav return t1; 3843bc421551SDag-Erling Smørgrav time_overflow(); 3844bc421551SDag-Erling Smørgrav } 3845bc421551SDag-Erling Smørgrav 3846bc421551SDag-Erling Smørgrav /* 3847bc421551SDag-Erling Smørgrav ** Given a rule, and a year, compute the date (in seconds since January 1, 3848bc421551SDag-Erling Smørgrav ** 1970, 00:00 LOCAL time) in that year that the rule refers to. 3849bc421551SDag-Erling Smørgrav */ 3850bc421551SDag-Erling Smørgrav 3851bc421551SDag-Erling Smørgrav static zic_t 3852bc421551SDag-Erling Smørgrav rpytime(const struct rule *rp, zic_t wantedy) 3853bc421551SDag-Erling Smørgrav { 3854bc421551SDag-Erling Smørgrav register int m, i; 3855bc421551SDag-Erling Smørgrav register zic_t dayoff; /* with a nod to Margaret O. */ 3856bc421551SDag-Erling Smørgrav register zic_t t, y; 3857bc421551SDag-Erling Smørgrav int yrem; 3858bc421551SDag-Erling Smørgrav 3859bc421551SDag-Erling Smørgrav if (wantedy == ZIC_MIN) 3860bc421551SDag-Erling Smørgrav return min_time; 3861bc421551SDag-Erling Smørgrav if (wantedy == ZIC_MAX) 3862bc421551SDag-Erling Smørgrav return max_time; 3863bc421551SDag-Erling Smørgrav m = TM_JANUARY; 3864bc421551SDag-Erling Smørgrav y = EPOCH_YEAR; 3865bc421551SDag-Erling Smørgrav 3866bc421551SDag-Erling Smørgrav /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT, 3867bc421551SDag-Erling Smørgrav sans overflow. */ 3868bc421551SDag-Erling Smørgrav yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT; 3869bc421551SDag-Erling Smørgrav dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT 3870bc421551SDag-Erling Smørgrav + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0)) 3871bc421551SDag-Erling Smørgrav * DAYSPERREPEAT); 3872bc421551SDag-Erling Smørgrav /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */ 3873bc421551SDag-Erling Smørgrav wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT; 3874bc421551SDag-Erling Smørgrav 3875bc421551SDag-Erling Smørgrav while (wantedy != y) { 3876bc421551SDag-Erling Smørgrav i = len_years[isleap(y)]; 3877bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, i); 3878bc421551SDag-Erling Smørgrav y++; 3879bc421551SDag-Erling Smørgrav } 3880bc421551SDag-Erling Smørgrav while (m != rp->r_month) { 3881bc421551SDag-Erling Smørgrav i = len_months[isleap(y)][m]; 3882bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, i); 3883bc421551SDag-Erling Smørgrav ++m; 3884bc421551SDag-Erling Smørgrav } 3885bc421551SDag-Erling Smørgrav i = rp->r_dayofmonth; 3886bc421551SDag-Erling Smørgrav if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 3887bc421551SDag-Erling Smørgrav if (rp->r_dycode == DC_DOWLEQ) 3888bc421551SDag-Erling Smørgrav --i; 3889bc421551SDag-Erling Smørgrav else { 3890bc421551SDag-Erling Smørgrav error(_("use of 2/29 in non leap-year")); 3891bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3892bc421551SDag-Erling Smørgrav } 3893bc421551SDag-Erling Smørgrav } 3894bc421551SDag-Erling Smørgrav --i; 3895bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, i); 3896bc421551SDag-Erling Smørgrav if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 3897bc421551SDag-Erling Smørgrav /* 3898bc421551SDag-Erling Smørgrav ** Don't trust mod of negative numbers. 3899bc421551SDag-Erling Smørgrav */ 3900bc421551SDag-Erling Smørgrav zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK) 3901bc421551SDag-Erling Smørgrav % DAYSPERWEEK); 3902bc421551SDag-Erling Smørgrav while (wday != rp->r_wday) 3903bc421551SDag-Erling Smørgrav if (rp->r_dycode == DC_DOWGEQ) { 3904bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, 1); 3905bc421551SDag-Erling Smørgrav if (++wday >= DAYSPERWEEK) 3906bc421551SDag-Erling Smørgrav wday = 0; 3907bc421551SDag-Erling Smørgrav ++i; 3908bc421551SDag-Erling Smørgrav } else { 3909bc421551SDag-Erling Smørgrav dayoff = oadd(dayoff, -1); 3910bc421551SDag-Erling Smørgrav if (--wday < 0) 3911bc421551SDag-Erling Smørgrav wday = DAYSPERWEEK - 1; 3912bc421551SDag-Erling Smørgrav --i; 3913bc421551SDag-Erling Smørgrav } 3914bc421551SDag-Erling Smørgrav if (i < 0 || i >= len_months[isleap(y)][m]) { 3915bc421551SDag-Erling Smørgrav if (noise) 3916bc421551SDag-Erling Smørgrav warning(_("rule goes past start/end of month; \ 3917bc421551SDag-Erling Smørgrav will not work with pre-2004 versions of zic")); 3918bc421551SDag-Erling Smørgrav } 3919bc421551SDag-Erling Smørgrav } 3920bc421551SDag-Erling Smørgrav if (dayoff < min_time / SECSPERDAY) 3921bc421551SDag-Erling Smørgrav return min_time; 3922bc421551SDag-Erling Smørgrav if (dayoff > max_time / SECSPERDAY) 3923bc421551SDag-Erling Smørgrav return max_time; 3924bc421551SDag-Erling Smørgrav t = (zic_t) dayoff * SECSPERDAY; 3925bc421551SDag-Erling Smørgrav return tadd(t, rp->r_tod); 3926bc421551SDag-Erling Smørgrav } 3927bc421551SDag-Erling Smørgrav 3928bc421551SDag-Erling Smørgrav static void 3929bc421551SDag-Erling Smørgrav newabbr(const char *string) 3930bc421551SDag-Erling Smørgrav { 3931bc421551SDag-Erling Smørgrav register int i; 3932bc421551SDag-Erling Smørgrav 3933bc421551SDag-Erling Smørgrav if (strcmp(string, GRANDPARENTED) != 0) { 3934bc421551SDag-Erling Smørgrav register const char * cp; 3935bc421551SDag-Erling Smørgrav const char * mp; 3936bc421551SDag-Erling Smørgrav 3937bc421551SDag-Erling Smørgrav cp = string; 3938bc421551SDag-Erling Smørgrav mp = NULL; 3939bc421551SDag-Erling Smørgrav while (is_alpha(*cp) || ('0' <= *cp && *cp <= '9') 3940bc421551SDag-Erling Smørgrav || *cp == '-' || *cp == '+') 3941bc421551SDag-Erling Smørgrav ++cp; 3942bc421551SDag-Erling Smørgrav if (noise && cp - string < 3) 3943bc421551SDag-Erling Smørgrav mp = _("time zone abbreviation has fewer than 3 characters"); 3944bc421551SDag-Erling Smørgrav if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 3945bc421551SDag-Erling Smørgrav mp = _("time zone abbreviation has too many characters"); 3946bc421551SDag-Erling Smørgrav if (*cp != '\0') 3947bc421551SDag-Erling Smørgrav mp = _("time zone abbreviation differs from POSIX standard"); 3948bc421551SDag-Erling Smørgrav if (mp != NULL) 3949bc421551SDag-Erling Smørgrav warning("%s (%s)", mp, string); 3950bc421551SDag-Erling Smørgrav } 3951bc421551SDag-Erling Smørgrav i = strlen(string) + 1; 3952bc421551SDag-Erling Smørgrav if (charcnt + i > TZ_MAX_CHARS) { 3953bc421551SDag-Erling Smørgrav error(_("too many, or too long, time zone abbreviations")); 3954bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 3955bc421551SDag-Erling Smørgrav } 3956bc421551SDag-Erling Smørgrav strcpy(&chars[charcnt], string); 3957bc421551SDag-Erling Smørgrav charcnt += i; 3958bc421551SDag-Erling Smørgrav } 3959bc421551SDag-Erling Smørgrav 3960bc421551SDag-Erling Smørgrav /* Ensure that the directories of ARGNAME exist, by making any missing 3961bc421551SDag-Erling Smørgrav ones. If ANCESTORS, do this only for ARGNAME's ancestors; otherwise, 3962bc421551SDag-Erling Smørgrav do it for ARGNAME too. Exit with failure if there is trouble. 3963bc421551SDag-Erling Smørgrav Do not consider an existing file to be trouble. */ 3964bc421551SDag-Erling Smørgrav static void 3965bc421551SDag-Erling Smørgrav mkdirs(char const *argname, bool ancestors) 3966bc421551SDag-Erling Smørgrav { 39672aad7570SDag-Erling Smørgrav /* 39682aad7570SDag-Erling Smørgrav * If -D was specified, do not create directories. A subsequent 39692aad7570SDag-Erling Smørgrav * file operation will fail and produce an appropriate error 39702aad7570SDag-Erling Smørgrav * message. 39712aad7570SDag-Erling Smørgrav */ 39722aad7570SDag-Erling Smørgrav if (Dflag) 39732aad7570SDag-Erling Smørgrav return; 39742aad7570SDag-Erling Smørgrav 3975bc421551SDag-Erling Smørgrav char *name = estrdup(argname); 3976bc421551SDag-Erling Smørgrav char *cp = name; 3977bc421551SDag-Erling Smørgrav 3978bc421551SDag-Erling Smørgrav /* On MS-Windows systems, do not worry about drive letters or 3979bc421551SDag-Erling Smørgrav backslashes, as this should suffice in practice. Time zone 3980bc421551SDag-Erling Smørgrav names do not use drive letters and backslashes. If the -d 3981bc421551SDag-Erling Smørgrav option of zic does not name an already-existing directory, 3982bc421551SDag-Erling Smørgrav it can use slashes to separate the already-existing 3983bc421551SDag-Erling Smørgrav ancestor prefix from the to-be-created subdirectories. */ 3984bc421551SDag-Erling Smørgrav 3985bc421551SDag-Erling Smørgrav /* Do not mkdir a root directory, as it must exist. */ 3986bc421551SDag-Erling Smørgrav while (*cp == '/') 3987bc421551SDag-Erling Smørgrav cp++; 3988bc421551SDag-Erling Smørgrav 3989bc421551SDag-Erling Smørgrav while (cp && ((cp = strchr(cp, '/')) || !ancestors)) { 3990bc421551SDag-Erling Smørgrav if (cp) 3991bc421551SDag-Erling Smørgrav *cp = '\0'; 3992bc421551SDag-Erling Smørgrav /* 3993bc421551SDag-Erling Smørgrav ** Try to create it. It's OK if creation fails because 3994bc421551SDag-Erling Smørgrav ** the directory already exists, perhaps because some 3995bc421551SDag-Erling Smørgrav ** other process just created it. For simplicity do 3996bc421551SDag-Erling Smørgrav ** not check first whether it already exists, as that 3997bc421551SDag-Erling Smørgrav ** is checked anyway if the mkdir fails. 3998bc421551SDag-Erling Smørgrav */ 3999bc421551SDag-Erling Smørgrav if (mkdir(name, MKDIR_UMASK) != 0) { 4000bc421551SDag-Erling Smørgrav /* Do not report an error if err == EEXIST, because 4001bc421551SDag-Erling Smørgrav some other process might have made the directory 4002bc421551SDag-Erling Smørgrav in the meantime. Likewise for ENOSYS, because 4003bc421551SDag-Erling Smørgrav Solaris 10 mkdir fails with ENOSYS if the 4004bc421551SDag-Erling Smørgrav directory is an automounted mount point. 4005bc421551SDag-Erling Smørgrav Likewise for EACCES, since mkdir can fail 4006bc421551SDag-Erling Smørgrav with EACCES merely because the parent directory 4007bc421551SDag-Erling Smørgrav is unwritable. Likewise for most other error 4008bc421551SDag-Erling Smørgrav numbers. */ 4009bc421551SDag-Erling Smørgrav int err = errno; 4010bc421551SDag-Erling Smørgrav if (err == ELOOP || err == ENAMETOOLONG 4011bc421551SDag-Erling Smørgrav || err == ENOENT || err == ENOTDIR) { 4012bc421551SDag-Erling Smørgrav error(_("%s: Can't create directory %s: %s"), 4013bc421551SDag-Erling Smørgrav progname, name, strerror(err)); 4014bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 4015bc421551SDag-Erling Smørgrav } 4016bc421551SDag-Erling Smørgrav } 4017bc421551SDag-Erling Smørgrav if (cp) 4018bc421551SDag-Erling Smørgrav *cp++ = '/'; 4019bc421551SDag-Erling Smørgrav } 4020bc421551SDag-Erling Smørgrav free(name); 4021bc421551SDag-Erling Smørgrav } 4022bc421551SDag-Erling Smørgrav 4023bc421551SDag-Erling Smørgrav #include <grp.h> 4024bc421551SDag-Erling Smørgrav #include <pwd.h> 4025bc421551SDag-Erling Smørgrav 4026bc421551SDag-Erling Smørgrav static void 4027d5c85ac6SDag-Erling Smørgrav setgroup(gid_t *flag, const char *name) 4028bc421551SDag-Erling Smørgrav { 4029bc421551SDag-Erling Smørgrav struct group *gr; 4030bc421551SDag-Erling Smørgrav 4031bc421551SDag-Erling Smørgrav if (*flag != (gid_t)-1) { 4032bc421551SDag-Erling Smørgrav fprintf(stderr, _("multiple -g flags specified")); 4033bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 4034bc421551SDag-Erling Smørgrav } 4035bc421551SDag-Erling Smørgrav 4036bc421551SDag-Erling Smørgrav gr = getgrnam(name); 4037bc421551SDag-Erling Smørgrav if (gr == 0) { 4038bc421551SDag-Erling Smørgrav char *ep; 4039bc421551SDag-Erling Smørgrav unsigned long ul; 4040bc421551SDag-Erling Smørgrav 4041bc421551SDag-Erling Smørgrav ul = strtoul(name, &ep, 10); 4042bc421551SDag-Erling Smørgrav if (ul == (unsigned long)(gid_t)ul && *ep == '\0') { 4043bc421551SDag-Erling Smørgrav *flag = ul; 4044bc421551SDag-Erling Smørgrav return; 4045bc421551SDag-Erling Smørgrav } 4046bc421551SDag-Erling Smørgrav fprintf(stderr, _("group `%s' not found"), name); 4047bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 4048bc421551SDag-Erling Smørgrav } 4049bc421551SDag-Erling Smørgrav *flag = gr->gr_gid; 4050bc421551SDag-Erling Smørgrav } 4051bc421551SDag-Erling Smørgrav 4052bc421551SDag-Erling Smørgrav static void 4053d5c85ac6SDag-Erling Smørgrav setuser(uid_t *flag, const char *name) 4054bc421551SDag-Erling Smørgrav { 4055bc421551SDag-Erling Smørgrav struct passwd *pw; 4056bc421551SDag-Erling Smørgrav 4057bc421551SDag-Erling Smørgrav if (*flag != (gid_t)-1) { 4058bc421551SDag-Erling Smørgrav fprintf(stderr, _("multiple -u flags specified")); 4059bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 4060bc421551SDag-Erling Smørgrav } 4061bc421551SDag-Erling Smørgrav 4062bc421551SDag-Erling Smørgrav pw = getpwnam(name); 4063bc421551SDag-Erling Smørgrav if (pw == 0) { 4064bc421551SDag-Erling Smørgrav char *ep; 4065bc421551SDag-Erling Smørgrav unsigned long ul; 4066bc421551SDag-Erling Smørgrav 4067bc421551SDag-Erling Smørgrav ul = strtoul(name, &ep, 10); 4068bc421551SDag-Erling Smørgrav if (ul == (unsigned long)(gid_t)ul && *ep == '\0') { 4069bc421551SDag-Erling Smørgrav *flag = ul; 4070bc421551SDag-Erling Smørgrav return; 4071bc421551SDag-Erling Smørgrav } 4072bc421551SDag-Erling Smørgrav fprintf(stderr, _("user `%s' not found"), name); 4073bc421551SDag-Erling Smørgrav exit(EXIT_FAILURE); 4074bc421551SDag-Erling Smørgrav } 4075bc421551SDag-Erling Smørgrav *flag = pw->pw_uid; 4076bc421551SDag-Erling Smørgrav } 4077bc421551SDag-Erling Smørgrav 4078bc421551SDag-Erling Smørgrav /* 4079bc421551SDag-Erling Smørgrav ** UNIX was a registered trademark of The Open Group in 2003. 4080bc421551SDag-Erling Smørgrav */ 4081