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