139991Sbostic #ifndef lint 239991Sbostic #ifndef NOID 339991Sbostic static char elsieid[] = "@(#)zic.c 4.12"; 439991Sbostic #endif /* !defined NOID */ 539991Sbostic #endif /* !defined lint */ 639991Sbostic 7*46793Sbostic #include <sys/types.h> 8*46793Sbostic #include <sys/cdefs.h> 9*46793Sbostic #include <sys/stat.h> 10*46793Sbostic #include <time.h> 11*46793Sbostic #include <tzfile.h> 12*46793Sbostic #include <stdio.h> 13*46793Sbostic #include <ctype.h> 14*46793Sbostic #include <string.h> 15*46793Sbostic #include <stdlib.h> 1639991Sbostic 1739991Sbostic #ifndef TRUE 1839991Sbostic #define TRUE 1 1939991Sbostic #define FALSE 0 2039991Sbostic #endif /* !defined TRUE */ 2139991Sbostic 2239991Sbostic struct rule { 2339991Sbostic const char * r_filename; 2439991Sbostic int r_linenum; 2539991Sbostic const char * r_name; 2639991Sbostic 2739991Sbostic int r_loyear; /* for example, 1986 */ 2839991Sbostic int r_hiyear; /* for example, 1986 */ 2939991Sbostic const char * r_yrtype; 3039991Sbostic 3139991Sbostic int r_month; /* 0..11 */ 3239991Sbostic 3339991Sbostic int r_dycode; /* see below */ 3439991Sbostic int r_dayofmonth; 3539991Sbostic int r_wday; 3639991Sbostic 3739991Sbostic long r_tod; /* time from midnight */ 3839991Sbostic int r_todisstd; /* above is standard time if TRUE */ 3939991Sbostic /* or wall clock time if FALSE */ 4039991Sbostic long r_stdoff; /* offset from standard time */ 4139991Sbostic const char * r_abbrvar; /* variable part of abbreviation */ 4239991Sbostic 4339991Sbostic int r_todo; /* a rule to do (used in outzone) */ 4439991Sbostic time_t r_temp; /* used in outzone */ 4539991Sbostic }; 4639991Sbostic 4739991Sbostic /* 4839991Sbostic ** r_dycode r_dayofmonth r_wday 4939991Sbostic */ 5039991Sbostic 5139991Sbostic #define DC_DOM 0 /* 1..31 */ /* unused */ 5239991Sbostic #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 5339991Sbostic #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 5439991Sbostic 5539991Sbostic struct zone { 5639991Sbostic const char * z_filename; 5739991Sbostic int z_linenum; 5839991Sbostic 5939991Sbostic const char * z_name; 6039991Sbostic long z_gmtoff; 6139991Sbostic const char * z_rule; 6239991Sbostic const char * z_format; 6339991Sbostic 6439991Sbostic long z_stdoff; 6539991Sbostic 6639991Sbostic struct rule * z_rules; 6739991Sbostic int z_nrules; 6839991Sbostic 6939991Sbostic struct rule z_untilrule; 7039991Sbostic time_t z_untiltime; 7139991Sbostic }; 7239991Sbostic 73*46793Sbostic extern char * icatalloc __P((char * old, const char * new)); 74*46793Sbostic extern char * icpyalloc __P((const char * string)); 75*46793Sbostic extern void ifree __P((char * p)); 76*46793Sbostic extern char * imalloc __P((int n)); 77*46793Sbostic extern char * irealloc __P((char * old, int n)); 78*46793Sbostic extern int link __P((const char * fromname, const char * toname)); 7939991Sbostic extern char * optarg; 8039991Sbostic extern int optind; 81*46793Sbostic extern void perror __P((const char * string)); 82*46793Sbostic extern char * scheck __P((const char * string, const char * format)); 83*46793Sbostic static void addtt __P((time_t starttime, int type)); 84*46793Sbostic static int addtype 85*46793Sbostic __P((long gmtoff, const char * abbr, int isdst, 86*46793Sbostic int ttisstd)); 87*46793Sbostic static void addleap __P((time_t t, int positive, int rolling)); 88*46793Sbostic static void adjleap __P((void)); 89*46793Sbostic static void associate __P((void)); 90*46793Sbostic static int ciequal __P((const char * ap, const char * bp)); 91*46793Sbostic static void convert __P((long val, char * buf)); 92*46793Sbostic static void dolink __P((const char * fromfile, const char * tofile)); 93*46793Sbostic static void eat __P((const char * name, int num)); 94*46793Sbostic static void eats __P((const char * name, int num, 95*46793Sbostic const char * rname, int rnum)); 96*46793Sbostic static long eitol __P((int i)); 97*46793Sbostic static void error __P((const char * message)); 98*46793Sbostic static char ** getfields __P((char * buf)); 99*46793Sbostic static long gethms __P((char * string, const char * errstrng, 100*46793Sbostic int signable)); 101*46793Sbostic static void infile __P((const char * filename)); 102*46793Sbostic static void inleap __P((char ** fields, int nfields)); 103*46793Sbostic static void inlink __P((char ** fields, int nfields)); 104*46793Sbostic static void inrule __P((char ** fields, int nfields)); 105*46793Sbostic static int inzcont __P((char ** fields, int nfields)); 106*46793Sbostic static int inzone __P((char ** fields, int nfields)); 107*46793Sbostic static int inzsub __P((char ** fields, int nfields, int iscont)); 108*46793Sbostic static int itsabbr __P((const char * abbr, const char * word)); 109*46793Sbostic static int itsdir __P((const char * name)); 110*46793Sbostic static int lowerit __P((int c)); 111*46793Sbostic static char * memcheck __P((char * tocheck)); 112*46793Sbostic static int mkdirs __P((char * filename)); 113*46793Sbostic static void newabbr __P((const char * abbr)); 114*46793Sbostic static long oadd __P((long t1, long t2)); 115*46793Sbostic static void outzone __P((const struct zone * zp, int ntzones)); 116*46793Sbostic static void puttzcode __P((long code, FILE * fp)); 117*46793Sbostic static int rcomp __P((const void *leftp, const void *rightp)); 118*46793Sbostic static time_t rpytime __P((const struct rule * rp, int wantedy)); 119*46793Sbostic static void rulesub __P((struct rule * rp, char * loyearp, char * hiyearp, 120*46793Sbostic char * typep, char * monthp, char * dayp, char * timep)); 121*46793Sbostic static void setboundaries __P((void)); 122*46793Sbostic static time_t tadd __P((time_t t1, long t2)); 123*46793Sbostic static void usage __P((void)); 124*46793Sbostic static void writezone __P((const char * name)); 125*46793Sbostic static int yearistype __P((int year, const char * type)); 12639991Sbostic 12739991Sbostic static int charcnt; 12839991Sbostic static int errors; 12939991Sbostic static const char * filename; 13039991Sbostic static int leapcnt; 13139991Sbostic static int linenum; 13239991Sbostic static time_t max_time; 13339991Sbostic static int max_year; 13439991Sbostic static time_t min_time; 13539991Sbostic static int min_year; 13639991Sbostic static int noise; 13739991Sbostic static const char * rfilename; 13839991Sbostic static int rlinenum; 13939991Sbostic static const char * progname; 14039991Sbostic static int timecnt; 14139991Sbostic static int typecnt; 14239991Sbostic static int tt_signed; 14339991Sbostic 14439991Sbostic /* 14539991Sbostic ** Line codes. 14639991Sbostic */ 14739991Sbostic 14839991Sbostic #define LC_RULE 0 14939991Sbostic #define LC_ZONE 1 15039991Sbostic #define LC_LINK 2 15139991Sbostic #define LC_LEAP 3 15239991Sbostic 15339991Sbostic /* 15439991Sbostic ** Which fields are which on a Zone line. 15539991Sbostic */ 15639991Sbostic 15739991Sbostic #define ZF_NAME 1 15839991Sbostic #define ZF_GMTOFF 2 15939991Sbostic #define ZF_RULE 3 16039991Sbostic #define ZF_FORMAT 4 16139991Sbostic #define ZF_TILYEAR 5 16239991Sbostic #define ZF_TILMONTH 6 16339991Sbostic #define ZF_TILDAY 7 16439991Sbostic #define ZF_TILTIME 8 16539991Sbostic #define ZONE_MINFIELDS 5 16639991Sbostic #define ZONE_MAXFIELDS 9 16739991Sbostic 16839991Sbostic /* 16939991Sbostic ** Which fields are which on a Zone continuation line. 17039991Sbostic */ 17139991Sbostic 17239991Sbostic #define ZFC_GMTOFF 0 17339991Sbostic #define ZFC_RULE 1 17439991Sbostic #define ZFC_FORMAT 2 17539991Sbostic #define ZFC_TILYEAR 3 17639991Sbostic #define ZFC_TILMONTH 4 17739991Sbostic #define ZFC_TILDAY 5 17839991Sbostic #define ZFC_TILTIME 6 17939991Sbostic #define ZONEC_MINFIELDS 3 18039991Sbostic #define ZONEC_MAXFIELDS 7 18139991Sbostic 18239991Sbostic /* 18339991Sbostic ** Which files are which on a Rule line. 18439991Sbostic */ 18539991Sbostic 18639991Sbostic #define RF_NAME 1 18739991Sbostic #define RF_LOYEAR 2 18839991Sbostic #define RF_HIYEAR 3 18939991Sbostic #define RF_COMMAND 4 19039991Sbostic #define RF_MONTH 5 19139991Sbostic #define RF_DAY 6 19239991Sbostic #define RF_TOD 7 19339991Sbostic #define RF_STDOFF 8 19439991Sbostic #define RF_ABBRVAR 9 19539991Sbostic #define RULE_FIELDS 10 19639991Sbostic 19739991Sbostic /* 19839991Sbostic ** Which fields are which on a Link line. 19939991Sbostic */ 20039991Sbostic 20139991Sbostic #define LF_FROM 1 20239991Sbostic #define LF_TO 2 20339991Sbostic #define LINK_FIELDS 3 20439991Sbostic 20539991Sbostic /* 20639991Sbostic ** Which fields are which on a Leap line. 20739991Sbostic */ 20839991Sbostic 20939991Sbostic #define LP_YEAR 1 21039991Sbostic #define LP_MONTH 2 21139991Sbostic #define LP_DAY 3 21239991Sbostic #define LP_TIME 4 21339991Sbostic #define LP_CORR 5 21439991Sbostic #define LP_ROLL 6 21539991Sbostic #define LEAP_FIELDS 7 21639991Sbostic 21739991Sbostic /* 21839991Sbostic ** Year synonyms. 21939991Sbostic */ 22039991Sbostic 22139991Sbostic #define YR_MINIMUM 0 22239991Sbostic #define YR_MAXIMUM 1 22339991Sbostic #define YR_ONLY 2 22439991Sbostic 22539991Sbostic static struct rule * rules; 22639991Sbostic static int nrules; /* number of rules */ 22739991Sbostic 22839991Sbostic static struct zone * zones; 22939991Sbostic static int nzones; /* number of zones */ 23039991Sbostic 23139991Sbostic struct link { 23239991Sbostic const char * l_filename; 23339991Sbostic int l_linenum; 23439991Sbostic const char * l_from; 23539991Sbostic const char * l_to; 23639991Sbostic }; 23739991Sbostic 23839991Sbostic static struct link * links; 23939991Sbostic static int nlinks; 24039991Sbostic 24139991Sbostic struct lookup { 24239991Sbostic const char * l_word; 24339991Sbostic const int l_value; 24439991Sbostic }; 24539991Sbostic 246*46793Sbostic static struct lookup const * byword __P((const char * string, 24739991Sbostic const struct lookup * lp)); 24839991Sbostic 24939991Sbostic static struct lookup const line_codes[] = { 25039991Sbostic "Rule", LC_RULE, 25139991Sbostic "Zone", LC_ZONE, 25239991Sbostic "Link", LC_LINK, 25339991Sbostic "Leap", LC_LEAP, 25439991Sbostic NULL, 0 25539991Sbostic }; 25639991Sbostic 25739991Sbostic static struct lookup const mon_names[] = { 25839991Sbostic "January", TM_JANUARY, 25939991Sbostic "February", TM_FEBRUARY, 26039991Sbostic "March", TM_MARCH, 26139991Sbostic "April", TM_APRIL, 26239991Sbostic "May", TM_MAY, 26339991Sbostic "June", TM_JUNE, 26439991Sbostic "July", TM_JULY, 26539991Sbostic "August", TM_AUGUST, 26639991Sbostic "September", TM_SEPTEMBER, 26739991Sbostic "October", TM_OCTOBER, 26839991Sbostic "November", TM_NOVEMBER, 26939991Sbostic "December", TM_DECEMBER, 27039991Sbostic NULL, 0 27139991Sbostic }; 27239991Sbostic 27339991Sbostic static struct lookup const wday_names[] = { 27439991Sbostic "Sunday", TM_SUNDAY, 27539991Sbostic "Monday", TM_MONDAY, 27639991Sbostic "Tuesday", TM_TUESDAY, 27739991Sbostic "Wednesday", TM_WEDNESDAY, 27839991Sbostic "Thursday", TM_THURSDAY, 27939991Sbostic "Friday", TM_FRIDAY, 28039991Sbostic "Saturday", TM_SATURDAY, 28139991Sbostic NULL, 0 28239991Sbostic }; 28339991Sbostic 28439991Sbostic static struct lookup const lasts[] = { 28539991Sbostic "last-Sunday", TM_SUNDAY, 28639991Sbostic "last-Monday", TM_MONDAY, 28739991Sbostic "last-Tuesday", TM_TUESDAY, 28839991Sbostic "last-Wednesday", TM_WEDNESDAY, 28939991Sbostic "last-Thursday", TM_THURSDAY, 29039991Sbostic "last-Friday", TM_FRIDAY, 29139991Sbostic "last-Saturday", TM_SATURDAY, 29239991Sbostic NULL, 0 29339991Sbostic }; 29439991Sbostic 29539991Sbostic static struct lookup const begin_years[] = { 29639991Sbostic "minimum", YR_MINIMUM, 29739991Sbostic "maximum", YR_MAXIMUM, 29839991Sbostic NULL, 0 29939991Sbostic }; 30039991Sbostic 30139991Sbostic static struct lookup const end_years[] = { 30239991Sbostic "minimum", YR_MINIMUM, 30339991Sbostic "maximum", YR_MAXIMUM, 30439991Sbostic "only", YR_ONLY, 30539991Sbostic NULL, 0 30639991Sbostic }; 30739991Sbostic 30839991Sbostic static struct lookup const leap_types[] = { 30939991Sbostic "Rolling", TRUE, 31039991Sbostic "Stationary", FALSE, 31139991Sbostic NULL, 0 31239991Sbostic }; 31339991Sbostic 31439991Sbostic static const int len_months[2][MONSPERYEAR] = { 31539991Sbostic 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31639991Sbostic 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 31739991Sbostic }; 31839991Sbostic 31939991Sbostic static const int len_years[2] = { 32039991Sbostic DAYSPERNYEAR, DAYSPERLYEAR 32139991Sbostic }; 32239991Sbostic 32339991Sbostic static time_t ats[TZ_MAX_TIMES]; 32439991Sbostic static unsigned char types[TZ_MAX_TIMES]; 32539991Sbostic static long gmtoffs[TZ_MAX_TYPES]; 32639991Sbostic static char isdsts[TZ_MAX_TYPES]; 32739991Sbostic static char abbrinds[TZ_MAX_TYPES]; 32839991Sbostic static char ttisstds[TZ_MAX_TYPES]; 32939991Sbostic static char chars[TZ_MAX_CHARS]; 33039991Sbostic static time_t trans[TZ_MAX_LEAPS]; 33139991Sbostic static long corr[TZ_MAX_LEAPS]; 33239991Sbostic static char roll[TZ_MAX_LEAPS]; 33339991Sbostic 33439991Sbostic /* 33539991Sbostic ** Memory allocation. 33639991Sbostic */ 33739991Sbostic 33839991Sbostic static char * 33939991Sbostic memcheck(ptr) 34039991Sbostic char * const ptr; 34139991Sbostic { 34239991Sbostic if (ptr == NULL) { 34339991Sbostic (void) perror(progname); 34439991Sbostic (void) exit(EXIT_FAILURE); 34539991Sbostic } 34639991Sbostic return ptr; 34739991Sbostic } 34839991Sbostic 34939991Sbostic #define emalloc(size) memcheck(imalloc(size)) 35039991Sbostic #define erealloc(ptr, size) memcheck(irealloc(ptr, size)) 35139991Sbostic #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 35239991Sbostic #define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp)) 35339991Sbostic 35439991Sbostic /* 35539991Sbostic ** Error handling. 35639991Sbostic */ 35739991Sbostic 35839991Sbostic static void 35939991Sbostic eats(name, num, rname, rnum) 36039991Sbostic const char * const name; 36139991Sbostic const int num; 36239991Sbostic const char * const rname; 36339991Sbostic const int rnum; 36439991Sbostic { 36539991Sbostic filename = name; 36639991Sbostic linenum = num; 36739991Sbostic rfilename = rname; 36839991Sbostic rlinenum = rnum; 36939991Sbostic } 37039991Sbostic 37139991Sbostic static void 37239991Sbostic eat(name, num) 37339991Sbostic const char * const name; 37439991Sbostic const int num; 37539991Sbostic { 37639991Sbostic eats(name, num, (char *) NULL, -1); 37739991Sbostic } 37839991Sbostic 37939991Sbostic static void 38039991Sbostic error(string) 38139991Sbostic const char * const string; 38239991Sbostic { 38339991Sbostic /* 38439991Sbostic ** Match the format of "cc" to allow sh users to 38539991Sbostic ** zic ... 2>&1 | error -t "*" -v 38639991Sbostic ** on BSD systems. 38739991Sbostic */ 38839991Sbostic (void) fprintf(stderr, "\"%s\", line %d: %s", 38939991Sbostic filename, linenum, string); 39039991Sbostic if (rfilename != NULL) 39139991Sbostic (void) fprintf(stderr, " (rule from \"%s\", line %d)", 39239991Sbostic rfilename, rlinenum); 39339991Sbostic (void) fprintf(stderr, "\n"); 39439991Sbostic ++errors; 39539991Sbostic } 39639991Sbostic 39739991Sbostic static void 39839991Sbostic usage() 39939991Sbostic { 40039991Sbostic (void) fprintf(stderr, 40139991Sbostic "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\ 40239991Sbostic \t[ -L leapseconds ] [ filename ... ]\n", 40339991Sbostic progname, progname); 40439991Sbostic (void) exit(EXIT_FAILURE); 40539991Sbostic } 40639991Sbostic 40739991Sbostic static const char * psxrules = NULL; 40839991Sbostic static const char * lcltime = NULL; 40939991Sbostic static const char * directory = NULL; 41039991Sbostic static const char * leapsec = NULL; 41139991Sbostic static int sflag = FALSE; 41239991Sbostic 41339991Sbostic int 41439991Sbostic main(argc, argv) 41539991Sbostic int argc; 41639991Sbostic char * argv[]; 41739991Sbostic { 41839991Sbostic register int i, j; 41939991Sbostic register int c; 42039991Sbostic 42139991Sbostic (void) umask(umask(022) | 022); 42239991Sbostic progname = argv[0]; 42339991Sbostic while ((c = getopt(argc, argv, "d:l:p:L:vs")) != EOF) 42439991Sbostic switch (c) { 42539991Sbostic default: 42639991Sbostic usage(); 42739991Sbostic case 'd': 42839991Sbostic if (directory == NULL) 42939991Sbostic directory = optarg; 43039991Sbostic else { 43139991Sbostic (void) fprintf(stderr, 43239991Sbostic "%s: More than one -d option specified\n", 43339991Sbostic progname); 43439991Sbostic (void) exit(EXIT_FAILURE); 43539991Sbostic } 43639991Sbostic break; 43739991Sbostic case 'l': 43839991Sbostic if (lcltime == NULL) 43939991Sbostic lcltime = optarg; 44039991Sbostic else { 44139991Sbostic (void) fprintf(stderr, 44239991Sbostic "%s: More than one -l option specified\n", 44339991Sbostic progname); 44439991Sbostic (void) exit(EXIT_FAILURE); 44539991Sbostic } 44639991Sbostic break; 44739991Sbostic case 'p': 44839991Sbostic if (psxrules == NULL) 44939991Sbostic psxrules = optarg; 45039991Sbostic else { 45139991Sbostic (void) fprintf(stderr, 45239991Sbostic "%s: More than one -p option specified\n", 45339991Sbostic progname); 45439991Sbostic (void) exit(EXIT_FAILURE); 45539991Sbostic } 45639991Sbostic break; 45739991Sbostic case 'L': 45839991Sbostic if (leapsec == NULL) 45939991Sbostic leapsec = optarg; 46039991Sbostic else { 46139991Sbostic (void) fprintf(stderr, 46239991Sbostic "%s: More than one -L option specified\n", 46339991Sbostic progname); 46439991Sbostic (void) exit(EXIT_FAILURE); 46539991Sbostic } 46639991Sbostic break; 46739991Sbostic case 'v': 46839991Sbostic noise = TRUE; 46939991Sbostic break; 47039991Sbostic case 's': 47139991Sbostic sflag = TRUE; 47239991Sbostic break; 47339991Sbostic } 47439991Sbostic if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 47539991Sbostic usage(); /* usage message by request */ 47639991Sbostic if (directory == NULL) 47739991Sbostic directory = TZDIR; 47839991Sbostic 47939991Sbostic setboundaries(); 48039991Sbostic 48139991Sbostic if (optind < argc && leapsec != NULL) { 48239991Sbostic infile(leapsec); 48339991Sbostic adjleap(); 48439991Sbostic } 48539991Sbostic 48639991Sbostic zones = (struct zone *) emalloc(0); 48739991Sbostic rules = (struct rule *) emalloc(0); 48839991Sbostic links = (struct link *) emalloc(0); 48939991Sbostic for (i = optind; i < argc; ++i) 49039991Sbostic infile(argv[i]); 49139991Sbostic if (errors) 49239991Sbostic (void) exit(EXIT_FAILURE); 49339991Sbostic associate(); 49439991Sbostic for (i = 0; i < nzones; i = j) { 49539991Sbostic /* 49639991Sbostic ** Find the next non-continuation zone entry. 49739991Sbostic */ 49839991Sbostic for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 49939991Sbostic ; 50039991Sbostic outzone(&zones[i], j - i); 50139991Sbostic } 50239991Sbostic /* 50339991Sbostic ** Make links. 50439991Sbostic */ 50539991Sbostic for (i = 0; i < nlinks; ++i) 50639991Sbostic dolink(links[i].l_from, links[i].l_to); 50739991Sbostic if (lcltime != NULL) 50839991Sbostic dolink(lcltime, TZDEFAULT); 50939991Sbostic if (psxrules != NULL) 51039991Sbostic dolink(psxrules, TZDEFRULES); 51139991Sbostic return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 51239991Sbostic } 51339991Sbostic 51439991Sbostic static void 51539991Sbostic dolink(fromfile, tofile) 51639991Sbostic const char * const fromfile; 51739991Sbostic const char * const tofile; 51839991Sbostic { 51939991Sbostic register char * fromname; 52039991Sbostic register char * toname; 52139991Sbostic 52239991Sbostic fromname = ecpyalloc(directory); 52339991Sbostic fromname = ecatalloc(fromname, "/"); 52439991Sbostic fromname = ecatalloc(fromname, fromfile); 52539991Sbostic toname = ecpyalloc(directory); 52639991Sbostic toname = ecatalloc(toname, "/"); 52739991Sbostic toname = ecatalloc(toname, tofile); 52839991Sbostic /* 52939991Sbostic ** We get to be careful here since 53039991Sbostic ** there's a fair chance of root running us. 53139991Sbostic */ 53239991Sbostic if (!itsdir(toname)) 53339991Sbostic (void) remove(toname); 53439991Sbostic if (link(fromname, toname) != 0) { 53539991Sbostic (void) fprintf(stderr, "%s: Can't link from %s to ", 53639991Sbostic progname, fromname); 53739991Sbostic (void) perror(toname); 53839991Sbostic (void) exit(EXIT_FAILURE); 53939991Sbostic } 54039991Sbostic ifree(fromname); 54139991Sbostic ifree(toname); 54239991Sbostic } 54339991Sbostic 54439991Sbostic static void 54539991Sbostic setboundaries() 54639991Sbostic { 54739991Sbostic register time_t bit; 54839991Sbostic 54939991Sbostic for (bit = 1; bit > 0; bit <<= 1) 55039991Sbostic ; 55139991Sbostic if (bit == 0) { /* time_t is an unsigned type */ 55239991Sbostic tt_signed = FALSE; 55339991Sbostic min_time = 0; 55439991Sbostic max_time = ~(time_t) 0; 55539991Sbostic if (sflag) 55639991Sbostic max_time >>= 1; 55739991Sbostic } else { 55839991Sbostic tt_signed = TRUE; 55939991Sbostic min_time = bit; 56039991Sbostic max_time = bit; 56139991Sbostic ++max_time; 56239991Sbostic max_time = -max_time; 56339991Sbostic if (sflag) 56439991Sbostic min_time = 0; 56539991Sbostic } 56639991Sbostic min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 56739991Sbostic max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 56839991Sbostic } 56939991Sbostic 57039991Sbostic static int 57139991Sbostic itsdir(name) 57239991Sbostic const char * const name; 57339991Sbostic { 57439991Sbostic struct stat s; 57539991Sbostic 576*46793Sbostic return (stat(name, &s) == 0 && S_ISDIR(s.st_mode)); 57739991Sbostic } 57839991Sbostic 57939991Sbostic /* 58039991Sbostic ** Associate sets of rules with zones. 58139991Sbostic */ 58239991Sbostic 58339991Sbostic /* 58439991Sbostic ** Sort by rule name. 58539991Sbostic */ 58639991Sbostic 58739991Sbostic static int 58839991Sbostic rcomp(cp1, cp2) 589*46793Sbostic const void * cp1; 590*46793Sbostic const void * cp2; 59139991Sbostic { 59239991Sbostic return strcmp(((struct rule *) cp1)->r_name, 59339991Sbostic ((struct rule *) cp2)->r_name); 59439991Sbostic } 59539991Sbostic 59639991Sbostic static void 59739991Sbostic associate() 59839991Sbostic { 59939991Sbostic register struct zone * zp; 60039991Sbostic register struct rule * rp; 60139991Sbostic register int base, out; 60239991Sbostic register int i; 60339991Sbostic 60439991Sbostic if (nrules != 0) 605*46793Sbostic (void) qsort((void *) rules, (size_t) nrules, 606*46793Sbostic (size_t) sizeof *rules, rcomp); 60739991Sbostic for (i = 0; i < nzones; ++i) { 60839991Sbostic zp = &zones[i]; 60939991Sbostic zp->z_rules = NULL; 61039991Sbostic zp->z_nrules = 0; 61139991Sbostic } 61239991Sbostic for (base = 0; base < nrules; base = out) { 61339991Sbostic rp = &rules[base]; 61439991Sbostic for (out = base + 1; out < nrules; ++out) 61539991Sbostic if (strcmp(rp->r_name, rules[out].r_name) != 0) 61639991Sbostic break; 61739991Sbostic for (i = 0; i < nzones; ++i) { 61839991Sbostic zp = &zones[i]; 61939991Sbostic if (strcmp(zp->z_rule, rp->r_name) != 0) 62039991Sbostic continue; 62139991Sbostic zp->z_rules = rp; 62239991Sbostic zp->z_nrules = out - base; 62339991Sbostic } 62439991Sbostic } 62539991Sbostic for (i = 0; i < nzones; ++i) { 62639991Sbostic zp = &zones[i]; 62739991Sbostic if (zp->z_nrules == 0) { 62839991Sbostic /* 62939991Sbostic ** Maybe we have a local standard time offset. 63039991Sbostic */ 63139991Sbostic eat(zp->z_filename, zp->z_linenum); 632*46793Sbostic zp->z_stdoff = 633*46793Sbostic gethms((char *)zp->z_rule, "unruly zone", TRUE); 63439991Sbostic /* 63539991Sbostic ** Note, though, that if there's no rule, 63639991Sbostic ** a '%s' in the format is a bad thing. 63739991Sbostic */ 63839991Sbostic if (strchr(zp->z_format, '%') != 0) 63939991Sbostic error("%s in ruleless zone"); 64039991Sbostic } 64139991Sbostic } 64239991Sbostic if (errors) 64339991Sbostic (void) exit(EXIT_FAILURE); 64439991Sbostic } 64539991Sbostic 64639991Sbostic static void 64739991Sbostic infile(name) 64839991Sbostic const char * name; 64939991Sbostic { 65039991Sbostic register FILE * fp; 65139991Sbostic register char ** fields; 65239991Sbostic register char * cp; 65339991Sbostic register const struct lookup * lp; 65439991Sbostic register int nfields; 65539991Sbostic register int wantcont; 65639991Sbostic register int num; 65739991Sbostic char buf[BUFSIZ]; 65839991Sbostic 65939991Sbostic if (strcmp(name, "-") == 0) { 66039991Sbostic name = "standard input"; 66139991Sbostic fp = stdin; 66239991Sbostic } else if ((fp = fopen(name, "r")) == NULL) { 66339991Sbostic (void) fprintf(stderr, "%s: Can't open ", progname); 66439991Sbostic (void) perror(name); 66539991Sbostic (void) exit(EXIT_FAILURE); 66639991Sbostic } 66739991Sbostic wantcont = FALSE; 66839991Sbostic for (num = 1; ; ++num) { 66939991Sbostic eat(name, num); 67039991Sbostic if (fgets(buf, (int) sizeof buf, fp) != buf) 67139991Sbostic break; 67239991Sbostic cp = strchr(buf, '\n'); 67339991Sbostic if (cp == NULL) { 67439991Sbostic error("line too long"); 67539991Sbostic (void) exit(EXIT_FAILURE); 67639991Sbostic } 67739991Sbostic *cp = '\0'; 67839991Sbostic fields = getfields(buf); 67939991Sbostic nfields = 0; 68039991Sbostic while (fields[nfields] != NULL) { 68139991Sbostic if (ciequal(fields[nfields], "-")) 68239991Sbostic fields[nfields] = ""; 68339991Sbostic ++nfields; 68439991Sbostic } 68539991Sbostic if (nfields == 0) { 68639991Sbostic /* nothing to do */ 68739991Sbostic } else if (wantcont) { 68839991Sbostic wantcont = inzcont(fields, nfields); 68939991Sbostic } else { 69039991Sbostic lp = byword(fields[0], line_codes); 69139991Sbostic if (lp == NULL) 69239991Sbostic error("input line of unknown type"); 69339991Sbostic else switch ((int) (lp->l_value)) { 69439991Sbostic case LC_RULE: 69539991Sbostic inrule(fields, nfields); 69639991Sbostic wantcont = FALSE; 69739991Sbostic break; 69839991Sbostic case LC_ZONE: 69939991Sbostic wantcont = inzone(fields, nfields); 70039991Sbostic break; 70139991Sbostic case LC_LINK: 70239991Sbostic inlink(fields, nfields); 70339991Sbostic wantcont = FALSE; 70439991Sbostic break; 70539991Sbostic case LC_LEAP: 70639991Sbostic if (name != leapsec) 70739991Sbostic (void) fprintf(stderr, 70839991Sbostic "%s: Leap line in non leap seconds file %s\n", 70939991Sbostic progname, name); 71039991Sbostic else inleap(fields, nfields); 71139991Sbostic wantcont = FALSE; 71239991Sbostic break; 71339991Sbostic default: /* "cannot happen" */ 71439991Sbostic (void) fprintf(stderr, 71539991Sbostic "%s: panic: Invalid l_value %d\n", 71639991Sbostic progname, lp->l_value); 71739991Sbostic (void) exit(EXIT_FAILURE); 71839991Sbostic } 71939991Sbostic } 72039991Sbostic ifree((char *) fields); 72139991Sbostic } 72239991Sbostic if (ferror(fp)) { 72339991Sbostic (void) fprintf(stderr, "%s: Error reading ", progname); 72439991Sbostic (void) perror(filename); 72539991Sbostic (void) exit(EXIT_FAILURE); 72639991Sbostic } 72739991Sbostic if (fp != stdin && fclose(fp)) { 72839991Sbostic (void) fprintf(stderr, "%s: Error closing ", progname); 72939991Sbostic (void) perror(filename); 73039991Sbostic (void) exit(EXIT_FAILURE); 73139991Sbostic } 73239991Sbostic if (wantcont) 73339991Sbostic error("expected continuation line not found"); 73439991Sbostic } 73539991Sbostic 73639991Sbostic /* 73739991Sbostic ** Convert a string of one of the forms 73839991Sbostic ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 73939991Sbostic ** into a number of seconds. 74039991Sbostic ** A null string maps to zero. 74139991Sbostic ** Call error with errstring and return zero on errors. 74239991Sbostic */ 74339991Sbostic 74439991Sbostic static long 74539991Sbostic gethms(string, errstring, signable) 746*46793Sbostic char * string; 74739991Sbostic const char * const errstring; 74839991Sbostic const int signable; 74939991Sbostic { 75039991Sbostic int hh, mm, ss, sign; 75139991Sbostic 75239991Sbostic if (string == NULL || *string == '\0') 75339991Sbostic return 0; 75439991Sbostic if (!signable) 75539991Sbostic sign = 1; 75639991Sbostic else if (*string == '-') { 75739991Sbostic sign = -1; 75839991Sbostic ++string; 75939991Sbostic } else sign = 1; 76039991Sbostic if (sscanf(string, scheck(string, "%d"), &hh) == 1) 76139991Sbostic mm = ss = 0; 76239991Sbostic else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 76339991Sbostic ss = 0; 76439991Sbostic else if (sscanf(string, scheck(string, "%d:%d:%d"), 76539991Sbostic &hh, &mm, &ss) != 3) { 76639991Sbostic error(errstring); 76739991Sbostic return 0; 76839991Sbostic } 76939991Sbostic if (hh < 0 || hh >= HOURSPERDAY || 77039991Sbostic mm < 0 || mm >= MINSPERHOUR || 77139991Sbostic ss < 0 || ss > SECSPERMIN) { 77239991Sbostic error(errstring); 77339991Sbostic return 0; 77439991Sbostic } 77539991Sbostic return eitol(sign) * 77639991Sbostic (eitol(hh * MINSPERHOUR + mm) * 77739991Sbostic eitol(SECSPERMIN) + eitol(ss)); 77839991Sbostic } 77939991Sbostic 78039991Sbostic static void 78139991Sbostic inrule(fields, nfields) 78239991Sbostic register char ** const fields; 78339991Sbostic const int nfields; 78439991Sbostic { 78539991Sbostic static struct rule r; 78639991Sbostic 78739991Sbostic if (nfields != RULE_FIELDS) { 78839991Sbostic error("wrong number of fields on Rule line"); 78939991Sbostic return; 79039991Sbostic } 79139991Sbostic if (*fields[RF_NAME] == '\0') { 79239991Sbostic error("nameless rule"); 79339991Sbostic return; 79439991Sbostic } 79539991Sbostic r.r_filename = filename; 79639991Sbostic r.r_linenum = linenum; 79739991Sbostic r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); 79839991Sbostic rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 79939991Sbostic fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 80039991Sbostic r.r_name = ecpyalloc(fields[RF_NAME]); 80139991Sbostic r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 80239991Sbostic rules = (struct rule *) erealloc((char *) rules, 80339991Sbostic (int) ((nrules + 1) * sizeof *rules)); 80439991Sbostic rules[nrules++] = r; 80539991Sbostic } 80639991Sbostic 80739991Sbostic static int 80839991Sbostic inzone(fields, nfields) 80939991Sbostic register char ** const fields; 81039991Sbostic const int nfields; 81139991Sbostic { 81239991Sbostic register int i; 81339991Sbostic char buf[132]; 81439991Sbostic 81539991Sbostic if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 81639991Sbostic error("wrong number of fields on Zone line"); 81739991Sbostic return FALSE; 81839991Sbostic } 81939991Sbostic if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 82039991Sbostic (void) sprintf(buf, 82139991Sbostic "\"Zone %s\" line and -l option are mutually exclusive", 82239991Sbostic TZDEFAULT); 82339991Sbostic error(buf); 82439991Sbostic return FALSE; 82539991Sbostic } 82639991Sbostic if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 82739991Sbostic (void) sprintf(buf, 82839991Sbostic "\"Zone %s\" line and -p option are mutually exclusive", 82939991Sbostic TZDEFRULES); 83039991Sbostic error(buf); 83139991Sbostic return FALSE; 83239991Sbostic } 83339991Sbostic for (i = 0; i < nzones; ++i) 83439991Sbostic if (zones[i].z_name != NULL && 83539991Sbostic strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 83639991Sbostic (void) sprintf(buf, 83739991Sbostic "duplicate zone name %s (file \"%s\", line %d)", 83839991Sbostic fields[ZF_NAME], 83939991Sbostic zones[i].z_filename, 84039991Sbostic zones[i].z_linenum); 84139991Sbostic error(buf); 84239991Sbostic return FALSE; 84339991Sbostic } 84439991Sbostic return inzsub(fields, nfields, FALSE); 84539991Sbostic } 84639991Sbostic 84739991Sbostic static int 84839991Sbostic inzcont(fields, nfields) 84939991Sbostic register char ** const fields; 85039991Sbostic const int nfields; 85139991Sbostic { 85239991Sbostic if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 85339991Sbostic error("wrong number of fields on Zone continuation line"); 85439991Sbostic return FALSE; 85539991Sbostic } 85639991Sbostic return inzsub(fields, nfields, TRUE); 85739991Sbostic } 85839991Sbostic 85939991Sbostic static int 86039991Sbostic inzsub(fields, nfields, iscont) 86139991Sbostic register char ** const fields; 86239991Sbostic const int nfields; 86339991Sbostic const int iscont; 86439991Sbostic { 86539991Sbostic register char * cp; 86639991Sbostic static struct zone z; 86739991Sbostic register int i_gmtoff, i_rule, i_format; 86839991Sbostic register int i_untilyear, i_untilmonth; 86939991Sbostic register int i_untilday, i_untiltime; 87039991Sbostic register int hasuntil; 87139991Sbostic 87239991Sbostic if (iscont) { 87339991Sbostic i_gmtoff = ZFC_GMTOFF; 87439991Sbostic i_rule = ZFC_RULE; 87539991Sbostic i_format = ZFC_FORMAT; 87639991Sbostic i_untilyear = ZFC_TILYEAR; 87739991Sbostic i_untilmonth = ZFC_TILMONTH; 87839991Sbostic i_untilday = ZFC_TILDAY; 87939991Sbostic i_untiltime = ZFC_TILTIME; 88039991Sbostic z.z_name = NULL; 88139991Sbostic } else { 88239991Sbostic i_gmtoff = ZF_GMTOFF; 88339991Sbostic i_rule = ZF_RULE; 88439991Sbostic i_format = ZF_FORMAT; 88539991Sbostic i_untilyear = ZF_TILYEAR; 88639991Sbostic i_untilmonth = ZF_TILMONTH; 88739991Sbostic i_untilday = ZF_TILDAY; 88839991Sbostic i_untiltime = ZF_TILTIME; 88939991Sbostic z.z_name = ecpyalloc(fields[ZF_NAME]); 89039991Sbostic } 89139991Sbostic z.z_filename = filename; 89239991Sbostic z.z_linenum = linenum; 89339991Sbostic z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); 89439991Sbostic if ((cp = strchr(fields[i_format], '%')) != 0) { 89539991Sbostic if (*++cp != 's' || strchr(cp, '%') != 0) { 89639991Sbostic error("invalid abbreviation format"); 89739991Sbostic return FALSE; 89839991Sbostic } 89939991Sbostic } 90039991Sbostic z.z_rule = ecpyalloc(fields[i_rule]); 90139991Sbostic z.z_format = ecpyalloc(fields[i_format]); 90239991Sbostic hasuntil = nfields > i_untilyear; 90339991Sbostic if (hasuntil) { 90439991Sbostic z.z_untilrule.r_filename = filename; 90539991Sbostic z.z_untilrule.r_linenum = linenum; 90639991Sbostic rulesub(&z.z_untilrule, 90739991Sbostic fields[i_untilyear], 90839991Sbostic "only", 90939991Sbostic "", 91039991Sbostic (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", 91139991Sbostic (nfields > i_untilday) ? fields[i_untilday] : "1", 91239991Sbostic (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 91339991Sbostic z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); 91439991Sbostic if (iscont && nzones > 0 && z.z_untiltime < max_time && 91539991Sbostic z.z_untiltime > min_time && 91639991Sbostic zones[nzones - 1].z_untiltime >= z.z_untiltime) { 91739991Sbostic error("Zone continuation line end time is not after end time of previous line"); 91839991Sbostic return FALSE; 91939991Sbostic } 92039991Sbostic } 92139991Sbostic zones = (struct zone *) erealloc((char *) zones, 92239991Sbostic (int) ((nzones + 1) * sizeof *zones)); 92339991Sbostic zones[nzones++] = z; 92439991Sbostic /* 92539991Sbostic ** If there was an UNTIL field on this line, 92639991Sbostic ** there's more information about the zone on the next line. 92739991Sbostic */ 92839991Sbostic return hasuntil; 92939991Sbostic } 93039991Sbostic 93139991Sbostic static void 93239991Sbostic inleap(fields, nfields) 93339991Sbostic register char ** const fields; 93439991Sbostic const int nfields; 93539991Sbostic { 93639991Sbostic register const char * cp; 93739991Sbostic register const struct lookup * lp; 93839991Sbostic register int i, j; 93939991Sbostic int year, month, day; 94039991Sbostic long dayoff, tod; 94139991Sbostic time_t t; 94239991Sbostic 94339991Sbostic if (nfields != LEAP_FIELDS) { 94439991Sbostic error("wrong number of fields on Leap line"); 94539991Sbostic return; 94639991Sbostic } 94739991Sbostic dayoff = 0; 94839991Sbostic cp = fields[LP_YEAR]; 949*46793Sbostic if (sscanf((char *)cp, scheck(cp, "%d"), &year) != 1 || 95039991Sbostic year < min_year || year > max_year) { 95139991Sbostic /* 95239991Sbostic * Leapin' Lizards! 95339991Sbostic */ 95439991Sbostic error("invalid leaping year"); 95539991Sbostic return; 95639991Sbostic } 95739991Sbostic j = EPOCH_YEAR; 95839991Sbostic while (j != year) { 95939991Sbostic if (year > j) { 96039991Sbostic i = len_years[isleap(j)]; 96139991Sbostic ++j; 96239991Sbostic } else { 96339991Sbostic --j; 96439991Sbostic i = -len_years[isleap(j)]; 96539991Sbostic } 96639991Sbostic dayoff = oadd(dayoff, eitol(i)); 96739991Sbostic } 96839991Sbostic if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 96939991Sbostic error("invalid month name"); 97039991Sbostic return; 97139991Sbostic } 97239991Sbostic month = lp->l_value; 97339991Sbostic j = TM_JANUARY; 97439991Sbostic while (j != month) { 97539991Sbostic i = len_months[isleap(year)][j]; 97639991Sbostic dayoff = oadd(dayoff, eitol(i)); 97739991Sbostic ++j; 97839991Sbostic } 97939991Sbostic cp = fields[LP_DAY]; 980*46793Sbostic if (sscanf((char *)cp, scheck(cp, "%d"), &day) != 1 || 98139991Sbostic day <= 0 || day > len_months[isleap(year)][month]) { 98239991Sbostic error("invalid day of month"); 98339991Sbostic return; 98439991Sbostic } 98539991Sbostic dayoff = oadd(dayoff, eitol(day - 1)); 98639991Sbostic if (dayoff < 0 && !tt_signed) { 98739991Sbostic error("time before zero"); 98839991Sbostic return; 98939991Sbostic } 99039991Sbostic t = (time_t) dayoff * SECSPERDAY; 99139991Sbostic /* 99239991Sbostic ** Cheap overflow check. 99339991Sbostic */ 99439991Sbostic if (t / SECSPERDAY != dayoff) { 99539991Sbostic error("time overflow"); 99639991Sbostic return; 99739991Sbostic } 99839991Sbostic tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); 99939991Sbostic cp = fields[LP_CORR]; 100039991Sbostic if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) { 100139991Sbostic /* infile() turned "-" into "" */ 100239991Sbostic error("illegal CORRECTION field on Leap line"); 100339991Sbostic return; 100439991Sbostic } 100539991Sbostic if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 100639991Sbostic error("illegal Rolling/Stationary field on Leap line"); 100739991Sbostic return; 100839991Sbostic } 100939991Sbostic addleap(tadd(t, tod), *cp == '+', lp->l_value); 101039991Sbostic } 101139991Sbostic 101239991Sbostic static void 101339991Sbostic inlink(fields, nfields) 101439991Sbostic register char ** const fields; 101539991Sbostic const int nfields; 101639991Sbostic { 101739991Sbostic struct link l; 101839991Sbostic 101939991Sbostic if (nfields != LINK_FIELDS) { 102039991Sbostic error("wrong number of fields on Link line"); 102139991Sbostic return; 102239991Sbostic } 102339991Sbostic if (*fields[LF_FROM] == '\0') { 102439991Sbostic error("blank FROM field on Link line"); 102539991Sbostic return; 102639991Sbostic } 102739991Sbostic if (*fields[LF_TO] == '\0') { 102839991Sbostic error("blank TO field on Link line"); 102939991Sbostic return; 103039991Sbostic } 103139991Sbostic l.l_filename = filename; 103239991Sbostic l.l_linenum = linenum; 103339991Sbostic l.l_from = ecpyalloc(fields[LF_FROM]); 103439991Sbostic l.l_to = ecpyalloc(fields[LF_TO]); 103539991Sbostic links = (struct link *) erealloc((char *) links, 103639991Sbostic (int) ((nlinks + 1) * sizeof *links)); 103739991Sbostic links[nlinks++] = l; 103839991Sbostic } 103939991Sbostic 104039991Sbostic static void 104139991Sbostic rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 104239991Sbostic register struct rule * const rp; 104339991Sbostic char * const loyearp; 104439991Sbostic char * const hiyearp; 104539991Sbostic char * const typep; 104639991Sbostic char * const monthp; 104739991Sbostic char * const dayp; 104839991Sbostic char * const timep; 104939991Sbostic { 105039991Sbostic register struct lookup const * lp; 105139991Sbostic register char * cp; 105239991Sbostic 105339991Sbostic if ((lp = byword(monthp, mon_names)) == NULL) { 105439991Sbostic error("invalid month name"); 105539991Sbostic return; 105639991Sbostic } 105739991Sbostic rp->r_month = lp->l_value; 105839991Sbostic rp->r_todisstd = FALSE; 105939991Sbostic cp = timep; 106039991Sbostic if (*cp != '\0') { 106139991Sbostic cp += strlen(cp) - 1; 106239991Sbostic switch (lowerit(*cp)) { 106339991Sbostic case 's': 106439991Sbostic rp->r_todisstd = TRUE; 106539991Sbostic *cp = '\0'; 106639991Sbostic break; 106739991Sbostic case 'w': 106839991Sbostic rp->r_todisstd = FALSE; 106939991Sbostic *cp = '\0'; 107039991Sbostic break; 107139991Sbostic } 107239991Sbostic } 107339991Sbostic rp->r_tod = gethms(timep, "invalid time of day", FALSE); 107439991Sbostic /* 107539991Sbostic ** Year work. 107639991Sbostic */ 107739991Sbostic cp = loyearp; 107839991Sbostic if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { 107939991Sbostic case YR_MINIMUM: 108039991Sbostic rp->r_loyear = min_year; 108139991Sbostic break; 108239991Sbostic case YR_MAXIMUM: 108339991Sbostic rp->r_loyear = max_year; 108439991Sbostic break; 108539991Sbostic default: /* "cannot happen" */ 108639991Sbostic (void) fprintf(stderr, 108739991Sbostic "%s: panic: Invalid l_value %d\n", 108839991Sbostic progname, lp->l_value); 108939991Sbostic (void) exit(EXIT_FAILURE); 109039991Sbostic } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 || 109139991Sbostic rp->r_loyear < min_year || rp->r_loyear > max_year) { 109239991Sbostic if (noise) 109339991Sbostic error("invalid starting year"); 109439991Sbostic if (rp->r_loyear > max_year) 109539991Sbostic return; 109639991Sbostic } 109739991Sbostic cp = hiyearp; 109839991Sbostic if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { 109939991Sbostic case YR_MINIMUM: 110039991Sbostic rp->r_hiyear = min_year; 110139991Sbostic break; 110239991Sbostic case YR_MAXIMUM: 110339991Sbostic rp->r_hiyear = max_year; 110439991Sbostic break; 110539991Sbostic case YR_ONLY: 110639991Sbostic rp->r_hiyear = rp->r_loyear; 110739991Sbostic break; 110839991Sbostic default: /* "cannot happen" */ 110939991Sbostic (void) fprintf(stderr, 111039991Sbostic "%s: panic: Invalid l_value %d\n", 111139991Sbostic progname, lp->l_value); 111239991Sbostic (void) exit(EXIT_FAILURE); 111339991Sbostic } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 || 111439991Sbostic rp->r_hiyear < min_year || rp->r_hiyear > max_year) { 111539991Sbostic if (noise) 111639991Sbostic error("invalid ending year"); 111739991Sbostic if (rp->r_hiyear < min_year) 111839991Sbostic return; 111939991Sbostic } 112039991Sbostic if (rp->r_hiyear < min_year) 112139991Sbostic return; 112239991Sbostic if (rp->r_loyear < min_year) 112339991Sbostic rp->r_loyear = min_year; 112439991Sbostic if (rp->r_hiyear > max_year) 112539991Sbostic rp->r_hiyear = max_year; 112639991Sbostic if (rp->r_loyear > rp->r_hiyear) { 112739991Sbostic error("starting year greater than ending year"); 112839991Sbostic return; 112939991Sbostic } 113039991Sbostic if (*typep == '\0') 113139991Sbostic rp->r_yrtype = NULL; 113239991Sbostic else { 113339991Sbostic if (rp->r_loyear == rp->r_hiyear) { 113439991Sbostic error("typed single year"); 113539991Sbostic return; 113639991Sbostic } 113739991Sbostic rp->r_yrtype = ecpyalloc(typep); 113839991Sbostic } 113939991Sbostic /* 114039991Sbostic ** Day work. 114139991Sbostic ** Accept things such as: 114239991Sbostic ** 1 114339991Sbostic ** last-Sunday 114439991Sbostic ** Sun<=20 114539991Sbostic ** Sun>=7 114639991Sbostic */ 114739991Sbostic if ((lp = byword(dayp, lasts)) != NULL) { 114839991Sbostic rp->r_dycode = DC_DOWLEQ; 114939991Sbostic rp->r_wday = lp->l_value; 115039991Sbostic rp->r_dayofmonth = len_months[1][rp->r_month]; 115139991Sbostic } else { 115239991Sbostic if ((cp = strchr(dayp, '<')) != 0) 115339991Sbostic rp->r_dycode = DC_DOWLEQ; 115439991Sbostic else if ((cp = strchr(dayp, '>')) != 0) 115539991Sbostic rp->r_dycode = DC_DOWGEQ; 115639991Sbostic else { 115739991Sbostic cp = dayp; 115839991Sbostic rp->r_dycode = DC_DOM; 115939991Sbostic } 116039991Sbostic if (rp->r_dycode != DC_DOM) { 116139991Sbostic *cp++ = 0; 116239991Sbostic if (*cp++ != '=') { 116339991Sbostic error("invalid day of month"); 116439991Sbostic return; 116539991Sbostic } 116639991Sbostic if ((lp = byword(dayp, wday_names)) == NULL) { 116739991Sbostic error("invalid weekday name"); 116839991Sbostic return; 116939991Sbostic } 117039991Sbostic rp->r_wday = lp->l_value; 117139991Sbostic } 117239991Sbostic if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || 117339991Sbostic rp->r_dayofmonth <= 0 || 117439991Sbostic (rp->r_dayofmonth > len_months[1][rp->r_month])) { 117539991Sbostic error("invalid day of month"); 117639991Sbostic return; 117739991Sbostic } 117839991Sbostic } 117939991Sbostic } 118039991Sbostic 118139991Sbostic static void 118239991Sbostic convert(val, buf) 118339991Sbostic const long val; 118439991Sbostic char * const buf; 118539991Sbostic { 118639991Sbostic register int i; 118739991Sbostic register long shift; 118839991Sbostic 118939991Sbostic for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 119039991Sbostic buf[i] = val >> shift; 119139991Sbostic } 119239991Sbostic 119339991Sbostic static void 119439991Sbostic puttzcode(val, fp) 119539991Sbostic const long val; 119639991Sbostic FILE * const fp; 119739991Sbostic { 119839991Sbostic char buf[4]; 119939991Sbostic 120039991Sbostic convert(val, buf); 1201*46793Sbostic (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 120239991Sbostic } 120339991Sbostic 120439991Sbostic static void 120539991Sbostic writezone(name) 120639991Sbostic const char * const name; 120739991Sbostic { 120839991Sbostic register FILE * fp; 120939991Sbostic register int i, j; 121039991Sbostic char fullname[BUFSIZ]; 121139991Sbostic static struct tzhead tzh; 121239991Sbostic 121339991Sbostic if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) { 121439991Sbostic (void) fprintf(stderr, 121539991Sbostic "%s: File name %s/%s too long\n", progname, 121639991Sbostic directory, name); 121739991Sbostic (void) exit(EXIT_FAILURE); 121839991Sbostic } 121939991Sbostic (void) sprintf(fullname, "%s/%s", directory, name); 122039991Sbostic if ((fp = fopen(fullname, "wb")) == NULL) { 122139991Sbostic if (mkdirs(fullname) != 0) 122239991Sbostic (void) exit(EXIT_FAILURE); 122339991Sbostic if ((fp = fopen(fullname, "wb")) == NULL) { 122439991Sbostic (void) fprintf(stderr, "%s: Can't create ", progname); 122539991Sbostic (void) perror(fullname); 122639991Sbostic (void) exit(EXIT_FAILURE); 122739991Sbostic } 122839991Sbostic } 122939991Sbostic convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 123039991Sbostic convert(eitol(leapcnt), tzh.tzh_leapcnt); 123139991Sbostic convert(eitol(timecnt), tzh.tzh_timecnt); 123239991Sbostic convert(eitol(typecnt), tzh.tzh_typecnt); 123339991Sbostic convert(eitol(charcnt), tzh.tzh_charcnt); 1234*46793Sbostic (void) fwrite((void *) &tzh, (size_t) sizeof tzh, (size_t) 1, fp); 123539991Sbostic for (i = 0; i < timecnt; ++i) { 123639991Sbostic j = leapcnt; 123739991Sbostic while (--j >= 0) 123839991Sbostic if (ats[i] >= trans[j]) { 123939991Sbostic ats[i] = tadd(ats[i], corr[j]); 124039991Sbostic break; 124139991Sbostic } 124239991Sbostic puttzcode((long) ats[i], fp); 124339991Sbostic } 124439991Sbostic if (timecnt > 0) 1245*46793Sbostic (void) fwrite((void *) types, (size_t) sizeof types[0], 1246*46793Sbostic (size_t) timecnt, fp); 124739991Sbostic for (i = 0; i < typecnt; ++i) { 124839991Sbostic puttzcode((long) gmtoffs[i], fp); 124939991Sbostic (void) putc(isdsts[i], fp); 125039991Sbostic (void) putc(abbrinds[i], fp); 125139991Sbostic } 125239991Sbostic if (charcnt != 0) 1253*46793Sbostic (void) fwrite((void *) chars, (size_t) sizeof chars[0], 1254*46793Sbostic (size_t) charcnt, fp); 125539991Sbostic for (i = 0; i < leapcnt; ++i) { 125639991Sbostic if (roll[i]) { 125739991Sbostic if (timecnt == 0 || trans[i] < ats[0]) { 125839991Sbostic j = 0; 125939991Sbostic while (isdsts[j]) 126039991Sbostic if (++j >= typecnt) { 126139991Sbostic j = 0; 126239991Sbostic break; 126339991Sbostic } 126439991Sbostic } else { 126539991Sbostic j = 1; 126639991Sbostic while (j < timecnt && trans[i] >= ats[j]) 126739991Sbostic ++j; 126839991Sbostic j = types[j - 1]; 126939991Sbostic } 127039991Sbostic puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 127139991Sbostic } else puttzcode((long) trans[i], fp); 127239991Sbostic puttzcode((long) corr[i], fp); 127339991Sbostic } 127439991Sbostic for (i = 0; i < typecnt; ++i) 127539991Sbostic (void) putc(ttisstds[i], fp); 127639991Sbostic if (ferror(fp) || fclose(fp)) { 127739991Sbostic (void) fprintf(stderr, "%s: Write error on ", progname); 127839991Sbostic (void) perror(fullname); 127939991Sbostic (void) exit(EXIT_FAILURE); 128039991Sbostic } 128139991Sbostic } 128239991Sbostic 128339991Sbostic static void 128439991Sbostic outzone(zpfirst, zonecount) 128539991Sbostic const struct zone * const zpfirst; 128639991Sbostic const int zonecount; 128739991Sbostic { 128839991Sbostic register const struct zone * zp; 128939991Sbostic register struct rule * rp; 129039991Sbostic register int i, j; 129139991Sbostic register int usestart, useuntil; 129239991Sbostic register time_t starttime, untiltime; 129339991Sbostic register long gmtoff; 129439991Sbostic register long stdoff; 129539991Sbostic register int year; 129639991Sbostic register long startoff; 129739991Sbostic register int startisdst; 129839991Sbostic register int startttisstd; 129939991Sbostic register int type; 130039991Sbostic char startbuf[BUFSIZ]; 130139991Sbostic 130239991Sbostic /* 130339991Sbostic ** Now. . .finally. . .generate some useful data! 130439991Sbostic */ 130539991Sbostic timecnt = 0; 130639991Sbostic typecnt = 0; 130739991Sbostic charcnt = 0; 130839991Sbostic /* 130939991Sbostic ** Two guesses. . .the second may well be corrected later. 131039991Sbostic */ 131139991Sbostic gmtoff = zpfirst->z_gmtoff; 131239991Sbostic stdoff = 0; 131339991Sbostic #ifdef lint 131439991Sbostic starttime = 0; 131539991Sbostic startttisstd = FALSE; 131639991Sbostic #endif /* defined lint */ 131739991Sbostic for (i = 0; i < zonecount; ++i) { 131839991Sbostic usestart = i > 0; 131939991Sbostic useuntil = i < (zonecount - 1); 132039991Sbostic zp = &zpfirst[i]; 132139991Sbostic eat(zp->z_filename, zp->z_linenum); 132239991Sbostic startisdst = -1; 132339991Sbostic if (zp->z_nrules == 0) { 132439991Sbostic type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff), 132539991Sbostic zp->z_format, zp->z_stdoff != 0, 132639991Sbostic startttisstd); 132739991Sbostic if (usestart) 132839991Sbostic addtt(starttime, type); 132939991Sbostic gmtoff = zp->z_gmtoff; 133039991Sbostic stdoff = zp->z_stdoff; 133139991Sbostic } else for (year = min_year; year <= max_year; ++year) { 133239991Sbostic if (useuntil && year > zp->z_untilrule.r_hiyear) 133339991Sbostic break; 133439991Sbostic /* 133539991Sbostic ** Mark which rules to do in the current year. 133639991Sbostic ** For those to do, calculate rpytime(rp, year); 133739991Sbostic */ 133839991Sbostic for (j = 0; j < zp->z_nrules; ++j) { 133939991Sbostic rp = &zp->z_rules[j]; 134039991Sbostic eats(zp->z_filename, zp->z_linenum, 134139991Sbostic rp->r_filename, rp->r_linenum); 134239991Sbostic rp->r_todo = year >= rp->r_loyear && 134339991Sbostic year <= rp->r_hiyear && 134439991Sbostic yearistype(year, rp->r_yrtype); 134539991Sbostic if (rp->r_todo) 134639991Sbostic rp->r_temp = rpytime(rp, year); 134739991Sbostic } 134839991Sbostic for ( ; ; ) { 134939991Sbostic register int k; 135039991Sbostic register time_t jtime, ktime; 135139991Sbostic register long offset; 135239991Sbostic char buf[BUFSIZ]; 135339991Sbostic 135439991Sbostic if (useuntil) { 135539991Sbostic /* 135639991Sbostic ** Turn untiltime into GMT 135739991Sbostic ** assuming the current gmtoff and 135839991Sbostic ** stdoff values. 135939991Sbostic */ 136039991Sbostic offset = gmtoff; 136139991Sbostic if (!zp->z_untilrule.r_todisstd) 136239991Sbostic offset = oadd(offset, stdoff); 136339991Sbostic untiltime = tadd(zp->z_untiltime, 136439991Sbostic -offset); 136539991Sbostic } 136639991Sbostic /* 136739991Sbostic ** Find the rule (of those to do, if any) 136839991Sbostic ** that takes effect earliest in the year. 136939991Sbostic */ 137039991Sbostic k = -1; 137139991Sbostic #ifdef lint 137239991Sbostic ktime = 0; 137339991Sbostic #endif /* defined lint */ 137439991Sbostic for (j = 0; j < zp->z_nrules; ++j) { 137539991Sbostic rp = &zp->z_rules[j]; 137639991Sbostic if (!rp->r_todo) 137739991Sbostic continue; 137839991Sbostic eats(zp->z_filename, zp->z_linenum, 137939991Sbostic rp->r_filename, rp->r_linenum); 138039991Sbostic offset = gmtoff; 138139991Sbostic if (!rp->r_todisstd) 138239991Sbostic offset = oadd(offset, stdoff); 138339991Sbostic jtime = rp->r_temp; 138439991Sbostic if (jtime == min_time || 138539991Sbostic jtime == max_time) 138639991Sbostic continue; 138739991Sbostic jtime = tadd(jtime, -offset); 138839991Sbostic if (k < 0 || jtime < ktime) { 138939991Sbostic k = j; 139039991Sbostic ktime = jtime; 139139991Sbostic } 139239991Sbostic } 139339991Sbostic if (k < 0) 139439991Sbostic break; /* go on to next year */ 139539991Sbostic rp = &zp->z_rules[k]; 139639991Sbostic rp->r_todo = FALSE; 139739991Sbostic if (useuntil && ktime >= untiltime) 139839991Sbostic break; 139939991Sbostic if (usestart) { 140039991Sbostic if (ktime < starttime) { 140139991Sbostic stdoff = rp->r_stdoff; 140239991Sbostic startoff = oadd(zp->z_gmtoff, 140339991Sbostic rp->r_stdoff); 140439991Sbostic (void) sprintf(startbuf, 140539991Sbostic zp->z_format, 140639991Sbostic rp->r_abbrvar); 140739991Sbostic startisdst = 140839991Sbostic rp->r_stdoff != 0; 140939991Sbostic continue; 141039991Sbostic } 141139991Sbostic if (ktime != starttime && 141239991Sbostic startisdst >= 0) 141339991Sbostic addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd)); 141439991Sbostic usestart = FALSE; 141539991Sbostic } 141639991Sbostic eats(zp->z_filename, zp->z_linenum, 141739991Sbostic rp->r_filename, rp->r_linenum); 141839991Sbostic (void) sprintf(buf, zp->z_format, 141939991Sbostic rp->r_abbrvar); 142039991Sbostic offset = oadd(zp->z_gmtoff, rp->r_stdoff); 142139991Sbostic type = addtype(offset, buf, rp->r_stdoff != 0, 142239991Sbostic rp->r_todisstd); 142339991Sbostic if (timecnt != 0 || rp->r_stdoff != 0) 142439991Sbostic addtt(ktime, type); 142539991Sbostic gmtoff = zp->z_gmtoff; 142639991Sbostic stdoff = rp->r_stdoff; 142739991Sbostic } 142839991Sbostic } 142939991Sbostic /* 143039991Sbostic ** Now we may get to set starttime for the next zone line. 143139991Sbostic */ 143239991Sbostic if (useuntil) { 143339991Sbostic starttime = tadd(zp->z_untiltime, 143439991Sbostic -gmtoffs[types[timecnt - 1]]); 143539991Sbostic startttisstd = zp->z_untilrule.r_todisstd; 143639991Sbostic } 143739991Sbostic } 143839991Sbostic writezone(zpfirst->z_name); 143939991Sbostic } 144039991Sbostic 144139991Sbostic static void 144239991Sbostic addtt(starttime, type) 144339991Sbostic const time_t starttime; 144439991Sbostic const int type; 144539991Sbostic { 144639991Sbostic if (timecnt != 0 && type == types[timecnt - 1]) 144739991Sbostic return; /* easy enough! */ 144839991Sbostic if (timecnt >= TZ_MAX_TIMES) { 144939991Sbostic error("too many transitions?!"); 145039991Sbostic (void) exit(EXIT_FAILURE); 145139991Sbostic } 145239991Sbostic ats[timecnt] = starttime; 145339991Sbostic types[timecnt] = type; 145439991Sbostic ++timecnt; 145539991Sbostic } 145639991Sbostic 145739991Sbostic static int 145839991Sbostic addtype(gmtoff, abbr, isdst, ttisstd) 145939991Sbostic const long gmtoff; 146039991Sbostic const char * const abbr; 146139991Sbostic const int isdst; 146239991Sbostic const int ttisstd; 146339991Sbostic { 146439991Sbostic register int i, j; 146539991Sbostic 146639991Sbostic /* 146739991Sbostic ** See if there's already an entry for this zone type. 146839991Sbostic ** If so, just return its index. 146939991Sbostic */ 147039991Sbostic for (i = 0; i < typecnt; ++i) { 147139991Sbostic if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 147239991Sbostic strcmp(abbr, &chars[abbrinds[i]]) == 0 && 147339991Sbostic ttisstd == ttisstds[i]) 147439991Sbostic return i; 147539991Sbostic } 147639991Sbostic /* 147739991Sbostic ** There isn't one; add a new one, unless there are already too 147839991Sbostic ** many. 147939991Sbostic */ 148039991Sbostic if (typecnt >= TZ_MAX_TYPES) { 148139991Sbostic error("too many local time types"); 148239991Sbostic (void) exit(EXIT_FAILURE); 148339991Sbostic } 148439991Sbostic gmtoffs[i] = gmtoff; 148539991Sbostic isdsts[i] = isdst; 148639991Sbostic ttisstds[i] = ttisstd; 148739991Sbostic 148839991Sbostic for (j = 0; j < charcnt; ++j) 148939991Sbostic if (strcmp(&chars[j], abbr) == 0) 149039991Sbostic break; 149139991Sbostic if (j == charcnt) 149239991Sbostic newabbr(abbr); 149339991Sbostic abbrinds[i] = j; 149439991Sbostic ++typecnt; 149539991Sbostic return i; 149639991Sbostic } 149739991Sbostic 149839991Sbostic static void 149939991Sbostic addleap(t, positive, rolling) 150039991Sbostic const time_t t; 150139991Sbostic const int positive; 150239991Sbostic const int rolling; 150339991Sbostic { 150439991Sbostic register int i, j; 150539991Sbostic 150639991Sbostic if (leapcnt >= TZ_MAX_LEAPS) { 150739991Sbostic error("too many leap seconds"); 150839991Sbostic (void) exit(EXIT_FAILURE); 150939991Sbostic } 151039991Sbostic for (i = 0; i < leapcnt; ++i) 151139991Sbostic if (t <= trans[i]) { 151239991Sbostic if (t == trans[i]) { 151339991Sbostic error("repeated leap second moment"); 151439991Sbostic (void) exit(EXIT_FAILURE); 151539991Sbostic } 151639991Sbostic break; 151739991Sbostic } 151839991Sbostic for (j = leapcnt; j > i; --j) { 151939991Sbostic trans[j] = trans[j-1]; 152039991Sbostic corr[j] = corr[j-1]; 152139991Sbostic roll[j] = roll[j-1]; 152239991Sbostic } 152339991Sbostic trans[i] = t; 152439991Sbostic corr[i] = (positive ? 1L : -1L); 152539991Sbostic roll[i] = rolling; 152639991Sbostic ++leapcnt; 152739991Sbostic } 152839991Sbostic 152939991Sbostic static void 153039991Sbostic adjleap() 153139991Sbostic { 153239991Sbostic register int i; 153339991Sbostic register long last = 0; 153439991Sbostic 153539991Sbostic /* 153639991Sbostic ** propagate leap seconds forward 153739991Sbostic */ 153839991Sbostic for (i = 0; i < leapcnt; ++i) { 153939991Sbostic trans[i] = tadd(trans[i], last); 154039991Sbostic last = corr[i] += last; 154139991Sbostic } 154239991Sbostic } 154339991Sbostic 154439991Sbostic static int 154539991Sbostic yearistype(year, type) 154639991Sbostic const int year; 154739991Sbostic const char * const type; 154839991Sbostic { 154939991Sbostic char buf[BUFSIZ]; 155039991Sbostic int result; 155139991Sbostic 155239991Sbostic if (type == NULL || *type == '\0') 155339991Sbostic return TRUE; 155439991Sbostic if (strcmp(type, "uspres") == 0) 155539991Sbostic return (year % 4) == 0; 155639991Sbostic if (strcmp(type, "nonpres") == 0) 155739991Sbostic return (year % 4) != 0; 155839991Sbostic (void) sprintf(buf, "yearistype %d %s", year, type); 155939991Sbostic result = system(buf); 156039991Sbostic if (result == 0) 156139991Sbostic return TRUE; 156239991Sbostic if (result == (1 << 8)) 156339991Sbostic return FALSE; 156439991Sbostic error("Wild result from command execution"); 156539991Sbostic (void) fprintf(stderr, "%s: command was '%s', result was %d\n", 156639991Sbostic progname, buf, result); 156739991Sbostic for ( ; ; ) 156839991Sbostic (void) exit(EXIT_FAILURE); 156939991Sbostic } 157039991Sbostic 157139991Sbostic static int 157239991Sbostic lowerit(a) 157339991Sbostic const int a; 157439991Sbostic { 157539991Sbostic return (isascii(a) && isupper(a)) ? tolower(a) : a; 157639991Sbostic } 157739991Sbostic 157839991Sbostic static int 157939991Sbostic ciequal(ap, bp) /* case-insensitive equality */ 158039991Sbostic register const char * ap; 158139991Sbostic register const char * bp; 158239991Sbostic { 158339991Sbostic while (lowerit(*ap) == lowerit(*bp++)) 158439991Sbostic if (*ap++ == '\0') 158539991Sbostic return TRUE; 158639991Sbostic return FALSE; 158739991Sbostic } 158839991Sbostic 158939991Sbostic static int 159039991Sbostic itsabbr(abbr, word) 159139991Sbostic register const char * abbr; 159239991Sbostic register const char * word; 159339991Sbostic { 159439991Sbostic if (lowerit(*abbr) != lowerit(*word)) 159539991Sbostic return FALSE; 159639991Sbostic ++word; 159739991Sbostic while (*++abbr != '\0') 159839991Sbostic do if (*word == '\0') 159939991Sbostic return FALSE; 160039991Sbostic while (lowerit(*word++) != lowerit(*abbr)); 160139991Sbostic return TRUE; 160239991Sbostic } 160339991Sbostic 160439991Sbostic static const struct lookup * 160539991Sbostic byword(word, table) 160639991Sbostic register const char * const word; 160739991Sbostic register const struct lookup * const table; 160839991Sbostic { 160939991Sbostic register const struct lookup * foundlp; 161039991Sbostic register const struct lookup * lp; 161139991Sbostic 161239991Sbostic if (word == NULL || table == NULL) 161339991Sbostic return NULL; 161439991Sbostic /* 161539991Sbostic ** Look for exact match. 161639991Sbostic */ 161739991Sbostic for (lp = table; lp->l_word != NULL; ++lp) 161839991Sbostic if (ciequal(word, lp->l_word)) 161939991Sbostic return lp; 162039991Sbostic /* 162139991Sbostic ** Look for inexact match. 162239991Sbostic */ 162339991Sbostic foundlp = NULL; 162439991Sbostic for (lp = table; lp->l_word != NULL; ++lp) 162539991Sbostic if (itsabbr(word, lp->l_word)) 162639991Sbostic if (foundlp == NULL) 162739991Sbostic foundlp = lp; 162839991Sbostic else return NULL; /* multiple inexact matches */ 162939991Sbostic return foundlp; 163039991Sbostic } 163139991Sbostic 163239991Sbostic static char ** 163339991Sbostic getfields(cp) 163439991Sbostic register char * cp; 163539991Sbostic { 163639991Sbostic register char * dp; 163739991Sbostic register char ** array; 163839991Sbostic register int nsubs; 163939991Sbostic 164039991Sbostic if (cp == NULL) 164139991Sbostic return NULL; 164239991Sbostic array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 164339991Sbostic nsubs = 0; 164439991Sbostic for ( ; ; ) { 164539991Sbostic while (isascii(*cp) && isspace(*cp)) 164639991Sbostic ++cp; 164739991Sbostic if (*cp == '\0' || *cp == '#') 164839991Sbostic break; 164939991Sbostic array[nsubs++] = dp = cp; 165039991Sbostic do { 165139991Sbostic if ((*dp = *cp++) != '"') 165239991Sbostic ++dp; 165339991Sbostic else while ((*dp = *cp++) != '"') 165439991Sbostic if (*dp != '\0') 165539991Sbostic ++dp; 165639991Sbostic else error("Odd number of quotation marks"); 165739991Sbostic } while (*cp != '\0' && *cp != '#' && 165839991Sbostic (!isascii(*cp) || !isspace(*cp))); 165939991Sbostic if (isascii(*cp) && isspace(*cp)) 166039991Sbostic ++cp; 166139991Sbostic *dp = '\0'; 166239991Sbostic } 166339991Sbostic array[nsubs] = NULL; 166439991Sbostic return array; 166539991Sbostic } 166639991Sbostic 166739991Sbostic static long 166839991Sbostic oadd(t1, t2) 166939991Sbostic const long t1; 167039991Sbostic const long t2; 167139991Sbostic { 167239991Sbostic register long t; 167339991Sbostic 167439991Sbostic t = t1 + t2; 167539991Sbostic if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { 167639991Sbostic error("time overflow"); 167739991Sbostic (void) exit(EXIT_FAILURE); 167839991Sbostic } 167939991Sbostic return t; 168039991Sbostic } 168139991Sbostic 168239991Sbostic static time_t 168339991Sbostic tadd(t1, t2) 168439991Sbostic const time_t t1; 168539991Sbostic const long t2; 168639991Sbostic { 168739991Sbostic register time_t t; 168839991Sbostic 168939991Sbostic if (t1 == max_time && t2 > 0) 169039991Sbostic return max_time; 169139991Sbostic if (t1 == min_time && t2 < 0) 169239991Sbostic return min_time; 169339991Sbostic t = t1 + t2; 169439991Sbostic if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { 169539991Sbostic error("time overflow"); 169639991Sbostic (void) exit(EXIT_FAILURE); 169739991Sbostic } 169839991Sbostic return t; 169939991Sbostic } 170039991Sbostic 170139991Sbostic /* 170239991Sbostic ** Given a rule, and a year, compute the date - in seconds since January 1, 170339991Sbostic ** 1970, 00:00 LOCAL time - in that year that the rule refers to. 170439991Sbostic */ 170539991Sbostic 170639991Sbostic static time_t 170739991Sbostic rpytime(rp, wantedy) 170839991Sbostic register const struct rule * const rp; 170939991Sbostic register const int wantedy; 171039991Sbostic { 171139991Sbostic register int y, m, i; 171239991Sbostic register long dayoff; /* with a nod to Margaret O. */ 171339991Sbostic register time_t t; 171439991Sbostic 171539991Sbostic dayoff = 0; 171639991Sbostic m = TM_JANUARY; 171739991Sbostic y = EPOCH_YEAR; 171839991Sbostic while (wantedy != y) { 171939991Sbostic if (wantedy > y) { 172039991Sbostic i = len_years[isleap(y)]; 172139991Sbostic ++y; 172239991Sbostic } else { 172339991Sbostic --y; 172439991Sbostic i = -len_years[isleap(y)]; 172539991Sbostic } 172639991Sbostic dayoff = oadd(dayoff, eitol(i)); 172739991Sbostic } 172839991Sbostic while (m != rp->r_month) { 172939991Sbostic i = len_months[isleap(y)][m]; 173039991Sbostic dayoff = oadd(dayoff, eitol(i)); 173139991Sbostic ++m; 173239991Sbostic } 173339991Sbostic i = rp->r_dayofmonth; 173439991Sbostic if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 173539991Sbostic if (rp->r_dycode == DC_DOWLEQ) 173639991Sbostic --i; 173739991Sbostic else { 173839991Sbostic error("use of 2/29 in non leap-year"); 173939991Sbostic (void) exit(EXIT_FAILURE); 174039991Sbostic } 174139991Sbostic } 174239991Sbostic --i; 174339991Sbostic dayoff = oadd(dayoff, eitol(i)); 174439991Sbostic if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 174539991Sbostic register long wday; 174639991Sbostic 174739991Sbostic #define LDAYSPERWEEK ((long) DAYSPERWEEK) 174839991Sbostic wday = eitol(EPOCH_WDAY); 174939991Sbostic /* 175039991Sbostic ** Don't trust mod of negative numbers. 175139991Sbostic */ 175239991Sbostic if (dayoff >= 0) 175339991Sbostic wday = (wday + dayoff) % LDAYSPERWEEK; 175439991Sbostic else { 175539991Sbostic wday -= ((-dayoff) % LDAYSPERWEEK); 175639991Sbostic if (wday < 0) 175739991Sbostic wday += LDAYSPERWEEK; 175839991Sbostic } 175939991Sbostic while (wday != eitol(rp->r_wday)) 176039991Sbostic if (rp->r_dycode == DC_DOWGEQ) { 176139991Sbostic dayoff = oadd(dayoff, (long) 1); 176239991Sbostic if (++wday >= LDAYSPERWEEK) 176339991Sbostic wday = 0; 176439991Sbostic ++i; 176539991Sbostic } else { 176639991Sbostic dayoff = oadd(dayoff, (long) -1); 176739991Sbostic if (--wday < 0) 176839991Sbostic wday = LDAYSPERWEEK; 176939991Sbostic --i; 177039991Sbostic } 177139991Sbostic if (i < 0 || i >= len_months[isleap(y)][m]) { 177239991Sbostic error("no day in month matches rule"); 177339991Sbostic (void) exit(EXIT_FAILURE); 177439991Sbostic } 177539991Sbostic } 177639991Sbostic if (dayoff < 0 && !tt_signed) { 177739991Sbostic if (wantedy == rp->r_loyear) 177839991Sbostic return min_time; 177939991Sbostic error("time before zero"); 178039991Sbostic (void) exit(EXIT_FAILURE); 178139991Sbostic } 178239991Sbostic t = (time_t) dayoff * SECSPERDAY; 178339991Sbostic /* 178439991Sbostic ** Cheap overflow check. 178539991Sbostic */ 178639991Sbostic if (t / SECSPERDAY != dayoff) { 178739991Sbostic if (wantedy == rp->r_hiyear) 178839991Sbostic return max_time; 178939991Sbostic if (wantedy == rp->r_loyear) 179039991Sbostic return min_time; 179139991Sbostic error("time overflow"); 179239991Sbostic (void) exit(EXIT_FAILURE); 179339991Sbostic } 179439991Sbostic return tadd(t, rp->r_tod); 179539991Sbostic } 179639991Sbostic 179739991Sbostic static void 179839991Sbostic newabbr(string) 179939991Sbostic const char * const string; 180039991Sbostic { 180139991Sbostic register int i; 180239991Sbostic 180339991Sbostic i = strlen(string) + 1; 180439991Sbostic if (charcnt + i >= TZ_MAX_CHARS) { 180539991Sbostic error("too many, or too long, time zone abbreviations"); 180639991Sbostic (void) exit(EXIT_FAILURE); 180739991Sbostic } 180839991Sbostic (void) strcpy(&chars[charcnt], string); 180939991Sbostic charcnt += eitol(i); 181039991Sbostic } 181139991Sbostic 181239991Sbostic static int 181339991Sbostic mkdirs(name) 181439991Sbostic char * const name; 181539991Sbostic { 181639991Sbostic register char * cp; 181739991Sbostic 181839991Sbostic if ((cp = name) == NULL || *cp == '\0') 181939991Sbostic return 0; 182039991Sbostic while ((cp = strchr(cp + 1, '/')) != 0) { 182139991Sbostic *cp = '\0'; 182239991Sbostic if (!itsdir(name)) { 182339991Sbostic /* 182439991Sbostic ** It doesn't seem to exist, so we try to create it. 182539991Sbostic */ 1826*46793Sbostic if (mkdir(name, 0755) != 0) { 182739991Sbostic (void) fprintf(stderr, 182839991Sbostic "%s: Can't create directory ", 182939991Sbostic progname); 183039991Sbostic (void) perror(name); 183139991Sbostic return -1; 183239991Sbostic } 183339991Sbostic } 183439991Sbostic *cp = '/'; 183539991Sbostic } 183639991Sbostic return 0; 183739991Sbostic } 183839991Sbostic 183939991Sbostic static long 184039991Sbostic eitol(i) 184139991Sbostic const int i; 184239991Sbostic { 184339991Sbostic long l; 184439991Sbostic 184539991Sbostic l = i; 184639991Sbostic if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) { 184739991Sbostic (void) fprintf(stderr, "%s: %d did not sign extend correctly\n", 184839991Sbostic progname, i); 184939991Sbostic (void) exit(EXIT_FAILURE); 185039991Sbostic } 185139991Sbostic return l; 185239991Sbostic } 185339991Sbostic 185439991Sbostic /* 185539991Sbostic ** UNIX is a registered trademark of AT&T. 185639991Sbostic */ 1857