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