1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1986-1999, by Sun Microsystems, Inc. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* static char elsieid[] = "@(#)zic.c 7.99"; */ 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate /* 11*7c478bd9Sstevel@tonic-gate * #define LEAPSECOND_SUPPORT 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #include "private.h" 15*7c478bd9Sstevel@tonic-gate #include <tzfile.h> /* this is in system headers at Sun */ 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> /* for umask manifest constants */ 18*7c478bd9Sstevel@tonic-gate #include <ctype.h> 19*7c478bd9Sstevel@tonic-gate #include <locale.h> 20*7c478bd9Sstevel@tonic-gate #include <stdlib.h> /* for getopt */ 21*7c478bd9Sstevel@tonic-gate 22*7c478bd9Sstevel@tonic-gate struct rule { 23*7c478bd9Sstevel@tonic-gate const char *r_filename; 24*7c478bd9Sstevel@tonic-gate int r_linenum; 25*7c478bd9Sstevel@tonic-gate const char *r_name; 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate int r_loyear; /* for example, 1986 */ 28*7c478bd9Sstevel@tonic-gate int r_hiyear; /* for example, 1986 */ 29*7c478bd9Sstevel@tonic-gate const char *r_yrtype; 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate int r_month; /* 0..11 */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate int r_dycode; /* see below */ 34*7c478bd9Sstevel@tonic-gate int r_dayofmonth; 35*7c478bd9Sstevel@tonic-gate int r_wday; 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate long r_tod; /* time from midnight */ 38*7c478bd9Sstevel@tonic-gate int r_todisstd; /* above is standard time if TRUE */ 39*7c478bd9Sstevel@tonic-gate /* or wall clock time if FALSE */ 40*7c478bd9Sstevel@tonic-gate int r_todisgmt; /* above is GMT if TRUE */ 41*7c478bd9Sstevel@tonic-gate /* or local time if FALSE */ 42*7c478bd9Sstevel@tonic-gate long r_stdoff; /* offset from standard time */ 43*7c478bd9Sstevel@tonic-gate const char *r_abbrvar; /* variable part of abbreviation */ 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate int r_todo; /* a rule to do (used in outzone) */ 46*7c478bd9Sstevel@tonic-gate time_t r_temp; /* used in outzone */ 47*7c478bd9Sstevel@tonic-gate }; 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * r_dycode r_dayofmonth r_wday 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #define DC_DOM 0 /* 1..31 */ /* unused */ 54*7c478bd9Sstevel@tonic-gate #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 55*7c478bd9Sstevel@tonic-gate #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate struct zone { 58*7c478bd9Sstevel@tonic-gate const char *z_filename; 59*7c478bd9Sstevel@tonic-gate int z_linenum; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate const char *z_name; 62*7c478bd9Sstevel@tonic-gate long z_gmtoff; 63*7c478bd9Sstevel@tonic-gate const char *z_rule; 64*7c478bd9Sstevel@tonic-gate const char *z_format; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate long z_stdoff; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate struct rule *z_rules; 69*7c478bd9Sstevel@tonic-gate int z_nrules; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate struct rule z_untilrule; 72*7c478bd9Sstevel@tonic-gate time_t z_untiltime; 73*7c478bd9Sstevel@tonic-gate }; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static void addtt(time_t starttime, int type); 76*7c478bd9Sstevel@tonic-gate static int addtype(long gmtoff, const char *abbr, int isdst, 77*7c478bd9Sstevel@tonic-gate int ttisstd, int ttisgmt); 78*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 79*7c478bd9Sstevel@tonic-gate static void leapadd(time_t t, int positive, int rolling, int count); 80*7c478bd9Sstevel@tonic-gate static void adjleap(void); 81*7c478bd9Sstevel@tonic-gate #endif 82*7c478bd9Sstevel@tonic-gate static void associate(void); 83*7c478bd9Sstevel@tonic-gate static int ciequal(const char *ap, const char *bp); 84*7c478bd9Sstevel@tonic-gate static void convert(long val, char *buf); 85*7c478bd9Sstevel@tonic-gate static void dolink(const char *fromfile, const char *tofile); 86*7c478bd9Sstevel@tonic-gate static void doabbr(char *abbr, const char *format, 87*7c478bd9Sstevel@tonic-gate const char *letters, int isdst); 88*7c478bd9Sstevel@tonic-gate static void eat(const char *name, int num); 89*7c478bd9Sstevel@tonic-gate static void eats(const char *name, int num, 90*7c478bd9Sstevel@tonic-gate const char *rname, int rnum); 91*7c478bd9Sstevel@tonic-gate static long eitol(int i); 92*7c478bd9Sstevel@tonic-gate static void error(const char *message); 93*7c478bd9Sstevel@tonic-gate static char **getfields(char *buf); 94*7c478bd9Sstevel@tonic-gate static long gethms(const char *string, const char *errstrng, int signable); 95*7c478bd9Sstevel@tonic-gate static void infile(const char *filename); 96*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 97*7c478bd9Sstevel@tonic-gate static void inleap(char **fields, int nfields); 98*7c478bd9Sstevel@tonic-gate #endif 99*7c478bd9Sstevel@tonic-gate static void inlink(char **fields, int nfields); 100*7c478bd9Sstevel@tonic-gate static void inrule(char **fields, int nfields); 101*7c478bd9Sstevel@tonic-gate static int inzcont(char **fields, int nfields); 102*7c478bd9Sstevel@tonic-gate static int inzone(char **fields, int nfields); 103*7c478bd9Sstevel@tonic-gate static int inzsub(char **fields, int nfields, int iscont); 104*7c478bd9Sstevel@tonic-gate static int itsabbr(const char *abbr, const char *word); 105*7c478bd9Sstevel@tonic-gate static int itsdir(const char *name); 106*7c478bd9Sstevel@tonic-gate static int lowerit(int c); 107*7c478bd9Sstevel@tonic-gate static char *memcheck(char *tocheck); 108*7c478bd9Sstevel@tonic-gate static int mkdirs(char *filename); 109*7c478bd9Sstevel@tonic-gate static void newabbr(const char *abbr); 110*7c478bd9Sstevel@tonic-gate static long oadd(long t1, long t2); 111*7c478bd9Sstevel@tonic-gate static void outzone(const struct zone *zp, int ntzones); 112*7c478bd9Sstevel@tonic-gate static void puttzcode(long code, FILE *fp); 113*7c478bd9Sstevel@tonic-gate static int rcomp(const void *leftp, const void *rightp); 114*7c478bd9Sstevel@tonic-gate static time_t rpytime(const struct rule *rp, int wantedy); 115*7c478bd9Sstevel@tonic-gate static void rulesub(struct rule *rp, 116*7c478bd9Sstevel@tonic-gate const char *loyearp, const char *hiyearp, 117*7c478bd9Sstevel@tonic-gate const char *typep, const char *monthp, 118*7c478bd9Sstevel@tonic-gate const char *dayp, const char *timep); 119*7c478bd9Sstevel@tonic-gate static void setboundaries(void); 120*7c478bd9Sstevel@tonic-gate static time_t tadd(time_t t1, long t2); 121*7c478bd9Sstevel@tonic-gate static void usage(void); 122*7c478bd9Sstevel@tonic-gate static void writezone(const char *name); 123*7c478bd9Sstevel@tonic-gate static int yearistype(int year, const char *type); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate static int charcnt; 126*7c478bd9Sstevel@tonic-gate static int errors; 127*7c478bd9Sstevel@tonic-gate static const char *filename; 128*7c478bd9Sstevel@tonic-gate static int leapcnt; 129*7c478bd9Sstevel@tonic-gate static int linenum; 130*7c478bd9Sstevel@tonic-gate static time_t max_time; 131*7c478bd9Sstevel@tonic-gate static int max_year; 132*7c478bd9Sstevel@tonic-gate static int max_year_representable; 133*7c478bd9Sstevel@tonic-gate static time_t min_time; 134*7c478bd9Sstevel@tonic-gate static int min_year; 135*7c478bd9Sstevel@tonic-gate static int min_year_representable; 136*7c478bd9Sstevel@tonic-gate static int noise; 137*7c478bd9Sstevel@tonic-gate static const char *rfilename; 138*7c478bd9Sstevel@tonic-gate static int rlinenum; 139*7c478bd9Sstevel@tonic-gate static const char *progname; 140*7c478bd9Sstevel@tonic-gate static int timecnt; 141*7c478bd9Sstevel@tonic-gate static int typecnt; 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* 144*7c478bd9Sstevel@tonic-gate * Line codes. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate #define LC_RULE 0 148*7c478bd9Sstevel@tonic-gate #define LC_ZONE 1 149*7c478bd9Sstevel@tonic-gate #define LC_LINK 2 150*7c478bd9Sstevel@tonic-gate #define LC_LEAP 3 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate * Which fields are which on a Zone line. 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate #define ZF_NAME 1 157*7c478bd9Sstevel@tonic-gate #define ZF_GMTOFF 2 158*7c478bd9Sstevel@tonic-gate #define ZF_RULE 3 159*7c478bd9Sstevel@tonic-gate #define ZF_FORMAT 4 160*7c478bd9Sstevel@tonic-gate #define ZF_TILYEAR 5 161*7c478bd9Sstevel@tonic-gate #define ZF_TILMONTH 6 162*7c478bd9Sstevel@tonic-gate #define ZF_TILDAY 7 163*7c478bd9Sstevel@tonic-gate #define ZF_TILTIME 8 164*7c478bd9Sstevel@tonic-gate #define ZONE_MINFIELDS 5 165*7c478bd9Sstevel@tonic-gate #define ZONE_MAXFIELDS 9 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate /* 168*7c478bd9Sstevel@tonic-gate * Which fields are which on a Zone continuation line. 169*7c478bd9Sstevel@tonic-gate */ 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate #define ZFC_GMTOFF 0 172*7c478bd9Sstevel@tonic-gate #define ZFC_RULE 1 173*7c478bd9Sstevel@tonic-gate #define ZFC_FORMAT 2 174*7c478bd9Sstevel@tonic-gate #define ZFC_TILYEAR 3 175*7c478bd9Sstevel@tonic-gate #define ZFC_TILMONTH 4 176*7c478bd9Sstevel@tonic-gate #define ZFC_TILDAY 5 177*7c478bd9Sstevel@tonic-gate #define ZFC_TILTIME 6 178*7c478bd9Sstevel@tonic-gate #define ZONEC_MINFIELDS 3 179*7c478bd9Sstevel@tonic-gate #define ZONEC_MAXFIELDS 7 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * Which files are which on a Rule line. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate #define RF_NAME 1 186*7c478bd9Sstevel@tonic-gate #define RF_LOYEAR 2 187*7c478bd9Sstevel@tonic-gate #define RF_HIYEAR 3 188*7c478bd9Sstevel@tonic-gate #define RF_COMMAND 4 189*7c478bd9Sstevel@tonic-gate #define RF_MONTH 5 190*7c478bd9Sstevel@tonic-gate #define RF_DAY 6 191*7c478bd9Sstevel@tonic-gate #define RF_TOD 7 192*7c478bd9Sstevel@tonic-gate #define RF_STDOFF 8 193*7c478bd9Sstevel@tonic-gate #define RF_ABBRVAR 9 194*7c478bd9Sstevel@tonic-gate #define RULE_FIELDS 10 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * Which fields are which on a Link line. 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate #define LF_FROM 1 201*7c478bd9Sstevel@tonic-gate #define LF_TO 2 202*7c478bd9Sstevel@tonic-gate #define LINK_FIELDS 3 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* 205*7c478bd9Sstevel@tonic-gate * Which fields are which on a Leap line. 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate #define LP_YEAR 1 209*7c478bd9Sstevel@tonic-gate #define LP_MONTH 2 210*7c478bd9Sstevel@tonic-gate #define LP_DAY 3 211*7c478bd9Sstevel@tonic-gate #define LP_TIME 4 212*7c478bd9Sstevel@tonic-gate #define LP_CORR 5 213*7c478bd9Sstevel@tonic-gate #define LP_ROLL 6 214*7c478bd9Sstevel@tonic-gate #define LEAP_FIELDS 7 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * Year synonyms. 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate #define YR_MINIMUM 0 221*7c478bd9Sstevel@tonic-gate #define YR_MAXIMUM 1 222*7c478bd9Sstevel@tonic-gate #define YR_ONLY 2 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate static struct rule *rules; 225*7c478bd9Sstevel@tonic-gate static int nrules; /* number of rules */ 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate static struct zone *zones; 228*7c478bd9Sstevel@tonic-gate static int nzones; /* number of zones */ 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate struct link { 231*7c478bd9Sstevel@tonic-gate const char *l_filename; 232*7c478bd9Sstevel@tonic-gate int l_linenum; 233*7c478bd9Sstevel@tonic-gate const char *l_from; 234*7c478bd9Sstevel@tonic-gate const char *l_to; 235*7c478bd9Sstevel@tonic-gate }; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate static struct link *links; 238*7c478bd9Sstevel@tonic-gate static int nlinks; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate struct lookup { 241*7c478bd9Sstevel@tonic-gate const char *l_word; 242*7c478bd9Sstevel@tonic-gate const int l_value; 243*7c478bd9Sstevel@tonic-gate }; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate static struct lookup const *byword(const char *string, 246*7c478bd9Sstevel@tonic-gate const struct lookup *lp); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static struct lookup const line_codes[] = { 249*7c478bd9Sstevel@tonic-gate { "Rule", LC_RULE }, 250*7c478bd9Sstevel@tonic-gate { "Zone", LC_ZONE }, 251*7c478bd9Sstevel@tonic-gate { "Link", LC_LINK }, 252*7c478bd9Sstevel@tonic-gate { "Leap", LC_LEAP }, 253*7c478bd9Sstevel@tonic-gate { NULL, 0} 254*7c478bd9Sstevel@tonic-gate }; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate static struct lookup const mon_names[] = { 257*7c478bd9Sstevel@tonic-gate { "January", TM_JANUARY }, 258*7c478bd9Sstevel@tonic-gate { "February", TM_FEBRUARY }, 259*7c478bd9Sstevel@tonic-gate { "March", TM_MARCH }, 260*7c478bd9Sstevel@tonic-gate { "April", TM_APRIL }, 261*7c478bd9Sstevel@tonic-gate { "May", TM_MAY }, 262*7c478bd9Sstevel@tonic-gate { "June", TM_JUNE }, 263*7c478bd9Sstevel@tonic-gate { "July", TM_JULY }, 264*7c478bd9Sstevel@tonic-gate { "August", TM_AUGUST }, 265*7c478bd9Sstevel@tonic-gate { "September", TM_SEPTEMBER }, 266*7c478bd9Sstevel@tonic-gate { "October", TM_OCTOBER }, 267*7c478bd9Sstevel@tonic-gate { "November", TM_NOVEMBER }, 268*7c478bd9Sstevel@tonic-gate { "December", TM_DECEMBER }, 269*7c478bd9Sstevel@tonic-gate { NULL, 0 } 270*7c478bd9Sstevel@tonic-gate }; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate static struct lookup const wday_names[] = { 273*7c478bd9Sstevel@tonic-gate { "Sunday", TM_SUNDAY }, 274*7c478bd9Sstevel@tonic-gate { "Monday", TM_MONDAY }, 275*7c478bd9Sstevel@tonic-gate { "Tuesday", TM_TUESDAY }, 276*7c478bd9Sstevel@tonic-gate { "Wednesday", TM_WEDNESDAY }, 277*7c478bd9Sstevel@tonic-gate { "Thursday", TM_THURSDAY }, 278*7c478bd9Sstevel@tonic-gate { "Friday", TM_FRIDAY }, 279*7c478bd9Sstevel@tonic-gate { "Saturday", TM_SATURDAY }, 280*7c478bd9Sstevel@tonic-gate { NULL, 0 } 281*7c478bd9Sstevel@tonic-gate }; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate static struct lookup const lasts[] = { 284*7c478bd9Sstevel@tonic-gate { "last-Sunday", TM_SUNDAY }, 285*7c478bd9Sstevel@tonic-gate { "last-Monday", TM_MONDAY }, 286*7c478bd9Sstevel@tonic-gate { "last-Tuesday", TM_TUESDAY }, 287*7c478bd9Sstevel@tonic-gate { "last-Wednesday", TM_WEDNESDAY }, 288*7c478bd9Sstevel@tonic-gate { "last-Thursday", TM_THURSDAY }, 289*7c478bd9Sstevel@tonic-gate { "last-Friday", TM_FRIDAY }, 290*7c478bd9Sstevel@tonic-gate { "last-Saturday", TM_SATURDAY }, 291*7c478bd9Sstevel@tonic-gate { NULL, 0 } 292*7c478bd9Sstevel@tonic-gate }; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate static struct lookup const begin_years[] = { 295*7c478bd9Sstevel@tonic-gate { "minimum", YR_MINIMUM }, 296*7c478bd9Sstevel@tonic-gate { "maximum", YR_MAXIMUM }, 297*7c478bd9Sstevel@tonic-gate { NULL, 0 } 298*7c478bd9Sstevel@tonic-gate }; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate static struct lookup const end_years[] = { 301*7c478bd9Sstevel@tonic-gate { "minimum", YR_MINIMUM }, 302*7c478bd9Sstevel@tonic-gate { "maximum", YR_MAXIMUM }, 303*7c478bd9Sstevel@tonic-gate { "only", YR_ONLY }, 304*7c478bd9Sstevel@tonic-gate { NULL, 0 } 305*7c478bd9Sstevel@tonic-gate }; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate static struct lookup const leap_types[] = { 308*7c478bd9Sstevel@tonic-gate { "Rolling", TRUE }, 309*7c478bd9Sstevel@tonic-gate { "Stationary", FALSE }, 310*7c478bd9Sstevel@tonic-gate { NULL, 0 } 311*7c478bd9Sstevel@tonic-gate }; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate static const int len_months[2][MONSPERYEAR] = { 314*7c478bd9Sstevel@tonic-gate { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 315*7c478bd9Sstevel@tonic-gate { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 316*7c478bd9Sstevel@tonic-gate }; 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate static const int len_years[2] = { 319*7c478bd9Sstevel@tonic-gate DAYSPERNYEAR, DAYSPERLYEAR 320*7c478bd9Sstevel@tonic-gate }; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate static struct attype { 323*7c478bd9Sstevel@tonic-gate time_t at; 324*7c478bd9Sstevel@tonic-gate unsigned char type; 325*7c478bd9Sstevel@tonic-gate } attypes[TZ_MAX_TIMES]; 326*7c478bd9Sstevel@tonic-gate static long gmtoffs[TZ_MAX_TYPES]; 327*7c478bd9Sstevel@tonic-gate static char isdsts[TZ_MAX_TYPES]; 328*7c478bd9Sstevel@tonic-gate static unsigned char abbrinds[TZ_MAX_TYPES]; 329*7c478bd9Sstevel@tonic-gate static char ttisstds[TZ_MAX_TYPES]; 330*7c478bd9Sstevel@tonic-gate static char ttisgmts[TZ_MAX_TYPES]; 331*7c478bd9Sstevel@tonic-gate static char chars[TZ_MAX_CHARS]; 332*7c478bd9Sstevel@tonic-gate static time_t trans[TZ_MAX_LEAPS]; 333*7c478bd9Sstevel@tonic-gate static long corr[TZ_MAX_LEAPS]; 334*7c478bd9Sstevel@tonic-gate static char roll[TZ_MAX_LEAPS]; 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate /* 337*7c478bd9Sstevel@tonic-gate * Memory allocation. 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate static char * 341*7c478bd9Sstevel@tonic-gate memcheck(ptr) 342*7c478bd9Sstevel@tonic-gate char * const ptr; 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 345*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 346*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Memory exhausted: %s\n"), 347*7c478bd9Sstevel@tonic-gate progname, e); 348*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate return (ptr); 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate #define emalloc(size) memcheck(imalloc(size)) 354*7c478bd9Sstevel@tonic-gate #define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 355*7c478bd9Sstevel@tonic-gate #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 356*7c478bd9Sstevel@tonic-gate #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate * Error handling. 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate static void 363*7c478bd9Sstevel@tonic-gate eats(name, num, rname, rnum) 364*7c478bd9Sstevel@tonic-gate const char * const name; 365*7c478bd9Sstevel@tonic-gate const int num; 366*7c478bd9Sstevel@tonic-gate const char * const rname; 367*7c478bd9Sstevel@tonic-gate const int rnum; 368*7c478bd9Sstevel@tonic-gate { 369*7c478bd9Sstevel@tonic-gate filename = name; 370*7c478bd9Sstevel@tonic-gate linenum = num; 371*7c478bd9Sstevel@tonic-gate rfilename = rname; 372*7c478bd9Sstevel@tonic-gate rlinenum = rnum; 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate static void 376*7c478bd9Sstevel@tonic-gate eat(name, num) 377*7c478bd9Sstevel@tonic-gate const char * const name; 378*7c478bd9Sstevel@tonic-gate const int num; 379*7c478bd9Sstevel@tonic-gate { 380*7c478bd9Sstevel@tonic-gate eats(name, num, (char *)NULL, -1); 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate static void 384*7c478bd9Sstevel@tonic-gate error(string) 385*7c478bd9Sstevel@tonic-gate const char * const string; 386*7c478bd9Sstevel@tonic-gate { 387*7c478bd9Sstevel@tonic-gate /* 388*7c478bd9Sstevel@tonic-gate * Match the format of "cc" to allow sh users to 389*7c478bd9Sstevel@tonic-gate * zic ... 2>&1 | error -t "*" -v 390*7c478bd9Sstevel@tonic-gate * on BSD systems. 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\"%s\", line %d: %s"), 393*7c478bd9Sstevel@tonic-gate filename, linenum, string); 394*7c478bd9Sstevel@tonic-gate if (rfilename != NULL) 395*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(" (rule from \"%s\", line %d)"), 396*7c478bd9Sstevel@tonic-gate rfilename, rlinenum); 397*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 398*7c478bd9Sstevel@tonic-gate ++errors; 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate static void 402*7c478bd9Sstevel@tonic-gate warning(string) 403*7c478bd9Sstevel@tonic-gate const char * const string; 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate char *cp; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate cp = ecpyalloc(gettext("warning: ")); 408*7c478bd9Sstevel@tonic-gate cp = ecatalloc(cp, string); 409*7c478bd9Sstevel@tonic-gate error(cp); 410*7c478bd9Sstevel@tonic-gate ifree(cp); 411*7c478bd9Sstevel@tonic-gate --errors; 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate static void 415*7c478bd9Sstevel@tonic-gate usage(void) 416*7c478bd9Sstevel@tonic-gate { 417*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 418*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 419*7c478bd9Sstevel@tonic-gate "usage: %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n" 420*7c478bd9Sstevel@tonic-gate "\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"), 421*7c478bd9Sstevel@tonic-gate progname); 422*7c478bd9Sstevel@tonic-gate #else /* ! LEAPSECOND_SUPPORT */ 423*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 424*7c478bd9Sstevel@tonic-gate "usage: %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n" 425*7c478bd9Sstevel@tonic-gate "\t[ -y yearistype ] [ filename ... ]\n"), 426*7c478bd9Sstevel@tonic-gate progname); 427*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate static const char *psxrules; 431*7c478bd9Sstevel@tonic-gate static const char *lcltime; 432*7c478bd9Sstevel@tonic-gate static const char *directory; 433*7c478bd9Sstevel@tonic-gate static const char *leapsec; 434*7c478bd9Sstevel@tonic-gate static const char *yitcommand; 435*7c478bd9Sstevel@tonic-gate static int sflag = FALSE; 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate int 438*7c478bd9Sstevel@tonic-gate main(argc, argv) 439*7c478bd9Sstevel@tonic-gate int argc; 440*7c478bd9Sstevel@tonic-gate char *argv[]; 441*7c478bd9Sstevel@tonic-gate { 442*7c478bd9Sstevel@tonic-gate register int i; 443*7c478bd9Sstevel@tonic-gate register int j; 444*7c478bd9Sstevel@tonic-gate register int c; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 449*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 450*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 451*7c478bd9Sstevel@tonic-gate #endif 452*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate progname = argv[0]; 455*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 456*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) 457*7c478bd9Sstevel@tonic-gate #else 458*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:l:p:vsy:")) != EOF) 459*7c478bd9Sstevel@tonic-gate #endif 460*7c478bd9Sstevel@tonic-gate switch (c) { 461*7c478bd9Sstevel@tonic-gate default: 462*7c478bd9Sstevel@tonic-gate usage(); 463*7c478bd9Sstevel@tonic-gate case 'd': 464*7c478bd9Sstevel@tonic-gate if (directory == NULL) 465*7c478bd9Sstevel@tonic-gate directory = optarg; 466*7c478bd9Sstevel@tonic-gate else { 467*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 468*7c478bd9Sstevel@tonic-gate "%s: More than one -d option specified\n"), 469*7c478bd9Sstevel@tonic-gate progname); 470*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate break; 473*7c478bd9Sstevel@tonic-gate case 'l': 474*7c478bd9Sstevel@tonic-gate if (lcltime == NULL) 475*7c478bd9Sstevel@tonic-gate lcltime = optarg; 476*7c478bd9Sstevel@tonic-gate else { 477*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 478*7c478bd9Sstevel@tonic-gate "%s: More than one -l option specified\n"), 479*7c478bd9Sstevel@tonic-gate progname); 480*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate break; 483*7c478bd9Sstevel@tonic-gate case 'p': 484*7c478bd9Sstevel@tonic-gate if (psxrules == NULL) 485*7c478bd9Sstevel@tonic-gate psxrules = optarg; 486*7c478bd9Sstevel@tonic-gate else { 487*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 488*7c478bd9Sstevel@tonic-gate "%s: More than one -p option specified\n"), 489*7c478bd9Sstevel@tonic-gate progname); 490*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate break; 493*7c478bd9Sstevel@tonic-gate case 'y': 494*7c478bd9Sstevel@tonic-gate if (yitcommand == NULL) 495*7c478bd9Sstevel@tonic-gate yitcommand = optarg; 496*7c478bd9Sstevel@tonic-gate else { 497*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 498*7c478bd9Sstevel@tonic-gate "%s: More than one -y option specified\n"), 499*7c478bd9Sstevel@tonic-gate progname); 500*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate break; 503*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 504*7c478bd9Sstevel@tonic-gate case 'L': 505*7c478bd9Sstevel@tonic-gate if (leapsec == NULL) 506*7c478bd9Sstevel@tonic-gate leapsec = optarg; 507*7c478bd9Sstevel@tonic-gate else { 508*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 509*7c478bd9Sstevel@tonic-gate "%s: More than one -L option specified\n"), 510*7c478bd9Sstevel@tonic-gate progname); 511*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate break; 514*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 515*7c478bd9Sstevel@tonic-gate case 'v': 516*7c478bd9Sstevel@tonic-gate noise = TRUE; 517*7c478bd9Sstevel@tonic-gate break; 518*7c478bd9Sstevel@tonic-gate case 's': 519*7c478bd9Sstevel@tonic-gate sflag = TRUE; 520*7c478bd9Sstevel@tonic-gate break; 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 523*7c478bd9Sstevel@tonic-gate usage(); /* usage message by request */ 524*7c478bd9Sstevel@tonic-gate if (directory == NULL) 525*7c478bd9Sstevel@tonic-gate directory = TZDIR; 526*7c478bd9Sstevel@tonic-gate if (yitcommand == NULL) 527*7c478bd9Sstevel@tonic-gate yitcommand = "yearistype"; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate setboundaries(); 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 532*7c478bd9Sstevel@tonic-gate if (optind < argc && leapsec != NULL) { 533*7c478bd9Sstevel@tonic-gate infile(leapsec); 534*7c478bd9Sstevel@tonic-gate adjleap(); 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) 539*7c478bd9Sstevel@tonic-gate infile(argv[i]); 540*7c478bd9Sstevel@tonic-gate if (errors) 541*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 542*7c478bd9Sstevel@tonic-gate associate(); 543*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; i = j) { 544*7c478bd9Sstevel@tonic-gate /* 545*7c478bd9Sstevel@tonic-gate * Find the next non-continuation zone entry. 546*7c478bd9Sstevel@tonic-gate */ 547*7c478bd9Sstevel@tonic-gate for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 548*7c478bd9Sstevel@tonic-gate continue; 549*7c478bd9Sstevel@tonic-gate outzone(&zones[i], j - i); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * Make links. 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate for (i = 0; i < nlinks; ++i) { 555*7c478bd9Sstevel@tonic-gate eat(links[i].l_filename, links[i].l_linenum); 556*7c478bd9Sstevel@tonic-gate dolink(links[i].l_from, links[i].l_to); 557*7c478bd9Sstevel@tonic-gate } 558*7c478bd9Sstevel@tonic-gate if (lcltime != NULL) { 559*7c478bd9Sstevel@tonic-gate eat("command line", 1); 560*7c478bd9Sstevel@tonic-gate dolink(lcltime, TZDEFAULT); 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate if (psxrules != NULL) { 563*7c478bd9Sstevel@tonic-gate eat("command line", 1); 564*7c478bd9Sstevel@tonic-gate dolink(psxrules, TZDEFRULES); 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate return ((errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE); 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate static void 570*7c478bd9Sstevel@tonic-gate dolink(fromfile, tofile) 571*7c478bd9Sstevel@tonic-gate const char * const fromfile; 572*7c478bd9Sstevel@tonic-gate const char * const tofile; 573*7c478bd9Sstevel@tonic-gate { 574*7c478bd9Sstevel@tonic-gate register char *fromname; 575*7c478bd9Sstevel@tonic-gate register char *toname; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if (fromfile[0] == '/') 578*7c478bd9Sstevel@tonic-gate fromname = ecpyalloc(fromfile); 579*7c478bd9Sstevel@tonic-gate else { 580*7c478bd9Sstevel@tonic-gate fromname = ecpyalloc(directory); 581*7c478bd9Sstevel@tonic-gate fromname = ecatalloc(fromname, "/"); 582*7c478bd9Sstevel@tonic-gate fromname = ecatalloc(fromname, fromfile); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate if (tofile[0] == '/') 585*7c478bd9Sstevel@tonic-gate toname = ecpyalloc(tofile); 586*7c478bd9Sstevel@tonic-gate else { 587*7c478bd9Sstevel@tonic-gate toname = ecpyalloc(directory); 588*7c478bd9Sstevel@tonic-gate toname = ecatalloc(toname, "/"); 589*7c478bd9Sstevel@tonic-gate toname = ecatalloc(toname, tofile); 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * We get to be careful here since 593*7c478bd9Sstevel@tonic-gate * there's a fair chance of root running us. 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if (!itsdir(toname)) 596*7c478bd9Sstevel@tonic-gate (void) remove(toname); 597*7c478bd9Sstevel@tonic-gate if (link(fromname, toname) != 0) { 598*7c478bd9Sstevel@tonic-gate int result; 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate if (mkdirs(toname) != 0) 601*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate result = link(fromname, toname); 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate if (result != 0) { 606*7c478bd9Sstevel@tonic-gate char *s = (char *)tofile; 607*7c478bd9Sstevel@tonic-gate register char *symlinkcontents = NULL; 608*7c478bd9Sstevel@tonic-gate while ((s = strchr(s+1, '/')) != NULL) 609*7c478bd9Sstevel@tonic-gate symlinkcontents = ecatalloc(symlinkcontents, 610*7c478bd9Sstevel@tonic-gate "../"); 611*7c478bd9Sstevel@tonic-gate symlinkcontents = ecatalloc(symlinkcontents, fromfile); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate result = symlink(symlinkcontents, toname); 614*7c478bd9Sstevel@tonic-gate if (result == 0) 615*7c478bd9Sstevel@tonic-gate warning(gettext( 616*7c478bd9Sstevel@tonic-gate "hard link failed, symbolic link used")); 617*7c478bd9Sstevel@tonic-gate ifree(symlinkcontents); 618*7c478bd9Sstevel@tonic-gate } 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate if (result != 0) { 621*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 624*7c478bd9Sstevel@tonic-gate "%s: Can't link from %s to %s: %s\n"), 625*7c478bd9Sstevel@tonic-gate progname, fromname, toname, e); 626*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate ifree(fromname); 630*7c478bd9Sstevel@tonic-gate ifree(toname); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate #ifndef INT_MAX 634*7c478bd9Sstevel@tonic-gate #define INT_MAX ((int)(((unsigned)~0)>>1)) 635*7c478bd9Sstevel@tonic-gate #endif /* !defined INT_MAX */ 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate #ifndef INT_MIN 638*7c478bd9Sstevel@tonic-gate #define INT_MIN ((int)~(((unsigned)~0)>>1)) 639*7c478bd9Sstevel@tonic-gate #endif /* !defined INT_MIN */ 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * The tz file format currently allows at most 32-bit quantities. 643*7c478bd9Sstevel@tonic-gate * This restriction should be removed before signed 32-bit values 644*7c478bd9Sstevel@tonic-gate * wrap around in 2038, but unfortunately this will require a 645*7c478bd9Sstevel@tonic-gate * change to the tz file format. 646*7c478bd9Sstevel@tonic-gate */ 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate #define MAX_BITS_IN_FILE 32 649*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 650*7c478bd9Sstevel@tonic-gate #define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? \ 651*7c478bd9Sstevel@tonic-gate TYPE_BIT(time_t): MAX_BITS_IN_FILE) 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate static void 654*7c478bd9Sstevel@tonic-gate setboundaries(void) 655*7c478bd9Sstevel@tonic-gate { 656*7c478bd9Sstevel@tonic-gate if (TYPE_SIGNED(time_t)) { 657*7c478bd9Sstevel@tonic-gate min_time = ~ (time_t)0; 658*7c478bd9Sstevel@tonic-gate min_time <<= TIME_T_BITS_IN_FILE - 1; 659*7c478bd9Sstevel@tonic-gate max_time = ~ (time_t)0 - min_time; 660*7c478bd9Sstevel@tonic-gate if (sflag) 661*7c478bd9Sstevel@tonic-gate min_time = 0; 662*7c478bd9Sstevel@tonic-gate } else { 663*7c478bd9Sstevel@tonic-gate min_time = 0; 664*7c478bd9Sstevel@tonic-gate max_time = 2 - sflag; 665*7c478bd9Sstevel@tonic-gate max_time <<= TIME_T_BITS_IN_FILE - 1; 666*7c478bd9Sstevel@tonic-gate --max_time; 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 669*7c478bd9Sstevel@tonic-gate max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 670*7c478bd9Sstevel@tonic-gate min_year_representable = min_year; 671*7c478bd9Sstevel@tonic-gate max_year_representable = max_year; 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate static int 675*7c478bd9Sstevel@tonic-gate itsdir(name) 676*7c478bd9Sstevel@tonic-gate const char * const name; 677*7c478bd9Sstevel@tonic-gate { 678*7c478bd9Sstevel@tonic-gate register char *myname; 679*7c478bd9Sstevel@tonic-gate register int accres; 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate myname = ecpyalloc(name); 682*7c478bd9Sstevel@tonic-gate myname = ecatalloc(myname, "/."); 683*7c478bd9Sstevel@tonic-gate accres = access(myname, F_OK); 684*7c478bd9Sstevel@tonic-gate ifree(myname); 685*7c478bd9Sstevel@tonic-gate return (accres == 0); 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate /* 689*7c478bd9Sstevel@tonic-gate * Associate sets of rules with zones. 690*7c478bd9Sstevel@tonic-gate */ 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * Sort by rule name. 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate static int 697*7c478bd9Sstevel@tonic-gate rcomp(cp1, cp2) 698*7c478bd9Sstevel@tonic-gate const void * cp1; 699*7c478bd9Sstevel@tonic-gate const void * cp2; 700*7c478bd9Sstevel@tonic-gate { 701*7c478bd9Sstevel@tonic-gate return (strcmp(((const struct rule *) cp1)->r_name, 702*7c478bd9Sstevel@tonic-gate ((const struct rule *) cp2)->r_name)); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate static void 706*7c478bd9Sstevel@tonic-gate associate(void) 707*7c478bd9Sstevel@tonic-gate { 708*7c478bd9Sstevel@tonic-gate register struct zone *zp; 709*7c478bd9Sstevel@tonic-gate register struct rule *rp; 710*7c478bd9Sstevel@tonic-gate register int base, out; 711*7c478bd9Sstevel@tonic-gate register int i, j; 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if (nrules != 0) { 714*7c478bd9Sstevel@tonic-gate (void) qsort((void *)rules, (size_t)nrules, 715*7c478bd9Sstevel@tonic-gate (size_t)sizeof (*rules), rcomp); 716*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrules - 1; ++i) { 717*7c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_name, 718*7c478bd9Sstevel@tonic-gate rules[i + 1].r_name) != 0) 719*7c478bd9Sstevel@tonic-gate continue; 720*7c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_filename, 721*7c478bd9Sstevel@tonic-gate rules[i + 1].r_filename) == 0) 722*7c478bd9Sstevel@tonic-gate continue; 723*7c478bd9Sstevel@tonic-gate eat(rules[i].r_filename, rules[i].r_linenum); 724*7c478bd9Sstevel@tonic-gate warning(gettext("same rule name in multiple files")); 725*7c478bd9Sstevel@tonic-gate eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 726*7c478bd9Sstevel@tonic-gate warning(gettext("same rule name in multiple files")); 727*7c478bd9Sstevel@tonic-gate for (j = i + 2; j < nrules; ++j) { 728*7c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_name, 729*7c478bd9Sstevel@tonic-gate rules[j].r_name) != 0) 730*7c478bd9Sstevel@tonic-gate break; 731*7c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_filename, 732*7c478bd9Sstevel@tonic-gate rules[j].r_filename) == 0) 733*7c478bd9Sstevel@tonic-gate continue; 734*7c478bd9Sstevel@tonic-gate if (strcmp(rules[i + 1].r_filename, 735*7c478bd9Sstevel@tonic-gate rules[j].r_filename) == 0) 736*7c478bd9Sstevel@tonic-gate continue; 737*7c478bd9Sstevel@tonic-gate break; 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate i = j - 1; 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 743*7c478bd9Sstevel@tonic-gate zp = &zones[i]; 744*7c478bd9Sstevel@tonic-gate zp->z_rules = NULL; 745*7c478bd9Sstevel@tonic-gate zp->z_nrules = 0; 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate for (base = 0; base < nrules; base = out) { 748*7c478bd9Sstevel@tonic-gate rp = &rules[base]; 749*7c478bd9Sstevel@tonic-gate for (out = base + 1; out < nrules; ++out) 750*7c478bd9Sstevel@tonic-gate if (strcmp(rp->r_name, rules[out].r_name) != 0) 751*7c478bd9Sstevel@tonic-gate break; 752*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 753*7c478bd9Sstevel@tonic-gate zp = &zones[i]; 754*7c478bd9Sstevel@tonic-gate if (strcmp(zp->z_rule, rp->r_name) != 0) 755*7c478bd9Sstevel@tonic-gate continue; 756*7c478bd9Sstevel@tonic-gate zp->z_rules = rp; 757*7c478bd9Sstevel@tonic-gate zp->z_nrules = out - base; 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 761*7c478bd9Sstevel@tonic-gate zp = &zones[i]; 762*7c478bd9Sstevel@tonic-gate if (zp->z_nrules == 0) { 763*7c478bd9Sstevel@tonic-gate /* 764*7c478bd9Sstevel@tonic-gate * Maybe we have a local standard time offset. 765*7c478bd9Sstevel@tonic-gate */ 766*7c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 767*7c478bd9Sstevel@tonic-gate zp->z_stdoff = gethms(zp->z_rule, 768*7c478bd9Sstevel@tonic-gate gettext("unruly zone"), TRUE); 769*7c478bd9Sstevel@tonic-gate /* 770*7c478bd9Sstevel@tonic-gate * Note, though, that if there's no rule, 771*7c478bd9Sstevel@tonic-gate * a '%s' in the format is a bad thing. 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate if (strchr(zp->z_format, '%') != 0) 774*7c478bd9Sstevel@tonic-gate error(gettext("%s in ruleless zone")); 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate if (errors) 778*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate static void 782*7c478bd9Sstevel@tonic-gate infile(name) 783*7c478bd9Sstevel@tonic-gate const char *name; 784*7c478bd9Sstevel@tonic-gate { 785*7c478bd9Sstevel@tonic-gate register FILE *fp; 786*7c478bd9Sstevel@tonic-gate register char **fields; 787*7c478bd9Sstevel@tonic-gate register char *cp; 788*7c478bd9Sstevel@tonic-gate register const struct lookup *lp; 789*7c478bd9Sstevel@tonic-gate register int nfields; 790*7c478bd9Sstevel@tonic-gate register int wantcont; 791*7c478bd9Sstevel@tonic-gate register int num; 792*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate if (strcmp(name, "-") == 0) { 795*7c478bd9Sstevel@tonic-gate name = gettext("standard input"); 796*7c478bd9Sstevel@tonic-gate fp = stdin; 797*7c478bd9Sstevel@tonic-gate } else if ((fp = fopen(name, "r")) == NULL) { 798*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Can't open %s: %s\n"), 801*7c478bd9Sstevel@tonic-gate progname, name, e); 802*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate wantcont = FALSE; 805*7c478bd9Sstevel@tonic-gate for (num = 1; ; ++num) { 806*7c478bd9Sstevel@tonic-gate eat(name, num); 807*7c478bd9Sstevel@tonic-gate if (fgets(buf, (int)sizeof (buf), fp) != buf) 808*7c478bd9Sstevel@tonic-gate break; 809*7c478bd9Sstevel@tonic-gate cp = strchr(buf, '\n'); 810*7c478bd9Sstevel@tonic-gate if (cp == NULL) { 811*7c478bd9Sstevel@tonic-gate error(gettext("line too long")); 812*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate *cp = '\0'; 815*7c478bd9Sstevel@tonic-gate fields = getfields(buf); 816*7c478bd9Sstevel@tonic-gate nfields = 0; 817*7c478bd9Sstevel@tonic-gate while (fields[nfields] != NULL) { 818*7c478bd9Sstevel@tonic-gate static char nada; 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate if (strcmp(fields[nfields], "-") == 0) 821*7c478bd9Sstevel@tonic-gate fields[nfields] = &nada; 822*7c478bd9Sstevel@tonic-gate ++nfields; 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate if (nfields == 0) { 825*7c478bd9Sstevel@tonic-gate /* nothing to do */ 826*7c478bd9Sstevel@tonic-gate } else if (wantcont) { 827*7c478bd9Sstevel@tonic-gate wantcont = inzcont(fields, nfields); 828*7c478bd9Sstevel@tonic-gate } else { 829*7c478bd9Sstevel@tonic-gate lp = byword(fields[0], line_codes); 830*7c478bd9Sstevel@tonic-gate if (lp == NULL) 831*7c478bd9Sstevel@tonic-gate error(gettext("input line of unknown type")); 832*7c478bd9Sstevel@tonic-gate else switch ((int)(lp->l_value)) { 833*7c478bd9Sstevel@tonic-gate case LC_RULE: 834*7c478bd9Sstevel@tonic-gate inrule(fields, nfields); 835*7c478bd9Sstevel@tonic-gate wantcont = FALSE; 836*7c478bd9Sstevel@tonic-gate break; 837*7c478bd9Sstevel@tonic-gate case LC_ZONE: 838*7c478bd9Sstevel@tonic-gate wantcont = inzone(fields, nfields); 839*7c478bd9Sstevel@tonic-gate break; 840*7c478bd9Sstevel@tonic-gate case LC_LINK: 841*7c478bd9Sstevel@tonic-gate inlink(fields, nfields); 842*7c478bd9Sstevel@tonic-gate wantcont = FALSE; 843*7c478bd9Sstevel@tonic-gate break; 844*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 845*7c478bd9Sstevel@tonic-gate case LC_LEAP: 846*7c478bd9Sstevel@tonic-gate if (name != leapsec) 847*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 848*7c478bd9Sstevel@tonic-gate "%s: Leap line in non leap seconds file %s\n"), 849*7c478bd9Sstevel@tonic-gate progname, name); 850*7c478bd9Sstevel@tonic-gate else inleap(fields, nfields); 851*7c478bd9Sstevel@tonic-gate wantcont = FALSE; 852*7c478bd9Sstevel@tonic-gate break; 853*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 854*7c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 855*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 856*7c478bd9Sstevel@tonic-gate "%s: panic: Invalid l_value %d\n"), 857*7c478bd9Sstevel@tonic-gate progname, lp->l_value); 858*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate ifree((char *)fields); 862*7c478bd9Sstevel@tonic-gate } 863*7c478bd9Sstevel@tonic-gate if (ferror(fp)) { 864*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error reading %s\n"), 865*7c478bd9Sstevel@tonic-gate progname, filename); 866*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate if (fp != stdin && fclose(fp)) { 869*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 870*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error closing %s: %s\n"), 871*7c478bd9Sstevel@tonic-gate progname, filename, e); 872*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate if (wantcont) 875*7c478bd9Sstevel@tonic-gate error(gettext("expected continuation line not found")); 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate /* 879*7c478bd9Sstevel@tonic-gate * Convert a string of one of the forms 880*7c478bd9Sstevel@tonic-gate * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 881*7c478bd9Sstevel@tonic-gate * into a number of seconds. 882*7c478bd9Sstevel@tonic-gate * A null string maps to zero. 883*7c478bd9Sstevel@tonic-gate * Call error with errstring and return zero on errors. 884*7c478bd9Sstevel@tonic-gate */ 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate static long 887*7c478bd9Sstevel@tonic-gate gethms(string, errstring, signable) 888*7c478bd9Sstevel@tonic-gate const char *string; 889*7c478bd9Sstevel@tonic-gate const char * const errstring; 890*7c478bd9Sstevel@tonic-gate const int signable; 891*7c478bd9Sstevel@tonic-gate { 892*7c478bd9Sstevel@tonic-gate int hh, mm, ss, sign; 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate if (string == NULL || *string == '\0') 895*7c478bd9Sstevel@tonic-gate return (0); 896*7c478bd9Sstevel@tonic-gate if (!signable) 897*7c478bd9Sstevel@tonic-gate sign = 1; 898*7c478bd9Sstevel@tonic-gate else if (*string == '-') { 899*7c478bd9Sstevel@tonic-gate sign = -1; 900*7c478bd9Sstevel@tonic-gate ++string; 901*7c478bd9Sstevel@tonic-gate } else sign = 1; 902*7c478bd9Sstevel@tonic-gate if (sscanf(string, scheck(string, "%d"), &hh) == 1) 903*7c478bd9Sstevel@tonic-gate mm = ss = 0; 904*7c478bd9Sstevel@tonic-gate else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 905*7c478bd9Sstevel@tonic-gate ss = 0; 906*7c478bd9Sstevel@tonic-gate else if (sscanf(string, scheck(string, "%d:%d:%d"), 907*7c478bd9Sstevel@tonic-gate &hh, &mm, &ss) != 3) { 908*7c478bd9Sstevel@tonic-gate error(errstring); 909*7c478bd9Sstevel@tonic-gate return (0); 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate if ((hh < 0 || hh >= HOURSPERDAY || 912*7c478bd9Sstevel@tonic-gate mm < 0 || mm >= MINSPERHOUR || 913*7c478bd9Sstevel@tonic-gate ss < 0 || ss > SECSPERMIN) && 914*7c478bd9Sstevel@tonic-gate !(hh == HOURSPERDAY && mm == 0 && ss == 0)) { 915*7c478bd9Sstevel@tonic-gate error(errstring); 916*7c478bd9Sstevel@tonic-gate return (0); 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate return (eitol(sign) * 919*7c478bd9Sstevel@tonic-gate (eitol(hh * MINSPERHOUR + mm) * 920*7c478bd9Sstevel@tonic-gate eitol(SECSPERMIN) + eitol(ss))); 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate static void 924*7c478bd9Sstevel@tonic-gate inrule(fields, nfields) 925*7c478bd9Sstevel@tonic-gate register char ** const fields; 926*7c478bd9Sstevel@tonic-gate const int nfields; 927*7c478bd9Sstevel@tonic-gate { 928*7c478bd9Sstevel@tonic-gate static struct rule r; 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate if (nfields != RULE_FIELDS) { 931*7c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Rule line")); 932*7c478bd9Sstevel@tonic-gate return; 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate if (*fields[RF_NAME] == '\0') { 935*7c478bd9Sstevel@tonic-gate error(gettext("nameless rule")); 936*7c478bd9Sstevel@tonic-gate return; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate r.r_filename = filename; 939*7c478bd9Sstevel@tonic-gate r.r_linenum = linenum; 940*7c478bd9Sstevel@tonic-gate r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"), 941*7c478bd9Sstevel@tonic-gate TRUE); 942*7c478bd9Sstevel@tonic-gate rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 943*7c478bd9Sstevel@tonic-gate fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 944*7c478bd9Sstevel@tonic-gate r.r_name = ecpyalloc(fields[RF_NAME]); 945*7c478bd9Sstevel@tonic-gate r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 946*7c478bd9Sstevel@tonic-gate rules = (struct rule *)(void *)erealloc((char *)rules, 947*7c478bd9Sstevel@tonic-gate (int)((nrules + 1) * sizeof (*rules))); 948*7c478bd9Sstevel@tonic-gate rules[nrules++] = r; 949*7c478bd9Sstevel@tonic-gate } 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate static int 952*7c478bd9Sstevel@tonic-gate inzone(fields, nfields) 953*7c478bd9Sstevel@tonic-gate register char ** const fields; 954*7c478bd9Sstevel@tonic-gate const int nfields; 955*7c478bd9Sstevel@tonic-gate { 956*7c478bd9Sstevel@tonic-gate register int i; 957*7c478bd9Sstevel@tonic-gate static char *buf; 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 960*7c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Zone line")); 961*7c478bd9Sstevel@tonic-gate return (FALSE); 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 964*7c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT))); 965*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, 966*7c478bd9Sstevel@tonic-gate gettext("\"Zone %s\" line and -l option are mutually exclusive"), 967*7c478bd9Sstevel@tonic-gate TZDEFAULT); 968*7c478bd9Sstevel@tonic-gate error(buf); 969*7c478bd9Sstevel@tonic-gate return (FALSE); 970*7c478bd9Sstevel@tonic-gate } 971*7c478bd9Sstevel@tonic-gate if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 972*7c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES))); 973*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, 974*7c478bd9Sstevel@tonic-gate gettext("\"Zone %s\" line and -p option are mutually exclusive"), 975*7c478bd9Sstevel@tonic-gate TZDEFRULES); 976*7c478bd9Sstevel@tonic-gate error(buf); 977*7c478bd9Sstevel@tonic-gate return (FALSE); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) 980*7c478bd9Sstevel@tonic-gate if (zones[i].z_name != NULL && 981*7c478bd9Sstevel@tonic-gate strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 982*7c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + 983*7c478bd9Sstevel@tonic-gate strlen(fields[ZF_NAME]) + 984*7c478bd9Sstevel@tonic-gate strlen(zones[i].z_filename))); 985*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, 986*7c478bd9Sstevel@tonic-gate gettext("duplicate zone name %s (file \"%s\", line %d)"), 987*7c478bd9Sstevel@tonic-gate fields[ZF_NAME], 988*7c478bd9Sstevel@tonic-gate zones[i].z_filename, 989*7c478bd9Sstevel@tonic-gate zones[i].z_linenum); 990*7c478bd9Sstevel@tonic-gate error(buf); 991*7c478bd9Sstevel@tonic-gate return (FALSE); 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate return (inzsub(fields, nfields, FALSE)); 994*7c478bd9Sstevel@tonic-gate } 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate static int 997*7c478bd9Sstevel@tonic-gate inzcont(fields, nfields) 998*7c478bd9Sstevel@tonic-gate register char ** const fields; 999*7c478bd9Sstevel@tonic-gate const int nfields; 1000*7c478bd9Sstevel@tonic-gate { 1001*7c478bd9Sstevel@tonic-gate if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 1002*7c478bd9Sstevel@tonic-gate error(gettext( 1003*7c478bd9Sstevel@tonic-gate "wrong number of fields on Zone continuation line")); 1004*7c478bd9Sstevel@tonic-gate return (FALSE); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate return (inzsub(fields, nfields, TRUE)); 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate static int 1010*7c478bd9Sstevel@tonic-gate inzsub(fields, nfields, iscont) 1011*7c478bd9Sstevel@tonic-gate register char ** const fields; 1012*7c478bd9Sstevel@tonic-gate const int nfields; 1013*7c478bd9Sstevel@tonic-gate const int iscont; 1014*7c478bd9Sstevel@tonic-gate { 1015*7c478bd9Sstevel@tonic-gate register char *cp; 1016*7c478bd9Sstevel@tonic-gate static struct zone z; 1017*7c478bd9Sstevel@tonic-gate register int i_gmtoff, i_rule, i_format; 1018*7c478bd9Sstevel@tonic-gate register int i_untilyear, i_untilmonth; 1019*7c478bd9Sstevel@tonic-gate register int i_untilday, i_untiltime; 1020*7c478bd9Sstevel@tonic-gate register int hasuntil; 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate if (iscont) { 1023*7c478bd9Sstevel@tonic-gate i_gmtoff = ZFC_GMTOFF; 1024*7c478bd9Sstevel@tonic-gate i_rule = ZFC_RULE; 1025*7c478bd9Sstevel@tonic-gate i_format = ZFC_FORMAT; 1026*7c478bd9Sstevel@tonic-gate i_untilyear = ZFC_TILYEAR; 1027*7c478bd9Sstevel@tonic-gate i_untilmonth = ZFC_TILMONTH; 1028*7c478bd9Sstevel@tonic-gate i_untilday = ZFC_TILDAY; 1029*7c478bd9Sstevel@tonic-gate i_untiltime = ZFC_TILTIME; 1030*7c478bd9Sstevel@tonic-gate z.z_name = NULL; 1031*7c478bd9Sstevel@tonic-gate } else { 1032*7c478bd9Sstevel@tonic-gate i_gmtoff = ZF_GMTOFF; 1033*7c478bd9Sstevel@tonic-gate i_rule = ZF_RULE; 1034*7c478bd9Sstevel@tonic-gate i_format = ZF_FORMAT; 1035*7c478bd9Sstevel@tonic-gate i_untilyear = ZF_TILYEAR; 1036*7c478bd9Sstevel@tonic-gate i_untilmonth = ZF_TILMONTH; 1037*7c478bd9Sstevel@tonic-gate i_untilday = ZF_TILDAY; 1038*7c478bd9Sstevel@tonic-gate i_untiltime = ZF_TILTIME; 1039*7c478bd9Sstevel@tonic-gate z.z_name = ecpyalloc(fields[ZF_NAME]); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate z.z_filename = filename; 1042*7c478bd9Sstevel@tonic-gate z.z_linenum = linenum; 1043*7c478bd9Sstevel@tonic-gate z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"), 1044*7c478bd9Sstevel@tonic-gate TRUE); 1045*7c478bd9Sstevel@tonic-gate if ((cp = strchr(fields[i_format], '%')) != 0) { 1046*7c478bd9Sstevel@tonic-gate if (*++cp != 's' || strchr(cp, '%') != 0) { 1047*7c478bd9Sstevel@tonic-gate error(gettext("invalid abbreviation format")); 1048*7c478bd9Sstevel@tonic-gate return (FALSE); 1049*7c478bd9Sstevel@tonic-gate } 1050*7c478bd9Sstevel@tonic-gate } 1051*7c478bd9Sstevel@tonic-gate z.z_rule = ecpyalloc(fields[i_rule]); 1052*7c478bd9Sstevel@tonic-gate z.z_format = ecpyalloc(fields[i_format]); 1053*7c478bd9Sstevel@tonic-gate hasuntil = nfields > i_untilyear; 1054*7c478bd9Sstevel@tonic-gate if (hasuntil) { 1055*7c478bd9Sstevel@tonic-gate z.z_untilrule.r_filename = filename; 1056*7c478bd9Sstevel@tonic-gate z.z_untilrule.r_linenum = linenum; 1057*7c478bd9Sstevel@tonic-gate rulesub(&z.z_untilrule, 1058*7c478bd9Sstevel@tonic-gate fields[i_untilyear], 1059*7c478bd9Sstevel@tonic-gate "only", 1060*7c478bd9Sstevel@tonic-gate "", 1061*7c478bd9Sstevel@tonic-gate (nfields > i_untilmonth) ? 1062*7c478bd9Sstevel@tonic-gate fields[i_untilmonth] : "Jan", 1063*7c478bd9Sstevel@tonic-gate (nfields > i_untilday) ? fields[i_untilday] : "1", 1064*7c478bd9Sstevel@tonic-gate (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 1065*7c478bd9Sstevel@tonic-gate z.z_untiltime = rpytime(&z.z_untilrule, 1066*7c478bd9Sstevel@tonic-gate z.z_untilrule.r_loyear); 1067*7c478bd9Sstevel@tonic-gate if (iscont && nzones > 0 && 1068*7c478bd9Sstevel@tonic-gate z.z_untiltime > min_time && 1069*7c478bd9Sstevel@tonic-gate z.z_untiltime < max_time && 1070*7c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime > min_time && 1071*7c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime < max_time && 1072*7c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime >= z.z_untiltime) { 1073*7c478bd9Sstevel@tonic-gate error(gettext( 1074*7c478bd9Sstevel@tonic-gate "Zone continuation line end time is not after end time of previous line")); 1075*7c478bd9Sstevel@tonic-gate return (FALSE); 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate zones = (struct zone *)(void *)erealloc((char *)zones, 1079*7c478bd9Sstevel@tonic-gate (int)((nzones + 1) * sizeof (*zones))); 1080*7c478bd9Sstevel@tonic-gate zones[nzones++] = z; 1081*7c478bd9Sstevel@tonic-gate /* 1082*7c478bd9Sstevel@tonic-gate * If there was an UNTIL field on this line, 1083*7c478bd9Sstevel@tonic-gate * there's more information about the zone on the next line. 1084*7c478bd9Sstevel@tonic-gate */ 1085*7c478bd9Sstevel@tonic-gate return (hasuntil); 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 1089*7c478bd9Sstevel@tonic-gate static void 1090*7c478bd9Sstevel@tonic-gate inleap(fields, nfields) 1091*7c478bd9Sstevel@tonic-gate register char ** const fields; 1092*7c478bd9Sstevel@tonic-gate const int nfields; 1093*7c478bd9Sstevel@tonic-gate { 1094*7c478bd9Sstevel@tonic-gate register const char *cp; 1095*7c478bd9Sstevel@tonic-gate register const struct lookup *lp; 1096*7c478bd9Sstevel@tonic-gate register int i, j; 1097*7c478bd9Sstevel@tonic-gate int year, month, day; 1098*7c478bd9Sstevel@tonic-gate long dayoff, tod; 1099*7c478bd9Sstevel@tonic-gate time_t t; 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate if (nfields != LEAP_FIELDS) { 1102*7c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Leap line")); 1103*7c478bd9Sstevel@tonic-gate return; 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate dayoff = 0; 1106*7c478bd9Sstevel@tonic-gate cp = fields[LP_YEAR]; 1107*7c478bd9Sstevel@tonic-gate if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 1108*7c478bd9Sstevel@tonic-gate /* 1109*7c478bd9Sstevel@tonic-gate * Leapin' Lizards! 1110*7c478bd9Sstevel@tonic-gate */ 1111*7c478bd9Sstevel@tonic-gate error(gettext("invalid leaping year")); 1112*7c478bd9Sstevel@tonic-gate return; 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate j = EPOCH_YEAR; 1115*7c478bd9Sstevel@tonic-gate while (j != year) { 1116*7c478bd9Sstevel@tonic-gate if (year > j) { 1117*7c478bd9Sstevel@tonic-gate i = len_years[isleap(j)]; 1118*7c478bd9Sstevel@tonic-gate ++j; 1119*7c478bd9Sstevel@tonic-gate } else { 1120*7c478bd9Sstevel@tonic-gate --j; 1121*7c478bd9Sstevel@tonic-gate i = -len_years[isleap(j)]; 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 1126*7c478bd9Sstevel@tonic-gate error(gettext("invalid month name")); 1127*7c478bd9Sstevel@tonic-gate return; 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate month = lp->l_value; 1130*7c478bd9Sstevel@tonic-gate j = TM_JANUARY; 1131*7c478bd9Sstevel@tonic-gate while (j != month) { 1132*7c478bd9Sstevel@tonic-gate i = len_months[isleap(year)][j]; 1133*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 1134*7c478bd9Sstevel@tonic-gate ++j; 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate cp = fields[LP_DAY]; 1137*7c478bd9Sstevel@tonic-gate if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 1138*7c478bd9Sstevel@tonic-gate day <= 0 || day > len_months[isleap(year)][month]) { 1139*7c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 1140*7c478bd9Sstevel@tonic-gate return; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(day - 1)); 1143*7c478bd9Sstevel@tonic-gate if (dayoff < 0 && !TYPE_SIGNED(time_t)) { 1144*7c478bd9Sstevel@tonic-gate error(gettext("time before zero")); 1145*7c478bd9Sstevel@tonic-gate return; 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate t = (time_t)dayoff * SECSPERDAY; 1148*7c478bd9Sstevel@tonic-gate /* 1149*7c478bd9Sstevel@tonic-gate * Cheap overflow check. 1150*7c478bd9Sstevel@tonic-gate */ 1151*7c478bd9Sstevel@tonic-gate if (t / SECSPERDAY != dayoff) { 1152*7c478bd9Sstevel@tonic-gate error(gettext("time overflow")); 1153*7c478bd9Sstevel@tonic-gate return; 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE); 1156*7c478bd9Sstevel@tonic-gate cp = fields[LP_CORR]; 1157*7c478bd9Sstevel@tonic-gate { 1158*7c478bd9Sstevel@tonic-gate register int positive; 1159*7c478bd9Sstevel@tonic-gate int count; 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 1162*7c478bd9Sstevel@tonic-gate positive = FALSE; 1163*7c478bd9Sstevel@tonic-gate count = 1; 1164*7c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "--") == 0) { 1165*7c478bd9Sstevel@tonic-gate positive = FALSE; 1166*7c478bd9Sstevel@tonic-gate count = 2; 1167*7c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "+") == 0) { 1168*7c478bd9Sstevel@tonic-gate positive = TRUE; 1169*7c478bd9Sstevel@tonic-gate count = 1; 1170*7c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "++") == 0) { 1171*7c478bd9Sstevel@tonic-gate positive = TRUE; 1172*7c478bd9Sstevel@tonic-gate count = 2; 1173*7c478bd9Sstevel@tonic-gate } else { 1174*7c478bd9Sstevel@tonic-gate error(gettext("illegal CORRECTION field on Leap line")); 1175*7c478bd9Sstevel@tonic-gate return; 1176*7c478bd9Sstevel@tonic-gate } 1177*7c478bd9Sstevel@tonic-gate if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 1178*7c478bd9Sstevel@tonic-gate error(gettext( 1179*7c478bd9Sstevel@tonic-gate "illegal Rolling/Stationary field on Leap line")); 1180*7c478bd9Sstevel@tonic-gate return; 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate leapadd(tadd(t, tod), positive, lp->l_value, count); 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate static void 1188*7c478bd9Sstevel@tonic-gate inlink(fields, nfields) 1189*7c478bd9Sstevel@tonic-gate register char ** const fields; 1190*7c478bd9Sstevel@tonic-gate const int nfields; 1191*7c478bd9Sstevel@tonic-gate { 1192*7c478bd9Sstevel@tonic-gate struct link l; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate if (nfields != LINK_FIELDS) { 1195*7c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Link line")); 1196*7c478bd9Sstevel@tonic-gate return; 1197*7c478bd9Sstevel@tonic-gate } 1198*7c478bd9Sstevel@tonic-gate if (*fields[LF_FROM] == '\0') { 1199*7c478bd9Sstevel@tonic-gate error(gettext("blank FROM field on Link line")); 1200*7c478bd9Sstevel@tonic-gate return; 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate if (*fields[LF_TO] == '\0') { 1203*7c478bd9Sstevel@tonic-gate error(gettext("blank TO field on Link line")); 1204*7c478bd9Sstevel@tonic-gate return; 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate l.l_filename = filename; 1207*7c478bd9Sstevel@tonic-gate l.l_linenum = linenum; 1208*7c478bd9Sstevel@tonic-gate l.l_from = ecpyalloc(fields[LF_FROM]); 1209*7c478bd9Sstevel@tonic-gate l.l_to = ecpyalloc(fields[LF_TO]); 1210*7c478bd9Sstevel@tonic-gate links = (struct link *)(void *)erealloc((char *)links, 1211*7c478bd9Sstevel@tonic-gate (int)((nlinks + 1) * sizeof (*links))); 1212*7c478bd9Sstevel@tonic-gate links[nlinks++] = l; 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate static void 1216*7c478bd9Sstevel@tonic-gate rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 1217*7c478bd9Sstevel@tonic-gate register struct rule * const rp; 1218*7c478bd9Sstevel@tonic-gate const char * const loyearp; 1219*7c478bd9Sstevel@tonic-gate const char * const hiyearp; 1220*7c478bd9Sstevel@tonic-gate const char * const typep; 1221*7c478bd9Sstevel@tonic-gate const char * const monthp; 1222*7c478bd9Sstevel@tonic-gate const char * const dayp; 1223*7c478bd9Sstevel@tonic-gate const char * const timep; 1224*7c478bd9Sstevel@tonic-gate { 1225*7c478bd9Sstevel@tonic-gate register const struct lookup *lp; 1226*7c478bd9Sstevel@tonic-gate register const char *cp; 1227*7c478bd9Sstevel@tonic-gate register char *dp; 1228*7c478bd9Sstevel@tonic-gate register char *ep; 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate if ((lp = byword(monthp, mon_names)) == NULL) { 1231*7c478bd9Sstevel@tonic-gate error(gettext("invalid month name")); 1232*7c478bd9Sstevel@tonic-gate return; 1233*7c478bd9Sstevel@tonic-gate } 1234*7c478bd9Sstevel@tonic-gate rp->r_month = lp->l_value; 1235*7c478bd9Sstevel@tonic-gate rp->r_todisstd = FALSE; 1236*7c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 1237*7c478bd9Sstevel@tonic-gate dp = ecpyalloc(timep); 1238*7c478bd9Sstevel@tonic-gate if (*dp != '\0') { 1239*7c478bd9Sstevel@tonic-gate ep = dp + strlen(dp) - 1; 1240*7c478bd9Sstevel@tonic-gate switch (lowerit(*ep)) { 1241*7c478bd9Sstevel@tonic-gate case 's': /* Standard */ 1242*7c478bd9Sstevel@tonic-gate rp->r_todisstd = TRUE; 1243*7c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 1244*7c478bd9Sstevel@tonic-gate *ep = '\0'; 1245*7c478bd9Sstevel@tonic-gate break; 1246*7c478bd9Sstevel@tonic-gate case 'w': /* Wall */ 1247*7c478bd9Sstevel@tonic-gate rp->r_todisstd = FALSE; 1248*7c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 1249*7c478bd9Sstevel@tonic-gate *ep = '\0'; 1250*7c478bd9Sstevel@tonic-gate break; 1251*7c478bd9Sstevel@tonic-gate case 'g': /* Greenwich */ 1252*7c478bd9Sstevel@tonic-gate case 'u': /* Universal */ 1253*7c478bd9Sstevel@tonic-gate case 'z': /* Zulu */ 1254*7c478bd9Sstevel@tonic-gate rp->r_todisstd = TRUE; 1255*7c478bd9Sstevel@tonic-gate rp->r_todisgmt = TRUE; 1256*7c478bd9Sstevel@tonic-gate *ep = '\0'; 1257*7c478bd9Sstevel@tonic-gate break; 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate } 1260*7c478bd9Sstevel@tonic-gate rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE); 1261*7c478bd9Sstevel@tonic-gate ifree(dp); 1262*7c478bd9Sstevel@tonic-gate /* 1263*7c478bd9Sstevel@tonic-gate * Year work. 1264*7c478bd9Sstevel@tonic-gate */ 1265*7c478bd9Sstevel@tonic-gate cp = loyearp; 1266*7c478bd9Sstevel@tonic-gate lp = byword(cp, begin_years); 1267*7c478bd9Sstevel@tonic-gate if (lp != NULL) { 1268*7c478bd9Sstevel@tonic-gate switch ((int)lp->l_value) { 1269*7c478bd9Sstevel@tonic-gate case YR_MINIMUM: 1270*7c478bd9Sstevel@tonic-gate rp->r_loyear = INT_MIN; 1271*7c478bd9Sstevel@tonic-gate break; 1272*7c478bd9Sstevel@tonic-gate case YR_MAXIMUM: 1273*7c478bd9Sstevel@tonic-gate rp->r_loyear = INT_MAX; 1274*7c478bd9Sstevel@tonic-gate break; 1275*7c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 1276*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1277*7c478bd9Sstevel@tonic-gate gettext("%s: panic: Invalid l_value %d\n"), 1278*7c478bd9Sstevel@tonic-gate progname, lp->l_value); 1279*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1280*7c478bd9Sstevel@tonic-gate } 1281*7c478bd9Sstevel@tonic-gate } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 1282*7c478bd9Sstevel@tonic-gate error(gettext("invalid starting year")); 1283*7c478bd9Sstevel@tonic-gate return; 1284*7c478bd9Sstevel@tonic-gate } else if (noise) { 1285*7c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year_representable) 1286*7c478bd9Sstevel@tonic-gate warning(gettext( 1287*7c478bd9Sstevel@tonic-gate "starting year too low to be represented")); 1288*7c478bd9Sstevel@tonic-gate else if (rp->r_loyear > max_year_representable) 1289*7c478bd9Sstevel@tonic-gate warning(gettext( 1290*7c478bd9Sstevel@tonic-gate "starting year too high to be represented")); 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate cp = hiyearp; 1293*7c478bd9Sstevel@tonic-gate if ((lp = byword(cp, end_years)) != NULL) { 1294*7c478bd9Sstevel@tonic-gate switch ((int)lp->l_value) { 1295*7c478bd9Sstevel@tonic-gate case YR_MINIMUM: 1296*7c478bd9Sstevel@tonic-gate rp->r_hiyear = INT_MIN; 1297*7c478bd9Sstevel@tonic-gate break; 1298*7c478bd9Sstevel@tonic-gate case YR_MAXIMUM: 1299*7c478bd9Sstevel@tonic-gate rp->r_hiyear = INT_MAX; 1300*7c478bd9Sstevel@tonic-gate break; 1301*7c478bd9Sstevel@tonic-gate case YR_ONLY: 1302*7c478bd9Sstevel@tonic-gate rp->r_hiyear = rp->r_loyear; 1303*7c478bd9Sstevel@tonic-gate break; 1304*7c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 1305*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1306*7c478bd9Sstevel@tonic-gate gettext("%s: panic: Invalid l_value %d\n"), 1307*7c478bd9Sstevel@tonic-gate progname, lp->l_value); 1308*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 1311*7c478bd9Sstevel@tonic-gate error(gettext("invalid ending year")); 1312*7c478bd9Sstevel@tonic-gate return; 1313*7c478bd9Sstevel@tonic-gate } else if (noise) { 1314*7c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year_representable) 1315*7c478bd9Sstevel@tonic-gate warning(gettext( 1316*7c478bd9Sstevel@tonic-gate "starting year too low to be represented")); 1317*7c478bd9Sstevel@tonic-gate else if (rp->r_loyear > max_year_representable) 1318*7c478bd9Sstevel@tonic-gate warning(gettext( 1319*7c478bd9Sstevel@tonic-gate "starting year too high to be represented")); 1320*7c478bd9Sstevel@tonic-gate } 1321*7c478bd9Sstevel@tonic-gate if (rp->r_loyear > rp->r_hiyear) { 1322*7c478bd9Sstevel@tonic-gate error(gettext("starting year greater than ending year")); 1323*7c478bd9Sstevel@tonic-gate return; 1324*7c478bd9Sstevel@tonic-gate } 1325*7c478bd9Sstevel@tonic-gate if (*typep == '\0') 1326*7c478bd9Sstevel@tonic-gate rp->r_yrtype = NULL; 1327*7c478bd9Sstevel@tonic-gate else { 1328*7c478bd9Sstevel@tonic-gate if (rp->r_loyear == rp->r_hiyear) { 1329*7c478bd9Sstevel@tonic-gate error(gettext("typed single year")); 1330*7c478bd9Sstevel@tonic-gate return; 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate rp->r_yrtype = ecpyalloc(typep); 1333*7c478bd9Sstevel@tonic-gate } 1334*7c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year && rp->r_loyear > 0) 1335*7c478bd9Sstevel@tonic-gate min_year = rp->r_loyear; 1336*7c478bd9Sstevel@tonic-gate /* 1337*7c478bd9Sstevel@tonic-gate * Day work. 1338*7c478bd9Sstevel@tonic-gate * Accept things such as: 1339*7c478bd9Sstevel@tonic-gate * 1 1340*7c478bd9Sstevel@tonic-gate * last-Sunday 1341*7c478bd9Sstevel@tonic-gate * Sun<=20 1342*7c478bd9Sstevel@tonic-gate * Sun>=7 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate dp = ecpyalloc(dayp); 1345*7c478bd9Sstevel@tonic-gate if ((lp = byword(dp, lasts)) != NULL) { 1346*7c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWLEQ; 1347*7c478bd9Sstevel@tonic-gate rp->r_wday = lp->l_value; 1348*7c478bd9Sstevel@tonic-gate rp->r_dayofmonth = len_months[1][rp->r_month]; 1349*7c478bd9Sstevel@tonic-gate } else { 1350*7c478bd9Sstevel@tonic-gate if ((ep = strchr(dp, '<')) != 0) 1351*7c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWLEQ; 1352*7c478bd9Sstevel@tonic-gate else if ((ep = strchr(dp, '>')) != 0) 1353*7c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWGEQ; 1354*7c478bd9Sstevel@tonic-gate else { 1355*7c478bd9Sstevel@tonic-gate ep = dp; 1356*7c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOM; 1357*7c478bd9Sstevel@tonic-gate } 1358*7c478bd9Sstevel@tonic-gate if (rp->r_dycode != DC_DOM) { 1359*7c478bd9Sstevel@tonic-gate *ep++ = 0; 1360*7c478bd9Sstevel@tonic-gate if (*ep++ != '=') { 1361*7c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 1362*7c478bd9Sstevel@tonic-gate ifree(dp); 1363*7c478bd9Sstevel@tonic-gate return; 1364*7c478bd9Sstevel@tonic-gate } 1365*7c478bd9Sstevel@tonic-gate if ((lp = byword(dp, wday_names)) == NULL) { 1366*7c478bd9Sstevel@tonic-gate error(gettext("invalid weekday name")); 1367*7c478bd9Sstevel@tonic-gate ifree(dp); 1368*7c478bd9Sstevel@tonic-gate return; 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate rp->r_wday = lp->l_value; 1371*7c478bd9Sstevel@tonic-gate } 1372*7c478bd9Sstevel@tonic-gate if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 1373*7c478bd9Sstevel@tonic-gate rp->r_dayofmonth <= 0 || 1374*7c478bd9Sstevel@tonic-gate (rp->r_dayofmonth > len_months[1][rp->r_month])) { 1375*7c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 1376*7c478bd9Sstevel@tonic-gate ifree(dp); 1377*7c478bd9Sstevel@tonic-gate return; 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate } 1380*7c478bd9Sstevel@tonic-gate ifree(dp); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate static void 1384*7c478bd9Sstevel@tonic-gate convert(val, buf) 1385*7c478bd9Sstevel@tonic-gate const long val; 1386*7c478bd9Sstevel@tonic-gate char * const buf; 1387*7c478bd9Sstevel@tonic-gate { 1388*7c478bd9Sstevel@tonic-gate register int i; 1389*7c478bd9Sstevel@tonic-gate register long shift; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 1392*7c478bd9Sstevel@tonic-gate buf[i] = val >> shift; 1393*7c478bd9Sstevel@tonic-gate } 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate static void 1396*7c478bd9Sstevel@tonic-gate puttzcode(val, fp) 1397*7c478bd9Sstevel@tonic-gate const long val; 1398*7c478bd9Sstevel@tonic-gate FILE * const fp; 1399*7c478bd9Sstevel@tonic-gate { 1400*7c478bd9Sstevel@tonic-gate char buf[4]; 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate convert(val, buf); 1403*7c478bd9Sstevel@tonic-gate (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp); 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate static int 1407*7c478bd9Sstevel@tonic-gate atcomp(avp, bvp) 1408*7c478bd9Sstevel@tonic-gate const void *avp; 1409*7c478bd9Sstevel@tonic-gate const void *bvp; 1410*7c478bd9Sstevel@tonic-gate { 1411*7c478bd9Sstevel@tonic-gate if (((struct attype *)avp)->at < ((struct attype *)bvp)->at) 1412*7c478bd9Sstevel@tonic-gate return (-1); 1413*7c478bd9Sstevel@tonic-gate else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at) 1414*7c478bd9Sstevel@tonic-gate return (1); 1415*7c478bd9Sstevel@tonic-gate else return (0); 1416*7c478bd9Sstevel@tonic-gate } 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate static void 1419*7c478bd9Sstevel@tonic-gate writezone(name) 1420*7c478bd9Sstevel@tonic-gate const char * const name; 1421*7c478bd9Sstevel@tonic-gate { 1422*7c478bd9Sstevel@tonic-gate register FILE *fp; 1423*7c478bd9Sstevel@tonic-gate register int i, j; 1424*7c478bd9Sstevel@tonic-gate static char *fullname; 1425*7c478bd9Sstevel@tonic-gate static struct tzhead tzh; 1426*7c478bd9Sstevel@tonic-gate time_t ats[TZ_MAX_TIMES]; 1427*7c478bd9Sstevel@tonic-gate unsigned char types[TZ_MAX_TIMES]; 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate /* 1430*7c478bd9Sstevel@tonic-gate * Sort. 1431*7c478bd9Sstevel@tonic-gate */ 1432*7c478bd9Sstevel@tonic-gate if (timecnt > 1) 1433*7c478bd9Sstevel@tonic-gate (void) qsort((void *)attypes, (size_t)timecnt, 1434*7c478bd9Sstevel@tonic-gate (size_t)sizeof (*attypes), atcomp); 1435*7c478bd9Sstevel@tonic-gate /* 1436*7c478bd9Sstevel@tonic-gate * Optimize. 1437*7c478bd9Sstevel@tonic-gate */ 1438*7c478bd9Sstevel@tonic-gate { 1439*7c478bd9Sstevel@tonic-gate int fromi; 1440*7c478bd9Sstevel@tonic-gate int toi; 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate toi = 0; 1443*7c478bd9Sstevel@tonic-gate fromi = 0; 1444*7c478bd9Sstevel@tonic-gate while (fromi < timecnt && attypes[fromi].at < min_time) 1445*7c478bd9Sstevel@tonic-gate ++fromi; 1446*7c478bd9Sstevel@tonic-gate if (isdsts[0] == 0) 1447*7c478bd9Sstevel@tonic-gate while (fromi < timecnt && attypes[fromi].type == 0) 1448*7c478bd9Sstevel@tonic-gate ++fromi; /* handled by default rule */ 1449*7c478bd9Sstevel@tonic-gate for (; fromi < timecnt; ++fromi) { 1450*7c478bd9Sstevel@tonic-gate if (toi != 0 && 1451*7c478bd9Sstevel@tonic-gate ((attypes[fromi].at + 1452*7c478bd9Sstevel@tonic-gate gmtoffs[attypes[toi - 1].type]) <= 1453*7c478bd9Sstevel@tonic-gate (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 1454*7c478bd9Sstevel@tonic-gate : attypes[toi - 2].type]))) { 1455*7c478bd9Sstevel@tonic-gate attypes[toi - 1].type = attypes[fromi].type; 1456*7c478bd9Sstevel@tonic-gate continue; 1457*7c478bd9Sstevel@tonic-gate } 1458*7c478bd9Sstevel@tonic-gate if (toi == 0 || 1459*7c478bd9Sstevel@tonic-gate attypes[toi - 1].type != attypes[fromi].type) 1460*7c478bd9Sstevel@tonic-gate attypes[toi++] = attypes[fromi]; 1461*7c478bd9Sstevel@tonic-gate } 1462*7c478bd9Sstevel@tonic-gate timecnt = toi; 1463*7c478bd9Sstevel@tonic-gate } 1464*7c478bd9Sstevel@tonic-gate /* 1465*7c478bd9Sstevel@tonic-gate * Transfer. 1466*7c478bd9Sstevel@tonic-gate */ 1467*7c478bd9Sstevel@tonic-gate for (i = 0; i < timecnt; ++i) { 1468*7c478bd9Sstevel@tonic-gate ats[i] = attypes[i].at; 1469*7c478bd9Sstevel@tonic-gate types[i] = attypes[i].type; 1470*7c478bd9Sstevel@tonic-gate } 1471*7c478bd9Sstevel@tonic-gate fullname = erealloc(fullname, 1472*7c478bd9Sstevel@tonic-gate (int)(strlen(directory) + 1 + strlen(name) + 1)); 1473*7c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%s/%s", directory, name); 1474*7c478bd9Sstevel@tonic-gate /* 1475*7c478bd9Sstevel@tonic-gate * Remove old file, if any, to snap links. 1476*7c478bd9Sstevel@tonic-gate */ 1477*7c478bd9Sstevel@tonic-gate if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 1478*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"), 1481*7c478bd9Sstevel@tonic-gate progname, fullname, e); 1482*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1483*7c478bd9Sstevel@tonic-gate } 1484*7c478bd9Sstevel@tonic-gate if ((fp = fopen(fullname, "wb")) == NULL) { 1485*7c478bd9Sstevel@tonic-gate if (mkdirs(fullname) != 0) 1486*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1487*7c478bd9Sstevel@tonic-gate if ((fp = fopen(fullname, "wb")) == NULL) { 1488*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 1489*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1490*7c478bd9Sstevel@tonic-gate "%s: Can't create %s: %s\n"), 1491*7c478bd9Sstevel@tonic-gate progname, fullname, e); 1492*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1493*7c478bd9Sstevel@tonic-gate } 1494*7c478bd9Sstevel@tonic-gate } 1495*7c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 1496*7c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 1497*7c478bd9Sstevel@tonic-gate convert(eitol(leapcnt), tzh.tzh_leapcnt); 1498*7c478bd9Sstevel@tonic-gate convert(eitol(timecnt), tzh.tzh_timecnt); 1499*7c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_typecnt); 1500*7c478bd9Sstevel@tonic-gate convert(eitol(charcnt), tzh.tzh_charcnt); 1501*7c478bd9Sstevel@tonic-gate (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic)); 1502*7c478bd9Sstevel@tonic-gate #define DO(field) (void) fwrite((void *) tzh.field, \ 1503*7c478bd9Sstevel@tonic-gate (size_t)sizeof (tzh.field), (size_t)1, fp) 1504*7c478bd9Sstevel@tonic-gate DO(tzh_magic); 1505*7c478bd9Sstevel@tonic-gate DO(tzh_reserved); 1506*7c478bd9Sstevel@tonic-gate DO(tzh_ttisgmtcnt); 1507*7c478bd9Sstevel@tonic-gate DO(tzh_ttisstdcnt); 1508*7c478bd9Sstevel@tonic-gate DO(tzh_leapcnt); 1509*7c478bd9Sstevel@tonic-gate DO(tzh_timecnt); 1510*7c478bd9Sstevel@tonic-gate DO(tzh_typecnt); 1511*7c478bd9Sstevel@tonic-gate DO(tzh_charcnt); 1512*7c478bd9Sstevel@tonic-gate #undef DO 1513*7c478bd9Sstevel@tonic-gate for (i = 0; i < timecnt; ++i) { 1514*7c478bd9Sstevel@tonic-gate j = leapcnt; 1515*7c478bd9Sstevel@tonic-gate while (--j >= 0) 1516*7c478bd9Sstevel@tonic-gate if (ats[i] >= trans[j]) { 1517*7c478bd9Sstevel@tonic-gate ats[i] = tadd(ats[i], corr[j]); 1518*7c478bd9Sstevel@tonic-gate break; 1519*7c478bd9Sstevel@tonic-gate } 1520*7c478bd9Sstevel@tonic-gate puttzcode((long)ats[i], fp); 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate if (timecnt > 0) 1523*7c478bd9Sstevel@tonic-gate (void) fwrite((void *)types, (size_t)sizeof (types[0]), 1524*7c478bd9Sstevel@tonic-gate (size_t)timecnt, fp); 1525*7c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) { 1526*7c478bd9Sstevel@tonic-gate puttzcode((long)gmtoffs[i], fp); 1527*7c478bd9Sstevel@tonic-gate (void) putc(isdsts[i], fp); 1528*7c478bd9Sstevel@tonic-gate (void) putc(abbrinds[i], fp); 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate if (charcnt != 0) 1531*7c478bd9Sstevel@tonic-gate (void) fwrite((void *)chars, (size_t)sizeof (chars[0]), 1532*7c478bd9Sstevel@tonic-gate (size_t)charcnt, fp); 1533*7c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) { 1534*7c478bd9Sstevel@tonic-gate if (roll[i]) { 1535*7c478bd9Sstevel@tonic-gate if (timecnt == 0 || trans[i] < ats[0]) { 1536*7c478bd9Sstevel@tonic-gate j = 0; 1537*7c478bd9Sstevel@tonic-gate while (isdsts[j]) 1538*7c478bd9Sstevel@tonic-gate if (++j >= typecnt) { 1539*7c478bd9Sstevel@tonic-gate j = 0; 1540*7c478bd9Sstevel@tonic-gate break; 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate } else { 1543*7c478bd9Sstevel@tonic-gate j = 1; 1544*7c478bd9Sstevel@tonic-gate while (j < timecnt && trans[i] >= ats[j]) 1545*7c478bd9Sstevel@tonic-gate ++j; 1546*7c478bd9Sstevel@tonic-gate j = types[j - 1]; 1547*7c478bd9Sstevel@tonic-gate } 1548*7c478bd9Sstevel@tonic-gate puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp); 1549*7c478bd9Sstevel@tonic-gate } else puttzcode((long)trans[i], fp); 1550*7c478bd9Sstevel@tonic-gate puttzcode((long)corr[i], fp); 1551*7c478bd9Sstevel@tonic-gate } 1552*7c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) 1553*7c478bd9Sstevel@tonic-gate (void) putc(ttisstds[i], fp); 1554*7c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) 1555*7c478bd9Sstevel@tonic-gate (void) putc(ttisgmts[i], fp); 1556*7c478bd9Sstevel@tonic-gate if (ferror(fp) || fclose(fp)) { 1557*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error writing %s\n"), 1558*7c478bd9Sstevel@tonic-gate progname, fullname); 1559*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1560*7c478bd9Sstevel@tonic-gate } 1561*7c478bd9Sstevel@tonic-gate } 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate static void 1564*7c478bd9Sstevel@tonic-gate doabbr(abbr, format, letters, isdst) 1565*7c478bd9Sstevel@tonic-gate char * const abbr; 1566*7c478bd9Sstevel@tonic-gate const char * const format; 1567*7c478bd9Sstevel@tonic-gate const char * const letters; 1568*7c478bd9Sstevel@tonic-gate const int isdst; 1569*7c478bd9Sstevel@tonic-gate { 1570*7c478bd9Sstevel@tonic-gate if (strchr(format, '/') == NULL) { 1571*7c478bd9Sstevel@tonic-gate if (letters == NULL) 1572*7c478bd9Sstevel@tonic-gate (void) strcpy(abbr, format); 1573*7c478bd9Sstevel@tonic-gate else 1574*7c478bd9Sstevel@tonic-gate (void) sprintf(abbr, format, letters); 1575*7c478bd9Sstevel@tonic-gate } else if (isdst) 1576*7c478bd9Sstevel@tonic-gate (void) strcpy(abbr, strchr(format, '/') + 1); 1577*7c478bd9Sstevel@tonic-gate else { 1578*7c478bd9Sstevel@tonic-gate (void) strcpy(abbr, format); 1579*7c478bd9Sstevel@tonic-gate *strchr(abbr, '/') = '\0'; 1580*7c478bd9Sstevel@tonic-gate } 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate static void 1584*7c478bd9Sstevel@tonic-gate outzone(zpfirst, zonecount) 1585*7c478bd9Sstevel@tonic-gate const struct zone * const zpfirst; 1586*7c478bd9Sstevel@tonic-gate const int zonecount; 1587*7c478bd9Sstevel@tonic-gate { 1588*7c478bd9Sstevel@tonic-gate register const struct zone *zp; 1589*7c478bd9Sstevel@tonic-gate register struct rule *rp; 1590*7c478bd9Sstevel@tonic-gate register int i, j; 1591*7c478bd9Sstevel@tonic-gate register int usestart, useuntil; 1592*7c478bd9Sstevel@tonic-gate register time_t starttime, untiltime; 1593*7c478bd9Sstevel@tonic-gate register long gmtoff; 1594*7c478bd9Sstevel@tonic-gate register long stdoff; 1595*7c478bd9Sstevel@tonic-gate register int year; 1596*7c478bd9Sstevel@tonic-gate register long startoff; 1597*7c478bd9Sstevel@tonic-gate register int startttisstd; 1598*7c478bd9Sstevel@tonic-gate register int startttisgmt; 1599*7c478bd9Sstevel@tonic-gate register int type; 1600*7c478bd9Sstevel@tonic-gate char startbuf[BUFSIZ]; 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate INITIALIZE(untiltime); 1603*7c478bd9Sstevel@tonic-gate INITIALIZE(starttime); 1604*7c478bd9Sstevel@tonic-gate /* 1605*7c478bd9Sstevel@tonic-gate * Now. . .finally. . .generate some useful data! 1606*7c478bd9Sstevel@tonic-gate */ 1607*7c478bd9Sstevel@tonic-gate timecnt = 0; 1608*7c478bd9Sstevel@tonic-gate typecnt = 0; 1609*7c478bd9Sstevel@tonic-gate charcnt = 0; 1610*7c478bd9Sstevel@tonic-gate /* 1611*7c478bd9Sstevel@tonic-gate * Thanks to Earl Chew (earl@dnd.icp.nec.com.au) 1612*7c478bd9Sstevel@tonic-gate * for noting the need to unconditionally initialize startttisstd. 1613*7c478bd9Sstevel@tonic-gate */ 1614*7c478bd9Sstevel@tonic-gate startttisstd = FALSE; 1615*7c478bd9Sstevel@tonic-gate startttisgmt = FALSE; 1616*7c478bd9Sstevel@tonic-gate for (i = 0; i < zonecount; ++i) { 1617*7c478bd9Sstevel@tonic-gate /* 1618*7c478bd9Sstevel@tonic-gate * A guess that may well be corrected later. 1619*7c478bd9Sstevel@tonic-gate */ 1620*7c478bd9Sstevel@tonic-gate stdoff = 0; 1621*7c478bd9Sstevel@tonic-gate zp = &zpfirst[i]; 1622*7c478bd9Sstevel@tonic-gate usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 1623*7c478bd9Sstevel@tonic-gate useuntil = i < (zonecount - 1); 1624*7c478bd9Sstevel@tonic-gate if (useuntil && zp->z_untiltime <= min_time) 1625*7c478bd9Sstevel@tonic-gate continue; 1626*7c478bd9Sstevel@tonic-gate gmtoff = zp->z_gmtoff; 1627*7c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 1628*7c478bd9Sstevel@tonic-gate *startbuf = '\0'; 1629*7c478bd9Sstevel@tonic-gate startoff = zp->z_gmtoff; 1630*7c478bd9Sstevel@tonic-gate if (zp->z_nrules == 0) { 1631*7c478bd9Sstevel@tonic-gate stdoff = zp->z_stdoff; 1632*7c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 1633*7c478bd9Sstevel@tonic-gate (char *)NULL, stdoff != 0); 1634*7c478bd9Sstevel@tonic-gate type = addtype(oadd(zp->z_gmtoff, stdoff), 1635*7c478bd9Sstevel@tonic-gate startbuf, stdoff != 0, startttisstd, 1636*7c478bd9Sstevel@tonic-gate startttisgmt); 1637*7c478bd9Sstevel@tonic-gate if (usestart) { 1638*7c478bd9Sstevel@tonic-gate addtt(starttime, type); 1639*7c478bd9Sstevel@tonic-gate usestart = FALSE; 1640*7c478bd9Sstevel@tonic-gate } else { 1641*7c478bd9Sstevel@tonic-gate if (stdoff != 0) 1642*7c478bd9Sstevel@tonic-gate addtt(min_time, type); 1643*7c478bd9Sstevel@tonic-gate } 1644*7c478bd9Sstevel@tonic-gate } else 1645*7c478bd9Sstevel@tonic-gate for (year = min_year; year <= max_year; ++year) { 1646*7c478bd9Sstevel@tonic-gate if (useuntil && year > zp->z_untilrule.r_hiyear) 1647*7c478bd9Sstevel@tonic-gate break; 1648*7c478bd9Sstevel@tonic-gate /* 1649*7c478bd9Sstevel@tonic-gate * Mark which rules to do in the current year. 1650*7c478bd9Sstevel@tonic-gate * For those to do, calculate rpytime(rp, year); 1651*7c478bd9Sstevel@tonic-gate */ 1652*7c478bd9Sstevel@tonic-gate for (j = 0; j < zp->z_nrules; ++j) { 1653*7c478bd9Sstevel@tonic-gate rp = &zp->z_rules[j]; 1654*7c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 1655*7c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 1656*7c478bd9Sstevel@tonic-gate rp->r_todo = year >= rp->r_loyear && 1657*7c478bd9Sstevel@tonic-gate year <= rp->r_hiyear && 1658*7c478bd9Sstevel@tonic-gate yearistype(year, rp->r_yrtype); 1659*7c478bd9Sstevel@tonic-gate if (rp->r_todo) 1660*7c478bd9Sstevel@tonic-gate rp->r_temp = rpytime(rp, year); 1661*7c478bd9Sstevel@tonic-gate } 1662*7c478bd9Sstevel@tonic-gate for (;;) { 1663*7c478bd9Sstevel@tonic-gate register int k; 1664*7c478bd9Sstevel@tonic-gate register time_t jtime, ktime; 1665*7c478bd9Sstevel@tonic-gate register long offset; 1666*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 1667*7c478bd9Sstevel@tonic-gate 1668*7c478bd9Sstevel@tonic-gate INITIALIZE(ktime); 1669*7c478bd9Sstevel@tonic-gate if (useuntil) { 1670*7c478bd9Sstevel@tonic-gate /* 1671*7c478bd9Sstevel@tonic-gate * Turn untiltime into UTC 1672*7c478bd9Sstevel@tonic-gate * assuming the current gmtoff and 1673*7c478bd9Sstevel@tonic-gate * stdoff values. 1674*7c478bd9Sstevel@tonic-gate */ 1675*7c478bd9Sstevel@tonic-gate untiltime = zp->z_untiltime; 1676*7c478bd9Sstevel@tonic-gate if (!zp->z_untilrule.r_todisgmt) 1677*7c478bd9Sstevel@tonic-gate untiltime = tadd(untiltime, 1678*7c478bd9Sstevel@tonic-gate -gmtoff); 1679*7c478bd9Sstevel@tonic-gate if (!zp->z_untilrule.r_todisstd) 1680*7c478bd9Sstevel@tonic-gate untiltime = tadd(untiltime, 1681*7c478bd9Sstevel@tonic-gate -stdoff); 1682*7c478bd9Sstevel@tonic-gate } 1683*7c478bd9Sstevel@tonic-gate /* 1684*7c478bd9Sstevel@tonic-gate * Find the rule (of those to do, if any) 1685*7c478bd9Sstevel@tonic-gate * that takes effect earliest in the year. 1686*7c478bd9Sstevel@tonic-gate */ 1687*7c478bd9Sstevel@tonic-gate k = -1; 1688*7c478bd9Sstevel@tonic-gate for (j = 0; j < zp->z_nrules; ++j) { 1689*7c478bd9Sstevel@tonic-gate rp = &zp->z_rules[j]; 1690*7c478bd9Sstevel@tonic-gate if (!rp->r_todo) 1691*7c478bd9Sstevel@tonic-gate continue; 1692*7c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 1693*7c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 1694*7c478bd9Sstevel@tonic-gate offset = rp->r_todisgmt ? 0 : gmtoff; 1695*7c478bd9Sstevel@tonic-gate if (!rp->r_todisstd) 1696*7c478bd9Sstevel@tonic-gate offset = oadd(offset, stdoff); 1697*7c478bd9Sstevel@tonic-gate jtime = rp->r_temp; 1698*7c478bd9Sstevel@tonic-gate if (jtime == min_time || 1699*7c478bd9Sstevel@tonic-gate jtime == max_time) 1700*7c478bd9Sstevel@tonic-gate continue; 1701*7c478bd9Sstevel@tonic-gate jtime = tadd(jtime, -offset); 1702*7c478bd9Sstevel@tonic-gate if (k < 0 || jtime < ktime) { 1703*7c478bd9Sstevel@tonic-gate k = j; 1704*7c478bd9Sstevel@tonic-gate ktime = jtime; 1705*7c478bd9Sstevel@tonic-gate } 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate if (k < 0) 1708*7c478bd9Sstevel@tonic-gate break; /* go on to next year */ 1709*7c478bd9Sstevel@tonic-gate rp = &zp->z_rules[k]; 1710*7c478bd9Sstevel@tonic-gate rp->r_todo = FALSE; 1711*7c478bd9Sstevel@tonic-gate if (useuntil && ktime >= untiltime) 1712*7c478bd9Sstevel@tonic-gate break; 1713*7c478bd9Sstevel@tonic-gate stdoff = rp->r_stdoff; 1714*7c478bd9Sstevel@tonic-gate if (usestart && ktime == starttime) 1715*7c478bd9Sstevel@tonic-gate usestart = FALSE; 1716*7c478bd9Sstevel@tonic-gate if (usestart) { 1717*7c478bd9Sstevel@tonic-gate if (ktime < starttime) { 1718*7c478bd9Sstevel@tonic-gate startoff = oadd(zp->z_gmtoff, 1719*7c478bd9Sstevel@tonic-gate stdoff); 1720*7c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 1721*7c478bd9Sstevel@tonic-gate rp->r_abbrvar, 1722*7c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 1723*7c478bd9Sstevel@tonic-gate continue; 1724*7c478bd9Sstevel@tonic-gate } 1725*7c478bd9Sstevel@tonic-gate if (*startbuf == '\0' && 1726*7c478bd9Sstevel@tonic-gate startoff == oadd(zp->z_gmtoff, 1727*7c478bd9Sstevel@tonic-gate stdoff)) { 1728*7c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 1729*7c478bd9Sstevel@tonic-gate rp->r_abbrvar, 1730*7c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 1731*7c478bd9Sstevel@tonic-gate } 1732*7c478bd9Sstevel@tonic-gate } 1733*7c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 1734*7c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 1735*7c478bd9Sstevel@tonic-gate doabbr(buf, zp->z_format, rp->r_abbrvar, 1736*7c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 1737*7c478bd9Sstevel@tonic-gate offset = oadd(zp->z_gmtoff, rp->r_stdoff); 1738*7c478bd9Sstevel@tonic-gate type = addtype(offset, buf, rp->r_stdoff != 0, 1739*7c478bd9Sstevel@tonic-gate rp->r_todisstd, rp->r_todisgmt); 1740*7c478bd9Sstevel@tonic-gate addtt(ktime, type); 1741*7c478bd9Sstevel@tonic-gate } 1742*7c478bd9Sstevel@tonic-gate } 1743*7c478bd9Sstevel@tonic-gate if (usestart) { 1744*7c478bd9Sstevel@tonic-gate if (*startbuf == '\0' && 1745*7c478bd9Sstevel@tonic-gate zp->z_format != NULL && 1746*7c478bd9Sstevel@tonic-gate strchr(zp->z_format, '%') == NULL && 1747*7c478bd9Sstevel@tonic-gate strchr(zp->z_format, '/') == NULL) 1748*7c478bd9Sstevel@tonic-gate (void) strcpy(startbuf, zp->z_format); 1749*7c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 1750*7c478bd9Sstevel@tonic-gate if (*startbuf == '\0') 1751*7c478bd9Sstevel@tonic-gate error(gettext( 1752*7c478bd9Sstevel@tonic-gate "can't determine time zone abbrevation to use just after until time")); 1753*7c478bd9Sstevel@tonic-gate else addtt(starttime, 1754*7c478bd9Sstevel@tonic-gate addtype(startoff, startbuf, 1755*7c478bd9Sstevel@tonic-gate startoff != zp->z_gmtoff, 1756*7c478bd9Sstevel@tonic-gate startttisstd, 1757*7c478bd9Sstevel@tonic-gate startttisgmt)); 1758*7c478bd9Sstevel@tonic-gate } 1759*7c478bd9Sstevel@tonic-gate /* 1760*7c478bd9Sstevel@tonic-gate * Now we may get to set starttime for the next zone line. 1761*7c478bd9Sstevel@tonic-gate */ 1762*7c478bd9Sstevel@tonic-gate if (useuntil) { 1763*7c478bd9Sstevel@tonic-gate startttisstd = zp->z_untilrule.r_todisstd; 1764*7c478bd9Sstevel@tonic-gate startttisgmt = zp->z_untilrule.r_todisgmt; 1765*7c478bd9Sstevel@tonic-gate starttime = zp->z_untiltime; 1766*7c478bd9Sstevel@tonic-gate if (!startttisstd) 1767*7c478bd9Sstevel@tonic-gate starttime = tadd(starttime, -stdoff); 1768*7c478bd9Sstevel@tonic-gate if (!startttisgmt) 1769*7c478bd9Sstevel@tonic-gate starttime = tadd(starttime, -gmtoff); 1770*7c478bd9Sstevel@tonic-gate } 1771*7c478bd9Sstevel@tonic-gate } 1772*7c478bd9Sstevel@tonic-gate writezone(zpfirst->z_name); 1773*7c478bd9Sstevel@tonic-gate } 1774*7c478bd9Sstevel@tonic-gate 1775*7c478bd9Sstevel@tonic-gate static void 1776*7c478bd9Sstevel@tonic-gate addtt(starttime, type) 1777*7c478bd9Sstevel@tonic-gate const time_t starttime; 1778*7c478bd9Sstevel@tonic-gate int type; 1779*7c478bd9Sstevel@tonic-gate { 1780*7c478bd9Sstevel@tonic-gate if (starttime <= min_time || 1781*7c478bd9Sstevel@tonic-gate (timecnt == 1 && attypes[0].at < min_time)) { 1782*7c478bd9Sstevel@tonic-gate gmtoffs[0] = gmtoffs[type]; 1783*7c478bd9Sstevel@tonic-gate isdsts[0] = isdsts[type]; 1784*7c478bd9Sstevel@tonic-gate ttisstds[0] = ttisstds[type]; 1785*7c478bd9Sstevel@tonic-gate ttisgmts[0] = ttisgmts[type]; 1786*7c478bd9Sstevel@tonic-gate if (abbrinds[type] != 0) 1787*7c478bd9Sstevel@tonic-gate (void) strcpy(chars, &chars[abbrinds[type]]); 1788*7c478bd9Sstevel@tonic-gate abbrinds[0] = 0; 1789*7c478bd9Sstevel@tonic-gate charcnt = strlen(chars) + 1; 1790*7c478bd9Sstevel@tonic-gate typecnt = 1; 1791*7c478bd9Sstevel@tonic-gate timecnt = 0; 1792*7c478bd9Sstevel@tonic-gate type = 0; 1793*7c478bd9Sstevel@tonic-gate } 1794*7c478bd9Sstevel@tonic-gate if (timecnt >= TZ_MAX_TIMES) { 1795*7c478bd9Sstevel@tonic-gate error(gettext("too many transitions?!")); 1796*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1797*7c478bd9Sstevel@tonic-gate } 1798*7c478bd9Sstevel@tonic-gate attypes[timecnt].at = starttime; 1799*7c478bd9Sstevel@tonic-gate attypes[timecnt].type = type; 1800*7c478bd9Sstevel@tonic-gate ++timecnt; 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate static int 1804*7c478bd9Sstevel@tonic-gate addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 1805*7c478bd9Sstevel@tonic-gate const long gmtoff; 1806*7c478bd9Sstevel@tonic-gate const char * const abbr; 1807*7c478bd9Sstevel@tonic-gate const int isdst; 1808*7c478bd9Sstevel@tonic-gate const int ttisstd; 1809*7c478bd9Sstevel@tonic-gate const int ttisgmt; 1810*7c478bd9Sstevel@tonic-gate { 1811*7c478bd9Sstevel@tonic-gate register int i, j; 1812*7c478bd9Sstevel@tonic-gate 1813*7c478bd9Sstevel@tonic-gate if (isdst != TRUE && isdst != FALSE) { 1814*7c478bd9Sstevel@tonic-gate error(gettext( 1815*7c478bd9Sstevel@tonic-gate "internal error - addtype called with bad isdst")); 1816*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1817*7c478bd9Sstevel@tonic-gate } 1818*7c478bd9Sstevel@tonic-gate if (ttisstd != TRUE && ttisstd != FALSE) { 1819*7c478bd9Sstevel@tonic-gate error(gettext( 1820*7c478bd9Sstevel@tonic-gate "internal error - addtype called with bad ttisstd")); 1821*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate if (ttisgmt != TRUE && ttisgmt != FALSE) { 1824*7c478bd9Sstevel@tonic-gate error(gettext( 1825*7c478bd9Sstevel@tonic-gate "internal error - addtype called with bad ttisgmt")); 1826*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1827*7c478bd9Sstevel@tonic-gate } 1828*7c478bd9Sstevel@tonic-gate /* 1829*7c478bd9Sstevel@tonic-gate * See if there's already an entry for this zone type. 1830*7c478bd9Sstevel@tonic-gate * If so, just return its index. 1831*7c478bd9Sstevel@tonic-gate */ 1832*7c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) { 1833*7c478bd9Sstevel@tonic-gate if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 1834*7c478bd9Sstevel@tonic-gate strcmp(abbr, &chars[abbrinds[i]]) == 0 && 1835*7c478bd9Sstevel@tonic-gate ttisstd == ttisstds[i] && 1836*7c478bd9Sstevel@tonic-gate ttisgmt == ttisgmts[i]) 1837*7c478bd9Sstevel@tonic-gate return (i); 1838*7c478bd9Sstevel@tonic-gate } 1839*7c478bd9Sstevel@tonic-gate /* 1840*7c478bd9Sstevel@tonic-gate * There isn't one; add a new one, unless there are already too 1841*7c478bd9Sstevel@tonic-gate * many. 1842*7c478bd9Sstevel@tonic-gate */ 1843*7c478bd9Sstevel@tonic-gate if (typecnt >= TZ_MAX_TYPES) { 1844*7c478bd9Sstevel@tonic-gate error(gettext("too many local time types")); 1845*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1846*7c478bd9Sstevel@tonic-gate } 1847*7c478bd9Sstevel@tonic-gate gmtoffs[i] = gmtoff; 1848*7c478bd9Sstevel@tonic-gate isdsts[i] = isdst; 1849*7c478bd9Sstevel@tonic-gate ttisstds[i] = ttisstd; 1850*7c478bd9Sstevel@tonic-gate ttisgmts[i] = ttisgmt; 1851*7c478bd9Sstevel@tonic-gate 1852*7c478bd9Sstevel@tonic-gate for (j = 0; j < charcnt; ++j) 1853*7c478bd9Sstevel@tonic-gate if (strcmp(&chars[j], abbr) == 0) 1854*7c478bd9Sstevel@tonic-gate break; 1855*7c478bd9Sstevel@tonic-gate if (j == charcnt) 1856*7c478bd9Sstevel@tonic-gate newabbr(abbr); 1857*7c478bd9Sstevel@tonic-gate abbrinds[i] = j; 1858*7c478bd9Sstevel@tonic-gate ++typecnt; 1859*7c478bd9Sstevel@tonic-gate return (i); 1860*7c478bd9Sstevel@tonic-gate } 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 1863*7c478bd9Sstevel@tonic-gate static void 1864*7c478bd9Sstevel@tonic-gate leapadd(t, positive, rolling, count) 1865*7c478bd9Sstevel@tonic-gate const time_t t; 1866*7c478bd9Sstevel@tonic-gate const int positive; 1867*7c478bd9Sstevel@tonic-gate const int rolling; 1868*7c478bd9Sstevel@tonic-gate int count; 1869*7c478bd9Sstevel@tonic-gate { 1870*7c478bd9Sstevel@tonic-gate register int i, j; 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 1873*7c478bd9Sstevel@tonic-gate error(gettext("too many leap seconds")); 1874*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1875*7c478bd9Sstevel@tonic-gate } 1876*7c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) 1877*7c478bd9Sstevel@tonic-gate if (t <= trans[i]) { 1878*7c478bd9Sstevel@tonic-gate if (t == trans[i]) { 1879*7c478bd9Sstevel@tonic-gate error(gettext("repeated leap second moment")); 1880*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1881*7c478bd9Sstevel@tonic-gate } 1882*7c478bd9Sstevel@tonic-gate break; 1883*7c478bd9Sstevel@tonic-gate } 1884*7c478bd9Sstevel@tonic-gate do { 1885*7c478bd9Sstevel@tonic-gate for (j = leapcnt; j > i; --j) { 1886*7c478bd9Sstevel@tonic-gate trans[j] = trans[j - 1]; 1887*7c478bd9Sstevel@tonic-gate corr[j] = corr[j - 1]; 1888*7c478bd9Sstevel@tonic-gate roll[j] = roll[j - 1]; 1889*7c478bd9Sstevel@tonic-gate } 1890*7c478bd9Sstevel@tonic-gate trans[i] = t; 1891*7c478bd9Sstevel@tonic-gate corr[i] = positive ? 1L : eitol(-count); 1892*7c478bd9Sstevel@tonic-gate roll[i] = rolling; 1893*7c478bd9Sstevel@tonic-gate ++leapcnt; 1894*7c478bd9Sstevel@tonic-gate } while (positive && --count != 0); 1895*7c478bd9Sstevel@tonic-gate } 1896*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 1899*7c478bd9Sstevel@tonic-gate static void 1900*7c478bd9Sstevel@tonic-gate adjleap(void) 1901*7c478bd9Sstevel@tonic-gate { 1902*7c478bd9Sstevel@tonic-gate register int i; 1903*7c478bd9Sstevel@tonic-gate register long last = 0; 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate /* 1906*7c478bd9Sstevel@tonic-gate * propagate leap seconds forward 1907*7c478bd9Sstevel@tonic-gate */ 1908*7c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) { 1909*7c478bd9Sstevel@tonic-gate trans[i] = tadd(trans[i], last); 1910*7c478bd9Sstevel@tonic-gate last = corr[i] += last; 1911*7c478bd9Sstevel@tonic-gate } 1912*7c478bd9Sstevel@tonic-gate } 1913*7c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 1914*7c478bd9Sstevel@tonic-gate 1915*7c478bd9Sstevel@tonic-gate static int 1916*7c478bd9Sstevel@tonic-gate yearistype(year, type) 1917*7c478bd9Sstevel@tonic-gate const int year; 1918*7c478bd9Sstevel@tonic-gate const char * const type; 1919*7c478bd9Sstevel@tonic-gate { 1920*7c478bd9Sstevel@tonic-gate static char *buf; 1921*7c478bd9Sstevel@tonic-gate int result; 1922*7c478bd9Sstevel@tonic-gate 1923*7c478bd9Sstevel@tonic-gate if (type == NULL || *type == '\0') 1924*7c478bd9Sstevel@tonic-gate return (TRUE); 1925*7c478bd9Sstevel@tonic-gate #if defined(sun) 1926*7c478bd9Sstevel@tonic-gate if (strcmp(type, "uspres") == 0) 1927*7c478bd9Sstevel@tonic-gate return ((year % 4) == 0); 1928*7c478bd9Sstevel@tonic-gate if (strcmp(type, "nonpres") == 0) 1929*7c478bd9Sstevel@tonic-gate return ((year % 4) != 0); 1930*7c478bd9Sstevel@tonic-gate if (strcmp(type, "even") == 0) 1931*7c478bd9Sstevel@tonic-gate return ((year % 2) == 0); 1932*7c478bd9Sstevel@tonic-gate if (strcmp(type, "odd") == 0) 1933*7c478bd9Sstevel@tonic-gate return ((year % 2) != 0); 1934*7c478bd9Sstevel@tonic-gate #endif /* defined(sun) */ 1935*7c478bd9Sstevel@tonic-gate 1936*7c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type))); 1937*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 1938*7c478bd9Sstevel@tonic-gate result = system(buf); 1939*7c478bd9Sstevel@tonic-gate if (result == 0) 1940*7c478bd9Sstevel@tonic-gate return (TRUE); 1941*7c478bd9Sstevel@tonic-gate if (result == (1 << 8)) 1942*7c478bd9Sstevel@tonic-gate return (FALSE); 1943*7c478bd9Sstevel@tonic-gate error(gettext("Wild result from command execution")); 1944*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"), 1945*7c478bd9Sstevel@tonic-gate progname, buf, result); 1946*7c478bd9Sstevel@tonic-gate for (;;) 1947*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 1948*7c478bd9Sstevel@tonic-gate } 1949*7c478bd9Sstevel@tonic-gate 1950*7c478bd9Sstevel@tonic-gate static int 1951*7c478bd9Sstevel@tonic-gate lowerit(a) 1952*7c478bd9Sstevel@tonic-gate int a; 1953*7c478bd9Sstevel@tonic-gate { 1954*7c478bd9Sstevel@tonic-gate a = (unsigned char) a; 1955*7c478bd9Sstevel@tonic-gate return ((isascii(a) && isupper(a)) ? tolower(a) : a); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate static int 1959*7c478bd9Sstevel@tonic-gate ciequal(ap, bp) /* case-insensitive equality */ 1960*7c478bd9Sstevel@tonic-gate register const char *ap; 1961*7c478bd9Sstevel@tonic-gate register const char *bp; 1962*7c478bd9Sstevel@tonic-gate { 1963*7c478bd9Sstevel@tonic-gate while (lowerit(*ap) == lowerit(*bp++)) 1964*7c478bd9Sstevel@tonic-gate if (*ap++ == '\0') 1965*7c478bd9Sstevel@tonic-gate return (TRUE); 1966*7c478bd9Sstevel@tonic-gate return (FALSE); 1967*7c478bd9Sstevel@tonic-gate } 1968*7c478bd9Sstevel@tonic-gate 1969*7c478bd9Sstevel@tonic-gate static int 1970*7c478bd9Sstevel@tonic-gate itsabbr(abbr, word) 1971*7c478bd9Sstevel@tonic-gate register const char *abbr; 1972*7c478bd9Sstevel@tonic-gate register const char *word; 1973*7c478bd9Sstevel@tonic-gate { 1974*7c478bd9Sstevel@tonic-gate if (lowerit(*abbr) != lowerit(*word)) 1975*7c478bd9Sstevel@tonic-gate return (FALSE); 1976*7c478bd9Sstevel@tonic-gate ++word; 1977*7c478bd9Sstevel@tonic-gate while (*++abbr != '\0') 1978*7c478bd9Sstevel@tonic-gate do { 1979*7c478bd9Sstevel@tonic-gate if (*word == '\0') 1980*7c478bd9Sstevel@tonic-gate return (FALSE); 1981*7c478bd9Sstevel@tonic-gate } while (lowerit(*word++) != lowerit(*abbr)); 1982*7c478bd9Sstevel@tonic-gate return (TRUE); 1983*7c478bd9Sstevel@tonic-gate } 1984*7c478bd9Sstevel@tonic-gate 1985*7c478bd9Sstevel@tonic-gate static const struct lookup * 1986*7c478bd9Sstevel@tonic-gate byword(word, table) 1987*7c478bd9Sstevel@tonic-gate register const char * const word; 1988*7c478bd9Sstevel@tonic-gate register const struct lookup * const table; 1989*7c478bd9Sstevel@tonic-gate { 1990*7c478bd9Sstevel@tonic-gate register const struct lookup *foundlp; 1991*7c478bd9Sstevel@tonic-gate register const struct lookup *lp; 1992*7c478bd9Sstevel@tonic-gate 1993*7c478bd9Sstevel@tonic-gate if (word == NULL || table == NULL) 1994*7c478bd9Sstevel@tonic-gate return (NULL); 1995*7c478bd9Sstevel@tonic-gate /* 1996*7c478bd9Sstevel@tonic-gate * Look for exact match. 1997*7c478bd9Sstevel@tonic-gate */ 1998*7c478bd9Sstevel@tonic-gate for (lp = table; lp->l_word != NULL; ++lp) 1999*7c478bd9Sstevel@tonic-gate if (ciequal(word, lp->l_word)) 2000*7c478bd9Sstevel@tonic-gate return (lp); 2001*7c478bd9Sstevel@tonic-gate /* 2002*7c478bd9Sstevel@tonic-gate * Look for inexact match. 2003*7c478bd9Sstevel@tonic-gate */ 2004*7c478bd9Sstevel@tonic-gate foundlp = NULL; 2005*7c478bd9Sstevel@tonic-gate for (lp = table; lp->l_word != NULL; ++lp) 2006*7c478bd9Sstevel@tonic-gate if (itsabbr(word, lp->l_word)) { 2007*7c478bd9Sstevel@tonic-gate if (foundlp == NULL) 2008*7c478bd9Sstevel@tonic-gate foundlp = lp; 2009*7c478bd9Sstevel@tonic-gate else return (NULL); /* multiple inexact matches */ 2010*7c478bd9Sstevel@tonic-gate } 2011*7c478bd9Sstevel@tonic-gate return (foundlp); 2012*7c478bd9Sstevel@tonic-gate } 2013*7c478bd9Sstevel@tonic-gate 2014*7c478bd9Sstevel@tonic-gate static char ** 2015*7c478bd9Sstevel@tonic-gate getfields(cp) 2016*7c478bd9Sstevel@tonic-gate register char *cp; 2017*7c478bd9Sstevel@tonic-gate { 2018*7c478bd9Sstevel@tonic-gate register char *dp; 2019*7c478bd9Sstevel@tonic-gate register char **array; 2020*7c478bd9Sstevel@tonic-gate register int nsubs; 2021*7c478bd9Sstevel@tonic-gate 2022*7c478bd9Sstevel@tonic-gate if (cp == NULL) 2023*7c478bd9Sstevel@tonic-gate return (NULL); 2024*7c478bd9Sstevel@tonic-gate array = (char **)(void *) 2025*7c478bd9Sstevel@tonic-gate emalloc((int)((strlen(cp) + 1) * sizeof (*array))); 2026*7c478bd9Sstevel@tonic-gate nsubs = 0; 2027*7c478bd9Sstevel@tonic-gate for (;;) { 2028*7c478bd9Sstevel@tonic-gate while (isascii(*cp) && isspace((unsigned char) *cp)) 2029*7c478bd9Sstevel@tonic-gate ++cp; 2030*7c478bd9Sstevel@tonic-gate if (*cp == '\0' || *cp == '#') 2031*7c478bd9Sstevel@tonic-gate break; 2032*7c478bd9Sstevel@tonic-gate array[nsubs++] = dp = cp; 2033*7c478bd9Sstevel@tonic-gate do { 2034*7c478bd9Sstevel@tonic-gate if ((*dp = *cp++) != '"') 2035*7c478bd9Sstevel@tonic-gate ++dp; 2036*7c478bd9Sstevel@tonic-gate else while ((*dp = *cp++) != '"') 2037*7c478bd9Sstevel@tonic-gate if (*dp != '\0') 2038*7c478bd9Sstevel@tonic-gate ++dp; 2039*7c478bd9Sstevel@tonic-gate else 2040*7c478bd9Sstevel@tonic-gate error(gettext( 2041*7c478bd9Sstevel@tonic-gate "Odd number of quotation marks")); 2042*7c478bd9Sstevel@tonic-gate } while (*cp != '\0' && *cp != '#' && 2043*7c478bd9Sstevel@tonic-gate (!isascii(*cp) || !isspace((unsigned char) *cp))); 2044*7c478bd9Sstevel@tonic-gate if (isascii(*cp) && isspace((unsigned char) *cp)) 2045*7c478bd9Sstevel@tonic-gate ++cp; 2046*7c478bd9Sstevel@tonic-gate *dp = '\0'; 2047*7c478bd9Sstevel@tonic-gate } 2048*7c478bd9Sstevel@tonic-gate array[nsubs] = NULL; 2049*7c478bd9Sstevel@tonic-gate return (array); 2050*7c478bd9Sstevel@tonic-gate } 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate static long 2053*7c478bd9Sstevel@tonic-gate oadd(t1, t2) 2054*7c478bd9Sstevel@tonic-gate const long t1; 2055*7c478bd9Sstevel@tonic-gate const long t2; 2056*7c478bd9Sstevel@tonic-gate { 2057*7c478bd9Sstevel@tonic-gate register long t; 2058*7c478bd9Sstevel@tonic-gate 2059*7c478bd9Sstevel@tonic-gate t = t1 + t2; 2060*7c478bd9Sstevel@tonic-gate if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2061*7c478bd9Sstevel@tonic-gate error(gettext("time overflow")); 2062*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2063*7c478bd9Sstevel@tonic-gate } 2064*7c478bd9Sstevel@tonic-gate return (t); 2065*7c478bd9Sstevel@tonic-gate } 2066*7c478bd9Sstevel@tonic-gate 2067*7c478bd9Sstevel@tonic-gate static time_t 2068*7c478bd9Sstevel@tonic-gate tadd(t1, t2) 2069*7c478bd9Sstevel@tonic-gate const time_t t1; 2070*7c478bd9Sstevel@tonic-gate const long t2; 2071*7c478bd9Sstevel@tonic-gate { 2072*7c478bd9Sstevel@tonic-gate register time_t t; 2073*7c478bd9Sstevel@tonic-gate 2074*7c478bd9Sstevel@tonic-gate if (t1 == max_time && t2 > 0) 2075*7c478bd9Sstevel@tonic-gate return (max_time); 2076*7c478bd9Sstevel@tonic-gate if (t1 == min_time && t2 < 0) 2077*7c478bd9Sstevel@tonic-gate return (min_time); 2078*7c478bd9Sstevel@tonic-gate t = t1 + t2; 2079*7c478bd9Sstevel@tonic-gate if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 2080*7c478bd9Sstevel@tonic-gate error(gettext("time overflow")); 2081*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2082*7c478bd9Sstevel@tonic-gate } 2083*7c478bd9Sstevel@tonic-gate return (t); 2084*7c478bd9Sstevel@tonic-gate } 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate /* 2087*7c478bd9Sstevel@tonic-gate * Given a rule, and a year, compute the date - in seconds since January 1, 2088*7c478bd9Sstevel@tonic-gate * 1970, 00:00 LOCAL time - in that year that the rule refers to. 2089*7c478bd9Sstevel@tonic-gate */ 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate static time_t 2092*7c478bd9Sstevel@tonic-gate rpytime(rp, wantedy) 2093*7c478bd9Sstevel@tonic-gate register const struct rule * const rp; 2094*7c478bd9Sstevel@tonic-gate register const int wantedy; 2095*7c478bd9Sstevel@tonic-gate { 2096*7c478bd9Sstevel@tonic-gate register int y, m, i; 2097*7c478bd9Sstevel@tonic-gate register long dayoff; /* with a nod to Margaret O. */ 2098*7c478bd9Sstevel@tonic-gate register time_t t; 2099*7c478bd9Sstevel@tonic-gate 2100*7c478bd9Sstevel@tonic-gate if (wantedy == INT_MIN) 2101*7c478bd9Sstevel@tonic-gate return (min_time); 2102*7c478bd9Sstevel@tonic-gate if (wantedy == INT_MAX) 2103*7c478bd9Sstevel@tonic-gate return (max_time); 2104*7c478bd9Sstevel@tonic-gate dayoff = 0; 2105*7c478bd9Sstevel@tonic-gate m = TM_JANUARY; 2106*7c478bd9Sstevel@tonic-gate y = EPOCH_YEAR; 2107*7c478bd9Sstevel@tonic-gate while (wantedy != y) { 2108*7c478bd9Sstevel@tonic-gate if (wantedy > y) { 2109*7c478bd9Sstevel@tonic-gate i = len_years[isleap(y)]; 2110*7c478bd9Sstevel@tonic-gate ++y; 2111*7c478bd9Sstevel@tonic-gate } else { 2112*7c478bd9Sstevel@tonic-gate --y; 2113*7c478bd9Sstevel@tonic-gate i = -len_years[isleap(y)]; 2114*7c478bd9Sstevel@tonic-gate } 2115*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 2116*7c478bd9Sstevel@tonic-gate } 2117*7c478bd9Sstevel@tonic-gate while (m != rp->r_month) { 2118*7c478bd9Sstevel@tonic-gate i = len_months[isleap(y)][m]; 2119*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 2120*7c478bd9Sstevel@tonic-gate ++m; 2121*7c478bd9Sstevel@tonic-gate } 2122*7c478bd9Sstevel@tonic-gate i = rp->r_dayofmonth; 2123*7c478bd9Sstevel@tonic-gate if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 2124*7c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWLEQ) 2125*7c478bd9Sstevel@tonic-gate --i; 2126*7c478bd9Sstevel@tonic-gate else { 2127*7c478bd9Sstevel@tonic-gate error(gettext("use of 2/29 in non leap-year")); 2128*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2129*7c478bd9Sstevel@tonic-gate } 2130*7c478bd9Sstevel@tonic-gate } 2131*7c478bd9Sstevel@tonic-gate --i; 2132*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 2133*7c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 2134*7c478bd9Sstevel@tonic-gate register long wday; 2135*7c478bd9Sstevel@tonic-gate 2136*7c478bd9Sstevel@tonic-gate #define LDAYSPERWEEK ((long)DAYSPERWEEK) 2137*7c478bd9Sstevel@tonic-gate wday = eitol(EPOCH_WDAY); 2138*7c478bd9Sstevel@tonic-gate /* 2139*7c478bd9Sstevel@tonic-gate * Don't trust mod of negative numbers. 2140*7c478bd9Sstevel@tonic-gate */ 2141*7c478bd9Sstevel@tonic-gate if (dayoff >= 0) 2142*7c478bd9Sstevel@tonic-gate wday = (wday + dayoff) % LDAYSPERWEEK; 2143*7c478bd9Sstevel@tonic-gate else { 2144*7c478bd9Sstevel@tonic-gate wday -= ((-dayoff) % LDAYSPERWEEK); 2145*7c478bd9Sstevel@tonic-gate if (wday < 0) 2146*7c478bd9Sstevel@tonic-gate wday += LDAYSPERWEEK; 2147*7c478bd9Sstevel@tonic-gate } 2148*7c478bd9Sstevel@tonic-gate while (wday != eitol(rp->r_wday)) 2149*7c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWGEQ) { 2150*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, (long)1); 2151*7c478bd9Sstevel@tonic-gate if (++wday >= LDAYSPERWEEK) 2152*7c478bd9Sstevel@tonic-gate wday = 0; 2153*7c478bd9Sstevel@tonic-gate ++i; 2154*7c478bd9Sstevel@tonic-gate } else { 2155*7c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, (long)-1); 2156*7c478bd9Sstevel@tonic-gate if (--wday < 0) 2157*7c478bd9Sstevel@tonic-gate wday = LDAYSPERWEEK - 1; 2158*7c478bd9Sstevel@tonic-gate --i; 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate if (i < 0 || i >= len_months[isleap(y)][m]) { 2161*7c478bd9Sstevel@tonic-gate error(gettext("no day in month matches rule")); 2162*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2163*7c478bd9Sstevel@tonic-gate } 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate if (dayoff < 0 && !TYPE_SIGNED(time_t)) 2166*7c478bd9Sstevel@tonic-gate return (min_time); 2167*7c478bd9Sstevel@tonic-gate t = (time_t)dayoff * SECSPERDAY; 2168*7c478bd9Sstevel@tonic-gate /* 2169*7c478bd9Sstevel@tonic-gate * Cheap overflow check. 2170*7c478bd9Sstevel@tonic-gate */ 2171*7c478bd9Sstevel@tonic-gate if (t / SECSPERDAY != dayoff) 2172*7c478bd9Sstevel@tonic-gate return ((dayoff > 0) ? max_time : min_time); 2173*7c478bd9Sstevel@tonic-gate return (tadd(t, rp->r_tod)); 2174*7c478bd9Sstevel@tonic-gate } 2175*7c478bd9Sstevel@tonic-gate 2176*7c478bd9Sstevel@tonic-gate static void 2177*7c478bd9Sstevel@tonic-gate newabbr(string) 2178*7c478bd9Sstevel@tonic-gate const char * const string; 2179*7c478bd9Sstevel@tonic-gate { 2180*7c478bd9Sstevel@tonic-gate register int i; 2181*7c478bd9Sstevel@tonic-gate 2182*7c478bd9Sstevel@tonic-gate i = strlen(string) + 1; 2183*7c478bd9Sstevel@tonic-gate if (charcnt + i > TZ_MAX_CHARS) { 2184*7c478bd9Sstevel@tonic-gate error(gettext( 2185*7c478bd9Sstevel@tonic-gate "too many, or too long, time zone abbreviations")); 2186*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2187*7c478bd9Sstevel@tonic-gate } 2188*7c478bd9Sstevel@tonic-gate (void) strcpy(&chars[charcnt], string); 2189*7c478bd9Sstevel@tonic-gate charcnt += eitol(i); 2190*7c478bd9Sstevel@tonic-gate } 2191*7c478bd9Sstevel@tonic-gate 2192*7c478bd9Sstevel@tonic-gate static int 2193*7c478bd9Sstevel@tonic-gate mkdirs(argname) 2194*7c478bd9Sstevel@tonic-gate char * const argname; 2195*7c478bd9Sstevel@tonic-gate { 2196*7c478bd9Sstevel@tonic-gate register char *name; 2197*7c478bd9Sstevel@tonic-gate register char *cp; 2198*7c478bd9Sstevel@tonic-gate 2199*7c478bd9Sstevel@tonic-gate if (argname == NULL || *argname == '\0') 2200*7c478bd9Sstevel@tonic-gate return (0); 2201*7c478bd9Sstevel@tonic-gate cp = name = ecpyalloc(argname); 2202*7c478bd9Sstevel@tonic-gate while ((cp = strchr(cp + 1, '/')) != 0) { 2203*7c478bd9Sstevel@tonic-gate *cp = '\0'; 2204*7c478bd9Sstevel@tonic-gate if (!itsdir(name)) { 2205*7c478bd9Sstevel@tonic-gate /* 2206*7c478bd9Sstevel@tonic-gate * It doesn't seem to exist, so we try to create it. 2207*7c478bd9Sstevel@tonic-gate * Creation may fail because of the directory being 2208*7c478bd9Sstevel@tonic-gate * created by some other multiprocessor, so we get 2209*7c478bd9Sstevel@tonic-gate * to do extra checking. 2210*7c478bd9Sstevel@tonic-gate */ 2211*7c478bd9Sstevel@tonic-gate if (mkdir(name, 2212*7c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) { 2213*7c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate if (errno != EEXIST || !itsdir(name)) { 2216*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2217*7c478bd9Sstevel@tonic-gate "%s: Can't create directory %s: %s\n"), 2218*7c478bd9Sstevel@tonic-gate progname, name, e); 2219*7c478bd9Sstevel@tonic-gate ifree(name); 2220*7c478bd9Sstevel@tonic-gate return (-1); 2221*7c478bd9Sstevel@tonic-gate } 2222*7c478bd9Sstevel@tonic-gate } 2223*7c478bd9Sstevel@tonic-gate } 2224*7c478bd9Sstevel@tonic-gate *cp = '/'; 2225*7c478bd9Sstevel@tonic-gate } 2226*7c478bd9Sstevel@tonic-gate ifree(name); 2227*7c478bd9Sstevel@tonic-gate return (0); 2228*7c478bd9Sstevel@tonic-gate } 2229*7c478bd9Sstevel@tonic-gate 2230*7c478bd9Sstevel@tonic-gate static long 2231*7c478bd9Sstevel@tonic-gate eitol(i) 2232*7c478bd9Sstevel@tonic-gate const int i; 2233*7c478bd9Sstevel@tonic-gate { 2234*7c478bd9Sstevel@tonic-gate long l; 2235*7c478bd9Sstevel@tonic-gate 2236*7c478bd9Sstevel@tonic-gate l = i; 2237*7c478bd9Sstevel@tonic-gate if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 2238*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2239*7c478bd9Sstevel@tonic-gate gettext("%s: %d did not sign extend correctly\n"), 2240*7c478bd9Sstevel@tonic-gate progname, i); 2241*7c478bd9Sstevel@tonic-gate (void) exit(EXIT_FAILURE); 2242*7c478bd9Sstevel@tonic-gate } 2243*7c478bd9Sstevel@tonic-gate return (l); 2244*7c478bd9Sstevel@tonic-gate } 2245*7c478bd9Sstevel@tonic-gate 2246*7c478bd9Sstevel@tonic-gate /* 2247*7c478bd9Sstevel@tonic-gate * UNIX was a registered trademark of UNIX System Laboratories in 1993. 2248*7c478bd9Sstevel@tonic-gate */ 2249