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