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