1192625Sedwin/* 2192625Sedwin** This file is in the public domain, so clarified as of 3192625Sedwin** 2006-07-17 by Arthur David Olson. 4192625Sedwin*/ 52702Swollman 6214411Sedwinstatic const char elsieid[] = "@(#)zic.c 8.22"; 7192625Sedwin 830829Scharnier#ifndef lint 930829Scharnierstatic const char rcsid[] = 1050479Speter "$FreeBSD: stable/11/contrib/tzcode/zic/zic.c 307358 2016-10-15 12:37:57Z bapt $"; 1130829Scharnier#endif /* not lint */ 1230829Scharnier 132702Swollman#include "private.h" 142702Swollman#include "tzfile.h" 1530829Scharnier#include <err.h> 1630829Scharnier#include <locale.h> 179937Swollman#include <sys/stat.h> /* for umask manifest constants */ 189937Swollman#include <sys/types.h> 199937Swollman#include <unistd.h> 202702Swollman 21192625Sedwin#define ZIC_VERSION '2' 22192625Sedwin 23192625Sedwintypedef int_fast64_t zic_t; 24192625Sedwin 25192625Sedwin#ifndef ZIC_MAX_ABBR_LEN_WO_WARN 26192625Sedwin#define ZIC_MAX_ABBR_LEN_WO_WARN 6 27192625Sedwin#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 28192625Sedwin 29130819Sstefanf#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 30130819Sstefanf 3117214Swollman/* 3217214Swollman** On some ancient hosts, predicates like `isspace(C)' are defined 33192625Sedwin** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, 3417214Swollman** which says they are defined only if C == ((unsigned char) C) || C == EOF. 3569315Scharnier** Neither the C Standard nor POSIX require that `isascii' exist. 3617214Swollman** For portability, we check both ancient and modern requirements. 3717214Swollman** If isascii is not defined, the isascii check succeeds trivially. 3817214Swollman*/ 3917214Swollman#include "ctype.h" 4017214Swollman#ifndef isascii 4117214Swollman#define isascii(x) 1 4217214Swollman#endif 4317214Swollman 44192625Sedwin#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long)) 45192625Sedwin#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */ 46192625Sedwin 47192625Sedwin#define end(cp) (strchr((cp), '\0')) 48192625Sedwin 492702Swollmanstruct rule { 502702Swollman const char * r_filename; 512702Swollman int r_linenum; 522702Swollman const char * r_name; 532702Swollman 542702Swollman int r_loyear; /* for example, 1986 */ 552702Swollman int r_hiyear; /* for example, 1986 */ 562702Swollman const char * r_yrtype; 57192625Sedwin int r_lowasnum; 58192625Sedwin int r_hiwasnum; 592702Swollman 602702Swollman int r_month; /* 0..11 */ 612702Swollman 622702Swollman int r_dycode; /* see below */ 632702Swollman int r_dayofmonth; 642702Swollman int r_wday; 652702Swollman 662702Swollman long r_tod; /* time from midnight */ 672702Swollman int r_todisstd; /* above is standard time if TRUE */ 682702Swollman /* or wall clock time if FALSE */ 699937Swollman int r_todisgmt; /* above is GMT if TRUE */ 709937Swollman /* or local time if FALSE */ 712702Swollman long r_stdoff; /* offset from standard time */ 722702Swollman const char * r_abbrvar; /* variable part of abbreviation */ 732702Swollman 742702Swollman int r_todo; /* a rule to do (used in outzone) */ 75192625Sedwin zic_t r_temp; /* used in outzone */ 762702Swollman}; 772702Swollman 782702Swollman/* 792702Swollman** r_dycode r_dayofmonth r_wday 802702Swollman*/ 812702Swollman 822702Swollman#define DC_DOM 0 /* 1..31 */ /* unused */ 832702Swollman#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 842702Swollman#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 852702Swollman 862702Swollmanstruct zone { 872702Swollman const char * z_filename; 882702Swollman int z_linenum; 892702Swollman 902702Swollman const char * z_name; 912702Swollman long z_gmtoff; 922702Swollman const char * z_rule; 932702Swollman const char * z_format; 942702Swollman 952702Swollman long z_stdoff; 962702Swollman 972702Swollman struct rule * z_rules; 982702Swollman int z_nrules; 992702Swollman 1002702Swollman struct rule z_untilrule; 101192625Sedwin zic_t z_untiltime; 1022702Swollman}; 1032702Swollman 104192625Sedwinstatic void addtt(zic_t starttime, int type); 105192625Sedwinstatic int addtype(long gmtoff, const char * abbr, int isdst, 106192625Sedwin int ttisstd, int ttisgmt); 107192625Sedwinstatic void leapadd(zic_t t, int positive, int rolling, int count); 108192625Sedwinstatic void adjleap(void); 109192625Sedwinstatic void associate(void); 110192625Sedwinstatic int ciequal(const char * ap, const char * bp); 111192625Sedwinstatic void convert(long val, char * buf); 112192625Sedwinstatic void convert64(zic_t val, char * buf); 113192625Sedwinstatic void dolink(const char * fromfield, const char * tofield); 114192625Sedwinstatic void doabbr(char * abbr, const char * format, 115192625Sedwin const char * letters, int isdst, int doquotes); 116192625Sedwinstatic void eat(const char * name, int num); 117192625Sedwinstatic void eats(const char * name, int num, 118192625Sedwin const char * rname, int rnum); 119192625Sedwinstatic long eitol(int i); 120192625Sedwinstatic void error(const char * message); 121192625Sedwinstatic char ** getfields(char * buf); 122192625Sedwinstatic long gethms(const char * string, const char * errstrng, 123192625Sedwin int signable); 124192625Sedwinstatic void infile(const char * filename); 125192625Sedwinstatic void inleap(char ** fields, int nfields); 126192625Sedwinstatic void inlink(char ** fields, int nfields); 127192625Sedwinstatic void inrule(char ** fields, int nfields); 128192625Sedwinstatic int inzcont(char ** fields, int nfields); 129192625Sedwinstatic int inzone(char ** fields, int nfields); 130192625Sedwinstatic int inzsub(char ** fields, int nfields, int iscont); 131192625Sedwinstatic int is32(zic_t x); 132192625Sedwinstatic int itsabbr(const char * abbr, const char * word); 133192625Sedwinstatic int itsdir(const char * name); 134192625Sedwinstatic int lowerit(int c); 135192625Sedwinstatic char * memcheck(char * tocheck); 136192625Sedwinstatic int mkdirs(char * filename); 137192625Sedwinstatic void newabbr(const char * abbr); 138192625Sedwinstatic long oadd(long t1, long t2); 139192625Sedwinstatic void outzone(const struct zone * zp, int ntzones); 140192625Sedwinstatic void puttzcode(long code, FILE * fp); 141192625Sedwinstatic void puttzcode64(zic_t code, FILE * fp); 142192625Sedwinstatic int rcomp(const void * leftp, const void * rightp); 143192625Sedwinstatic zic_t rpytime(const struct rule * rp, int wantedy); 144192625Sedwinstatic void rulesub(struct rule * rp, 1459937Swollman const char * loyearp, const char * hiyearp, 1469937Swollman const char * typep, const char * monthp, 147192625Sedwin const char * dayp, const char * timep); 148192625Sedwinstatic int stringoffset(char * result, long offset); 149192625Sedwinstatic int stringrule(char * result, const struct rule * rp, 150192625Sedwin long dstoff, long gmtoff); 151192625Sedwinstatic void stringzone(char * result, 152192625Sedwin const struct zone * zp, int ntzones); 153192625Sedwinstatic void setboundaries(void); 154192625Sedwinstatic void setgroup(gid_t *flag, const char *name); 155192625Sedwinstatic void setuser(uid_t *flag, const char *name); 156192625Sedwinstatic zic_t tadd(zic_t t1, long t2); 157192625Sedwinstatic void usage(FILE *stream, int status); 158192625Sedwinstatic void writezone(const char * name, const char * string); 159192625Sedwinstatic int yearistype(int year, const char * type); 1602702Swollman 1612702Swollmanstatic int charcnt; 1622702Swollmanstatic int errors; 1632702Swollmanstatic const char * filename; 1642702Swollmanstatic int leapcnt; 165192625Sedwinstatic int leapseen; 166192625Sedwinstatic int leapminyear; 167192625Sedwinstatic int leapmaxyear; 1682702Swollmanstatic int linenum; 169192625Sedwinstatic int max_abbrvar_len; 170192625Sedwinstatic int max_format_len; 171192625Sedwinstatic zic_t max_time; 1722702Swollmanstatic int max_year; 173192625Sedwinstatic zic_t min_time; 1742702Swollmanstatic int min_year; 175192625Sedwinstatic zic_t min_time; 1762702Swollmanstatic int noise; 1772702Swollmanstatic const char * rfilename; 1782702Swollmanstatic int rlinenum; 1792702Swollmanstatic int timecnt; 1802702Swollmanstatic int typecnt; 1812702Swollman 1822702Swollman/* 1832702Swollman** Line codes. 1842702Swollman*/ 1852702Swollman 1862702Swollman#define LC_RULE 0 1872702Swollman#define LC_ZONE 1 1882702Swollman#define LC_LINK 2 1892702Swollman#define LC_LEAP 3 1902702Swollman 1912702Swollman/* 1922702Swollman** Which fields are which on a Zone line. 1932702Swollman*/ 1942702Swollman 1952702Swollman#define ZF_NAME 1 1962702Swollman#define ZF_GMTOFF 2 1972702Swollman#define ZF_RULE 3 1982702Swollman#define ZF_FORMAT 4 1992702Swollman#define ZF_TILYEAR 5 2002702Swollman#define ZF_TILMONTH 6 2012702Swollman#define ZF_TILDAY 7 2022702Swollman#define ZF_TILTIME 8 2032702Swollman#define ZONE_MINFIELDS 5 2042702Swollman#define ZONE_MAXFIELDS 9 2052702Swollman 2062702Swollman/* 2072702Swollman** Which fields are which on a Zone continuation line. 2082702Swollman*/ 2092702Swollman 2102702Swollman#define ZFC_GMTOFF 0 2112702Swollman#define ZFC_RULE 1 2122702Swollman#define ZFC_FORMAT 2 2132702Swollman#define ZFC_TILYEAR 3 2142702Swollman#define ZFC_TILMONTH 4 2152702Swollman#define ZFC_TILDAY 5 2162702Swollman#define ZFC_TILTIME 6 2172702Swollman#define ZONEC_MINFIELDS 3 2182702Swollman#define ZONEC_MAXFIELDS 7 2192702Swollman 2202702Swollman/* 2212702Swollman** Which files are which on a Rule line. 2222702Swollman*/ 2232702Swollman 2242702Swollman#define RF_NAME 1 2252702Swollman#define RF_LOYEAR 2 2262702Swollman#define RF_HIYEAR 3 2272702Swollman#define RF_COMMAND 4 2282702Swollman#define RF_MONTH 5 2292702Swollman#define RF_DAY 6 2302702Swollman#define RF_TOD 7 2312702Swollman#define RF_STDOFF 8 2322702Swollman#define RF_ABBRVAR 9 2332702Swollman#define RULE_FIELDS 10 2342702Swollman 2352702Swollman/* 2362702Swollman** Which fields are which on a Link line. 2372702Swollman*/ 2382702Swollman 2392702Swollman#define LF_FROM 1 2402702Swollman#define LF_TO 2 2412702Swollman#define LINK_FIELDS 3 2422702Swollman 2432702Swollman/* 2442702Swollman** Which fields are which on a Leap line. 2452702Swollman*/ 2462702Swollman 2472702Swollman#define LP_YEAR 1 2482702Swollman#define LP_MONTH 2 2492702Swollman#define LP_DAY 3 2502702Swollman#define LP_TIME 4 2512702Swollman#define LP_CORR 5 2522702Swollman#define LP_ROLL 6 2532702Swollman#define LEAP_FIELDS 7 2542702Swollman 2552702Swollman/* 2562702Swollman** Year synonyms. 2572702Swollman*/ 2582702Swollman 2592702Swollman#define YR_MINIMUM 0 2602702Swollman#define YR_MAXIMUM 1 2612702Swollman#define YR_ONLY 2 2622702Swollman 2632702Swollmanstatic struct rule * rules; 2642702Swollmanstatic int nrules; /* number of rules */ 2652702Swollman 2662702Swollmanstatic struct zone * zones; 2672702Swollmanstatic int nzones; /* number of zones */ 2682702Swollman 2692702Swollmanstruct link { 2702702Swollman const char * l_filename; 2712702Swollman int l_linenum; 2722702Swollman const char * l_from; 2732702Swollman const char * l_to; 2742702Swollman}; 2752702Swollman 2762702Swollmanstatic struct link * links; 2772702Swollmanstatic int nlinks; 2782702Swollman 2792702Swollmanstruct lookup { 2802702Swollman const char * l_word; 2812702Swollman const int l_value; 2822702Swollman}; 2832702Swollman 284192625Sedwinstatic struct lookup const * byword(const char * string, 285192625Sedwin const struct lookup * lp); 2862702Swollman 2872702Swollmanstatic struct lookup const line_codes[] = { 2882702Swollman { "Rule", LC_RULE }, 2892702Swollman { "Zone", LC_ZONE }, 2902702Swollman { "Link", LC_LINK }, 2912702Swollman { "Leap", LC_LEAP }, 2922702Swollman { NULL, 0} 2932702Swollman}; 2942702Swollman 2952702Swollmanstatic struct lookup const mon_names[] = { 2962702Swollman { "January", TM_JANUARY }, 2972702Swollman { "February", TM_FEBRUARY }, 2982702Swollman { "March", TM_MARCH }, 2992702Swollman { "April", TM_APRIL }, 3002702Swollman { "May", TM_MAY }, 3012702Swollman { "June", TM_JUNE }, 3022702Swollman { "July", TM_JULY }, 3032702Swollman { "August", TM_AUGUST }, 3042702Swollman { "September", TM_SEPTEMBER }, 3052702Swollman { "October", TM_OCTOBER }, 3062702Swollman { "November", TM_NOVEMBER }, 3072702Swollman { "December", TM_DECEMBER }, 3082702Swollman { NULL, 0 } 3092702Swollman}; 3102702Swollman 3112702Swollmanstatic struct lookup const wday_names[] = { 3122702Swollman { "Sunday", TM_SUNDAY }, 3132702Swollman { "Monday", TM_MONDAY }, 3142702Swollman { "Tuesday", TM_TUESDAY }, 3152702Swollman { "Wednesday", TM_WEDNESDAY }, 3162702Swollman { "Thursday", TM_THURSDAY }, 3172702Swollman { "Friday", TM_FRIDAY }, 3182702Swollman { "Saturday", TM_SATURDAY }, 3192702Swollman { NULL, 0 } 3202702Swollman}; 3212702Swollman 3222702Swollmanstatic struct lookup const lasts[] = { 3232702Swollman { "last-Sunday", TM_SUNDAY }, 3242702Swollman { "last-Monday", TM_MONDAY }, 3252702Swollman { "last-Tuesday", TM_TUESDAY }, 3262702Swollman { "last-Wednesday", TM_WEDNESDAY }, 3272702Swollman { "last-Thursday", TM_THURSDAY }, 3282702Swollman { "last-Friday", TM_FRIDAY }, 3292702Swollman { "last-Saturday", TM_SATURDAY }, 3302702Swollman { NULL, 0 } 3312702Swollman}; 3322702Swollman 3332702Swollmanstatic struct lookup const begin_years[] = { 3342702Swollman { "minimum", YR_MINIMUM }, 3352702Swollman { "maximum", YR_MAXIMUM }, 3362702Swollman { NULL, 0 } 3372702Swollman}; 3382702Swollman 3392702Swollmanstatic struct lookup const end_years[] = { 3402702Swollman { "minimum", YR_MINIMUM }, 3412702Swollman { "maximum", YR_MAXIMUM }, 3422702Swollman { "only", YR_ONLY }, 3432702Swollman { NULL, 0 } 3442702Swollman}; 3452702Swollman 3462702Swollmanstatic struct lookup const leap_types[] = { 3472702Swollman { "Rolling", TRUE }, 3482702Swollman { "Stationary", FALSE }, 3492702Swollman { NULL, 0 } 3502702Swollman}; 3512702Swollman 3522702Swollmanstatic const int len_months[2][MONSPERYEAR] = { 3532702Swollman { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 3542702Swollman { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 3552702Swollman}; 3562702Swollman 3572702Swollmanstatic const int len_years[2] = { 3582702Swollman DAYSPERNYEAR, DAYSPERLYEAR 3592702Swollman}; 3602702Swollman 36117214Swollmanstatic struct attype { 362192625Sedwin zic_t at; 36317214Swollman unsigned char type; 36417214Swollman} attypes[TZ_MAX_TIMES]; 3652702Swollmanstatic long gmtoffs[TZ_MAX_TYPES]; 3662702Swollmanstatic char isdsts[TZ_MAX_TYPES]; 3672702Swollmanstatic unsigned char abbrinds[TZ_MAX_TYPES]; 3682702Swollmanstatic char ttisstds[TZ_MAX_TYPES]; 3699937Swollmanstatic char ttisgmts[TZ_MAX_TYPES]; 3702702Swollmanstatic char chars[TZ_MAX_CHARS]; 371192625Sedwinstatic zic_t trans[TZ_MAX_LEAPS]; 3722702Swollmanstatic long corr[TZ_MAX_LEAPS]; 3732702Swollmanstatic char roll[TZ_MAX_LEAPS]; 3742702Swollman 3752702Swollman/* 3762702Swollman** Memory allocation. 3772702Swollman*/ 3782702Swollman 3792702Swollmanstatic char * 3802702Swollmanmemcheck(ptr) 3812702Swollmanchar * const ptr; 3822702Swollman{ 38330829Scharnier if (ptr == NULL) 38430829Scharnier errx(EXIT_FAILURE, _("memory exhausted")); 3852702Swollman return ptr; 3862702Swollman} 3872702Swollman 3882702Swollman#define emalloc(size) memcheck(imalloc(size)) 3899937Swollman#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 3902702Swollman#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 3919937Swollman#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 3922702Swollman 3932702Swollman/* 3942702Swollman** Error handling. 3952702Swollman*/ 3962702Swollman 3972702Swollmanstatic void 3982702Swollmaneats(name, num, rname, rnum) 3992702Swollmanconst char * const name; 4002702Swollmanconst int num; 4012702Swollmanconst char * const rname; 4022702Swollmanconst int rnum; 4032702Swollman{ 4042702Swollman filename = name; 4052702Swollman linenum = num; 4062702Swollman rfilename = rname; 4072702Swollman rlinenum = rnum; 4082702Swollman} 4092702Swollman 4102702Swollmanstatic void 4112702Swollmaneat(name, num) 4122702Swollmanconst char * const name; 4132702Swollmanconst int num; 4142702Swollman{ 4152702Swollman eats(name, num, (char *) NULL, -1); 4162702Swollman} 4172702Swollman 4182702Swollmanstatic void 4192702Swollmanerror(string) 4202702Swollmanconst char * const string; 4212702Swollman{ 4222702Swollman /* 4232702Swollman ** Match the format of "cc" to allow sh users to 4249937Swollman ** zic ... 2>&1 | error -t "*" -v 4252702Swollman ** on BSD systems. 4262702Swollman */ 42717214Swollman (void) fprintf(stderr, _("\"%s\", line %d: %s"), 4282702Swollman filename, linenum, string); 4292702Swollman if (rfilename != NULL) 43017214Swollman (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), 4312702Swollman rfilename, rlinenum); 4322702Swollman (void) fprintf(stderr, "\n"); 4332702Swollman ++errors; 4342702Swollman} 4352702Swollman 4362702Swollmanstatic void 43717214Swollmanwarning(string) 43817214Swollmanconst char * const string; 43917214Swollman{ 44017214Swollman char * cp; 44117214Swollman 44242997Swollman cp = ecpyalloc(_("warning: ")); 44317214Swollman cp = ecatalloc(cp, string); 44442997Swollman error(cp); 44517214Swollman ifree(cp); 44617214Swollman --errors; 44717214Swollman} 44817214Swollman 44917214Swollmanstatic void 450192625Sedwinusage(FILE *stream, int status) 451192625Sedwin { 452192625Sedwin (void) fprintf(stream, _("usage is zic \ 453192625Sedwin[ --version ] [--help] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\ 454192625Sedwin\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\ 455192625Sedwin\n\ 456192625SedwinReport bugs to tz@elsie.nci.nih.gov.\n")); 457192625Sedwin exit(status); 4582702Swollman} 4592702Swollman 4602702Swollmanstatic const char * psxrules; 4612702Swollmanstatic const char * lcltime; 4622702Swollmanstatic const char * directory; 4632702Swollmanstatic const char * leapsec; 4642702Swollmanstatic const char * yitcommand; 46542997Swollmanstatic int Dflag; 46643006Swollmanstatic uid_t uflag = (uid_t)-1; 46742997Swollmanstatic gid_t gflag = (gid_t)-1; 46842997Swollmanstatic mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH 46942997Swollman | S_IWUSR); 4702702Swollman 4712702Swollmanint 4722702Swollmanmain(argc, argv) 4732702Swollmanint argc; 4742702Swollmanchar * argv[]; 4752702Swollman{ 4769937Swollman register int i; 4779937Swollman register int j; 4782702Swollman register int c; 4792702Swollman 4802702Swollman#ifdef unix 4819937Swollman (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 4822702Swollman#endif /* defined unix */ 483192625Sedwin#if HAVE_GETTEXT 484192625Sedwin (void) setlocale(LC_ALL, ""); 48517214Swollman#ifdef TZ_DOMAINDIR 48617214Swollman (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 48717214Swollman#endif /* defined TEXTDOMAINDIR */ 48817214Swollman (void) textdomain(TZ_DOMAIN); 489192625Sedwin#endif /* HAVE_GETTEXT */ 490192625Sedwin if (TYPE_BIT(zic_t) < 64) { 491192625Sedwin (void) fprintf(stderr, "zic: %s\n", 492192625Sedwin _("wild compilation-time specification of zic_t")); 493192625Sedwin exit(EXIT_FAILURE); 494192625Sedwin } 495130819Sstefanf for (i = 1; i < argc; ++i) 496130819Sstefanf if (strcmp(argv[i], "--version") == 0) { 497130819Sstefanf errx(EXIT_SUCCESS, "%s", elsieid); 498192625Sedwin } else if (strcmp(argv[i], "--help") == 0) { 499192625Sedwin usage(stdout, EXIT_SUCCESS); 500130819Sstefanf } 50142997Swollman while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1) 5022702Swollman switch (c) { 5032702Swollman default: 504192625Sedwin usage(stderr, EXIT_FAILURE); 50542997Swollman case 'D': 50642997Swollman Dflag = 1; 50742997Swollman break; 5082702Swollman case 'd': 5092702Swollman if (directory == NULL) 5102702Swollman directory = optarg; 51130829Scharnier else 51230829Scharnier errx(EXIT_FAILURE, 51330829Scharnier_("more than one -d option specified")); 5142702Swollman break; 51542997Swollman case 'g': 51642997Swollman setgroup(&gflag, optarg); 51742997Swollman break; 5182702Swollman case 'l': 5192702Swollman if (lcltime == NULL) 5202702Swollman lcltime = optarg; 52130829Scharnier else 52230829Scharnier errx(EXIT_FAILURE, 52330829Scharnier_("more than one -l option specified")); 5242702Swollman break; 52542997Swollman case 'm': 52642997Swollman { 52742997Swollman void *set = setmode(optarg); 528111414Smikeh if (set == NULL) 529111414Smikeh errx(EXIT_FAILURE, 530111414Smikeh_("invalid file mode")); 531136708Sru mflag = getmode(set, mflag); 532111414Smikeh free(set); 53342997Swollman break; 53442997Swollman } 5352702Swollman case 'p': 5362702Swollman if (psxrules == NULL) 5372702Swollman psxrules = optarg; 53830829Scharnier else 53930829Scharnier errx(EXIT_FAILURE, 54030829Scharnier_("more than one -p option specified")); 5412702Swollman break; 54242997Swollman case 'u': 54342997Swollman setuser(&uflag, optarg); 54442997Swollman break; 5452702Swollman case 'y': 5462702Swollman if (yitcommand == NULL) 5472702Swollman yitcommand = optarg; 54830829Scharnier else 54930829Scharnier errx(EXIT_FAILURE, 55030829Scharnier_("more than one -y option specified")); 5512702Swollman break; 5522702Swollman case 'L': 5532702Swollman if (leapsec == NULL) 5542702Swollman leapsec = optarg; 55530829Scharnier else 55630829Scharnier errx(EXIT_FAILURE, 55730829Scharnier_("more than one -L option specified")); 5582702Swollman break; 5592702Swollman case 'v': 5602702Swollman noise = TRUE; 5612702Swollman break; 5622702Swollman case 's': 563192625Sedwin (void) printf("zic: -s ignored\n"); 5642702Swollman break; 5652702Swollman } 5662702Swollman if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 567192625Sedwin usage(stderr, EXIT_FAILURE); /* usage message by request */ 5682702Swollman if (directory == NULL) 5692702Swollman directory = TZDIR; 5702702Swollman if (yitcommand == NULL) 5712702Swollman yitcommand = "yearistype"; 5722702Swollman 5732702Swollman setboundaries(); 5742702Swollman 5752702Swollman if (optind < argc && leapsec != NULL) { 5762702Swollman infile(leapsec); 5772702Swollman adjleap(); 5782702Swollman } 5792702Swollman 5802702Swollman for (i = optind; i < argc; ++i) 5812702Swollman infile(argv[i]); 5822702Swollman if (errors) 583192625Sedwin exit(EXIT_FAILURE); 5842702Swollman associate(); 5852702Swollman for (i = 0; i < nzones; i = j) { 5862702Swollman /* 5872702Swollman ** Find the next non-continuation zone entry. 5882702Swollman */ 5892702Swollman for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 5902702Swollman continue; 5912702Swollman outzone(&zones[i], j - i); 5922702Swollman } 5932702Swollman /* 5942702Swollman ** Make links. 5952702Swollman */ 596130819Sstefanf for (i = 0; i < nlinks; ++i) { 597130819Sstefanf eat(links[i].l_filename, links[i].l_linenum); 5982702Swollman dolink(links[i].l_from, links[i].l_to); 599192625Sedwin if (noise) 600192625Sedwin for (j = 0; j < nlinks; ++j) 601192625Sedwin if (strcmp(links[i].l_to, 602192625Sedwin links[j].l_from) == 0) 603192625Sedwin warning(_("link to link")); 604130819Sstefanf } 605130819Sstefanf if (lcltime != NULL) { 606130819Sstefanf eat("command line", 1); 6072702Swollman dolink(lcltime, TZDEFAULT); 608130819Sstefanf } 609130819Sstefanf if (psxrules != NULL) { 610130819Sstefanf eat("command line", 1); 6112702Swollman dolink(psxrules, TZDEFRULES); 612130819Sstefanf } 6132702Swollman return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 6142702Swollman} 6152702Swollman 6162702Swollmanstatic void 617192625Sedwindolink(fromfield, tofield) 618192625Sedwinconst char * const fromfield; 619192625Sedwinconst char * const tofield; 6202702Swollman{ 6212702Swollman register char * fromname; 6222702Swollman register char * toname; 6232702Swollman 624192625Sedwin if (fromfield[0] == '/') 625192625Sedwin fromname = ecpyalloc(fromfield); 6262702Swollman else { 6272702Swollman fromname = ecpyalloc(directory); 6282702Swollman fromname = ecatalloc(fromname, "/"); 629192625Sedwin fromname = ecatalloc(fromname, fromfield); 6302702Swollman } 631192625Sedwin if (tofield[0] == '/') 632192625Sedwin toname = ecpyalloc(tofield); 6332702Swollman else { 6342702Swollman toname = ecpyalloc(directory); 6352702Swollman toname = ecatalloc(toname, "/"); 636192625Sedwin toname = ecatalloc(toname, tofield); 6372702Swollman } 6382702Swollman /* 6392702Swollman ** We get to be careful here since 6402702Swollman ** there's a fair chance of root running us. 6412702Swollman */ 6422702Swollman if (!itsdir(toname)) 6432702Swollman (void) remove(toname); 6442702Swollman if (link(fromname, toname) != 0) { 64542997Swollman int result; 64642997Swollman 6472702Swollman if (mkdirs(toname) != 0) 648192625Sedwin exit(EXIT_FAILURE); 649130819Sstefanf 65042997Swollman result = link(fromname, toname); 651192625Sedwin#if HAVE_SYMLINK 652130819Sstefanf if (result != 0 && 653192625Sedwin access(fromname, F_OK) == 0 && 654192625Sedwin !itsdir(fromname)) { 655192625Sedwin const char *s = tofield; 656192625Sedwin register char * symlinkcontents = NULL; 657192625Sedwin while ((s = strchr(s+1, '/')) != NULL) 658192625Sedwin symlinkcontents = 659192625Sedwin ecatalloc(symlinkcontents, 660192625Sedwin "../"); 661192625Sedwin symlinkcontents = 662192625Sedwin ecatalloc(symlinkcontents, 663192625Sedwin fromname); 664192625Sedwin result = 665192625Sedwin symlink(symlinkcontents, 666192625Sedwin toname); 667192625Sedwin if (result == 0) 66842997Swollmanwarning(_("hard link failed, symbolic link used")); 669192625Sedwin ifree(symlinkcontents); 67042997Swollman } 671192625Sedwin#endif /* HAVE_SYMLINK */ 67242997Swollman if (result != 0) { 67343774Swollman err(EXIT_FAILURE, _("can't link from %s to %s"), 67442997Swollman fromname, toname); 67542997Swollman } 6762702Swollman } 6779937Swollman ifree(fromname); 6789937Swollman ifree(toname); 6792702Swollman} 6802702Swollman 681192625Sedwin#define TIME_T_BITS_IN_FILE 64 68217214Swollman 6832702Swollmanstatic void 684192625Sedwinsetboundaries (void) 6852702Swollman{ 686192625Sedwin register int i; 687192625Sedwin 688192625Sedwin min_time = -1; 689192625Sedwin for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) 690192625Sedwin min_time *= 2; 691192625Sedwin max_time = -(min_time + 1); 6922702Swollman} 6932702Swollman 6942702Swollmanstatic int 6952702Swollmanitsdir(name) 6962702Swollmanconst char * const name; 6972702Swollman{ 6982702Swollman register char * myname; 6992702Swollman register int accres; 7002702Swollman 7012702Swollman myname = ecpyalloc(name); 7022702Swollman myname = ecatalloc(myname, "/."); 7039937Swollman accres = access(myname, F_OK); 7042702Swollman ifree(myname); 7052702Swollman return accres == 0; 7062702Swollman} 7072702Swollman 7082702Swollman/* 7092702Swollman** Associate sets of rules with zones. 7102702Swollman*/ 7112702Swollman 7122702Swollman/* 7132702Swollman** Sort by rule name. 7142702Swollman*/ 7152702Swollman 7162702Swollmanstatic int 7172702Swollmanrcomp(cp1, cp2) 7189937Swollmanconst void * cp1; 7199937Swollmanconst void * cp2; 7202702Swollman{ 7219937Swollman return strcmp(((const struct rule *) cp1)->r_name, 7229937Swollman ((const struct rule *) cp2)->r_name); 7232702Swollman} 7242702Swollman 7252702Swollmanstatic void 726192625Sedwinassociate(void) 7272702Swollman{ 7282702Swollman register struct zone * zp; 7292702Swollman register struct rule * rp; 7302702Swollman register int base, out; 73117214Swollman register int i, j; 7322702Swollman 73317214Swollman if (nrules != 0) { 7349937Swollman (void) qsort((void *) rules, (size_t) nrules, 7359937Swollman (size_t) sizeof *rules, rcomp); 73617214Swollman for (i = 0; i < nrules - 1; ++i) { 73717214Swollman if (strcmp(rules[i].r_name, 73817214Swollman rules[i + 1].r_name) != 0) 73917214Swollman continue; 74017214Swollman if (strcmp(rules[i].r_filename, 74117214Swollman rules[i + 1].r_filename) == 0) 74217214Swollman continue; 74317214Swollman eat(rules[i].r_filename, rules[i].r_linenum); 74417214Swollman warning(_("same rule name in multiple files")); 74517214Swollman eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 74617214Swollman warning(_("same rule name in multiple files")); 74717214Swollman for (j = i + 2; j < nrules; ++j) { 74817214Swollman if (strcmp(rules[i].r_name, 74917214Swollman rules[j].r_name) != 0) 75017214Swollman break; 75117214Swollman if (strcmp(rules[i].r_filename, 75217214Swollman rules[j].r_filename) == 0) 75317214Swollman continue; 75417214Swollman if (strcmp(rules[i + 1].r_filename, 75517214Swollman rules[j].r_filename) == 0) 75617214Swollman continue; 75717214Swollman break; 75817214Swollman } 75917214Swollman i = j - 1; 76017214Swollman } 76117214Swollman } 7622702Swollman for (i = 0; i < nzones; ++i) { 7632702Swollman zp = &zones[i]; 7642702Swollman zp->z_rules = NULL; 7652702Swollman zp->z_nrules = 0; 7662702Swollman } 7672702Swollman for (base = 0; base < nrules; base = out) { 7682702Swollman rp = &rules[base]; 7692702Swollman for (out = base + 1; out < nrules; ++out) 7702702Swollman if (strcmp(rp->r_name, rules[out].r_name) != 0) 7712702Swollman break; 7722702Swollman for (i = 0; i < nzones; ++i) { 7732702Swollman zp = &zones[i]; 7742702Swollman if (strcmp(zp->z_rule, rp->r_name) != 0) 7752702Swollman continue; 7762702Swollman zp->z_rules = rp; 7772702Swollman zp->z_nrules = out - base; 7782702Swollman } 7792702Swollman } 7802702Swollman for (i = 0; i < nzones; ++i) { 7812702Swollman zp = &zones[i]; 7822702Swollman if (zp->z_nrules == 0) { 7832702Swollman /* 7842702Swollman ** Maybe we have a local standard time offset. 7852702Swollman */ 7862702Swollman eat(zp->z_filename, zp->z_linenum); 78717214Swollman zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), 788192625Sedwin TRUE); 7892702Swollman /* 7902702Swollman ** Note, though, that if there's no rule, 7912702Swollman ** a '%s' in the format is a bad thing. 7922702Swollman */ 7932702Swollman if (strchr(zp->z_format, '%') != 0) 79417214Swollman error(_("%s in ruleless zone")); 7952702Swollman } 7962702Swollman } 7972702Swollman if (errors) 798192625Sedwin exit(EXIT_FAILURE); 7992702Swollman} 8002702Swollman 8012702Swollmanstatic void 8022702Swollmaninfile(name) 8032702Swollmanconst char * name; 8042702Swollman{ 8052702Swollman register FILE * fp; 8062702Swollman register char ** fields; 8072702Swollman register char * cp; 8082702Swollman register const struct lookup * lp; 8092702Swollman register int nfields; 8102702Swollman register int wantcont; 8112702Swollman register int num; 8122702Swollman char buf[BUFSIZ]; 8132702Swollman 8142702Swollman if (strcmp(name, "-") == 0) { 81517214Swollman name = _("standard input"); 8162702Swollman fp = stdin; 81730829Scharnier } else if ((fp = fopen(name, "r")) == NULL) 81830829Scharnier err(EXIT_FAILURE, _("can't open %s"), name); 8192702Swollman wantcont = FALSE; 8202702Swollman for (num = 1; ; ++num) { 8212702Swollman eat(name, num); 8222702Swollman if (fgets(buf, (int) sizeof buf, fp) != buf) 8232702Swollman break; 8242702Swollman cp = strchr(buf, '\n'); 8252702Swollman if (cp == NULL) { 82617214Swollman error(_("line too long")); 827192625Sedwin exit(EXIT_FAILURE); 8282702Swollman } 8292702Swollman *cp = '\0'; 8302702Swollman fields = getfields(buf); 8312702Swollman nfields = 0; 8322702Swollman while (fields[nfields] != NULL) { 8339937Swollman static char nada; 8342702Swollman 83517214Swollman if (strcmp(fields[nfields], "-") == 0) 8369937Swollman fields[nfields] = &nada; 8372702Swollman ++nfields; 8382702Swollman } 8392702Swollman if (nfields == 0) { 8402702Swollman /* nothing to do */ 8412702Swollman } else if (wantcont) { 8422702Swollman wantcont = inzcont(fields, nfields); 8432702Swollman } else { 8442702Swollman lp = byword(fields[0], line_codes); 8452702Swollman if (lp == NULL) 84617214Swollman error(_("input line of unknown type")); 8472702Swollman else switch ((int) (lp->l_value)) { 8482702Swollman case LC_RULE: 8492702Swollman inrule(fields, nfields); 8502702Swollman wantcont = FALSE; 8512702Swollman break; 8522702Swollman case LC_ZONE: 8532702Swollman wantcont = inzone(fields, nfields); 8542702Swollman break; 8552702Swollman case LC_LINK: 8562702Swollman inlink(fields, nfields); 8572702Swollman wantcont = FALSE; 8582702Swollman break; 8592702Swollman case LC_LEAP: 8602702Swollman if (name != leapsec) 86130829Scharnier warnx( 86230829Scharnier_("leap line in non leap seconds file %s"), name); 8632702Swollman else inleap(fields, nfields); 8642702Swollman wantcont = FALSE; 8652702Swollman break; 8662702Swollman default: /* "cannot happen" */ 86730829Scharnier errx(EXIT_FAILURE, 86830829Scharnier_("panic: invalid l_value %d"), lp->l_value); 8692702Swollman } 8702702Swollman } 8712702Swollman ifree((char *) fields); 8722702Swollman } 87330829Scharnier if (ferror(fp)) 87430829Scharnier errx(EXIT_FAILURE, _("error reading %s"), filename); 87530829Scharnier if (fp != stdin && fclose(fp)) 87630829Scharnier err(EXIT_FAILURE, _("error closing %s"), filename); 8772702Swollman if (wantcont) 87817214Swollman error(_("expected continuation line not found")); 8792702Swollman} 8802702Swollman 8812702Swollman/* 8822702Swollman** Convert a string of one of the forms 8839937Swollman** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 8842702Swollman** into a number of seconds. 8852702Swollman** A null string maps to zero. 8862702Swollman** Call error with errstring and return zero on errors. 8872702Swollman*/ 8882702Swollman 8892702Swollmanstatic long 8902702Swollmangethms(string, errstring, signable) 8912702Swollmanconst char * string; 8922702Swollmanconst char * const errstring; 8932702Swollmanconst int signable; 8942702Swollman{ 895192625Sedwin long hh; 896192625Sedwin int mm, ss, sign; 8972702Swollman 8982702Swollman if (string == NULL || *string == '\0') 8992702Swollman return 0; 9002702Swollman if (!signable) 9012702Swollman sign = 1; 9022702Swollman else if (*string == '-') { 9032702Swollman sign = -1; 9042702Swollman ++string; 9052702Swollman } else sign = 1; 906192625Sedwin if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 9072702Swollman mm = ss = 0; 908192625Sedwin else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 9092702Swollman ss = 0; 910192625Sedwin else if (sscanf(string, scheck(string, "%ld:%d:%d"), 9112702Swollman &hh, &mm, &ss) != 3) { 9122702Swollman error(errstring); 9132702Swollman return 0; 9142702Swollman } 915192625Sedwin if (hh < 0 || 9162702Swollman mm < 0 || mm >= MINSPERHOUR || 917192625Sedwin ss < 0 || ss > SECSPERMIN) { 9182702Swollman error(errstring); 9192702Swollman return 0; 9202702Swollman } 921192625Sedwin if (LONG_MAX / SECSPERHOUR < hh) { 922192625Sedwin error(_("time overflow")); 923192625Sedwin return 0; 924192625Sedwin } 925192625Sedwin if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 926130819Sstefanf warning(_("24:00 not handled by pre-1998 versions of zic")); 927192625Sedwin if (noise && (hh > HOURSPERDAY || 928192625Sedwin (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 929192625Sedwinwarning(_("values over 24 hours not handled by pre-2007 versions of zic")); 930192625Sedwin return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 931192625Sedwin eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); 9322702Swollman} 9332702Swollman 9342702Swollmanstatic void 9352702Swollmaninrule(fields, nfields) 9362702Swollmanregister char ** const fields; 9372702Swollmanconst int nfields; 9382702Swollman{ 9392702Swollman static struct rule r; 9402702Swollman 9412702Swollman if (nfields != RULE_FIELDS) { 94217214Swollman error(_("wrong number of fields on Rule line")); 9432702Swollman return; 9442702Swollman } 9452702Swollman if (*fields[RF_NAME] == '\0') { 94617214Swollman error(_("nameless rule")); 9472702Swollman return; 9482702Swollman } 9492702Swollman r.r_filename = filename; 9502702Swollman r.r_linenum = linenum; 95117214Swollman r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); 9522702Swollman rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 9532702Swollman fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 9542702Swollman r.r_name = ecpyalloc(fields[RF_NAME]); 9552702Swollman r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 956192625Sedwin if (max_abbrvar_len < strlen(r.r_abbrvar)) 957192625Sedwin max_abbrvar_len = strlen(r.r_abbrvar); 9589937Swollman rules = (struct rule *) (void *) erealloc((char *) rules, 9592702Swollman (int) ((nrules + 1) * sizeof *rules)); 9602702Swollman rules[nrules++] = r; 9612702Swollman} 9622702Swollman 9632702Swollmanstatic int 9642702Swollmaninzone(fields, nfields) 9652702Swollmanregister char ** const fields; 9662702Swollmanconst int nfields; 9672702Swollman{ 9682702Swollman register int i; 9692702Swollman static char * buf; 9702702Swollman 9712702Swollman if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 97217214Swollman error(_("wrong number of fields on Zone line")); 9732702Swollman return FALSE; 9742702Swollman } 9752702Swollman if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 9769937Swollman buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); 9772702Swollman (void) sprintf(buf, 97817214Swollman_("\"Zone %s\" line and -l option are mutually exclusive"), 9792702Swollman TZDEFAULT); 9802702Swollman error(buf); 9812702Swollman return FALSE; 9822702Swollman } 9832702Swollman if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 9849937Swollman buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); 9852702Swollman (void) sprintf(buf, 98617214Swollman_("\"Zone %s\" line and -p option are mutually exclusive"), 9872702Swollman TZDEFRULES); 9882702Swollman error(buf); 9892702Swollman return FALSE; 9902702Swollman } 9912702Swollman for (i = 0; i < nzones; ++i) 9922702Swollman if (zones[i].z_name != NULL && 9932702Swollman strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 9949937Swollman buf = erealloc(buf, (int) (132 + 9952702Swollman strlen(fields[ZF_NAME]) + 9969937Swollman strlen(zones[i].z_filename))); 9972702Swollman (void) sprintf(buf, 99817214Swollman_("duplicate zone name %s (file \"%s\", line %d)"), 9992702Swollman fields[ZF_NAME], 10002702Swollman zones[i].z_filename, 10012702Swollman zones[i].z_linenum); 10022702Swollman error(buf); 10032702Swollman return FALSE; 10042702Swollman } 10052702Swollman return inzsub(fields, nfields, FALSE); 10062702Swollman} 10072702Swollman 10082702Swollmanstatic int 10092702Swollmaninzcont(fields, nfields) 10102702Swollmanregister char ** const fields; 10112702Swollmanconst int nfields; 10122702Swollman{ 10132702Swollman if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 101417214Swollman error(_("wrong number of fields on Zone continuation line")); 10152702Swollman return FALSE; 10162702Swollman } 10172702Swollman return inzsub(fields, nfields, TRUE); 10182702Swollman} 10192702Swollman 10202702Swollmanstatic int 10212702Swollmaninzsub(fields, nfields, iscont) 10222702Swollmanregister char ** const fields; 10232702Swollmanconst int nfields; 10242702Swollmanconst int iscont; 10252702Swollman{ 10262702Swollman register char * cp; 10272702Swollman static struct zone z; 10282702Swollman register int i_gmtoff, i_rule, i_format; 10292702Swollman register int i_untilyear, i_untilmonth; 10302702Swollman register int i_untilday, i_untiltime; 10312702Swollman register int hasuntil; 10322702Swollman 10332702Swollman if (iscont) { 10342702Swollman i_gmtoff = ZFC_GMTOFF; 10352702Swollman i_rule = ZFC_RULE; 10362702Swollman i_format = ZFC_FORMAT; 10372702Swollman i_untilyear = ZFC_TILYEAR; 10382702Swollman i_untilmonth = ZFC_TILMONTH; 10392702Swollman i_untilday = ZFC_TILDAY; 10402702Swollman i_untiltime = ZFC_TILTIME; 10412702Swollman z.z_name = NULL; 10422702Swollman } else { 10432702Swollman i_gmtoff = ZF_GMTOFF; 10442702Swollman i_rule = ZF_RULE; 10452702Swollman i_format = ZF_FORMAT; 10462702Swollman i_untilyear = ZF_TILYEAR; 10472702Swollman i_untilmonth = ZF_TILMONTH; 10482702Swollman i_untilday = ZF_TILDAY; 10492702Swollman i_untiltime = ZF_TILTIME; 10502702Swollman z.z_name = ecpyalloc(fields[ZF_NAME]); 10512702Swollman } 10522702Swollman z.z_filename = filename; 10532702Swollman z.z_linenum = linenum; 105442997Swollman z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE); 10552702Swollman if ((cp = strchr(fields[i_format], '%')) != 0) { 10562702Swollman if (*++cp != 's' || strchr(cp, '%') != 0) { 105717214Swollman error(_("invalid abbreviation format")); 10582702Swollman return FALSE; 10592702Swollman } 10602702Swollman } 10612702Swollman z.z_rule = ecpyalloc(fields[i_rule]); 10622702Swollman z.z_format = ecpyalloc(fields[i_format]); 1063192625Sedwin if (max_format_len < strlen(z.z_format)) 1064192625Sedwin max_format_len = strlen(z.z_format); 10652702Swollman hasuntil = nfields > i_untilyear; 10662702Swollman if (hasuntil) { 10672702Swollman z.z_untilrule.r_filename = filename; 10682702Swollman z.z_untilrule.r_linenum = linenum; 10692702Swollman rulesub(&z.z_untilrule, 10702702Swollman fields[i_untilyear], 10712702Swollman "only", 10722702Swollman "", 10732702Swollman (nfields > i_untilmonth) ? 10742702Swollman fields[i_untilmonth] : "Jan", 10752702Swollman (nfields > i_untilday) ? fields[i_untilday] : "1", 10762702Swollman (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 10772702Swollman z.z_untiltime = rpytime(&z.z_untilrule, 10782702Swollman z.z_untilrule.r_loyear); 10792702Swollman if (iscont && nzones > 0 && 10802702Swollman z.z_untiltime > min_time && 10812702Swollman z.z_untiltime < max_time && 10822702Swollman zones[nzones - 1].z_untiltime > min_time && 10832702Swollman zones[nzones - 1].z_untiltime < max_time && 10842702Swollman zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1085192625Sedwin error(_( 1086192625Sedwin"Zone continuation line end time is not after end time of previous line" 1087192625Sedwin )); 10882702Swollman return FALSE; 10892702Swollman } 10902702Swollman } 10919937Swollman zones = (struct zone *) (void *) erealloc((char *) zones, 10922702Swollman (int) ((nzones + 1) * sizeof *zones)); 10932702Swollman zones[nzones++] = z; 10942702Swollman /* 10952702Swollman ** If there was an UNTIL field on this line, 10962702Swollman ** there's more information about the zone on the next line. 10972702Swollman */ 10982702Swollman return hasuntil; 10992702Swollman} 11002702Swollman 11012702Swollmanstatic void 11022702Swollmaninleap(fields, nfields) 11032702Swollmanregister char ** const fields; 11042702Swollmanconst int nfields; 11052702Swollman{ 11062702Swollman register const char * cp; 11072702Swollman register const struct lookup * lp; 11082702Swollman register int i, j; 11092702Swollman int year, month, day; 11102702Swollman long dayoff, tod; 1111192625Sedwin zic_t t; 11122702Swollman 11132702Swollman if (nfields != LEAP_FIELDS) { 111417214Swollman error(_("wrong number of fields on Leap line")); 11152702Swollman return; 11162702Swollman } 11172702Swollman dayoff = 0; 11182702Swollman cp = fields[LP_YEAR]; 11192702Swollman if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1120192625Sedwin /* 1121192625Sedwin ** Leapin' Lizards! 1122192625Sedwin */ 1123192625Sedwin error(_("invalid leaping year")); 1124192625Sedwin return; 11252702Swollman } 1126192625Sedwin if (!leapseen || leapmaxyear < year) 1127192625Sedwin leapmaxyear = year; 1128192625Sedwin if (!leapseen || leapminyear > year) 1129192625Sedwin leapminyear = year; 1130192625Sedwin leapseen = TRUE; 11312702Swollman j = EPOCH_YEAR; 11322702Swollman while (j != year) { 11332702Swollman if (year > j) { 11342702Swollman i = len_years[isleap(j)]; 11352702Swollman ++j; 11362702Swollman } else { 11372702Swollman --j; 11382702Swollman i = -len_years[isleap(j)]; 11392702Swollman } 11402702Swollman dayoff = oadd(dayoff, eitol(i)); 11412702Swollman } 11422702Swollman if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 114317214Swollman error(_("invalid month name")); 11442702Swollman return; 11452702Swollman } 11462702Swollman month = lp->l_value; 11472702Swollman j = TM_JANUARY; 11482702Swollman while (j != month) { 11492702Swollman i = len_months[isleap(year)][j]; 11502702Swollman dayoff = oadd(dayoff, eitol(i)); 11512702Swollman ++j; 11522702Swollman } 11532702Swollman cp = fields[LP_DAY]; 11542702Swollman if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 11552702Swollman day <= 0 || day > len_months[isleap(year)][month]) { 115617214Swollman error(_("invalid day of month")); 11572702Swollman return; 11582702Swollman } 11592702Swollman dayoff = oadd(dayoff, eitol(day - 1)); 1160192625Sedwin if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 116117214Swollman error(_("time before zero")); 11622702Swollman return; 11632702Swollman } 1164130819Sstefanf if (dayoff < min_time / SECSPERDAY) { 1165130819Sstefanf error(_("time too small")); 11662702Swollman return; 11672702Swollman } 1168130819Sstefanf if (dayoff > max_time / SECSPERDAY) { 1169130819Sstefanf error(_("time too large")); 1170130819Sstefanf return; 1171130819Sstefanf } 1172192625Sedwin t = (zic_t) dayoff * SECSPERDAY; 117317214Swollman tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); 11742702Swollman cp = fields[LP_CORR]; 11752702Swollman { 11762702Swollman register int positive; 11772702Swollman int count; 11782702Swollman 11792702Swollman if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 11802702Swollman positive = FALSE; 11812702Swollman count = 1; 11822702Swollman } else if (strcmp(cp, "--") == 0) { 11832702Swollman positive = FALSE; 11842702Swollman count = 2; 11852702Swollman } else if (strcmp(cp, "+") == 0) { 11862702Swollman positive = TRUE; 11872702Swollman count = 1; 11882702Swollman } else if (strcmp(cp, "++") == 0) { 11892702Swollman positive = TRUE; 11902702Swollman count = 2; 11912702Swollman } else { 119217214Swollman error(_("illegal CORRECTION field on Leap line")); 11932702Swollman return; 11942702Swollman } 11952702Swollman if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1196192625Sedwin error(_( 1197192625Sedwin "illegal Rolling/Stationary field on Leap line" 1198192625Sedwin )); 11992702Swollman return; 12002702Swollman } 12012702Swollman leapadd(tadd(t, tod), positive, lp->l_value, count); 12022702Swollman } 12032702Swollman} 12042702Swollman 12052702Swollmanstatic void 12062702Swollmaninlink(fields, nfields) 12072702Swollmanregister char ** const fields; 12082702Swollmanconst int nfields; 12092702Swollman{ 12102702Swollman struct link l; 12112702Swollman 12122702Swollman if (nfields != LINK_FIELDS) { 121317214Swollman error(_("wrong number of fields on Link line")); 12142702Swollman return; 12152702Swollman } 12162702Swollman if (*fields[LF_FROM] == '\0') { 121717214Swollman error(_("blank FROM field on Link line")); 12182702Swollman return; 12192702Swollman } 12202702Swollman if (*fields[LF_TO] == '\0') { 122117214Swollman error(_("blank TO field on Link line")); 12222702Swollman return; 12232702Swollman } 12242702Swollman l.l_filename = filename; 12252702Swollman l.l_linenum = linenum; 12262702Swollman l.l_from = ecpyalloc(fields[LF_FROM]); 12272702Swollman l.l_to = ecpyalloc(fields[LF_TO]); 12289937Swollman links = (struct link *) (void *) erealloc((char *) links, 12292702Swollman (int) ((nlinks + 1) * sizeof *links)); 12302702Swollman links[nlinks++] = l; 12312702Swollman} 12322702Swollman 12332702Swollmanstatic void 12342702Swollmanrulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 12352702Swollmanregister struct rule * const rp; 12369937Swollmanconst char * const loyearp; 12379937Swollmanconst char * const hiyearp; 12389937Swollmanconst char * const typep; 12399937Swollmanconst char * const monthp; 12409937Swollmanconst char * const dayp; 12419937Swollmanconst char * const timep; 12422702Swollman{ 12439937Swollman register const struct lookup * lp; 12449937Swollman register const char * cp; 12459937Swollman register char * dp; 12469937Swollman register char * ep; 12472702Swollman 12482702Swollman if ((lp = byword(monthp, mon_names)) == NULL) { 124917214Swollman error(_("invalid month name")); 12502702Swollman return; 12512702Swollman } 12522702Swollman rp->r_month = lp->l_value; 12532702Swollman rp->r_todisstd = FALSE; 12549937Swollman rp->r_todisgmt = FALSE; 12559937Swollman dp = ecpyalloc(timep); 12569937Swollman if (*dp != '\0') { 12579937Swollman ep = dp + strlen(dp) - 1; 12589937Swollman switch (lowerit(*ep)) { 12599937Swollman case 's': /* Standard */ 12602702Swollman rp->r_todisstd = TRUE; 12619937Swollman rp->r_todisgmt = FALSE; 12629937Swollman *ep = '\0'; 12632702Swollman break; 12649937Swollman case 'w': /* Wall */ 12652702Swollman rp->r_todisstd = FALSE; 12669937Swollman rp->r_todisgmt = FALSE; 12679937Swollman *ep = '\0'; 126842997Swollman break; 12699937Swollman case 'g': /* Greenwich */ 12709937Swollman case 'u': /* Universal */ 12719937Swollman case 'z': /* Zulu */ 12729937Swollman rp->r_todisstd = TRUE; 12739937Swollman rp->r_todisgmt = TRUE; 12749937Swollman *ep = '\0'; 12752702Swollman break; 12762702Swollman } 12772702Swollman } 127817214Swollman rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); 12799937Swollman ifree(dp); 12802702Swollman /* 12812702Swollman ** Year work. 12822702Swollman */ 12832702Swollman cp = loyearp; 12849937Swollman lp = byword(cp, begin_years); 1285192625Sedwin rp->r_lowasnum = lp == NULL; 1286192625Sedwin if (!rp->r_lowasnum) switch ((int) lp->l_value) { 12872702Swollman case YR_MINIMUM: 128817214Swollman rp->r_loyear = INT_MIN; 12892702Swollman break; 12902702Swollman case YR_MAXIMUM: 129117214Swollman rp->r_loyear = INT_MAX; 12922702Swollman break; 12932702Swollman default: /* "cannot happen" */ 129430829Scharnier errx(EXIT_FAILURE, 129530829Scharnier _("panic: invalid l_value %d"), lp->l_value); 12962702Swollman } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 129717214Swollman error(_("invalid starting year")); 12982702Swollman return; 12992702Swollman } 13002702Swollman cp = hiyearp; 1301192625Sedwin lp = byword(cp, end_years); 1302192625Sedwin rp->r_hiwasnum = lp == NULL; 1303192625Sedwin if (!rp->r_hiwasnum) switch ((int) lp->l_value) { 13042702Swollman case YR_MINIMUM: 130517214Swollman rp->r_hiyear = INT_MIN; 13062702Swollman break; 13072702Swollman case YR_MAXIMUM: 130817214Swollman rp->r_hiyear = INT_MAX; 13092702Swollman break; 13102702Swollman case YR_ONLY: 13112702Swollman rp->r_hiyear = rp->r_loyear; 13122702Swollman break; 13132702Swollman default: /* "cannot happen" */ 131430829Scharnier errx(EXIT_FAILURE, 131530829Scharnier _("panic: invalid l_value %d"), lp->l_value); 13162702Swollman } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 131717214Swollman error(_("invalid ending year")); 13182702Swollman return; 13192702Swollman } 13202702Swollman if (rp->r_loyear > rp->r_hiyear) { 132117214Swollman error(_("starting year greater than ending year")); 13222702Swollman return; 13232702Swollman } 13242702Swollman if (*typep == '\0') 13252702Swollman rp->r_yrtype = NULL; 13262702Swollman else { 13272702Swollman if (rp->r_loyear == rp->r_hiyear) { 132817214Swollman error(_("typed single year")); 13292702Swollman return; 13302702Swollman } 13312702Swollman rp->r_yrtype = ecpyalloc(typep); 13322702Swollman } 13332702Swollman /* 13342702Swollman ** Day work. 13352702Swollman ** Accept things such as: 13362702Swollman ** 1 13372702Swollman ** last-Sunday 13382702Swollman ** Sun<=20 13392702Swollman ** Sun>=7 13402702Swollman */ 13419937Swollman dp = ecpyalloc(dayp); 13429937Swollman if ((lp = byword(dp, lasts)) != NULL) { 13432702Swollman rp->r_dycode = DC_DOWLEQ; 13442702Swollman rp->r_wday = lp->l_value; 13452702Swollman rp->r_dayofmonth = len_months[1][rp->r_month]; 13462702Swollman } else { 13479937Swollman if ((ep = strchr(dp, '<')) != 0) 13482702Swollman rp->r_dycode = DC_DOWLEQ; 13499937Swollman else if ((ep = strchr(dp, '>')) != 0) 13502702Swollman rp->r_dycode = DC_DOWGEQ; 13512702Swollman else { 13529937Swollman ep = dp; 13532702Swollman rp->r_dycode = DC_DOM; 13542702Swollman } 13552702Swollman if (rp->r_dycode != DC_DOM) { 13569937Swollman *ep++ = 0; 13579937Swollman if (*ep++ != '=') { 135817214Swollman error(_("invalid day of month")); 13599937Swollman ifree(dp); 13602702Swollman return; 13612702Swollman } 13629937Swollman if ((lp = byword(dp, wday_names)) == NULL) { 136317214Swollman error(_("invalid weekday name")); 13649937Swollman ifree(dp); 13652702Swollman return; 13662702Swollman } 13672702Swollman rp->r_wday = lp->l_value; 13682702Swollman } 13699937Swollman if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 13702702Swollman rp->r_dayofmonth <= 0 || 13712702Swollman (rp->r_dayofmonth > len_months[1][rp->r_month])) { 137217214Swollman error(_("invalid day of month")); 13739937Swollman ifree(dp); 13742702Swollman return; 13752702Swollman } 13762702Swollman } 13779937Swollman ifree(dp); 13782702Swollman} 13792702Swollman 13802702Swollmanstatic void 13812702Swollmanconvert(val, buf) 13822702Swollmanconst long val; 13832702Swollmanchar * const buf; 13842702Swollman{ 13852702Swollman register int i; 1386192625Sedwin register int shift; 13872702Swollman 13882702Swollman for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 13892702Swollman buf[i] = val >> shift; 13902702Swollman} 13912702Swollman 13922702Swollmanstatic void 1393192625Sedwinconvert64(val, buf) 1394192625Sedwinconst zic_t val; 1395192625Sedwinchar * const buf; 1396192625Sedwin{ 1397192625Sedwin register int i; 1398192625Sedwin register int shift; 1399192625Sedwin 1400192625Sedwin for (i = 0, shift = 56; i < 8; ++i, shift -= 8) 1401192625Sedwin buf[i] = val >> shift; 1402192625Sedwin} 1403192625Sedwin 1404192625Sedwinstatic void 14052702Swollmanputtzcode(val, fp) 14062702Swollmanconst long val; 14072702SwollmanFILE * const fp; 14082702Swollman{ 14092702Swollman char buf[4]; 14102702Swollman 14112702Swollman convert(val, buf); 14129937Swollman (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 14132702Swollman} 14142702Swollman 1415192625Sedwinstatic void 1416192625Sedwinputtzcode64(val, fp) 1417192625Sedwinconst zic_t val; 1418192625SedwinFILE * const fp; 1419192625Sedwin{ 1420192625Sedwin char buf[8]; 1421192625Sedwin 1422192625Sedwin convert64(val, buf); 1423192625Sedwin (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 1424192625Sedwin} 1425192625Sedwin 142617214Swollmanstatic int 142717214Swollmanatcomp(avp, bvp) 1428192625Sedwinconst void * avp; 1429192625Sedwinconst void * bvp; 143017214Swollman{ 1431192625Sedwin const zic_t a = ((const struct attype *) avp)->at; 1432192625Sedwin const zic_t b = ((const struct attype *) bvp)->at; 1433192625Sedwin 1434192625Sedwin return (a < b) ? -1 : (a > b); 143517214Swollman} 143617214Swollman 1437192625Sedwinstatic int 1438192625Sedwinis32(x) 1439192625Sedwinconst zic_t x; 1440192625Sedwin{ 1441192625Sedwin return INT32_MIN <= x && x <= INT32_MAX; 1442192625Sedwin} 1443192625Sedwin 14442702Swollmanstatic void 1445192625Sedwinwritezone(name, string) 14462702Swollmanconst char * const name; 1447192625Sedwinconst char * const string; 14482702Swollman{ 1449192625Sedwin register FILE * fp; 1450192625Sedwin register int i, j; 1451192625Sedwin register int leapcnt32, leapi32; 1452192625Sedwin register int timecnt32, timei32; 1453192625Sedwin register int pass; 1454192625Sedwin static char * fullname; 1455192625Sedwin static const struct tzhead tzh0; 1456192625Sedwin static struct tzhead tzh; 1457192625Sedwin zic_t ats[TZ_MAX_TIMES]; 1458192625Sedwin unsigned char types[TZ_MAX_TIMES]; 14592702Swollman 146017214Swollman /* 146117214Swollman ** Sort. 146217214Swollman */ 146317214Swollman if (timecnt > 1) 146417214Swollman (void) qsort((void *) attypes, (size_t) timecnt, 146517214Swollman (size_t) sizeof *attypes, atcomp); 146617214Swollman /* 146717214Swollman ** Optimize. 146817214Swollman */ 146917214Swollman { 147017214Swollman int fromi; 147117214Swollman int toi; 147217214Swollman 147317214Swollman toi = 0; 147417214Swollman fromi = 0; 147542997Swollman while (fromi < timecnt && attypes[fromi].at < min_time) 147642997Swollman ++fromi; 147717214Swollman if (isdsts[0] == 0) 147842997Swollman while (fromi < timecnt && attypes[fromi].type == 0) 147917214Swollman ++fromi; /* handled by default rule */ 148017214Swollman for ( ; fromi < timecnt; ++fromi) { 1481192625Sedwin if (toi != 0 && ((attypes[fromi].at + 1482192625Sedwin gmtoffs[attypes[toi - 1].type]) <= 1483192625Sedwin (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 1484192625Sedwin : attypes[toi - 2].type]))) { 1485192625Sedwin attypes[toi - 1].type = 1486192625Sedwin attypes[fromi].type; 1487192625Sedwin continue; 148817214Swollman } 148917214Swollman if (toi == 0 || 149017214Swollman attypes[toi - 1].type != attypes[fromi].type) 149117214Swollman attypes[toi++] = attypes[fromi]; 149217214Swollman } 149317214Swollman timecnt = toi; 149417214Swollman } 149517214Swollman /* 149617214Swollman ** Transfer. 149717214Swollman */ 149817214Swollman for (i = 0; i < timecnt; ++i) { 149917214Swollman ats[i] = attypes[i].at; 150017214Swollman types[i] = attypes[i].type; 150117214Swollman } 1502192625Sedwin /* 1503192625Sedwin ** Correct for leap seconds. 1504192625Sedwin */ 1505192625Sedwin for (i = 0; i < timecnt; ++i) { 1506192625Sedwin j = leapcnt; 1507192625Sedwin while (--j >= 0) 1508192625Sedwin if (ats[i] > trans[j] - corr[j]) { 1509192625Sedwin ats[i] = tadd(ats[i], corr[j]); 1510192625Sedwin break; 1511192625Sedwin } 1512192625Sedwin } 1513192625Sedwin /* 1514192625Sedwin ** Figure out 32-bit-limited starts and counts. 1515192625Sedwin */ 1516192625Sedwin timecnt32 = timecnt; 1517192625Sedwin timei32 = 0; 1518192625Sedwin leapcnt32 = leapcnt; 1519192625Sedwin leapi32 = 0; 1520192625Sedwin while (timecnt32 > 0 && !is32(ats[timecnt32 - 1])) 1521192625Sedwin --timecnt32; 1522192625Sedwin while (timecnt32 > 0 && !is32(ats[timei32])) { 1523192625Sedwin --timecnt32; 1524192625Sedwin ++timei32; 1525192625Sedwin } 1526192625Sedwin while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1])) 1527192625Sedwin --leapcnt32; 1528192625Sedwin while (leapcnt32 > 0 && !is32(trans[leapi32])) { 1529192625Sedwin --leapcnt32; 1530192625Sedwin ++leapi32; 1531192625Sedwin } 15322702Swollman fullname = erealloc(fullname, 15339937Swollman (int) (strlen(directory) + 1 + strlen(name) + 1)); 15342702Swollman (void) sprintf(fullname, "%s/%s", directory, name); 153523859Sbde 153623859Sbde /* 153723859Sbde * Remove old file, if any, to snap links. 153823859Sbde */ 153930829Scharnier if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) 154030829Scharnier err(EXIT_FAILURE, _("can't remove %s"), fullname); 154123859Sbde 15422702Swollman if ((fp = fopen(fullname, "wb")) == NULL) { 15432702Swollman if (mkdirs(fullname) != 0) 1544192625Sedwin exit(EXIT_FAILURE); 154530829Scharnier if ((fp = fopen(fullname, "wb")) == NULL) 154630829Scharnier err(EXIT_FAILURE, _("can't create %s"), fullname); 15472702Swollman } 1548192625Sedwin for (pass = 1; pass <= 2; ++pass) { 1549192625Sedwin register int thistimei, thistimecnt; 1550192625Sedwin register int thisleapi, thisleapcnt; 1551192625Sedwin register int thistimelim, thisleaplim; 1552192625Sedwin int writetype[TZ_MAX_TIMES]; 1553192625Sedwin int typemap[TZ_MAX_TYPES]; 1554192625Sedwin register int thistypecnt; 1555192625Sedwin char thischars[TZ_MAX_CHARS]; 1556192625Sedwin char thischarcnt; 1557192625Sedwin int indmap[TZ_MAX_CHARS]; 1558192625Sedwin 1559192625Sedwin if (pass == 1) { 1560192625Sedwin thistimei = timei32; 1561192625Sedwin thistimecnt = timecnt32; 1562192625Sedwin thisleapi = leapi32; 1563192625Sedwin thisleapcnt = leapcnt32; 1564192625Sedwin } else { 1565192625Sedwin thistimei = 0; 1566192625Sedwin thistimecnt = timecnt; 1567192625Sedwin thisleapi = 0; 1568192625Sedwin thisleapcnt = leapcnt; 1569192625Sedwin } 1570192625Sedwin thistimelim = thistimei + thistimecnt; 1571192625Sedwin thisleaplim = thisleapi + thisleapcnt; 1572192625Sedwin for (i = 0; i < typecnt; ++i) 1573192625Sedwin writetype[i] = thistimecnt == timecnt; 1574192625Sedwin if (thistimecnt == 0) { 1575192625Sedwin /* 1576192625Sedwin ** No transition times fall in the current 1577192625Sedwin ** (32- or 64-bit) window. 1578192625Sedwin */ 1579192625Sedwin if (typecnt != 0) 1580192625Sedwin writetype[typecnt - 1] = TRUE; 1581192625Sedwin } else { 1582192625Sedwin for (i = thistimei - 1; i < thistimelim; ++i) 1583192625Sedwin if (i >= 0) 1584192625Sedwin writetype[types[i]] = TRUE; 1585192625Sedwin /* 1586192625Sedwin ** For America/Godthab and Antarctica/Palmer 1587192625Sedwin */ 1588192625Sedwin if (thistimei == 0) 1589192625Sedwin writetype[0] = TRUE; 1590192625Sedwin } 1591214411Sedwin#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH 1592214411Sedwin /* 1593214411Sedwin ** For some pre-2011 systems: if the last-to-be-written 1594214411Sedwin ** standard (or daylight) type has an offset different from the 1595214411Sedwin ** most recently used offset, 1596214411Sedwin ** append an (unused) copy of the most recently used type 1597214411Sedwin ** (to help get global "altzone" and "timezone" variables 1598214411Sedwin ** set correctly). 1599214411Sedwin */ 1600214411Sedwin { 1601214411Sedwin register int mrudst, mrustd, hidst, histd, type; 1602214411Sedwin 1603214411Sedwin hidst = histd = mrudst = mrustd = -1; 1604214411Sedwin for (i = thistimei; i < thistimelim; ++i) 1605214411Sedwin if (isdsts[types[i]]) 1606214411Sedwin mrudst = types[i]; 1607214411Sedwin else mrustd = types[i]; 1608214411Sedwin for (i = 0; i < typecnt; ++i) 1609214411Sedwin if (writetype[i]) { 1610214411Sedwin if (isdsts[i]) 1611214411Sedwin hidst = i; 1612214411Sedwin else histd = i; 1613214411Sedwin } 1614214411Sedwin if (hidst >= 0 && mrudst >= 0 && hidst != mrudst && 1615214411Sedwin gmtoffs[hidst] != gmtoffs[mrudst]) { 1616214411Sedwin isdsts[mrudst] = -1; 1617214411Sedwin type = addtype(gmtoffs[mrudst], 1618214411Sedwin &chars[abbrinds[mrudst]], 1619214411Sedwin TRUE, 1620214411Sedwin ttisstds[mrudst], 1621214411Sedwin ttisgmts[mrudst]); 1622214411Sedwin isdsts[mrudst] = TRUE; 1623214411Sedwin writetype[type] = TRUE; 1624214411Sedwin } 1625214411Sedwin if (histd >= 0 && mrustd >= 0 && histd != mrustd && 1626214411Sedwin gmtoffs[histd] != gmtoffs[mrustd]) { 1627214411Sedwin isdsts[mrustd] = -1; 1628214411Sedwin type = addtype(gmtoffs[mrustd], 1629214411Sedwin &chars[abbrinds[mrustd]], 1630214411Sedwin FALSE, 1631214411Sedwin ttisstds[mrustd], 1632214411Sedwin ttisgmts[mrustd]); 1633214411Sedwin isdsts[mrustd] = FALSE; 1634214411Sedwin writetype[type] = TRUE; 1635214411Sedwin } 1636214411Sedwin } 1637214411Sedwin#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */ 1638192625Sedwin thistypecnt = 0; 1639192625Sedwin for (i = 0; i < typecnt; ++i) 1640192625Sedwin typemap[i] = writetype[i] ? thistypecnt++ : -1; 1641192625Sedwin for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i) 1642192625Sedwin indmap[i] = -1; 1643192625Sedwin thischarcnt = 0; 1644192625Sedwin for (i = 0; i < typecnt; ++i) { 1645192625Sedwin register char * thisabbr; 1646192625Sedwin 1647192625Sedwin if (!writetype[i]) 1648192625Sedwin continue; 1649192625Sedwin if (indmap[abbrinds[i]] >= 0) 1650192625Sedwin continue; 1651192625Sedwin thisabbr = &chars[abbrinds[i]]; 1652192625Sedwin for (j = 0; j < thischarcnt; ++j) 1653192625Sedwin if (strcmp(&thischars[j], thisabbr) == 0) 1654192625Sedwin break; 1655192625Sedwin if (j == thischarcnt) { 1656192625Sedwin (void) strcpy(&thischars[(int) thischarcnt], 1657192625Sedwin thisabbr); 1658192625Sedwin thischarcnt += strlen(thisabbr) + 1; 1659192625Sedwin } 1660192625Sedwin indmap[abbrinds[i]] = j; 1661192625Sedwin } 1662192625Sedwin#define DO(field) (void) fwrite((void *) tzh.field, \ 1663192625Sedwin (size_t) sizeof tzh.field, (size_t) 1, fp) 1664192625Sedwin tzh = tzh0; 1665192625Sedwin (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic); 1666192625Sedwin tzh.tzh_version[0] = ZIC_VERSION; 1667192625Sedwin convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt); 1668192625Sedwin convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt); 1669192625Sedwin convert(eitol(thisleapcnt), tzh.tzh_leapcnt); 1670192625Sedwin convert(eitol(thistimecnt), tzh.tzh_timecnt); 1671192625Sedwin convert(eitol(thistypecnt), tzh.tzh_typecnt); 1672192625Sedwin convert(eitol(thischarcnt), tzh.tzh_charcnt); 1673192625Sedwin DO(tzh_magic); 1674192625Sedwin DO(tzh_version); 1675192625Sedwin DO(tzh_reserved); 1676192625Sedwin DO(tzh_ttisgmtcnt); 1677192625Sedwin DO(tzh_ttisstdcnt); 1678192625Sedwin DO(tzh_leapcnt); 1679192625Sedwin DO(tzh_timecnt); 1680192625Sedwin DO(tzh_typecnt); 1681192625Sedwin DO(tzh_charcnt); 16829937Swollman#undef DO 1683192625Sedwin for (i = thistimei; i < thistimelim; ++i) 1684192625Sedwin if (pass == 1) 1685192625Sedwin puttzcode((long) ats[i], fp); 1686192625Sedwin else puttzcode64(ats[i], fp); 1687192625Sedwin for (i = thistimei; i < thistimelim; ++i) { 1688192625Sedwin unsigned char uc; 1689192625Sedwin 1690192625Sedwin uc = typemap[types[i]]; 1691192625Sedwin (void) fwrite((void *) &uc, 1692192625Sedwin (size_t) sizeof uc, 1693192625Sedwin (size_t) 1, 1694192625Sedwin fp); 1695192625Sedwin } 1696192625Sedwin for (i = 0; i < typecnt; ++i) 1697192625Sedwin if (writetype[i]) { 1698192625Sedwin puttzcode(gmtoffs[i], fp); 1699192625Sedwin (void) putc(isdsts[i], fp); 1700192625Sedwin (void) putc((unsigned char) indmap[abbrinds[i]], fp); 17012702Swollman } 1702192625Sedwin if (thischarcnt != 0) 1703192625Sedwin (void) fwrite((void *) thischars, 1704192625Sedwin (size_t) sizeof thischars[0], 1705192625Sedwin (size_t) thischarcnt, fp); 1706192625Sedwin for (i = thisleapi; i < thisleaplim; ++i) { 1707192625Sedwin register zic_t todo; 1708192625Sedwin 1709192625Sedwin if (roll[i]) { 1710192625Sedwin if (timecnt == 0 || trans[i] < ats[0]) { 1711192625Sedwin j = 0; 1712192625Sedwin while (isdsts[j]) 1713192625Sedwin if (++j >= typecnt) { 1714192625Sedwin j = 0; 1715192625Sedwin break; 1716192625Sedwin } 1717192625Sedwin } else { 1718192625Sedwin j = 1; 1719192625Sedwin while (j < timecnt && 1720192625Sedwin trans[i] >= ats[j]) 1721192625Sedwin ++j; 1722192625Sedwin j = types[j - 1]; 1723192625Sedwin } 1724192625Sedwin todo = tadd(trans[i], -gmtoffs[j]); 1725192625Sedwin } else todo = trans[i]; 1726192625Sedwin if (pass == 1) 1727192625Sedwin puttzcode((long) todo, fp); 1728192625Sedwin else puttzcode64(todo, fp); 1729192625Sedwin puttzcode(corr[i], fp); 1730192625Sedwin } 1731192625Sedwin for (i = 0; i < typecnt; ++i) 1732192625Sedwin if (writetype[i]) 1733192625Sedwin (void) putc(ttisstds[i], fp); 1734192625Sedwin for (i = 0; i < typecnt; ++i) 1735192625Sedwin if (writetype[i]) 1736192625Sedwin (void) putc(ttisgmts[i], fp); 17372702Swollman } 1738192625Sedwin (void) fprintf(fp, "\n%s\n", string); 173930829Scharnier if (ferror(fp) || fclose(fp)) 174030829Scharnier errx(EXIT_FAILURE, _("error writing %s"), fullname); 174142997Swollman if (chmod(fullname, mflag) < 0) 174242997Swollman err(EXIT_FAILURE, _("cannot change mode of %s to %03o"), 174342997Swollman fullname, (unsigned)mflag); 174442997Swollman if ((uflag != (uid_t)-1 || gflag != (gid_t)-1) 174542997Swollman && chown(fullname, uflag, gflag) < 0) 174642997Swollman err(EXIT_FAILURE, _("cannot change ownership of %s"), 174742997Swollman fullname); 17482702Swollman} 17492702Swollman 17502702Swollmanstatic void 1751192625Sedwindoabbr(abbr, format, letters, isdst, doquotes) 17529937Swollmanchar * const abbr; 17539937Swollmanconst char * const format; 17549937Swollmanconst char * const letters; 17559937Swollmanconst int isdst; 1756192625Sedwinconst int doquotes; 17579937Swollman{ 1758192625Sedwin register char * cp; 1759192625Sedwin register char * slashp; 1760192625Sedwin register int len; 1761192625Sedwin 1762192625Sedwin slashp = strchr(format, '/'); 1763192625Sedwin if (slashp == NULL) { 17649937Swollman if (letters == NULL) 17659937Swollman (void) strcpy(abbr, format); 17669937Swollman else (void) sprintf(abbr, format, letters); 1767192625Sedwin } else if (isdst) { 1768192625Sedwin (void) strcpy(abbr, slashp + 1); 1769192625Sedwin } else { 1770192625Sedwin if (slashp > format) 1771192625Sedwin (void) strncpy(abbr, format, 1772192625Sedwin (unsigned) (slashp - format)); 1773192625Sedwin abbr[slashp - format] = '\0'; 17749937Swollman } 1775192625Sedwin if (!doquotes) 1776192625Sedwin return; 1777192625Sedwin for (cp = abbr; *cp != '\0'; ++cp) 1778192625Sedwin if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL && 1779192625Sedwin strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL) 1780192625Sedwin break; 1781192625Sedwin len = strlen(abbr); 1782192625Sedwin if (len > 0 && *cp == '\0') 1783192625Sedwin return; 1784192625Sedwin abbr[len + 2] = '\0'; 1785192625Sedwin abbr[len + 1] = '>'; 1786192625Sedwin for ( ; len > 0; --len) 1787192625Sedwin abbr[len] = abbr[len - 1]; 1788192625Sedwin abbr[0] = '<'; 17899937Swollman} 17909937Swollman 17919937Swollmanstatic void 1792192625Sedwinupdateminmax(x) 1793192625Sedwinconst int x; 1794192625Sedwin{ 1795192625Sedwin if (min_year > x) 1796192625Sedwin min_year = x; 1797192625Sedwin if (max_year < x) 1798192625Sedwin max_year = x; 1799192625Sedwin} 1800192625Sedwin 1801192625Sedwinstatic int 1802192625Sedwinstringoffset(result, offset) 1803192625Sedwinchar * result; 1804192625Sedwinlong offset; 1805192625Sedwin{ 1806192625Sedwin register int hours; 1807192625Sedwin register int minutes; 1808192625Sedwin register int seconds; 1809192625Sedwin 1810192625Sedwin result[0] = '\0'; 1811192625Sedwin if (offset < 0) { 1812192625Sedwin (void) strcpy(result, "-"); 1813192625Sedwin offset = -offset; 1814192625Sedwin } 1815192625Sedwin seconds = offset % SECSPERMIN; 1816192625Sedwin offset /= SECSPERMIN; 1817192625Sedwin minutes = offset % MINSPERHOUR; 1818192625Sedwin offset /= MINSPERHOUR; 1819192625Sedwin hours = offset; 1820192625Sedwin if (hours >= HOURSPERDAY) { 1821192625Sedwin result[0] = '\0'; 1822192625Sedwin return -1; 1823192625Sedwin } 1824192625Sedwin (void) sprintf(end(result), "%d", hours); 1825192625Sedwin if (minutes != 0 || seconds != 0) { 1826192625Sedwin (void) sprintf(end(result), ":%02d", minutes); 1827192625Sedwin if (seconds != 0) 1828192625Sedwin (void) sprintf(end(result), ":%02d", seconds); 1829192625Sedwin } 1830192625Sedwin return 0; 1831192625Sedwin} 1832192625Sedwin 1833192625Sedwinstatic int 1834192625Sedwinstringrule(result, rp, dstoff, gmtoff) 1835192625Sedwinchar * result; 1836192625Sedwinconst struct rule * const rp; 1837192625Sedwinconst long dstoff; 1838192625Sedwinconst long gmtoff; 1839192625Sedwin{ 1840192625Sedwin register long tod; 1841192625Sedwin 1842192625Sedwin result = end(result); 1843192625Sedwin if (rp->r_dycode == DC_DOM) { 1844192625Sedwin register int month, total; 1845192625Sedwin 1846192625Sedwin if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY) 1847192625Sedwin return -1; 1848192625Sedwin total = 0; 1849192625Sedwin for (month = 0; month < rp->r_month; ++month) 1850192625Sedwin total += len_months[0][month]; 1851192625Sedwin (void) sprintf(result, "J%d", total + rp->r_dayofmonth); 1852192625Sedwin } else { 1853192625Sedwin register int week; 1854192625Sedwin 1855192625Sedwin if (rp->r_dycode == DC_DOWGEQ) { 1856192625Sedwin week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1857192625Sedwin if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth) 1858192625Sedwin return -1; 1859192625Sedwin } else if (rp->r_dycode == DC_DOWLEQ) { 1860192625Sedwin if (rp->r_dayofmonth == len_months[1][rp->r_month]) 1861192625Sedwin week = 5; 1862192625Sedwin else { 1863192625Sedwin week = 1 + rp->r_dayofmonth / DAYSPERWEEK; 1864192625Sedwin if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth) 1865192625Sedwin return -1; 1866192625Sedwin } 1867192625Sedwin } else return -1; /* "cannot happen" */ 1868192625Sedwin (void) sprintf(result, "M%d.%d.%d", 1869192625Sedwin rp->r_month + 1, week, rp->r_wday); 1870192625Sedwin } 1871192625Sedwin tod = rp->r_tod; 1872192625Sedwin if (rp->r_todisgmt) 1873192625Sedwin tod += gmtoff; 1874192625Sedwin if (rp->r_todisstd && rp->r_stdoff == 0) 1875192625Sedwin tod += dstoff; 1876192625Sedwin if (tod < 0) { 1877192625Sedwin result[0] = '\0'; 1878192625Sedwin return -1; 1879192625Sedwin } 1880192625Sedwin if (tod != 2 * SECSPERMIN * MINSPERHOUR) { 1881192625Sedwin (void) strcat(result, "/"); 1882192625Sedwin if (stringoffset(end(result), tod) != 0) 1883192625Sedwin return -1; 1884192625Sedwin } 1885192625Sedwin return 0; 1886192625Sedwin} 1887192625Sedwin 1888192625Sedwinstatic void 1889192625Sedwinstringzone(result, zpfirst, zonecount) 1890192625Sedwinchar * result; 1891192625Sedwinconst struct zone * const zpfirst; 1892192625Sedwinconst int zonecount; 1893192625Sedwin{ 1894192625Sedwin register const struct zone * zp; 1895192625Sedwin register struct rule * rp; 1896192625Sedwin register struct rule * stdrp; 1897192625Sedwin register struct rule * dstrp; 1898192625Sedwin register int i; 1899192625Sedwin register const char * abbrvar; 1900192625Sedwin 1901192625Sedwin result[0] = '\0'; 1902192625Sedwin zp = zpfirst + zonecount - 1; 1903192625Sedwin stdrp = dstrp = NULL; 1904192625Sedwin for (i = 0; i < zp->z_nrules; ++i) { 1905192625Sedwin rp = &zp->z_rules[i]; 1906192625Sedwin if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX) 1907192625Sedwin continue; 1908192625Sedwin if (rp->r_yrtype != NULL) 1909192625Sedwin continue; 1910192625Sedwin if (rp->r_stdoff == 0) { 1911192625Sedwin if (stdrp == NULL) 1912192625Sedwin stdrp = rp; 1913192625Sedwin else return; 1914192625Sedwin } else { 1915192625Sedwin if (dstrp == NULL) 1916192625Sedwin dstrp = rp; 1917192625Sedwin else return; 1918192625Sedwin } 1919192625Sedwin } 1920192625Sedwin if (stdrp == NULL && dstrp == NULL) { 1921192625Sedwin /* 1922192625Sedwin ** There are no rules running through "max". 1923192625Sedwin ** Let's find the latest rule. 1924192625Sedwin */ 1925192625Sedwin for (i = 0; i < zp->z_nrules; ++i) { 1926192625Sedwin rp = &zp->z_rules[i]; 1927192625Sedwin if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear || 1928192625Sedwin (rp->r_hiyear == stdrp->r_hiyear && 1929192625Sedwin rp->r_month > stdrp->r_month)) 1930192625Sedwin stdrp = rp; 1931192625Sedwin } 1932192625Sedwin if (stdrp != NULL && stdrp->r_stdoff != 0) 1933192625Sedwin return; /* We end up in DST (a POSIX no-no). */ 1934192625Sedwin /* 1935192625Sedwin ** Horrid special case: if year is 2037, 1936192625Sedwin ** presume this is a zone handled on a year-by-year basis; 1937192625Sedwin ** do not try to apply a rule to the zone. 1938192625Sedwin */ 1939192625Sedwin if (stdrp != NULL && stdrp->r_hiyear == 2037) 1940192625Sedwin return; 1941192625Sedwin } 1942196587Sedwin if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0)) 1943192625Sedwin return; 1944192625Sedwin abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar; 1945192625Sedwin doabbr(result, zp->z_format, abbrvar, FALSE, TRUE); 1946192625Sedwin if (stringoffset(end(result), -zp->z_gmtoff) != 0) { 1947192625Sedwin result[0] = '\0'; 1948192625Sedwin return; 1949192625Sedwin } 1950192625Sedwin if (dstrp == NULL) 1951192625Sedwin return; 1952192625Sedwin doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE); 1953192625Sedwin if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) 1954192625Sedwin if (stringoffset(end(result), 1955192625Sedwin -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) { 1956192625Sedwin result[0] = '\0'; 1957192625Sedwin return; 1958192625Sedwin } 1959192625Sedwin (void) strcat(result, ","); 1960192625Sedwin if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1961192625Sedwin result[0] = '\0'; 1962192625Sedwin return; 1963192625Sedwin } 1964192625Sedwin (void) strcat(result, ","); 1965192625Sedwin if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) { 1966192625Sedwin result[0] = '\0'; 1967192625Sedwin return; 1968192625Sedwin } 1969192625Sedwin} 1970192625Sedwin 1971192625Sedwinstatic void 19722702Swollmanoutzone(zpfirst, zonecount) 19732702Swollmanconst struct zone * const zpfirst; 19742702Swollmanconst int zonecount; 19752702Swollman{ 19762702Swollman register const struct zone * zp; 19772702Swollman register struct rule * rp; 19782702Swollman register int i, j; 19792702Swollman register int usestart, useuntil; 1980192625Sedwin register zic_t starttime, untiltime; 19812702Swollman register long gmtoff; 19822702Swollman register long stdoff; 19832702Swollman register int year; 19842702Swollman register long startoff; 19852702Swollman register int startttisstd; 19869937Swollman register int startttisgmt; 19872702Swollman register int type; 1988192625Sedwin register char * startbuf; 1989192625Sedwin register char * ab; 1990192625Sedwin register char * envvar; 1991192625Sedwin register int max_abbr_len; 1992192625Sedwin register int max_envvar_len; 19932702Swollman 1994192625Sedwin max_abbr_len = 2 + max_format_len + max_abbrvar_len; 1995192625Sedwin max_envvar_len = 2 * max_abbr_len + 5 * 9; 1996192625Sedwin startbuf = emalloc(max_abbr_len + 1); 1997192625Sedwin ab = emalloc(max_abbr_len + 1); 1998192625Sedwin envvar = emalloc(max_envvar_len + 1); 19999937Swollman INITIALIZE(untiltime); 20009937Swollman INITIALIZE(starttime); 20012702Swollman /* 20022702Swollman ** Now. . .finally. . .generate some useful data! 20032702Swollman */ 20042702Swollman timecnt = 0; 20052702Swollman typecnt = 0; 20062702Swollman charcnt = 0; 20072702Swollman /* 2008192625Sedwin ** Thanks to Earl Chew 20092702Swollman ** for noting the need to unconditionally initialize startttisstd. 20102702Swollman */ 20112702Swollman startttisstd = FALSE; 20129937Swollman startttisgmt = FALSE; 2013192625Sedwin min_year = max_year = EPOCH_YEAR; 2014192625Sedwin if (leapseen) { 2015192625Sedwin updateminmax(leapminyear); 2016192625Sedwin updateminmax(leapmaxyear + (leapmaxyear < INT_MAX)); 2017192625Sedwin } 20182702Swollman for (i = 0; i < zonecount; ++i) { 2019192625Sedwin zp = &zpfirst[i]; 2020192625Sedwin if (i < zonecount - 1) 2021192625Sedwin updateminmax(zp->z_untilrule.r_loyear); 2022192625Sedwin for (j = 0; j < zp->z_nrules; ++j) { 2023192625Sedwin rp = &zp->z_rules[j]; 2024192625Sedwin if (rp->r_lowasnum) 2025192625Sedwin updateminmax(rp->r_loyear); 2026192625Sedwin if (rp->r_hiwasnum) 2027192625Sedwin updateminmax(rp->r_hiyear); 2028192625Sedwin } 2029192625Sedwin } 2030192625Sedwin /* 2031192625Sedwin ** Generate lots of data if a rule can't cover all future times. 2032192625Sedwin */ 2033192625Sedwin stringzone(envvar, zpfirst, zonecount); 2034192625Sedwin if (noise && envvar[0] == '\0') { 2035192625Sedwin register char * wp; 2036192625Sedwin 2037192625Sedwinwp = ecpyalloc(_("no POSIX environment variable for zone")); 2038192625Sedwin wp = ecatalloc(wp, " "); 2039192625Sedwin wp = ecatalloc(wp, zpfirst->z_name); 2040192625Sedwin warning(wp); 2041192625Sedwin ifree(wp); 2042192625Sedwin } 2043192625Sedwin if (envvar[0] == '\0') { 2044192625Sedwin if (min_year >= INT_MIN + YEARSPERREPEAT) 2045192625Sedwin min_year -= YEARSPERREPEAT; 2046192625Sedwin else min_year = INT_MIN; 2047192625Sedwin if (max_year <= INT_MAX - YEARSPERREPEAT) 2048192625Sedwin max_year += YEARSPERREPEAT; 2049192625Sedwin else max_year = INT_MAX; 2050192625Sedwin } 2051192625Sedwin /* 2052192625Sedwin ** For the benefit of older systems, 2053192625Sedwin ** generate data from 1900 through 2037. 2054192625Sedwin */ 2055192625Sedwin if (min_year > 1900) 2056192625Sedwin min_year = 1900; 2057192625Sedwin if (max_year < 2037) 2058192625Sedwin max_year = 2037; 2059192625Sedwin for (i = 0; i < zonecount; ++i) { 2060130819Sstefanf /* 2061130819Sstefanf ** A guess that may well be corrected later. 2062130819Sstefanf */ 2063130819Sstefanf stdoff = 0; 20642702Swollman zp = &zpfirst[i]; 20652702Swollman usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 20662702Swollman useuntil = i < (zonecount - 1); 20672702Swollman if (useuntil && zp->z_untiltime <= min_time) 20682702Swollman continue; 20692702Swollman gmtoff = zp->z_gmtoff; 20702702Swollman eat(zp->z_filename, zp->z_linenum); 207117214Swollman *startbuf = '\0'; 207217214Swollman startoff = zp->z_gmtoff; 20732702Swollman if (zp->z_nrules == 0) { 20742702Swollman stdoff = zp->z_stdoff; 20759937Swollman doabbr(startbuf, zp->z_format, 2076192625Sedwin (char *) NULL, stdoff != 0, FALSE); 20772702Swollman type = addtype(oadd(zp->z_gmtoff, stdoff), 20789937Swollman startbuf, stdoff != 0, startttisstd, 20799937Swollman startttisgmt); 208017214Swollman if (usestart) { 20812702Swollman addtt(starttime, type); 208217214Swollman usestart = FALSE; 2083130819Sstefanf } else if (stdoff != 0) 20842702Swollman addtt(min_time, type); 20852702Swollman } else for (year = min_year; year <= max_year; ++year) { 20862702Swollman if (useuntil && year > zp->z_untilrule.r_hiyear) 20872702Swollman break; 20882702Swollman /* 20892702Swollman ** Mark which rules to do in the current year. 20902702Swollman ** For those to do, calculate rpytime(rp, year); 20912702Swollman */ 20922702Swollman for (j = 0; j < zp->z_nrules; ++j) { 20932702Swollman rp = &zp->z_rules[j]; 20942702Swollman eats(zp->z_filename, zp->z_linenum, 20952702Swollman rp->r_filename, rp->r_linenum); 20962702Swollman rp->r_todo = year >= rp->r_loyear && 20972702Swollman year <= rp->r_hiyear && 20982702Swollman yearistype(year, rp->r_yrtype); 20992702Swollman if (rp->r_todo) 21002702Swollman rp->r_temp = rpytime(rp, year); 21012702Swollman } 21022702Swollman for ( ; ; ) { 21032702Swollman register int k; 2104192625Sedwin register zic_t jtime, ktime; 21052702Swollman register long offset; 21062702Swollman 21079937Swollman INITIALIZE(ktime); 21082702Swollman if (useuntil) { 21092702Swollman /* 211042997Swollman ** Turn untiltime into UTC 21112702Swollman ** assuming the current gmtoff and 21122702Swollman ** stdoff values. 21132702Swollman */ 21149937Swollman untiltime = zp->z_untiltime; 21159937Swollman if (!zp->z_untilrule.r_todisgmt) 21169937Swollman untiltime = tadd(untiltime, 21179937Swollman -gmtoff); 21182702Swollman if (!zp->z_untilrule.r_todisstd) 21192702Swollman untiltime = tadd(untiltime, 21202702Swollman -stdoff); 21212702Swollman } 21222702Swollman /* 21232702Swollman ** Find the rule (of those to do, if any) 21242702Swollman ** that takes effect earliest in the year. 21252702Swollman */ 21262702Swollman k = -1; 21272702Swollman for (j = 0; j < zp->z_nrules; ++j) { 21282702Swollman rp = &zp->z_rules[j]; 21292702Swollman if (!rp->r_todo) 21302702Swollman continue; 21312702Swollman eats(zp->z_filename, zp->z_linenum, 21322702Swollman rp->r_filename, rp->r_linenum); 21339937Swollman offset = rp->r_todisgmt ? 0 : gmtoff; 21342702Swollman if (!rp->r_todisstd) 21352702Swollman offset = oadd(offset, stdoff); 21362702Swollman jtime = rp->r_temp; 21372702Swollman if (jtime == min_time || 21382702Swollman jtime == max_time) 21392702Swollman continue; 21402702Swollman jtime = tadd(jtime, -offset); 21412702Swollman if (k < 0 || jtime < ktime) { 21422702Swollman k = j; 21432702Swollman ktime = jtime; 21442702Swollman } 21452702Swollman } 21462702Swollman if (k < 0) 21472702Swollman break; /* go on to next year */ 21482702Swollman rp = &zp->z_rules[k]; 21492702Swollman rp->r_todo = FALSE; 21502702Swollman if (useuntil && ktime >= untiltime) 21512702Swollman break; 215217214Swollman stdoff = rp->r_stdoff; 215317214Swollman if (usestart && ktime == starttime) 215417214Swollman usestart = FALSE; 21552702Swollman if (usestart) { 215617214Swollman if (ktime < starttime) { 215717214Swollman startoff = oadd(zp->z_gmtoff, 215817214Swollman stdoff); 215917214Swollman doabbr(startbuf, zp->z_format, 216017214Swollman rp->r_abbrvar, 2161192625Sedwin rp->r_stdoff != 0, 2162192625Sedwin FALSE); 216317214Swollman continue; 21642702Swollman } 216517214Swollman if (*startbuf == '\0' && 2166192625Sedwin startoff == oadd(zp->z_gmtoff, 2167192625Sedwin stdoff)) { 2168192625Sedwin doabbr(startbuf, 2169192625Sedwin zp->z_format, 2170192625Sedwin rp->r_abbrvar, 2171192625Sedwin rp->r_stdoff != 2172192625Sedwin 0, 2173192625Sedwin FALSE); 217417214Swollman } 21752702Swollman } 21762702Swollman eats(zp->z_filename, zp->z_linenum, 21772702Swollman rp->r_filename, rp->r_linenum); 2178192625Sedwin doabbr(ab, zp->z_format, rp->r_abbrvar, 2179192625Sedwin rp->r_stdoff != 0, FALSE); 21802702Swollman offset = oadd(zp->z_gmtoff, rp->r_stdoff); 2181192625Sedwin type = addtype(offset, ab, rp->r_stdoff != 0, 21829937Swollman rp->r_todisstd, rp->r_todisgmt); 21832702Swollman addtt(ktime, type); 21842702Swollman } 21852702Swollman } 218617214Swollman if (usestart) { 218717214Swollman if (*startbuf == '\0' && 218817214Swollman zp->z_format != NULL && 218917214Swollman strchr(zp->z_format, '%') == NULL && 219017214Swollman strchr(zp->z_format, '/') == NULL) 219117214Swollman (void) strcpy(startbuf, zp->z_format); 219217214Swollman eat(zp->z_filename, zp->z_linenum); 219317214Swollman if (*startbuf == '\0') 219442997Swollmanerror(_("can't determine time zone abbreviation to use just after until time")); 219517214Swollman else addtt(starttime, 219617214Swollman addtype(startoff, startbuf, 219717214Swollman startoff != zp->z_gmtoff, 219817214Swollman startttisstd, 219917214Swollman startttisgmt)); 220017214Swollman } 22012702Swollman /* 22022702Swollman ** Now we may get to set starttime for the next zone line. 22032702Swollman */ 22042702Swollman if (useuntil) { 22052702Swollman startttisstd = zp->z_untilrule.r_todisstd; 22069937Swollman startttisgmt = zp->z_untilrule.r_todisgmt; 220717214Swollman starttime = zp->z_untiltime; 22082702Swollman if (!startttisstd) 22092702Swollman starttime = tadd(starttime, -stdoff); 221017214Swollman if (!startttisgmt) 221117214Swollman starttime = tadd(starttime, -gmtoff); 22122702Swollman } 22132702Swollman } 2214192625Sedwin writezone(zpfirst->z_name, envvar); 2215192625Sedwin ifree(startbuf); 2216192625Sedwin ifree(ab); 2217192625Sedwin ifree(envvar); 22182702Swollman} 22192702Swollman 22202702Swollmanstatic void 22212702Swollmanaddtt(starttime, type) 2222192625Sedwinconst zic_t starttime; 222342997Swollmanint type; 22242702Swollman{ 222542997Swollman if (starttime <= min_time || 222642997Swollman (timecnt == 1 && attypes[0].at < min_time)) { 222742997Swollman gmtoffs[0] = gmtoffs[type]; 222842997Swollman isdsts[0] = isdsts[type]; 222942997Swollman ttisstds[0] = ttisstds[type]; 223042997Swollman ttisgmts[0] = ttisgmts[type]; 223142997Swollman if (abbrinds[type] != 0) 223242997Swollman (void) strcpy(chars, &chars[abbrinds[type]]); 223342997Swollman abbrinds[0] = 0; 223442997Swollman charcnt = strlen(chars) + 1; 223542997Swollman typecnt = 1; 223642997Swollman timecnt = 0; 223742997Swollman type = 0; 223842997Swollman } 22392702Swollman if (timecnt >= TZ_MAX_TIMES) { 224017214Swollman error(_("too many transitions?!")); 2241192625Sedwin exit(EXIT_FAILURE); 22422702Swollman } 224317214Swollman attypes[timecnt].at = starttime; 224417214Swollman attypes[timecnt].type = type; 22452702Swollman ++timecnt; 22462702Swollman} 22472702Swollman 22482702Swollmanstatic int 22499937Swollmanaddtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 22502702Swollmanconst long gmtoff; 22512702Swollmanconst char * const abbr; 22522702Swollmanconst int isdst; 22532702Swollmanconst int ttisstd; 22549937Swollmanconst int ttisgmt; 22552702Swollman{ 22562702Swollman register int i, j; 22572702Swollman 225817214Swollman if (isdst != TRUE && isdst != FALSE) { 225917214Swollman error(_("internal error - addtype called with bad isdst")); 2260192625Sedwin exit(EXIT_FAILURE); 226117214Swollman } 226217214Swollman if (ttisstd != TRUE && ttisstd != FALSE) { 226317214Swollman error(_("internal error - addtype called with bad ttisstd")); 2264192625Sedwin exit(EXIT_FAILURE); 226517214Swollman } 226617214Swollman if (ttisgmt != TRUE && ttisgmt != FALSE) { 226717214Swollman error(_("internal error - addtype called with bad ttisgmt")); 2268192625Sedwin exit(EXIT_FAILURE); 226917214Swollman } 22702702Swollman /* 22712702Swollman ** See if there's already an entry for this zone type. 22722702Swollman ** If so, just return its index. 22732702Swollman */ 22742702Swollman for (i = 0; i < typecnt; ++i) { 22752702Swollman if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 22762702Swollman strcmp(abbr, &chars[abbrinds[i]]) == 0 && 22779937Swollman ttisstd == ttisstds[i] && 22789937Swollman ttisgmt == ttisgmts[i]) 22792702Swollman return i; 22802702Swollman } 22812702Swollman /* 22822702Swollman ** There isn't one; add a new one, unless there are already too 22832702Swollman ** many. 22842702Swollman */ 22852702Swollman if (typecnt >= TZ_MAX_TYPES) { 228617214Swollman error(_("too many local time types")); 2287192625Sedwin exit(EXIT_FAILURE); 22882702Swollman } 2289192625Sedwin if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 2290192625Sedwin error(_("UTC offset out of range")); 2291192625Sedwin exit(EXIT_FAILURE); 2292192625Sedwin } 22932702Swollman gmtoffs[i] = gmtoff; 22942702Swollman isdsts[i] = isdst; 22952702Swollman ttisstds[i] = ttisstd; 22969937Swollman ttisgmts[i] = ttisgmt; 22972702Swollman 22982702Swollman for (j = 0; j < charcnt; ++j) 22992702Swollman if (strcmp(&chars[j], abbr) == 0) 23002702Swollman break; 23012702Swollman if (j == charcnt) 23022702Swollman newabbr(abbr); 23032702Swollman abbrinds[i] = j; 23042702Swollman ++typecnt; 23052702Swollman return i; 23062702Swollman} 23072702Swollman 23082702Swollmanstatic void 23092702Swollmanleapadd(t, positive, rolling, count) 2310192625Sedwinconst zic_t t; 23112702Swollmanconst int positive; 23122702Swollmanconst int rolling; 23132702Swollmanint count; 23142702Swollman{ 23152702Swollman register int i, j; 23162702Swollman 23172702Swollman if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 231817214Swollman error(_("too many leap seconds")); 2319192625Sedwin exit(EXIT_FAILURE); 23202702Swollman } 23212702Swollman for (i = 0; i < leapcnt; ++i) 23222702Swollman if (t <= trans[i]) { 23232702Swollman if (t == trans[i]) { 232417214Swollman error(_("repeated leap second moment")); 2325192625Sedwin exit(EXIT_FAILURE); 23262702Swollman } 23272702Swollman break; 23282702Swollman } 23292702Swollman do { 23302702Swollman for (j = leapcnt; j > i; --j) { 23312702Swollman trans[j] = trans[j - 1]; 23322702Swollman corr[j] = corr[j - 1]; 23332702Swollman roll[j] = roll[j - 1]; 23342702Swollman } 23352702Swollman trans[i] = t; 23362702Swollman corr[i] = positive ? 1L : eitol(-count); 23372702Swollman roll[i] = rolling; 23382702Swollman ++leapcnt; 23392702Swollman } while (positive && --count != 0); 23402702Swollman} 23412702Swollman 23422702Swollmanstatic void 2343192625Sedwinadjleap(void) 23442702Swollman{ 23452702Swollman register int i; 23462702Swollman register long last = 0; 23472702Swollman 23482702Swollman /* 23492702Swollman ** propagate leap seconds forward 23502702Swollman */ 23512702Swollman for (i = 0; i < leapcnt; ++i) { 23522702Swollman trans[i] = tadd(trans[i], last); 23532702Swollman last = corr[i] += last; 23542702Swollman } 23552702Swollman} 23562702Swollman 23572702Swollmanstatic int 23582702Swollmanyearistype(year, type) 23592702Swollmanconst int year; 23602702Swollmanconst char * const type; 23612702Swollman{ 23622702Swollman static char * buf; 23632702Swollman int result; 23642702Swollman 23652702Swollman if (type == NULL || *type == '\0') 23662702Swollman return TRUE; 23679937Swollman buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); 23682702Swollman (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 23692702Swollman result = system(buf); 2370130819Sstefanf if (WIFEXITED(result)) switch (WEXITSTATUS(result)) { 2371130819Sstefanf case 0: 2372130819Sstefanf return TRUE; 2373130819Sstefanf case 1: 2374130819Sstefanf return FALSE; 2375130819Sstefanf } 237630829Scharnier error(_("wild result from command execution")); 237730829Scharnier warnx(_("command was '%s', result was %d"), buf, result); 23782702Swollman for ( ; ; ) 2379192625Sedwin exit(EXIT_FAILURE); 23802702Swollman} 23812702Swollman 23822702Swollmanstatic int 23832702Swollmanlowerit(a) 238417214Swollmanint a; 23852702Swollman{ 238617214Swollman a = (unsigned char) a; 23872702Swollman return (isascii(a) && isupper(a)) ? tolower(a) : a; 23882702Swollman} 23892702Swollman 23902702Swollmanstatic int 23912702Swollmanciequal(ap, bp) /* case-insensitive equality */ 23922702Swollmanregister const char * ap; 23932702Swollmanregister const char * bp; 23942702Swollman{ 23952702Swollman while (lowerit(*ap) == lowerit(*bp++)) 23962702Swollman if (*ap++ == '\0') 23972702Swollman return TRUE; 23982702Swollman return FALSE; 23992702Swollman} 24002702Swollman 24012702Swollmanstatic int 24022702Swollmanitsabbr(abbr, word) 24032702Swollmanregister const char * abbr; 24042702Swollmanregister const char * word; 24052702Swollman{ 24062702Swollman if (lowerit(*abbr) != lowerit(*word)) 24072702Swollman return FALSE; 24082702Swollman ++word; 24092702Swollman while (*++abbr != '\0') 241017214Swollman do { 241117214Swollman if (*word == '\0') 241217214Swollman return FALSE; 241317214Swollman } while (lowerit(*word++) != lowerit(*abbr)); 24142702Swollman return TRUE; 24152702Swollman} 24162702Swollman 24172702Swollmanstatic const struct lookup * 24182702Swollmanbyword(word, table) 24192702Swollmanregister const char * const word; 24202702Swollmanregister const struct lookup * const table; 24212702Swollman{ 24222702Swollman register const struct lookup * foundlp; 24232702Swollman register const struct lookup * lp; 24242702Swollman 24252702Swollman if (word == NULL || table == NULL) 24262702Swollman return NULL; 24272702Swollman /* 24282702Swollman ** Look for exact match. 24292702Swollman */ 24302702Swollman for (lp = table; lp->l_word != NULL; ++lp) 24312702Swollman if (ciequal(word, lp->l_word)) 24322702Swollman return lp; 24332702Swollman /* 24342702Swollman ** Look for inexact match. 24352702Swollman */ 24362702Swollman foundlp = NULL; 24372702Swollman for (lp = table; lp->l_word != NULL; ++lp) 243842997Swollman if (itsabbr(word, lp->l_word)) { 24392702Swollman if (foundlp == NULL) 24402702Swollman foundlp = lp; 24412702Swollman else return NULL; /* multiple inexact matches */ 244242997Swollman } 24432702Swollman return foundlp; 24442702Swollman} 24452702Swollman 24462702Swollmanstatic char ** 24472702Swollmangetfields(cp) 24482702Swollmanregister char * cp; 24492702Swollman{ 24502702Swollman register char * dp; 24512702Swollman register char ** array; 24522702Swollman register int nsubs; 24532702Swollman 24542702Swollman if (cp == NULL) 24552702Swollman return NULL; 24569937Swollman array = (char **) (void *) 24579937Swollman emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 24582702Swollman nsubs = 0; 24592702Swollman for ( ; ; ) { 2460192625Sedwin while (isascii((unsigned char) *cp) && 2461192625Sedwin isspace((unsigned char) *cp)) 2462192625Sedwin ++cp; 24632702Swollman if (*cp == '\0' || *cp == '#') 24642702Swollman break; 24652702Swollman array[nsubs++] = dp = cp; 24662702Swollman do { 24672702Swollman if ((*dp = *cp++) != '"') 24682702Swollman ++dp; 24692702Swollman else while ((*dp = *cp++) != '"') 24702702Swollman if (*dp != '\0') 24712702Swollman ++dp; 2472174210Skevlo else { 2473174210Skevlo error(_("odd number of quotation marks")); 2474174210Skevlo exit(EXIT_FAILURE); 2475174210Skevlo } 24762702Swollman } while (*cp != '\0' && *cp != '#' && 247717214Swollman (!isascii(*cp) || !isspace((unsigned char) *cp))); 247817214Swollman if (isascii(*cp) && isspace((unsigned char) *cp)) 24792702Swollman ++cp; 24802702Swollman *dp = '\0'; 24812702Swollman } 24822702Swollman array[nsubs] = NULL; 24832702Swollman return array; 24842702Swollman} 24852702Swollman 24862702Swollmanstatic long 24872702Swollmanoadd(t1, t2) 24882702Swollmanconst long t1; 24892702Swollmanconst long t2; 24902702Swollman{ 24912702Swollman register long t; 24922702Swollman 24932702Swollman t = t1 + t2; 24942702Swollman if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 249517214Swollman error(_("time overflow")); 2496192625Sedwin exit(EXIT_FAILURE); 24972702Swollman } 24982702Swollman return t; 24992702Swollman} 25002702Swollman 2501192625Sedwinstatic zic_t 25022702Swollmantadd(t1, t2) 2503192625Sedwinconst zic_t t1; 25042702Swollmanconst long t2; 25052702Swollman{ 2506192625Sedwin register zic_t t; 25072702Swollman 25082702Swollman if (t1 == max_time && t2 > 0) 25092702Swollman return max_time; 25102702Swollman if (t1 == min_time && t2 < 0) 25112702Swollman return min_time; 25122702Swollman t = t1 + t2; 25132702Swollman if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 251417214Swollman error(_("time overflow")); 2515192625Sedwin exit(EXIT_FAILURE); 25162702Swollman } 25172702Swollman return t; 25182702Swollman} 25192702Swollman 25202702Swollman/* 25212702Swollman** Given a rule, and a year, compute the date - in seconds since January 1, 25222702Swollman** 1970, 00:00 LOCAL time - in that year that the rule refers to. 25232702Swollman*/ 25242702Swollman 2525192625Sedwinstatic zic_t 25262702Swollmanrpytime(rp, wantedy) 25272702Swollmanregister const struct rule * const rp; 25282702Swollmanregister const int wantedy; 25292702Swollman{ 25302702Swollman register int y, m, i; 25312702Swollman register long dayoff; /* with a nod to Margaret O. */ 2532192625Sedwin register zic_t t; 25332702Swollman 253417214Swollman if (wantedy == INT_MIN) 25352702Swollman return min_time; 253617214Swollman if (wantedy == INT_MAX) 25372702Swollman return max_time; 25382702Swollman dayoff = 0; 25392702Swollman m = TM_JANUARY; 25402702Swollman y = EPOCH_YEAR; 25412702Swollman while (wantedy != y) { 25422702Swollman if (wantedy > y) { 25432702Swollman i = len_years[isleap(y)]; 25442702Swollman ++y; 25452702Swollman } else { 25462702Swollman --y; 25472702Swollman i = -len_years[isleap(y)]; 25482702Swollman } 25492702Swollman dayoff = oadd(dayoff, eitol(i)); 25502702Swollman } 25512702Swollman while (m != rp->r_month) { 25522702Swollman i = len_months[isleap(y)][m]; 25532702Swollman dayoff = oadd(dayoff, eitol(i)); 25542702Swollman ++m; 25552702Swollman } 25562702Swollman i = rp->r_dayofmonth; 25572702Swollman if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 25582702Swollman if (rp->r_dycode == DC_DOWLEQ) 25592702Swollman --i; 25602702Swollman else { 256117214Swollman error(_("use of 2/29 in non leap-year")); 2562192625Sedwin exit(EXIT_FAILURE); 25632702Swollman } 25642702Swollman } 25652702Swollman --i; 25662702Swollman dayoff = oadd(dayoff, eitol(i)); 25672702Swollman if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 25682702Swollman register long wday; 25692702Swollman 25702702Swollman#define LDAYSPERWEEK ((long) DAYSPERWEEK) 25712702Swollman wday = eitol(EPOCH_WDAY); 25722702Swollman /* 25732702Swollman ** Don't trust mod of negative numbers. 25742702Swollman */ 25752702Swollman if (dayoff >= 0) 25762702Swollman wday = (wday + dayoff) % LDAYSPERWEEK; 25772702Swollman else { 25782702Swollman wday -= ((-dayoff) % LDAYSPERWEEK); 25792702Swollman if (wday < 0) 25802702Swollman wday += LDAYSPERWEEK; 25812702Swollman } 25822702Swollman while (wday != eitol(rp->r_wday)) 25832702Swollman if (rp->r_dycode == DC_DOWGEQ) { 25842702Swollman dayoff = oadd(dayoff, (long) 1); 25852702Swollman if (++wday >= LDAYSPERWEEK) 25862702Swollman wday = 0; 25872702Swollman ++i; 25882702Swollman } else { 25892702Swollman dayoff = oadd(dayoff, (long) -1); 25902702Swollman if (--wday < 0) 25912702Swollman wday = LDAYSPERWEEK - 1; 25922702Swollman --i; 25932702Swollman } 25942702Swollman if (i < 0 || i >= len_months[isleap(y)][m]) { 2595130819Sstefanf if (noise) 2596192625Sedwin warning(_("rule goes past start/end of month--\ 2597192625Sedwinwill not work with pre-2004 versions of zic")); 25982702Swollman } 25992702Swollman } 2600130819Sstefanf if (dayoff < min_time / SECSPERDAY) 2601130819Sstefanf return min_time; 2602130819Sstefanf if (dayoff > max_time / SECSPERDAY) 2603130819Sstefanf return max_time; 2604192625Sedwin t = (zic_t) dayoff * SECSPERDAY; 26052702Swollman return tadd(t, rp->r_tod); 26062702Swollman} 26072702Swollman 26082702Swollmanstatic void 26092702Swollmannewabbr(string) 26102702Swollmanconst char * const string; 26112702Swollman{ 26122702Swollman register int i; 26132702Swollman 2614192625Sedwin if (strcmp(string, GRANDPARENTED) != 0) { 2615192625Sedwin register const char * cp; 2616192625Sedwin register char * wp; 2617192625Sedwin 2618192625Sedwin cp = string; 2619192625Sedwin wp = NULL; 2620192625Sedwin while (isascii((unsigned char) *cp) && 2621307358Sbapt (isalnum((unsigned char)*cp) || *cp == '-' || *cp == '+')) 2622192625Sedwin ++cp; 2623192625Sedwin if (noise && cp - string > 3) 2624307358Sbaptwp = _("time zone abbreviation has more than 3 characters"); 2625192625Sedwin if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 2626307358Sbaptwp = _("time zone abbreviation has too many characters"); 2627192625Sedwin if (*cp != '\0') 2628192625Sedwinwp = _("time zone abbreviation differs from POSIX standard"); 2629192625Sedwin if (wp != NULL) { 2630192625Sedwin wp = ecpyalloc(wp); 2631192625Sedwin wp = ecatalloc(wp, " ("); 2632192625Sedwin wp = ecatalloc(wp, string); 2633192625Sedwin wp = ecatalloc(wp, ")"); 2634192625Sedwin warning(wp); 2635192625Sedwin ifree(wp); 2636192625Sedwin } 2637192625Sedwin } 26382702Swollman i = strlen(string) + 1; 26392702Swollman if (charcnt + i > TZ_MAX_CHARS) { 264017214Swollman error(_("too many, or too long, time zone abbreviations")); 2641192625Sedwin exit(EXIT_FAILURE); 26422702Swollman } 26432702Swollman (void) strcpy(&chars[charcnt], string); 26442702Swollman charcnt += eitol(i); 26452702Swollman} 26462702Swollman 26472702Swollmanstatic int 26482702Swollmanmkdirs(argname) 2649192625Sedwinchar * argname; 26502702Swollman{ 26512702Swollman register char * name; 26522702Swollman register char * cp; 26532702Swollman 265442997Swollman if (argname == NULL || *argname == '\0' || Dflag) 26552702Swollman return 0; 26562702Swollman cp = name = ecpyalloc(argname); 26572702Swollman while ((cp = strchr(cp + 1, '/')) != 0) { 26582702Swollman *cp = '\0'; 26592702Swollman#ifndef unix 26602702Swollman /* 26619937Swollman ** DOS drive specifier? 26622702Swollman */ 266317214Swollman if (isalpha((unsigned char) name[0]) && 266417214Swollman name[1] == ':' && name[2] == '\0') { 26652702Swollman *cp = '/'; 26662702Swollman continue; 26672702Swollman } 26682702Swollman#endif /* !defined unix */ 26692702Swollman if (!itsdir(name)) { 26702702Swollman /* 26712702Swollman ** It doesn't seem to exist, so we try to create it. 267242997Swollman ** Creation may fail because of the directory being 267342997Swollman ** created by some other multiprocessor, so we get 267442997Swollman ** to do extra checking. 26752702Swollman */ 2676130819Sstefanf if (mkdir(name, MKDIR_UMASK) != 0 267742997Swollman && (errno != EEXIST || !itsdir(name))) { 267830829Scharnier warn(_("can't create directory %s"), name); 26792702Swollman ifree(name); 26802702Swollman return -1; 26812702Swollman } 26822702Swollman } 26832702Swollman *cp = '/'; 26842702Swollman } 26852702Swollman ifree(name); 26862702Swollman return 0; 26872702Swollman} 26882702Swollman 26892702Swollmanstatic long 26902702Swollmaneitol(i) 26912702Swollmanconst int i; 26922702Swollman{ 26932702Swollman long l; 26942702Swollman 26952702Swollman l = i; 269630829Scharnier if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) 269730829Scharnier errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i); 26982702Swollman return l; 26992702Swollman} 27002702Swollman 270142997Swollman#include <grp.h> 270242997Swollman#include <pwd.h> 270342997Swollman 270442997Swollmanstatic void 270542997Swollmansetgroup(flag, name) 270642997Swollman gid_t *flag; 270742997Swollman const char *name; 270842997Swollman{ 270942997Swollman struct group *gr; 271042997Swollman 271142997Swollman if (*flag != (gid_t)-1) 271242997Swollman errx(EXIT_FAILURE, _("multiple -g flags specified")); 271342997Swollman 271442997Swollman gr = getgrnam(name); 271542997Swollman if (gr == 0) { 271642997Swollman char *ep; 271742997Swollman unsigned long ul; 271842997Swollman 271942997Swollman ul = strtoul(name, &ep, 10); 272042997Swollman if (ul == (unsigned long)(gid_t)ul && *ep == '\0') { 272142997Swollman *flag = ul; 272242997Swollman return; 272342997Swollman } 272442997Swollman errx(EXIT_FAILURE, _("group `%s' not found"), name); 272542997Swollman } 272642997Swollman *flag = gr->gr_gid; 272742997Swollman} 272842997Swollman 272942997Swollmanstatic void 273042997Swollmansetuser(flag, name) 273142997Swollman uid_t *flag; 273242997Swollman const char *name; 273342997Swollman{ 273442997Swollman struct passwd *pw; 273542997Swollman 273642997Swollman if (*flag != (gid_t)-1) 273742997Swollman errx(EXIT_FAILURE, _("multiple -u flags specified")); 273842997Swollman 273942997Swollman pw = getpwnam(name); 274042997Swollman if (pw == 0) { 274142997Swollman char *ep; 274242997Swollman unsigned long ul; 274342997Swollman 274442997Swollman ul = strtoul(name, &ep, 10); 274542997Swollman if (ul == (unsigned long)(gid_t)ul && *ep == '\0') { 274642997Swollman *flag = ul; 274742997Swollman return; 274842997Swollman } 274942997Swollman errx(EXIT_FAILURE, _("user `%s' not found"), name); 275042997Swollman } 275142997Swollman *flag = pw->pw_uid; 275242997Swollman} 275342997Swollman 27542702Swollman/* 2755130819Sstefanf** UNIX was a registered trademark of The Open Group in 2003. 27562702Swollman*/ 2757