17b35baebSbostic /*- 27b35baebSbostic * Copyright (c) 1991 The Regents of the University of California. 37b35baebSbostic * All rights reserved. 47b35baebSbostic * 57b35baebSbostic * This code is derived from software contributed to Berkeley by 67b35baebSbostic * Arthur David Olson of the National Cancer Institute. 77b35baebSbostic * 87b35baebSbostic * %sccs.include.redist.c% 97b35baebSbostic */ 107b35baebSbostic 1151034c06Sbostic #ifndef lint 12*3044ec37Sbostic static char sccsid[] = "@(#)zic.c 5.5 (Berkeley) 07/19/93"; 137b35baebSbostic #endif /* not lint */ 147b35baebSbostic 157b35baebSbostic #ifdef notdef 1651034c06Sbostic static char elsieid[] = "@(#)zic.c 4.12"; 177b35baebSbostic #endif 1851034c06Sbostic 196068c877Sbostic #include <sys/types.h> 206068c877Sbostic #include <sys/cdefs.h> 216068c877Sbostic #include <sys/stat.h> 226068c877Sbostic #include <time.h> 236068c877Sbostic #include <tzfile.h> 246068c877Sbostic #include <stdio.h> 256068c877Sbostic #include <ctype.h> 266068c877Sbostic #include <string.h> 276068c877Sbostic #include <stdlib.h> 2851034c06Sbostic 2951034c06Sbostic #ifndef TRUE 3051034c06Sbostic #define TRUE 1 3151034c06Sbostic #define FALSE 0 3251034c06Sbostic #endif /* !defined TRUE */ 3351034c06Sbostic 3451034c06Sbostic struct rule { 3551034c06Sbostic const char * r_filename; 3651034c06Sbostic int r_linenum; 3751034c06Sbostic const char * r_name; 3851034c06Sbostic 3951034c06Sbostic int r_loyear; /* for example, 1986 */ 4051034c06Sbostic int r_hiyear; /* for example, 1986 */ 4151034c06Sbostic const char * r_yrtype; 4251034c06Sbostic 4351034c06Sbostic int r_month; /* 0..11 */ 4451034c06Sbostic 4551034c06Sbostic int r_dycode; /* see below */ 4651034c06Sbostic int r_dayofmonth; 4751034c06Sbostic int r_wday; 4851034c06Sbostic 4951034c06Sbostic long r_tod; /* time from midnight */ 5051034c06Sbostic int r_todisstd; /* above is standard time if TRUE */ 5151034c06Sbostic /* or wall clock time if FALSE */ 5251034c06Sbostic long r_stdoff; /* offset from standard time */ 5351034c06Sbostic const char * r_abbrvar; /* variable part of abbreviation */ 5451034c06Sbostic 5551034c06Sbostic int r_todo; /* a rule to do (used in outzone) */ 5651034c06Sbostic time_t r_temp; /* used in outzone */ 5751034c06Sbostic }; 5851034c06Sbostic 5951034c06Sbostic /* 6051034c06Sbostic ** r_dycode r_dayofmonth r_wday 6151034c06Sbostic */ 6251034c06Sbostic 6351034c06Sbostic #define DC_DOM 0 /* 1..31 */ /* unused */ 6451034c06Sbostic #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 6551034c06Sbostic #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 6651034c06Sbostic 6751034c06Sbostic struct zone { 6851034c06Sbostic const char * z_filename; 6951034c06Sbostic int z_linenum; 7051034c06Sbostic 7151034c06Sbostic const char * z_name; 7251034c06Sbostic long z_gmtoff; 7351034c06Sbostic const char * z_rule; 7451034c06Sbostic const char * z_format; 7551034c06Sbostic 7651034c06Sbostic long z_stdoff; 7751034c06Sbostic 7851034c06Sbostic struct rule * z_rules; 7951034c06Sbostic int z_nrules; 8051034c06Sbostic 8151034c06Sbostic struct rule z_untilrule; 8251034c06Sbostic time_t z_untiltime; 8351034c06Sbostic }; 8451034c06Sbostic 856068c877Sbostic extern char * icatalloc __P((char * old, const char * new)); 866068c877Sbostic extern char * icpyalloc __P((const char * string)); 876068c877Sbostic extern void ifree __P((char * p)); 886068c877Sbostic extern char * imalloc __P((int n)); 896068c877Sbostic extern char * irealloc __P((char * old, int n)); 906068c877Sbostic extern int link __P((const char * fromname, const char * toname)); 9151034c06Sbostic extern char * optarg; 9251034c06Sbostic extern int optind; 936068c877Sbostic extern void perror __P((const char * string)); 946068c877Sbostic extern char * scheck __P((const char * string, const char * format)); 956068c877Sbostic static void addtt __P((time_t starttime, int type)); 966068c877Sbostic static int addtype 976068c877Sbostic __P((long gmtoff, const char * abbr, int isdst, 9851034c06Sbostic int ttisstd)); 996068c877Sbostic static void addleap __P((time_t t, int positive, int rolling)); 1006068c877Sbostic static void adjleap __P((void)); 1016068c877Sbostic static void associate __P((void)); 1026068c877Sbostic static int ciequal __P((const char * ap, const char * bp)); 1036068c877Sbostic static void convert __P((long val, char * buf)); 1046068c877Sbostic static void dolink __P((const char * fromfile, const char * tofile)); 1056068c877Sbostic static void eat __P((const char * name, int num)); 1066068c877Sbostic static void eats __P((const char * name, int num, 10751034c06Sbostic const char * rname, int rnum)); 1086068c877Sbostic static long eitol __P((int i)); 1096068c877Sbostic static void error __P((const char * message)); 1106068c877Sbostic static char ** getfields __P((char * buf)); 1116068c877Sbostic static long gethms __P((char * string, const char * errstrng, 11251034c06Sbostic int signable)); 1136068c877Sbostic static void infile __P((const char * filename)); 1146068c877Sbostic static void inleap __P((char ** fields, int nfields)); 1156068c877Sbostic static void inlink __P((char ** fields, int nfields)); 1166068c877Sbostic static void inrule __P((char ** fields, int nfields)); 1176068c877Sbostic static int inzcont __P((char ** fields, int nfields)); 1186068c877Sbostic static int inzone __P((char ** fields, int nfields)); 1196068c877Sbostic static int inzsub __P((char ** fields, int nfields, int iscont)); 1206068c877Sbostic static int itsabbr __P((const char * abbr, const char * word)); 1216068c877Sbostic static int itsdir __P((const char * name)); 1226068c877Sbostic static int lowerit __P((int c)); 1236068c877Sbostic static char * memcheck __P((char * tocheck)); 1246068c877Sbostic static int mkdirs __P((char * filename)); 1256068c877Sbostic static void newabbr __P((const char * abbr)); 1266068c877Sbostic static long oadd __P((long t1, long t2)); 1276068c877Sbostic static void outzone __P((const struct zone * zp, int ntzones)); 1286068c877Sbostic static void puttzcode __P((long code, FILE * fp)); 1296068c877Sbostic static int rcomp __P((const void *leftp, const void *rightp)); 1306068c877Sbostic static time_t rpytime __P((const struct rule * rp, int wantedy)); 1316068c877Sbostic static void rulesub __P((struct rule * rp, char * loyearp, char * hiyearp, 1326068c877Sbostic char * typep, char * monthp, char * dayp, char * timep)); 1336068c877Sbostic static void setboundaries __P((void)); 1346068c877Sbostic static time_t tadd __P((time_t t1, long t2)); 1356068c877Sbostic static void usage __P((void)); 1366068c877Sbostic static void writezone __P((const char * name)); 1376068c877Sbostic static int yearistype __P((int year, const char * type)); 13851034c06Sbostic 13951034c06Sbostic static int charcnt; 14051034c06Sbostic static int errors; 14151034c06Sbostic static const char * filename; 14251034c06Sbostic static int leapcnt; 14351034c06Sbostic static int linenum; 14451034c06Sbostic static time_t max_time; 14551034c06Sbostic static int max_year; 14651034c06Sbostic static time_t min_time; 14751034c06Sbostic static int min_year; 14851034c06Sbostic static int noise; 14951034c06Sbostic static const char * rfilename; 15051034c06Sbostic static int rlinenum; 15151034c06Sbostic static const char * progname; 15251034c06Sbostic static int timecnt; 15351034c06Sbostic static int typecnt; 15451034c06Sbostic static int tt_signed; 15551034c06Sbostic 15651034c06Sbostic /* 15751034c06Sbostic ** Line codes. 15851034c06Sbostic */ 15951034c06Sbostic 16051034c06Sbostic #define LC_RULE 0 16151034c06Sbostic #define LC_ZONE 1 16251034c06Sbostic #define LC_LINK 2 16351034c06Sbostic #define LC_LEAP 3 16451034c06Sbostic 16551034c06Sbostic /* 16651034c06Sbostic ** Which fields are which on a Zone line. 16751034c06Sbostic */ 16851034c06Sbostic 16951034c06Sbostic #define ZF_NAME 1 17051034c06Sbostic #define ZF_GMTOFF 2 17151034c06Sbostic #define ZF_RULE 3 17251034c06Sbostic #define ZF_FORMAT 4 17351034c06Sbostic #define ZF_TILYEAR 5 17451034c06Sbostic #define ZF_TILMONTH 6 17551034c06Sbostic #define ZF_TILDAY 7 17651034c06Sbostic #define ZF_TILTIME 8 17751034c06Sbostic #define ZONE_MINFIELDS 5 17851034c06Sbostic #define ZONE_MAXFIELDS 9 17951034c06Sbostic 18051034c06Sbostic /* 18151034c06Sbostic ** Which fields are which on a Zone continuation line. 18251034c06Sbostic */ 18351034c06Sbostic 18451034c06Sbostic #define ZFC_GMTOFF 0 18551034c06Sbostic #define ZFC_RULE 1 18651034c06Sbostic #define ZFC_FORMAT 2 18751034c06Sbostic #define ZFC_TILYEAR 3 18851034c06Sbostic #define ZFC_TILMONTH 4 18951034c06Sbostic #define ZFC_TILDAY 5 19051034c06Sbostic #define ZFC_TILTIME 6 19151034c06Sbostic #define ZONEC_MINFIELDS 3 19251034c06Sbostic #define ZONEC_MAXFIELDS 7 19351034c06Sbostic 19451034c06Sbostic /* 19551034c06Sbostic ** Which files are which on a Rule line. 19651034c06Sbostic */ 19751034c06Sbostic 19851034c06Sbostic #define RF_NAME 1 19951034c06Sbostic #define RF_LOYEAR 2 20051034c06Sbostic #define RF_HIYEAR 3 20151034c06Sbostic #define RF_COMMAND 4 20251034c06Sbostic #define RF_MONTH 5 20351034c06Sbostic #define RF_DAY 6 20451034c06Sbostic #define RF_TOD 7 20551034c06Sbostic #define RF_STDOFF 8 20651034c06Sbostic #define RF_ABBRVAR 9 20751034c06Sbostic #define RULE_FIELDS 10 20851034c06Sbostic 20951034c06Sbostic /* 21051034c06Sbostic ** Which fields are which on a Link line. 21151034c06Sbostic */ 21251034c06Sbostic 21351034c06Sbostic #define LF_FROM 1 21451034c06Sbostic #define LF_TO 2 21551034c06Sbostic #define LINK_FIELDS 3 21651034c06Sbostic 21751034c06Sbostic /* 21851034c06Sbostic ** Which fields are which on a Leap line. 21951034c06Sbostic */ 22051034c06Sbostic 22151034c06Sbostic #define LP_YEAR 1 22251034c06Sbostic #define LP_MONTH 2 22351034c06Sbostic #define LP_DAY 3 22451034c06Sbostic #define LP_TIME 4 22551034c06Sbostic #define LP_CORR 5 22651034c06Sbostic #define LP_ROLL 6 22751034c06Sbostic #define LEAP_FIELDS 7 22851034c06Sbostic 22951034c06Sbostic /* 23051034c06Sbostic ** Year synonyms. 23151034c06Sbostic */ 23251034c06Sbostic 23351034c06Sbostic #define YR_MINIMUM 0 23451034c06Sbostic #define YR_MAXIMUM 1 23551034c06Sbostic #define YR_ONLY 2 23651034c06Sbostic 23751034c06Sbostic static struct rule * rules; 23851034c06Sbostic static int nrules; /* number of rules */ 23951034c06Sbostic 24051034c06Sbostic static struct zone * zones; 24151034c06Sbostic static int nzones; /* number of zones */ 24251034c06Sbostic 24351034c06Sbostic struct link { 24451034c06Sbostic const char * l_filename; 24551034c06Sbostic int l_linenum; 24651034c06Sbostic const char * l_from; 24751034c06Sbostic const char * l_to; 24851034c06Sbostic }; 24951034c06Sbostic 25051034c06Sbostic static struct link * links; 25151034c06Sbostic static int nlinks; 25251034c06Sbostic 25351034c06Sbostic struct lookup { 25451034c06Sbostic const char * l_word; 25551034c06Sbostic const int l_value; 25651034c06Sbostic }; 25751034c06Sbostic 2586068c877Sbostic static struct lookup const * byword __P((const char * string, 25951034c06Sbostic const struct lookup * lp)); 26051034c06Sbostic 26151034c06Sbostic static struct lookup const line_codes[] = { 26251034c06Sbostic "Rule", LC_RULE, 26351034c06Sbostic "Zone", LC_ZONE, 26451034c06Sbostic "Link", LC_LINK, 26551034c06Sbostic "Leap", LC_LEAP, 26651034c06Sbostic NULL, 0 26751034c06Sbostic }; 26851034c06Sbostic 26951034c06Sbostic static struct lookup const mon_names[] = { 27051034c06Sbostic "January", TM_JANUARY, 27151034c06Sbostic "February", TM_FEBRUARY, 27251034c06Sbostic "March", TM_MARCH, 27351034c06Sbostic "April", TM_APRIL, 27451034c06Sbostic "May", TM_MAY, 27551034c06Sbostic "June", TM_JUNE, 27651034c06Sbostic "July", TM_JULY, 27751034c06Sbostic "August", TM_AUGUST, 27851034c06Sbostic "September", TM_SEPTEMBER, 27951034c06Sbostic "October", TM_OCTOBER, 28051034c06Sbostic "November", TM_NOVEMBER, 28151034c06Sbostic "December", TM_DECEMBER, 28251034c06Sbostic NULL, 0 28351034c06Sbostic }; 28451034c06Sbostic 28551034c06Sbostic static struct lookup const wday_names[] = { 28651034c06Sbostic "Sunday", TM_SUNDAY, 28751034c06Sbostic "Monday", TM_MONDAY, 28851034c06Sbostic "Tuesday", TM_TUESDAY, 28951034c06Sbostic "Wednesday", TM_WEDNESDAY, 29051034c06Sbostic "Thursday", TM_THURSDAY, 29151034c06Sbostic "Friday", TM_FRIDAY, 29251034c06Sbostic "Saturday", TM_SATURDAY, 29351034c06Sbostic NULL, 0 29451034c06Sbostic }; 29551034c06Sbostic 29651034c06Sbostic static struct lookup const lasts[] = { 29751034c06Sbostic "last-Sunday", TM_SUNDAY, 29851034c06Sbostic "last-Monday", TM_MONDAY, 29951034c06Sbostic "last-Tuesday", TM_TUESDAY, 30051034c06Sbostic "last-Wednesday", TM_WEDNESDAY, 30151034c06Sbostic "last-Thursday", TM_THURSDAY, 30251034c06Sbostic "last-Friday", TM_FRIDAY, 30351034c06Sbostic "last-Saturday", TM_SATURDAY, 30451034c06Sbostic NULL, 0 30551034c06Sbostic }; 30651034c06Sbostic 30751034c06Sbostic static struct lookup const begin_years[] = { 30851034c06Sbostic "minimum", YR_MINIMUM, 30951034c06Sbostic "maximum", YR_MAXIMUM, 31051034c06Sbostic NULL, 0 31151034c06Sbostic }; 31251034c06Sbostic 31351034c06Sbostic static struct lookup const end_years[] = { 31451034c06Sbostic "minimum", YR_MINIMUM, 31551034c06Sbostic "maximum", YR_MAXIMUM, 31651034c06Sbostic "only", YR_ONLY, 31751034c06Sbostic NULL, 0 31851034c06Sbostic }; 31951034c06Sbostic 32051034c06Sbostic static struct lookup const leap_types[] = { 32151034c06Sbostic "Rolling", TRUE, 32251034c06Sbostic "Stationary", FALSE, 32351034c06Sbostic NULL, 0 32451034c06Sbostic }; 32551034c06Sbostic 32651034c06Sbostic static const int len_months[2][MONSPERYEAR] = { 32751034c06Sbostic 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 32851034c06Sbostic 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 32951034c06Sbostic }; 33051034c06Sbostic 33151034c06Sbostic static const int len_years[2] = { 33251034c06Sbostic DAYSPERNYEAR, DAYSPERLYEAR 33351034c06Sbostic }; 33451034c06Sbostic 33551034c06Sbostic static time_t ats[TZ_MAX_TIMES]; 33651034c06Sbostic static unsigned char types[TZ_MAX_TIMES]; 33751034c06Sbostic static long gmtoffs[TZ_MAX_TYPES]; 33851034c06Sbostic static char isdsts[TZ_MAX_TYPES]; 33951034c06Sbostic static char abbrinds[TZ_MAX_TYPES]; 34051034c06Sbostic static char ttisstds[TZ_MAX_TYPES]; 34151034c06Sbostic static char chars[TZ_MAX_CHARS]; 34251034c06Sbostic static time_t trans[TZ_MAX_LEAPS]; 34351034c06Sbostic static long corr[TZ_MAX_LEAPS]; 34451034c06Sbostic static char roll[TZ_MAX_LEAPS]; 34551034c06Sbostic 34651034c06Sbostic /* 34751034c06Sbostic ** Memory allocation. 34851034c06Sbostic */ 34951034c06Sbostic 35051034c06Sbostic static char * 35151034c06Sbostic memcheck(ptr) 35251034c06Sbostic char * const ptr; 35351034c06Sbostic { 35451034c06Sbostic if (ptr == NULL) { 35551034c06Sbostic (void) perror(progname); 35651034c06Sbostic (void) exit(EXIT_FAILURE); 35751034c06Sbostic } 35851034c06Sbostic return ptr; 35951034c06Sbostic } 36051034c06Sbostic 36151034c06Sbostic #define emalloc(size) memcheck(imalloc(size)) 36251034c06Sbostic #define erealloc(ptr, size) memcheck(irealloc(ptr, size)) 36351034c06Sbostic #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 36451034c06Sbostic #define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp)) 36551034c06Sbostic 36651034c06Sbostic /* 36751034c06Sbostic ** Error handling. 36851034c06Sbostic */ 36951034c06Sbostic 37051034c06Sbostic static void 37151034c06Sbostic eats(name, num, rname, rnum) 37251034c06Sbostic const char * const name; 37351034c06Sbostic const int num; 37451034c06Sbostic const char * const rname; 37551034c06Sbostic const int rnum; 37651034c06Sbostic { 37751034c06Sbostic filename = name; 37851034c06Sbostic linenum = num; 37951034c06Sbostic rfilename = rname; 38051034c06Sbostic rlinenum = rnum; 38151034c06Sbostic } 38251034c06Sbostic 38351034c06Sbostic static void 38451034c06Sbostic eat(name, num) 38551034c06Sbostic const char * const name; 38651034c06Sbostic const int num; 38751034c06Sbostic { 38851034c06Sbostic eats(name, num, (char *) NULL, -1); 38951034c06Sbostic } 39051034c06Sbostic 39151034c06Sbostic static void 39251034c06Sbostic error(string) 39351034c06Sbostic const char * const string; 39451034c06Sbostic { 39551034c06Sbostic /* 39651034c06Sbostic ** Match the format of "cc" to allow sh users to 39751034c06Sbostic ** zic ... 2>&1 | error -t "*" -v 39851034c06Sbostic ** on BSD systems. 39951034c06Sbostic */ 40051034c06Sbostic (void) fprintf(stderr, "\"%s\", line %d: %s", 40151034c06Sbostic filename, linenum, string); 40251034c06Sbostic if (rfilename != NULL) 40351034c06Sbostic (void) fprintf(stderr, " (rule from \"%s\", line %d)", 40451034c06Sbostic rfilename, rlinenum); 40551034c06Sbostic (void) fprintf(stderr, "\n"); 40651034c06Sbostic ++errors; 40751034c06Sbostic } 40851034c06Sbostic 40951034c06Sbostic static void 41051034c06Sbostic usage() 41151034c06Sbostic { 41251034c06Sbostic (void) fprintf(stderr, 41351034c06Sbostic "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\ 41451034c06Sbostic \t[ -L leapseconds ] [ filename ... ]\n", 41551034c06Sbostic progname, progname); 41651034c06Sbostic (void) exit(EXIT_FAILURE); 41751034c06Sbostic } 41851034c06Sbostic 41951034c06Sbostic static const char * psxrules = NULL; 42051034c06Sbostic static const char * lcltime = NULL; 42151034c06Sbostic static const char * directory = NULL; 42251034c06Sbostic static const char * leapsec = NULL; 42351034c06Sbostic static int sflag = FALSE; 42451034c06Sbostic 42551034c06Sbostic int 42651034c06Sbostic main(argc, argv) 42751034c06Sbostic int argc; 42851034c06Sbostic char * argv[]; 42951034c06Sbostic { 43051034c06Sbostic register int i, j; 43151034c06Sbostic register int c; 43251034c06Sbostic 43351034c06Sbostic (void) umask(umask(022) | 022); 43451034c06Sbostic progname = argv[0]; 43551034c06Sbostic while ((c = getopt(argc, argv, "d:l:p:L:vs")) != EOF) 43651034c06Sbostic switch (c) { 43751034c06Sbostic default: 43851034c06Sbostic usage(); 43951034c06Sbostic case 'd': 44051034c06Sbostic if (directory == NULL) 44151034c06Sbostic directory = optarg; 44251034c06Sbostic else { 44351034c06Sbostic (void) fprintf(stderr, 44451034c06Sbostic "%s: More than one -d option specified\n", 44551034c06Sbostic progname); 44651034c06Sbostic (void) exit(EXIT_FAILURE); 44751034c06Sbostic } 44851034c06Sbostic break; 44951034c06Sbostic case 'l': 45051034c06Sbostic if (lcltime == NULL) 45151034c06Sbostic lcltime = optarg; 45251034c06Sbostic else { 45351034c06Sbostic (void) fprintf(stderr, 45451034c06Sbostic "%s: More than one -l option specified\n", 45551034c06Sbostic progname); 45651034c06Sbostic (void) exit(EXIT_FAILURE); 45751034c06Sbostic } 45851034c06Sbostic break; 45951034c06Sbostic case 'p': 46051034c06Sbostic if (psxrules == NULL) 46151034c06Sbostic psxrules = optarg; 46251034c06Sbostic else { 46351034c06Sbostic (void) fprintf(stderr, 46451034c06Sbostic "%s: More than one -p option specified\n", 46551034c06Sbostic progname); 46651034c06Sbostic (void) exit(EXIT_FAILURE); 46751034c06Sbostic } 46851034c06Sbostic break; 46951034c06Sbostic case 'L': 47051034c06Sbostic if (leapsec == NULL) 47151034c06Sbostic leapsec = optarg; 47251034c06Sbostic else { 47351034c06Sbostic (void) fprintf(stderr, 47451034c06Sbostic "%s: More than one -L option specified\n", 47551034c06Sbostic progname); 47651034c06Sbostic (void) exit(EXIT_FAILURE); 47751034c06Sbostic } 47851034c06Sbostic break; 47951034c06Sbostic case 'v': 48051034c06Sbostic noise = TRUE; 48151034c06Sbostic break; 48251034c06Sbostic case 's': 48351034c06Sbostic sflag = TRUE; 48451034c06Sbostic break; 48551034c06Sbostic } 48651034c06Sbostic if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 48751034c06Sbostic usage(); /* usage message by request */ 48851034c06Sbostic if (directory == NULL) 48951034c06Sbostic directory = TZDIR; 49051034c06Sbostic 49151034c06Sbostic setboundaries(); 49251034c06Sbostic 49351034c06Sbostic if (optind < argc && leapsec != NULL) { 49451034c06Sbostic infile(leapsec); 49551034c06Sbostic adjleap(); 49651034c06Sbostic } 49751034c06Sbostic 49851034c06Sbostic zones = (struct zone *) emalloc(0); 49951034c06Sbostic rules = (struct rule *) emalloc(0); 50051034c06Sbostic links = (struct link *) emalloc(0); 50151034c06Sbostic for (i = optind; i < argc; ++i) 50251034c06Sbostic infile(argv[i]); 50351034c06Sbostic if (errors) 50451034c06Sbostic (void) exit(EXIT_FAILURE); 50551034c06Sbostic associate(); 50651034c06Sbostic for (i = 0; i < nzones; i = j) { 50751034c06Sbostic /* 50851034c06Sbostic ** Find the next non-continuation zone entry. 50951034c06Sbostic */ 51051034c06Sbostic for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 51151034c06Sbostic ; 51251034c06Sbostic outzone(&zones[i], j - i); 51351034c06Sbostic } 51451034c06Sbostic /* 51551034c06Sbostic ** Make links. 51651034c06Sbostic */ 51751034c06Sbostic for (i = 0; i < nlinks; ++i) 51851034c06Sbostic dolink(links[i].l_from, links[i].l_to); 51951034c06Sbostic if (lcltime != NULL) 52051034c06Sbostic dolink(lcltime, TZDEFAULT); 52151034c06Sbostic if (psxrules != NULL) 52251034c06Sbostic dolink(psxrules, TZDEFRULES); 52351034c06Sbostic return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 52451034c06Sbostic } 52551034c06Sbostic 52651034c06Sbostic static void 52751034c06Sbostic dolink(fromfile, tofile) 52851034c06Sbostic const char * const fromfile; 52951034c06Sbostic const char * const tofile; 53051034c06Sbostic { 53151034c06Sbostic register char * fromname; 53251034c06Sbostic register char * toname; 53351034c06Sbostic 53451034c06Sbostic fromname = ecpyalloc(directory); 53551034c06Sbostic fromname = ecatalloc(fromname, "/"); 53651034c06Sbostic fromname = ecatalloc(fromname, fromfile); 53751034c06Sbostic toname = ecpyalloc(directory); 53851034c06Sbostic toname = ecatalloc(toname, "/"); 53951034c06Sbostic toname = ecatalloc(toname, tofile); 54051034c06Sbostic /* 54151034c06Sbostic ** We get to be careful here since 54251034c06Sbostic ** there's a fair chance of root running us. 54351034c06Sbostic */ 54451034c06Sbostic if (!itsdir(toname)) 54551034c06Sbostic (void) remove(toname); 54651034c06Sbostic if (link(fromname, toname) != 0) { 54751034c06Sbostic (void) fprintf(stderr, "%s: Can't link from %s to ", 54851034c06Sbostic progname, fromname); 54951034c06Sbostic (void) perror(toname); 55051034c06Sbostic (void) exit(EXIT_FAILURE); 55151034c06Sbostic } 55251034c06Sbostic ifree(fromname); 55351034c06Sbostic ifree(toname); 55451034c06Sbostic } 55551034c06Sbostic 55651034c06Sbostic static void 55751034c06Sbostic setboundaries() 55851034c06Sbostic { 55951034c06Sbostic register time_t bit; 56051034c06Sbostic 56151034c06Sbostic for (bit = 1; bit > 0; bit <<= 1) 56251034c06Sbostic ; 56351034c06Sbostic if (bit == 0) { /* time_t is an unsigned type */ 56451034c06Sbostic tt_signed = FALSE; 56551034c06Sbostic min_time = 0; 56651034c06Sbostic max_time = ~(time_t) 0; 56751034c06Sbostic if (sflag) 56851034c06Sbostic max_time >>= 1; 56951034c06Sbostic } else { 57051034c06Sbostic tt_signed = TRUE; 57151034c06Sbostic min_time = bit; 57251034c06Sbostic max_time = bit; 57351034c06Sbostic ++max_time; 57451034c06Sbostic max_time = -max_time; 57551034c06Sbostic if (sflag) 57651034c06Sbostic min_time = 0; 57751034c06Sbostic } 57851034c06Sbostic min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; 57951034c06Sbostic max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; 58051034c06Sbostic } 58151034c06Sbostic 58251034c06Sbostic static int 58351034c06Sbostic itsdir(name) 58451034c06Sbostic const char * const name; 58551034c06Sbostic { 58651034c06Sbostic struct stat s; 58751034c06Sbostic 5886068c877Sbostic return (stat(name, &s) == 0 && S_ISDIR(s.st_mode)); 58951034c06Sbostic } 59051034c06Sbostic 59151034c06Sbostic /* 59251034c06Sbostic ** Associate sets of rules with zones. 59351034c06Sbostic */ 59451034c06Sbostic 59551034c06Sbostic /* 59651034c06Sbostic ** Sort by rule name. 59751034c06Sbostic */ 59851034c06Sbostic 59951034c06Sbostic static int 60051034c06Sbostic rcomp(cp1, cp2) 6016068c877Sbostic const void * cp1; 6026068c877Sbostic const void * cp2; 60351034c06Sbostic { 60451034c06Sbostic return strcmp(((struct rule *) cp1)->r_name, 60551034c06Sbostic ((struct rule *) cp2)->r_name); 60651034c06Sbostic } 60751034c06Sbostic 60851034c06Sbostic static void 60951034c06Sbostic associate() 61051034c06Sbostic { 61151034c06Sbostic register struct zone * zp; 61251034c06Sbostic register struct rule * rp; 61351034c06Sbostic register int base, out; 61451034c06Sbostic register int i; 61551034c06Sbostic 61651034c06Sbostic if (nrules != 0) 6176068c877Sbostic (void) qsort((void *) rules, (size_t) nrules, 6186068c877Sbostic (size_t) sizeof *rules, rcomp); 61951034c06Sbostic for (i = 0; i < nzones; ++i) { 62051034c06Sbostic zp = &zones[i]; 62151034c06Sbostic zp->z_rules = NULL; 62251034c06Sbostic zp->z_nrules = 0; 62351034c06Sbostic } 62451034c06Sbostic for (base = 0; base < nrules; base = out) { 62551034c06Sbostic rp = &rules[base]; 62651034c06Sbostic for (out = base + 1; out < nrules; ++out) 62751034c06Sbostic if (strcmp(rp->r_name, rules[out].r_name) != 0) 62851034c06Sbostic break; 62951034c06Sbostic for (i = 0; i < nzones; ++i) { 63051034c06Sbostic zp = &zones[i]; 63151034c06Sbostic if (strcmp(zp->z_rule, rp->r_name) != 0) 63251034c06Sbostic continue; 63351034c06Sbostic zp->z_rules = rp; 63451034c06Sbostic zp->z_nrules = out - base; 63551034c06Sbostic } 63651034c06Sbostic } 63751034c06Sbostic for (i = 0; i < nzones; ++i) { 63851034c06Sbostic zp = &zones[i]; 63951034c06Sbostic if (zp->z_nrules == 0) { 64051034c06Sbostic /* 64151034c06Sbostic ** Maybe we have a local standard time offset. 64251034c06Sbostic */ 64351034c06Sbostic eat(zp->z_filename, zp->z_linenum); 6446068c877Sbostic zp->z_stdoff = 6456068c877Sbostic gethms((char *)zp->z_rule, "unruly zone", TRUE); 64651034c06Sbostic /* 64751034c06Sbostic ** Note, though, that if there's no rule, 64851034c06Sbostic ** a '%s' in the format is a bad thing. 64951034c06Sbostic */ 65051034c06Sbostic if (strchr(zp->z_format, '%') != 0) 65151034c06Sbostic error("%s in ruleless zone"); 65251034c06Sbostic } 65351034c06Sbostic } 65451034c06Sbostic if (errors) 65551034c06Sbostic (void) exit(EXIT_FAILURE); 65651034c06Sbostic } 65751034c06Sbostic 65851034c06Sbostic static void 65951034c06Sbostic infile(name) 66051034c06Sbostic const char * name; 66151034c06Sbostic { 66251034c06Sbostic register FILE * fp; 66351034c06Sbostic register char ** fields; 66451034c06Sbostic register char * cp; 66551034c06Sbostic register const struct lookup * lp; 66651034c06Sbostic register int nfields; 66751034c06Sbostic register int wantcont; 66851034c06Sbostic register int num; 66951034c06Sbostic char buf[BUFSIZ]; 67051034c06Sbostic 67151034c06Sbostic if (strcmp(name, "-") == 0) { 67251034c06Sbostic name = "standard input"; 67351034c06Sbostic fp = stdin; 67451034c06Sbostic } else if ((fp = fopen(name, "r")) == NULL) { 67551034c06Sbostic (void) fprintf(stderr, "%s: Can't open ", progname); 67651034c06Sbostic (void) perror(name); 67751034c06Sbostic (void) exit(EXIT_FAILURE); 67851034c06Sbostic } 67951034c06Sbostic wantcont = FALSE; 68051034c06Sbostic for (num = 1; ; ++num) { 68151034c06Sbostic eat(name, num); 68251034c06Sbostic if (fgets(buf, (int) sizeof buf, fp) != buf) 68351034c06Sbostic break; 68451034c06Sbostic cp = strchr(buf, '\n'); 68551034c06Sbostic if (cp == NULL) { 68651034c06Sbostic error("line too long"); 68751034c06Sbostic (void) exit(EXIT_FAILURE); 68851034c06Sbostic } 68951034c06Sbostic *cp = '\0'; 69051034c06Sbostic fields = getfields(buf); 69151034c06Sbostic nfields = 0; 69251034c06Sbostic while (fields[nfields] != NULL) { 69351034c06Sbostic if (ciequal(fields[nfields], "-")) 69451034c06Sbostic fields[nfields] = ""; 69551034c06Sbostic ++nfields; 69651034c06Sbostic } 69751034c06Sbostic if (nfields == 0) { 69851034c06Sbostic /* nothing to do */ 69951034c06Sbostic } else if (wantcont) { 70051034c06Sbostic wantcont = inzcont(fields, nfields); 70151034c06Sbostic } else { 70251034c06Sbostic lp = byword(fields[0], line_codes); 70351034c06Sbostic if (lp == NULL) 70451034c06Sbostic error("input line of unknown type"); 70551034c06Sbostic else switch ((int) (lp->l_value)) { 70651034c06Sbostic case LC_RULE: 70751034c06Sbostic inrule(fields, nfields); 70851034c06Sbostic wantcont = FALSE; 70951034c06Sbostic break; 71051034c06Sbostic case LC_ZONE: 71151034c06Sbostic wantcont = inzone(fields, nfields); 71251034c06Sbostic break; 71351034c06Sbostic case LC_LINK: 71451034c06Sbostic inlink(fields, nfields); 71551034c06Sbostic wantcont = FALSE; 71651034c06Sbostic break; 71751034c06Sbostic case LC_LEAP: 71851034c06Sbostic if (name != leapsec) 71951034c06Sbostic (void) fprintf(stderr, 72051034c06Sbostic "%s: Leap line in non leap seconds file %s\n", 72151034c06Sbostic progname, name); 72251034c06Sbostic else inleap(fields, nfields); 72351034c06Sbostic wantcont = FALSE; 72451034c06Sbostic break; 72551034c06Sbostic default: /* "cannot happen" */ 72651034c06Sbostic (void) fprintf(stderr, 72751034c06Sbostic "%s: panic: Invalid l_value %d\n", 72851034c06Sbostic progname, lp->l_value); 72951034c06Sbostic (void) exit(EXIT_FAILURE); 73051034c06Sbostic } 73151034c06Sbostic } 73251034c06Sbostic ifree((char *) fields); 73351034c06Sbostic } 73451034c06Sbostic if (ferror(fp)) { 73551034c06Sbostic (void) fprintf(stderr, "%s: Error reading ", progname); 73651034c06Sbostic (void) perror(filename); 73751034c06Sbostic (void) exit(EXIT_FAILURE); 73851034c06Sbostic } 73951034c06Sbostic if (fp != stdin && fclose(fp)) { 74051034c06Sbostic (void) fprintf(stderr, "%s: Error closing ", progname); 74151034c06Sbostic (void) perror(filename); 74251034c06Sbostic (void) exit(EXIT_FAILURE); 74351034c06Sbostic } 74451034c06Sbostic if (wantcont) 74551034c06Sbostic error("expected continuation line not found"); 74651034c06Sbostic } 74751034c06Sbostic 74851034c06Sbostic /* 74951034c06Sbostic ** Convert a string of one of the forms 75051034c06Sbostic ** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 75151034c06Sbostic ** into a number of seconds. 75251034c06Sbostic ** A null string maps to zero. 75351034c06Sbostic ** Call error with errstring and return zero on errors. 75451034c06Sbostic */ 75551034c06Sbostic 75651034c06Sbostic static long 75751034c06Sbostic gethms(string, errstring, signable) 7586068c877Sbostic char * string; 75951034c06Sbostic const char * const errstring; 76051034c06Sbostic const int signable; 76151034c06Sbostic { 76251034c06Sbostic int hh, mm, ss, sign; 76351034c06Sbostic 76451034c06Sbostic if (string == NULL || *string == '\0') 76551034c06Sbostic return 0; 76651034c06Sbostic if (!signable) 76751034c06Sbostic sign = 1; 76851034c06Sbostic else if (*string == '-') { 76951034c06Sbostic sign = -1; 77051034c06Sbostic ++string; 77151034c06Sbostic } else sign = 1; 77251034c06Sbostic if (sscanf(string, scheck(string, "%d"), &hh) == 1) 77351034c06Sbostic mm = ss = 0; 77451034c06Sbostic else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) 77551034c06Sbostic ss = 0; 77651034c06Sbostic else if (sscanf(string, scheck(string, "%d:%d:%d"), 77751034c06Sbostic &hh, &mm, &ss) != 3) { 77851034c06Sbostic error(errstring); 77951034c06Sbostic return 0; 78051034c06Sbostic } 78151034c06Sbostic if (hh < 0 || hh >= HOURSPERDAY || 78251034c06Sbostic mm < 0 || mm >= MINSPERHOUR || 78351034c06Sbostic ss < 0 || ss > SECSPERMIN) { 78451034c06Sbostic error(errstring); 78551034c06Sbostic return 0; 78651034c06Sbostic } 78751034c06Sbostic return eitol(sign) * 78851034c06Sbostic (eitol(hh * MINSPERHOUR + mm) * 78951034c06Sbostic eitol(SECSPERMIN) + eitol(ss)); 79051034c06Sbostic } 79151034c06Sbostic 79251034c06Sbostic static void 79351034c06Sbostic inrule(fields, nfields) 79451034c06Sbostic register char ** const fields; 79551034c06Sbostic const int nfields; 79651034c06Sbostic { 79751034c06Sbostic static struct rule r; 79851034c06Sbostic 79951034c06Sbostic if (nfields != RULE_FIELDS) { 80051034c06Sbostic error("wrong number of fields on Rule line"); 80151034c06Sbostic return; 80251034c06Sbostic } 80351034c06Sbostic if (*fields[RF_NAME] == '\0') { 80451034c06Sbostic error("nameless rule"); 80551034c06Sbostic return; 80651034c06Sbostic } 80751034c06Sbostic r.r_filename = filename; 80851034c06Sbostic r.r_linenum = linenum; 80951034c06Sbostic r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); 81051034c06Sbostic rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 81151034c06Sbostic fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 81251034c06Sbostic r.r_name = ecpyalloc(fields[RF_NAME]); 81351034c06Sbostic r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 81451034c06Sbostic rules = (struct rule *) erealloc((char *) rules, 81551034c06Sbostic (int) ((nrules + 1) * sizeof *rules)); 81651034c06Sbostic rules[nrules++] = r; 81751034c06Sbostic } 81851034c06Sbostic 81951034c06Sbostic static int 82051034c06Sbostic inzone(fields, nfields) 82151034c06Sbostic register char ** const fields; 82251034c06Sbostic const int nfields; 82351034c06Sbostic { 82451034c06Sbostic register int i; 82551034c06Sbostic char buf[132]; 82651034c06Sbostic 82751034c06Sbostic if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 82851034c06Sbostic error("wrong number of fields on Zone line"); 82951034c06Sbostic return FALSE; 83051034c06Sbostic } 83151034c06Sbostic if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 83251034c06Sbostic (void) sprintf(buf, 83351034c06Sbostic "\"Zone %s\" line and -l option are mutually exclusive", 83451034c06Sbostic TZDEFAULT); 83551034c06Sbostic error(buf); 83651034c06Sbostic return FALSE; 83751034c06Sbostic } 83851034c06Sbostic if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 83951034c06Sbostic (void) sprintf(buf, 84051034c06Sbostic "\"Zone %s\" line and -p option are mutually exclusive", 84151034c06Sbostic TZDEFRULES); 84251034c06Sbostic error(buf); 84351034c06Sbostic return FALSE; 84451034c06Sbostic } 84551034c06Sbostic for (i = 0; i < nzones; ++i) 84651034c06Sbostic if (zones[i].z_name != NULL && 84751034c06Sbostic strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 84851034c06Sbostic (void) sprintf(buf, 84951034c06Sbostic "duplicate zone name %s (file \"%s\", line %d)", 85051034c06Sbostic fields[ZF_NAME], 85151034c06Sbostic zones[i].z_filename, 85251034c06Sbostic zones[i].z_linenum); 85351034c06Sbostic error(buf); 85451034c06Sbostic return FALSE; 85551034c06Sbostic } 85651034c06Sbostic return inzsub(fields, nfields, FALSE); 85751034c06Sbostic } 85851034c06Sbostic 85951034c06Sbostic static int 86051034c06Sbostic inzcont(fields, nfields) 86151034c06Sbostic register char ** const fields; 86251034c06Sbostic const int nfields; 86351034c06Sbostic { 86451034c06Sbostic if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 86551034c06Sbostic error("wrong number of fields on Zone continuation line"); 86651034c06Sbostic return FALSE; 86751034c06Sbostic } 86851034c06Sbostic return inzsub(fields, nfields, TRUE); 86951034c06Sbostic } 87051034c06Sbostic 87151034c06Sbostic static int 87251034c06Sbostic inzsub(fields, nfields, iscont) 87351034c06Sbostic register char ** const fields; 87451034c06Sbostic const int nfields; 87551034c06Sbostic const int iscont; 87651034c06Sbostic { 87751034c06Sbostic register char * cp; 87851034c06Sbostic static struct zone z; 87951034c06Sbostic register int i_gmtoff, i_rule, i_format; 88051034c06Sbostic register int i_untilyear, i_untilmonth; 88151034c06Sbostic register int i_untilday, i_untiltime; 88251034c06Sbostic register int hasuntil; 88351034c06Sbostic 88451034c06Sbostic if (iscont) { 88551034c06Sbostic i_gmtoff = ZFC_GMTOFF; 88651034c06Sbostic i_rule = ZFC_RULE; 88751034c06Sbostic i_format = ZFC_FORMAT; 88851034c06Sbostic i_untilyear = ZFC_TILYEAR; 88951034c06Sbostic i_untilmonth = ZFC_TILMONTH; 89051034c06Sbostic i_untilday = ZFC_TILDAY; 89151034c06Sbostic i_untiltime = ZFC_TILTIME; 89251034c06Sbostic z.z_name = NULL; 89351034c06Sbostic } else { 89451034c06Sbostic i_gmtoff = ZF_GMTOFF; 89551034c06Sbostic i_rule = ZF_RULE; 89651034c06Sbostic i_format = ZF_FORMAT; 89751034c06Sbostic i_untilyear = ZF_TILYEAR; 89851034c06Sbostic i_untilmonth = ZF_TILMONTH; 89951034c06Sbostic i_untilday = ZF_TILDAY; 90051034c06Sbostic i_untiltime = ZF_TILTIME; 90151034c06Sbostic z.z_name = ecpyalloc(fields[ZF_NAME]); 90251034c06Sbostic } 90351034c06Sbostic z.z_filename = filename; 90451034c06Sbostic z.z_linenum = linenum; 90551034c06Sbostic z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); 90651034c06Sbostic if ((cp = strchr(fields[i_format], '%')) != 0) { 90751034c06Sbostic if (*++cp != 's' || strchr(cp, '%') != 0) { 90851034c06Sbostic error("invalid abbreviation format"); 90951034c06Sbostic return FALSE; 91051034c06Sbostic } 91151034c06Sbostic } 91251034c06Sbostic z.z_rule = ecpyalloc(fields[i_rule]); 91351034c06Sbostic z.z_format = ecpyalloc(fields[i_format]); 91451034c06Sbostic hasuntil = nfields > i_untilyear; 91551034c06Sbostic if (hasuntil) { 91651034c06Sbostic z.z_untilrule.r_filename = filename; 91751034c06Sbostic z.z_untilrule.r_linenum = linenum; 91851034c06Sbostic rulesub(&z.z_untilrule, 91951034c06Sbostic fields[i_untilyear], 92051034c06Sbostic "only", 92151034c06Sbostic "", 92251034c06Sbostic (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", 92351034c06Sbostic (nfields > i_untilday) ? fields[i_untilday] : "1", 92451034c06Sbostic (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 92551034c06Sbostic z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); 92651034c06Sbostic if (iscont && nzones > 0 && z.z_untiltime < max_time && 92751034c06Sbostic z.z_untiltime > min_time && 92851034c06Sbostic zones[nzones - 1].z_untiltime >= z.z_untiltime) { 92951034c06Sbostic error("Zone continuation line end time is not after end time of previous line"); 93051034c06Sbostic return FALSE; 93151034c06Sbostic } 93251034c06Sbostic } 93351034c06Sbostic zones = (struct zone *) erealloc((char *) zones, 93451034c06Sbostic (int) ((nzones + 1) * sizeof *zones)); 93551034c06Sbostic zones[nzones++] = z; 93651034c06Sbostic /* 93751034c06Sbostic ** If there was an UNTIL field on this line, 93851034c06Sbostic ** there's more information about the zone on the next line. 93951034c06Sbostic */ 94051034c06Sbostic return hasuntil; 94151034c06Sbostic } 94251034c06Sbostic 94351034c06Sbostic static void 94451034c06Sbostic inleap(fields, nfields) 94551034c06Sbostic register char ** const fields; 94651034c06Sbostic const int nfields; 94751034c06Sbostic { 94851034c06Sbostic register const char * cp; 94951034c06Sbostic register const struct lookup * lp; 95051034c06Sbostic register int i, j; 95151034c06Sbostic int year, month, day; 95251034c06Sbostic long dayoff, tod; 95351034c06Sbostic time_t t; 95451034c06Sbostic 95551034c06Sbostic if (nfields != LEAP_FIELDS) { 95651034c06Sbostic error("wrong number of fields on Leap line"); 95751034c06Sbostic return; 95851034c06Sbostic } 95951034c06Sbostic dayoff = 0; 96051034c06Sbostic cp = fields[LP_YEAR]; 9616068c877Sbostic if (sscanf((char *)cp, scheck(cp, "%d"), &year) != 1 || 96251034c06Sbostic year < min_year || year > max_year) { 96351034c06Sbostic /* 96451034c06Sbostic * Leapin' Lizards! 96551034c06Sbostic */ 96651034c06Sbostic error("invalid leaping year"); 96751034c06Sbostic return; 96851034c06Sbostic } 96951034c06Sbostic j = EPOCH_YEAR; 97051034c06Sbostic while (j != year) { 97151034c06Sbostic if (year > j) { 97251034c06Sbostic i = len_years[isleap(j)]; 97351034c06Sbostic ++j; 97451034c06Sbostic } else { 97551034c06Sbostic --j; 97651034c06Sbostic i = -len_years[isleap(j)]; 97751034c06Sbostic } 97851034c06Sbostic dayoff = oadd(dayoff, eitol(i)); 97951034c06Sbostic } 98051034c06Sbostic if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 98151034c06Sbostic error("invalid month name"); 98251034c06Sbostic return; 98351034c06Sbostic } 98451034c06Sbostic month = lp->l_value; 98551034c06Sbostic j = TM_JANUARY; 98651034c06Sbostic while (j != month) { 98751034c06Sbostic i = len_months[isleap(year)][j]; 98851034c06Sbostic dayoff = oadd(dayoff, eitol(i)); 98951034c06Sbostic ++j; 99051034c06Sbostic } 99151034c06Sbostic cp = fields[LP_DAY]; 9926068c877Sbostic if (sscanf((char *)cp, scheck(cp, "%d"), &day) != 1 || 99351034c06Sbostic day <= 0 || day > len_months[isleap(year)][month]) { 99451034c06Sbostic error("invalid day of month"); 99551034c06Sbostic return; 99651034c06Sbostic } 99751034c06Sbostic dayoff = oadd(dayoff, eitol(day - 1)); 99851034c06Sbostic if (dayoff < 0 && !tt_signed) { 99951034c06Sbostic error("time before zero"); 100051034c06Sbostic return; 100151034c06Sbostic } 100251034c06Sbostic t = (time_t) dayoff * SECSPERDAY; 100351034c06Sbostic /* 100451034c06Sbostic ** Cheap overflow check. 100551034c06Sbostic */ 100651034c06Sbostic if (t / SECSPERDAY != dayoff) { 100751034c06Sbostic error("time overflow"); 100851034c06Sbostic return; 100951034c06Sbostic } 101051034c06Sbostic tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); 101151034c06Sbostic cp = fields[LP_CORR]; 101251034c06Sbostic if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) { 101351034c06Sbostic /* infile() turned "-" into "" */ 101451034c06Sbostic error("illegal CORRECTION field on Leap line"); 101551034c06Sbostic return; 101651034c06Sbostic } 101751034c06Sbostic if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 101851034c06Sbostic error("illegal Rolling/Stationary field on Leap line"); 101951034c06Sbostic return; 102051034c06Sbostic } 102151034c06Sbostic addleap(tadd(t, tod), *cp == '+', lp->l_value); 102251034c06Sbostic } 102351034c06Sbostic 102451034c06Sbostic static void 102551034c06Sbostic inlink(fields, nfields) 102651034c06Sbostic register char ** const fields; 102751034c06Sbostic const int nfields; 102851034c06Sbostic { 102951034c06Sbostic struct link l; 103051034c06Sbostic 103151034c06Sbostic if (nfields != LINK_FIELDS) { 103251034c06Sbostic error("wrong number of fields on Link line"); 103351034c06Sbostic return; 103451034c06Sbostic } 103551034c06Sbostic if (*fields[LF_FROM] == '\0') { 103651034c06Sbostic error("blank FROM field on Link line"); 103751034c06Sbostic return; 103851034c06Sbostic } 103951034c06Sbostic if (*fields[LF_TO] == '\0') { 104051034c06Sbostic error("blank TO field on Link line"); 104151034c06Sbostic return; 104251034c06Sbostic } 104351034c06Sbostic l.l_filename = filename; 104451034c06Sbostic l.l_linenum = linenum; 104551034c06Sbostic l.l_from = ecpyalloc(fields[LF_FROM]); 104651034c06Sbostic l.l_to = ecpyalloc(fields[LF_TO]); 104751034c06Sbostic links = (struct link *) erealloc((char *) links, 104851034c06Sbostic (int) ((nlinks + 1) * sizeof *links)); 104951034c06Sbostic links[nlinks++] = l; 105051034c06Sbostic } 105151034c06Sbostic 105251034c06Sbostic static void 105351034c06Sbostic rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 105451034c06Sbostic register struct rule * const rp; 105551034c06Sbostic char * const loyearp; 105651034c06Sbostic char * const hiyearp; 105751034c06Sbostic char * const typep; 105851034c06Sbostic char * const monthp; 105951034c06Sbostic char * const dayp; 106051034c06Sbostic char * const timep; 106151034c06Sbostic { 106251034c06Sbostic register struct lookup const * lp; 106351034c06Sbostic register char * cp; 106451034c06Sbostic 106551034c06Sbostic if ((lp = byword(monthp, mon_names)) == NULL) { 106651034c06Sbostic error("invalid month name"); 106751034c06Sbostic return; 106851034c06Sbostic } 106951034c06Sbostic rp->r_month = lp->l_value; 107051034c06Sbostic rp->r_todisstd = FALSE; 107151034c06Sbostic cp = timep; 107251034c06Sbostic if (*cp != '\0') { 107351034c06Sbostic cp += strlen(cp) - 1; 107451034c06Sbostic switch (lowerit(*cp)) { 107551034c06Sbostic case 's': 107651034c06Sbostic rp->r_todisstd = TRUE; 107751034c06Sbostic *cp = '\0'; 107851034c06Sbostic break; 107951034c06Sbostic case 'w': 108051034c06Sbostic rp->r_todisstd = FALSE; 108151034c06Sbostic *cp = '\0'; 108251034c06Sbostic break; 108351034c06Sbostic } 108451034c06Sbostic } 108551034c06Sbostic rp->r_tod = gethms(timep, "invalid time of day", FALSE); 108651034c06Sbostic /* 108751034c06Sbostic ** Year work. 108851034c06Sbostic */ 108951034c06Sbostic cp = loyearp; 109051034c06Sbostic if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { 109151034c06Sbostic case YR_MINIMUM: 109251034c06Sbostic rp->r_loyear = min_year; 109351034c06Sbostic break; 109451034c06Sbostic case YR_MAXIMUM: 109551034c06Sbostic rp->r_loyear = max_year; 109651034c06Sbostic break; 109751034c06Sbostic default: /* "cannot happen" */ 109851034c06Sbostic (void) fprintf(stderr, 109951034c06Sbostic "%s: panic: Invalid l_value %d\n", 110051034c06Sbostic progname, lp->l_value); 110151034c06Sbostic (void) exit(EXIT_FAILURE); 110251034c06Sbostic } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 || 110351034c06Sbostic rp->r_loyear < min_year || rp->r_loyear > max_year) { 110451034c06Sbostic if (noise) 110551034c06Sbostic error("invalid starting year"); 110651034c06Sbostic if (rp->r_loyear > max_year) 110751034c06Sbostic return; 110851034c06Sbostic } 110951034c06Sbostic cp = hiyearp; 111051034c06Sbostic if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { 111151034c06Sbostic case YR_MINIMUM: 111251034c06Sbostic rp->r_hiyear = min_year; 111351034c06Sbostic break; 111451034c06Sbostic case YR_MAXIMUM: 111551034c06Sbostic rp->r_hiyear = max_year; 111651034c06Sbostic break; 111751034c06Sbostic case YR_ONLY: 111851034c06Sbostic rp->r_hiyear = rp->r_loyear; 111951034c06Sbostic break; 112051034c06Sbostic default: /* "cannot happen" */ 112151034c06Sbostic (void) fprintf(stderr, 112251034c06Sbostic "%s: panic: Invalid l_value %d\n", 112351034c06Sbostic progname, lp->l_value); 112451034c06Sbostic (void) exit(EXIT_FAILURE); 112551034c06Sbostic } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 || 112651034c06Sbostic rp->r_hiyear < min_year || rp->r_hiyear > max_year) { 112751034c06Sbostic if (noise) 112851034c06Sbostic error("invalid ending year"); 112951034c06Sbostic if (rp->r_hiyear < min_year) 113051034c06Sbostic return; 113151034c06Sbostic } 113251034c06Sbostic if (rp->r_hiyear < min_year) 113351034c06Sbostic return; 113451034c06Sbostic if (rp->r_loyear < min_year) 113551034c06Sbostic rp->r_loyear = min_year; 113651034c06Sbostic if (rp->r_hiyear > max_year) 113751034c06Sbostic rp->r_hiyear = max_year; 113851034c06Sbostic if (rp->r_loyear > rp->r_hiyear) { 113951034c06Sbostic error("starting year greater than ending year"); 114051034c06Sbostic return; 114151034c06Sbostic } 114251034c06Sbostic if (*typep == '\0') 114351034c06Sbostic rp->r_yrtype = NULL; 114451034c06Sbostic else { 114551034c06Sbostic if (rp->r_loyear == rp->r_hiyear) { 114651034c06Sbostic error("typed single year"); 114751034c06Sbostic return; 114851034c06Sbostic } 114951034c06Sbostic rp->r_yrtype = ecpyalloc(typep); 115051034c06Sbostic } 115151034c06Sbostic /* 115251034c06Sbostic ** Day work. 115351034c06Sbostic ** Accept things such as: 115451034c06Sbostic ** 1 115551034c06Sbostic ** last-Sunday 115651034c06Sbostic ** Sun<=20 115751034c06Sbostic ** Sun>=7 115851034c06Sbostic */ 115951034c06Sbostic if ((lp = byword(dayp, lasts)) != NULL) { 116051034c06Sbostic rp->r_dycode = DC_DOWLEQ; 116151034c06Sbostic rp->r_wday = lp->l_value; 116251034c06Sbostic rp->r_dayofmonth = len_months[1][rp->r_month]; 116351034c06Sbostic } else { 116451034c06Sbostic if ((cp = strchr(dayp, '<')) != 0) 116551034c06Sbostic rp->r_dycode = DC_DOWLEQ; 116651034c06Sbostic else if ((cp = strchr(dayp, '>')) != 0) 116751034c06Sbostic rp->r_dycode = DC_DOWGEQ; 116851034c06Sbostic else { 116951034c06Sbostic cp = dayp; 117051034c06Sbostic rp->r_dycode = DC_DOM; 117151034c06Sbostic } 117251034c06Sbostic if (rp->r_dycode != DC_DOM) { 117351034c06Sbostic *cp++ = 0; 117451034c06Sbostic if (*cp++ != '=') { 117551034c06Sbostic error("invalid day of month"); 117651034c06Sbostic return; 117751034c06Sbostic } 117851034c06Sbostic if ((lp = byword(dayp, wday_names)) == NULL) { 117951034c06Sbostic error("invalid weekday name"); 118051034c06Sbostic return; 118151034c06Sbostic } 118251034c06Sbostic rp->r_wday = lp->l_value; 118351034c06Sbostic } 118451034c06Sbostic if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || 118551034c06Sbostic rp->r_dayofmonth <= 0 || 118651034c06Sbostic (rp->r_dayofmonth > len_months[1][rp->r_month])) { 118751034c06Sbostic error("invalid day of month"); 118851034c06Sbostic return; 118951034c06Sbostic } 119051034c06Sbostic } 119151034c06Sbostic } 119251034c06Sbostic 119351034c06Sbostic static void 119451034c06Sbostic convert(val, buf) 119551034c06Sbostic const long val; 119651034c06Sbostic char * const buf; 119751034c06Sbostic { 119851034c06Sbostic register int i; 119951034c06Sbostic register long shift; 120051034c06Sbostic 120151034c06Sbostic for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 120251034c06Sbostic buf[i] = val >> shift; 120351034c06Sbostic } 120451034c06Sbostic 120551034c06Sbostic static void 120651034c06Sbostic puttzcode(val, fp) 120751034c06Sbostic const long val; 120851034c06Sbostic FILE * const fp; 120951034c06Sbostic { 121051034c06Sbostic char buf[4]; 121151034c06Sbostic 121251034c06Sbostic convert(val, buf); 12136068c877Sbostic (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); 121451034c06Sbostic } 121551034c06Sbostic 121651034c06Sbostic static void 121751034c06Sbostic writezone(name) 121851034c06Sbostic const char * const name; 121951034c06Sbostic { 122051034c06Sbostic register FILE * fp; 122151034c06Sbostic register int i, j; 122251034c06Sbostic char fullname[BUFSIZ]; 122351034c06Sbostic static struct tzhead tzh; 122451034c06Sbostic 122551034c06Sbostic if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) { 122651034c06Sbostic (void) fprintf(stderr, 122751034c06Sbostic "%s: File name %s/%s too long\n", progname, 122851034c06Sbostic directory, name); 122951034c06Sbostic (void) exit(EXIT_FAILURE); 123051034c06Sbostic } 123151034c06Sbostic (void) sprintf(fullname, "%s/%s", directory, name); 123251034c06Sbostic if ((fp = fopen(fullname, "wb")) == NULL) { 123351034c06Sbostic if (mkdirs(fullname) != 0) 123451034c06Sbostic (void) exit(EXIT_FAILURE); 123551034c06Sbostic if ((fp = fopen(fullname, "wb")) == NULL) { 123651034c06Sbostic (void) fprintf(stderr, "%s: Can't create ", progname); 123751034c06Sbostic (void) perror(fullname); 123851034c06Sbostic (void) exit(EXIT_FAILURE); 123951034c06Sbostic } 124051034c06Sbostic } 124151034c06Sbostic convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 124251034c06Sbostic convert(eitol(leapcnt), tzh.tzh_leapcnt); 124351034c06Sbostic convert(eitol(timecnt), tzh.tzh_timecnt); 124451034c06Sbostic convert(eitol(typecnt), tzh.tzh_typecnt); 124551034c06Sbostic convert(eitol(charcnt), tzh.tzh_charcnt); 12466068c877Sbostic (void) fwrite((void *) &tzh, (size_t) sizeof tzh, (size_t) 1, fp); 124751034c06Sbostic for (i = 0; i < timecnt; ++i) { 124851034c06Sbostic j = leapcnt; 124951034c06Sbostic while (--j >= 0) 125051034c06Sbostic if (ats[i] >= trans[j]) { 125151034c06Sbostic ats[i] = tadd(ats[i], corr[j]); 125251034c06Sbostic break; 125351034c06Sbostic } 125451034c06Sbostic puttzcode((long) ats[i], fp); 125551034c06Sbostic } 125651034c06Sbostic if (timecnt > 0) 12576068c877Sbostic (void) fwrite((void *) types, (size_t) sizeof types[0], 12586068c877Sbostic (size_t) timecnt, fp); 125951034c06Sbostic for (i = 0; i < typecnt; ++i) { 126051034c06Sbostic puttzcode((long) gmtoffs[i], fp); 126151034c06Sbostic (void) putc(isdsts[i], fp); 126251034c06Sbostic (void) putc(abbrinds[i], fp); 126351034c06Sbostic } 126451034c06Sbostic if (charcnt != 0) 12656068c877Sbostic (void) fwrite((void *) chars, (size_t) sizeof chars[0], 12666068c877Sbostic (size_t) charcnt, fp); 126751034c06Sbostic for (i = 0; i < leapcnt; ++i) { 126851034c06Sbostic if (roll[i]) { 126951034c06Sbostic if (timecnt == 0 || trans[i] < ats[0]) { 127051034c06Sbostic j = 0; 127151034c06Sbostic while (isdsts[j]) 127251034c06Sbostic if (++j >= typecnt) { 127351034c06Sbostic j = 0; 127451034c06Sbostic break; 127551034c06Sbostic } 127651034c06Sbostic } else { 127751034c06Sbostic j = 1; 127851034c06Sbostic while (j < timecnt && trans[i] >= ats[j]) 127951034c06Sbostic ++j; 128051034c06Sbostic j = types[j - 1]; 128151034c06Sbostic } 128251034c06Sbostic puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp); 128351034c06Sbostic } else puttzcode((long) trans[i], fp); 128451034c06Sbostic puttzcode((long) corr[i], fp); 128551034c06Sbostic } 128651034c06Sbostic for (i = 0; i < typecnt; ++i) 128751034c06Sbostic (void) putc(ttisstds[i], fp); 128851034c06Sbostic if (ferror(fp) || fclose(fp)) { 128951034c06Sbostic (void) fprintf(stderr, "%s: Write error on ", progname); 129051034c06Sbostic (void) perror(fullname); 129151034c06Sbostic (void) exit(EXIT_FAILURE); 129251034c06Sbostic } 129351034c06Sbostic } 129451034c06Sbostic 129551034c06Sbostic static void 129651034c06Sbostic outzone(zpfirst, zonecount) 129751034c06Sbostic const struct zone * const zpfirst; 129851034c06Sbostic const int zonecount; 129951034c06Sbostic { 130051034c06Sbostic register const struct zone * zp; 130151034c06Sbostic register struct rule * rp; 130251034c06Sbostic register int i, j; 130351034c06Sbostic register int usestart, useuntil; 130451034c06Sbostic register time_t starttime, untiltime; 130551034c06Sbostic register long gmtoff; 130651034c06Sbostic register long stdoff; 130751034c06Sbostic register int year; 130851034c06Sbostic register long startoff; 130951034c06Sbostic register int startisdst; 131051034c06Sbostic register int startttisstd; 131151034c06Sbostic register int type; 131251034c06Sbostic char startbuf[BUFSIZ]; 131351034c06Sbostic 131451034c06Sbostic /* 131551034c06Sbostic ** Now. . .finally. . .generate some useful data! 131651034c06Sbostic */ 131751034c06Sbostic timecnt = 0; 131851034c06Sbostic typecnt = 0; 131951034c06Sbostic charcnt = 0; 132051034c06Sbostic /* 132151034c06Sbostic ** Two guesses. . .the second may well be corrected later. 132251034c06Sbostic */ 132351034c06Sbostic gmtoff = zpfirst->z_gmtoff; 132451034c06Sbostic stdoff = 0; 132551034c06Sbostic starttime = 0; 132651034c06Sbostic startttisstd = FALSE; 132751034c06Sbostic for (i = 0; i < zonecount; ++i) { 132851034c06Sbostic usestart = i > 0; 132951034c06Sbostic useuntil = i < (zonecount - 1); 133051034c06Sbostic zp = &zpfirst[i]; 133151034c06Sbostic eat(zp->z_filename, zp->z_linenum); 133251034c06Sbostic startisdst = -1; 133351034c06Sbostic if (zp->z_nrules == 0) { 133451034c06Sbostic type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff), 133551034c06Sbostic zp->z_format, zp->z_stdoff != 0, 133651034c06Sbostic startttisstd); 133751034c06Sbostic if (usestart) 133851034c06Sbostic addtt(starttime, type); 133951034c06Sbostic gmtoff = zp->z_gmtoff; 134051034c06Sbostic stdoff = zp->z_stdoff; 134151034c06Sbostic } else for (year = min_year; year <= max_year; ++year) { 134251034c06Sbostic if (useuntil && year > zp->z_untilrule.r_hiyear) 134351034c06Sbostic break; 134451034c06Sbostic /* 134551034c06Sbostic ** Mark which rules to do in the current year. 134651034c06Sbostic ** For those to do, calculate rpytime(rp, year); 134751034c06Sbostic */ 134851034c06Sbostic for (j = 0; j < zp->z_nrules; ++j) { 134951034c06Sbostic rp = &zp->z_rules[j]; 135051034c06Sbostic eats(zp->z_filename, zp->z_linenum, 135151034c06Sbostic rp->r_filename, rp->r_linenum); 135251034c06Sbostic rp->r_todo = year >= rp->r_loyear && 135351034c06Sbostic year <= rp->r_hiyear && 135451034c06Sbostic yearistype(year, rp->r_yrtype); 135551034c06Sbostic if (rp->r_todo) 135651034c06Sbostic rp->r_temp = rpytime(rp, year); 135751034c06Sbostic } 135851034c06Sbostic for ( ; ; ) { 135951034c06Sbostic register int k; 136051034c06Sbostic register time_t jtime, ktime; 136151034c06Sbostic register long offset; 136251034c06Sbostic char buf[BUFSIZ]; 136351034c06Sbostic 136451034c06Sbostic if (useuntil) { 136551034c06Sbostic /* 136651034c06Sbostic ** Turn untiltime into GMT 136751034c06Sbostic ** assuming the current gmtoff and 136851034c06Sbostic ** stdoff values. 136951034c06Sbostic */ 137051034c06Sbostic offset = gmtoff; 137151034c06Sbostic if (!zp->z_untilrule.r_todisstd) 137251034c06Sbostic offset = oadd(offset, stdoff); 137351034c06Sbostic untiltime = tadd(zp->z_untiltime, 137451034c06Sbostic -offset); 137551034c06Sbostic } 137651034c06Sbostic /* 137751034c06Sbostic ** Find the rule (of those to do, if any) 137851034c06Sbostic ** that takes effect earliest in the year. 137951034c06Sbostic */ 138051034c06Sbostic k = -1; 138151034c06Sbostic #ifdef lint 138251034c06Sbostic ktime = 0; 138351034c06Sbostic #endif /* defined lint */ 138451034c06Sbostic for (j = 0; j < zp->z_nrules; ++j) { 138551034c06Sbostic rp = &zp->z_rules[j]; 138651034c06Sbostic if (!rp->r_todo) 138751034c06Sbostic continue; 138851034c06Sbostic eats(zp->z_filename, zp->z_linenum, 138951034c06Sbostic rp->r_filename, rp->r_linenum); 139051034c06Sbostic offset = gmtoff; 139151034c06Sbostic if (!rp->r_todisstd) 139251034c06Sbostic offset = oadd(offset, stdoff); 139351034c06Sbostic jtime = rp->r_temp; 139451034c06Sbostic if (jtime == min_time || 139551034c06Sbostic jtime == max_time) 139651034c06Sbostic continue; 139751034c06Sbostic jtime = tadd(jtime, -offset); 139851034c06Sbostic if (k < 0 || jtime < ktime) { 139951034c06Sbostic k = j; 140051034c06Sbostic ktime = jtime; 140151034c06Sbostic } 140251034c06Sbostic } 140351034c06Sbostic if (k < 0) 140451034c06Sbostic break; /* go on to next year */ 140551034c06Sbostic rp = &zp->z_rules[k]; 140651034c06Sbostic rp->r_todo = FALSE; 140751034c06Sbostic if (useuntil && ktime >= untiltime) 140851034c06Sbostic break; 140951034c06Sbostic if (usestart) { 141051034c06Sbostic if (ktime < starttime) { 141151034c06Sbostic stdoff = rp->r_stdoff; 141251034c06Sbostic startoff = oadd(zp->z_gmtoff, 141351034c06Sbostic rp->r_stdoff); 141451034c06Sbostic (void) sprintf(startbuf, 141551034c06Sbostic zp->z_format, 141651034c06Sbostic rp->r_abbrvar); 141751034c06Sbostic startisdst = 141851034c06Sbostic rp->r_stdoff != 0; 141951034c06Sbostic continue; 142051034c06Sbostic } 142151034c06Sbostic if (ktime != starttime && 142251034c06Sbostic startisdst >= 0) 142351034c06Sbostic addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd)); 142451034c06Sbostic usestart = FALSE; 142551034c06Sbostic } 142651034c06Sbostic eats(zp->z_filename, zp->z_linenum, 142751034c06Sbostic rp->r_filename, rp->r_linenum); 142851034c06Sbostic (void) sprintf(buf, zp->z_format, 142951034c06Sbostic rp->r_abbrvar); 143051034c06Sbostic offset = oadd(zp->z_gmtoff, rp->r_stdoff); 143151034c06Sbostic type = addtype(offset, buf, rp->r_stdoff != 0, 143251034c06Sbostic rp->r_todisstd); 143351034c06Sbostic if (timecnt != 0 || rp->r_stdoff != 0) 143451034c06Sbostic addtt(ktime, type); 143551034c06Sbostic gmtoff = zp->z_gmtoff; 143651034c06Sbostic stdoff = rp->r_stdoff; 143751034c06Sbostic } 143851034c06Sbostic } 143951034c06Sbostic /* 144051034c06Sbostic ** Now we may get to set starttime for the next zone line. 144151034c06Sbostic */ 144251034c06Sbostic if (useuntil) { 144351034c06Sbostic starttime = tadd(zp->z_untiltime, 144451034c06Sbostic -gmtoffs[types[timecnt - 1]]); 144551034c06Sbostic startttisstd = zp->z_untilrule.r_todisstd; 144651034c06Sbostic } 144751034c06Sbostic } 144851034c06Sbostic writezone(zpfirst->z_name); 144951034c06Sbostic } 145051034c06Sbostic 145151034c06Sbostic static void 145251034c06Sbostic addtt(starttime, type) 145351034c06Sbostic const time_t starttime; 145451034c06Sbostic const int type; 145551034c06Sbostic { 145651034c06Sbostic if (timecnt != 0 && type == types[timecnt - 1]) 145751034c06Sbostic return; /* easy enough! */ 145851034c06Sbostic if (timecnt >= TZ_MAX_TIMES) { 145951034c06Sbostic error("too many transitions?!"); 146051034c06Sbostic (void) exit(EXIT_FAILURE); 146151034c06Sbostic } 146251034c06Sbostic ats[timecnt] = starttime; 146351034c06Sbostic types[timecnt] = type; 146451034c06Sbostic ++timecnt; 146551034c06Sbostic } 146651034c06Sbostic 146751034c06Sbostic static int 146851034c06Sbostic addtype(gmtoff, abbr, isdst, ttisstd) 146951034c06Sbostic const long gmtoff; 147051034c06Sbostic const char * const abbr; 147151034c06Sbostic const int isdst; 147251034c06Sbostic const int ttisstd; 147351034c06Sbostic { 147451034c06Sbostic register int i, j; 147551034c06Sbostic 147651034c06Sbostic /* 147751034c06Sbostic ** See if there's already an entry for this zone type. 147851034c06Sbostic ** If so, just return its index. 147951034c06Sbostic */ 148051034c06Sbostic for (i = 0; i < typecnt; ++i) { 148151034c06Sbostic if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 148251034c06Sbostic strcmp(abbr, &chars[abbrinds[i]]) == 0 && 148351034c06Sbostic ttisstd == ttisstds[i]) 148451034c06Sbostic return i; 148551034c06Sbostic } 148651034c06Sbostic /* 148751034c06Sbostic ** There isn't one; add a new one, unless there are already too 148851034c06Sbostic ** many. 148951034c06Sbostic */ 149051034c06Sbostic if (typecnt >= TZ_MAX_TYPES) { 149151034c06Sbostic error("too many local time types"); 149251034c06Sbostic (void) exit(EXIT_FAILURE); 149351034c06Sbostic } 149451034c06Sbostic gmtoffs[i] = gmtoff; 149551034c06Sbostic isdsts[i] = isdst; 149651034c06Sbostic ttisstds[i] = ttisstd; 149751034c06Sbostic 149851034c06Sbostic for (j = 0; j < charcnt; ++j) 149951034c06Sbostic if (strcmp(&chars[j], abbr) == 0) 150051034c06Sbostic break; 150151034c06Sbostic if (j == charcnt) 150251034c06Sbostic newabbr(abbr); 150351034c06Sbostic abbrinds[i] = j; 150451034c06Sbostic ++typecnt; 150551034c06Sbostic return i; 150651034c06Sbostic } 150751034c06Sbostic 150851034c06Sbostic static void 150951034c06Sbostic addleap(t, positive, rolling) 151051034c06Sbostic const time_t t; 151151034c06Sbostic const int positive; 151251034c06Sbostic const int rolling; 151351034c06Sbostic { 151451034c06Sbostic register int i, j; 151551034c06Sbostic 151651034c06Sbostic if (leapcnt >= TZ_MAX_LEAPS) { 151751034c06Sbostic error("too many leap seconds"); 151851034c06Sbostic (void) exit(EXIT_FAILURE); 151951034c06Sbostic } 152051034c06Sbostic for (i = 0; i < leapcnt; ++i) 152151034c06Sbostic if (t <= trans[i]) { 152251034c06Sbostic if (t == trans[i]) { 152351034c06Sbostic error("repeated leap second moment"); 152451034c06Sbostic (void) exit(EXIT_FAILURE); 152551034c06Sbostic } 152651034c06Sbostic break; 152751034c06Sbostic } 152851034c06Sbostic for (j = leapcnt; j > i; --j) { 152951034c06Sbostic trans[j] = trans[j-1]; 153051034c06Sbostic corr[j] = corr[j-1]; 153151034c06Sbostic roll[j] = roll[j-1]; 153251034c06Sbostic } 153351034c06Sbostic trans[i] = t; 153451034c06Sbostic corr[i] = (positive ? 1L : -1L); 153551034c06Sbostic roll[i] = rolling; 153651034c06Sbostic ++leapcnt; 153751034c06Sbostic } 153851034c06Sbostic 153951034c06Sbostic static void 154051034c06Sbostic adjleap() 154151034c06Sbostic { 154251034c06Sbostic register int i; 154351034c06Sbostic register long last = 0; 154451034c06Sbostic 154551034c06Sbostic /* 154651034c06Sbostic ** propagate leap seconds forward 154751034c06Sbostic */ 154851034c06Sbostic for (i = 0; i < leapcnt; ++i) { 154951034c06Sbostic trans[i] = tadd(trans[i], last); 155051034c06Sbostic last = corr[i] += last; 155151034c06Sbostic } 155251034c06Sbostic } 155351034c06Sbostic 155451034c06Sbostic static int 155551034c06Sbostic yearistype(year, type) 155651034c06Sbostic const int year; 155751034c06Sbostic const char * const type; 155851034c06Sbostic { 155951034c06Sbostic char buf[BUFSIZ]; 156051034c06Sbostic int result; 156151034c06Sbostic 156251034c06Sbostic if (type == NULL || *type == '\0') 156351034c06Sbostic return TRUE; 156451034c06Sbostic if (strcmp(type, "uspres") == 0) 156551034c06Sbostic return (year % 4) == 0; 156651034c06Sbostic if (strcmp(type, "nonpres") == 0) 156751034c06Sbostic return (year % 4) != 0; 156851034c06Sbostic (void) sprintf(buf, "yearistype %d %s", year, type); 156951034c06Sbostic result = system(buf); 157051034c06Sbostic if (result == 0) 157151034c06Sbostic return TRUE; 157251034c06Sbostic if (result == (1 << 8)) 157351034c06Sbostic return FALSE; 157451034c06Sbostic error("Wild result from command execution"); 157551034c06Sbostic (void) fprintf(stderr, "%s: command was '%s', result was %d\n", 157651034c06Sbostic progname, buf, result); 157751034c06Sbostic for ( ; ; ) 157851034c06Sbostic (void) exit(EXIT_FAILURE); 157951034c06Sbostic } 158051034c06Sbostic 158151034c06Sbostic static int 158251034c06Sbostic lowerit(a) 158351034c06Sbostic const int a; 158451034c06Sbostic { 158551034c06Sbostic return (isascii(a) && isupper(a)) ? tolower(a) : a; 158651034c06Sbostic } 158751034c06Sbostic 158851034c06Sbostic static int 158951034c06Sbostic ciequal(ap, bp) /* case-insensitive equality */ 159051034c06Sbostic register const char * ap; 159151034c06Sbostic register const char * bp; 159251034c06Sbostic { 159351034c06Sbostic while (lowerit(*ap) == lowerit(*bp++)) 159451034c06Sbostic if (*ap++ == '\0') 159551034c06Sbostic return TRUE; 159651034c06Sbostic return FALSE; 159751034c06Sbostic } 159851034c06Sbostic 159951034c06Sbostic static int 160051034c06Sbostic itsabbr(abbr, word) 160151034c06Sbostic register const char * abbr; 160251034c06Sbostic register const char * word; 160351034c06Sbostic { 160451034c06Sbostic if (lowerit(*abbr) != lowerit(*word)) 160551034c06Sbostic return FALSE; 160651034c06Sbostic ++word; 160751034c06Sbostic while (*++abbr != '\0') 160851034c06Sbostic do if (*word == '\0') 160951034c06Sbostic return FALSE; 161051034c06Sbostic while (lowerit(*word++) != lowerit(*abbr)); 161151034c06Sbostic return TRUE; 161251034c06Sbostic } 161351034c06Sbostic 161451034c06Sbostic static const struct lookup * 161551034c06Sbostic byword(word, table) 161651034c06Sbostic register const char * const word; 161751034c06Sbostic register const struct lookup * const table; 161851034c06Sbostic { 161951034c06Sbostic register const struct lookup * foundlp; 162051034c06Sbostic register const struct lookup * lp; 162151034c06Sbostic 162251034c06Sbostic if (word == NULL || table == NULL) 162351034c06Sbostic return NULL; 162451034c06Sbostic /* 162551034c06Sbostic ** Look for exact match. 162651034c06Sbostic */ 162751034c06Sbostic for (lp = table; lp->l_word != NULL; ++lp) 162851034c06Sbostic if (ciequal(word, lp->l_word)) 162951034c06Sbostic return lp; 163051034c06Sbostic /* 163151034c06Sbostic ** Look for inexact match. 163251034c06Sbostic */ 163351034c06Sbostic foundlp = NULL; 163451034c06Sbostic for (lp = table; lp->l_word != NULL; ++lp) 163551034c06Sbostic if (itsabbr(word, lp->l_word)) 163651034c06Sbostic if (foundlp == NULL) 163751034c06Sbostic foundlp = lp; 163851034c06Sbostic else return NULL; /* multiple inexact matches */ 163951034c06Sbostic return foundlp; 164051034c06Sbostic } 164151034c06Sbostic 164251034c06Sbostic static char ** 164351034c06Sbostic getfields(cp) 164451034c06Sbostic register char * cp; 164551034c06Sbostic { 164651034c06Sbostic register char * dp; 164751034c06Sbostic register char ** array; 164851034c06Sbostic register int nsubs; 164951034c06Sbostic 165051034c06Sbostic if (cp == NULL) 165151034c06Sbostic return NULL; 165251034c06Sbostic array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array)); 165351034c06Sbostic nsubs = 0; 165451034c06Sbostic for ( ; ; ) { 165551034c06Sbostic while (isascii(*cp) && isspace(*cp)) 165651034c06Sbostic ++cp; 165751034c06Sbostic if (*cp == '\0' || *cp == '#') 165851034c06Sbostic break; 165951034c06Sbostic array[nsubs++] = dp = cp; 166051034c06Sbostic do { 166151034c06Sbostic if ((*dp = *cp++) != '"') 166251034c06Sbostic ++dp; 166351034c06Sbostic else while ((*dp = *cp++) != '"') 166451034c06Sbostic if (*dp != '\0') 166551034c06Sbostic ++dp; 166651034c06Sbostic else error("Odd number of quotation marks"); 166751034c06Sbostic } while (*cp != '\0' && *cp != '#' && 166851034c06Sbostic (!isascii(*cp) || !isspace(*cp))); 166951034c06Sbostic if (isascii(*cp) && isspace(*cp)) 167051034c06Sbostic ++cp; 167151034c06Sbostic *dp = '\0'; 167251034c06Sbostic } 167351034c06Sbostic array[nsubs] = NULL; 167451034c06Sbostic return array; 167551034c06Sbostic } 167651034c06Sbostic 167751034c06Sbostic static long 167851034c06Sbostic oadd(t1, t2) 167951034c06Sbostic const long t1; 168051034c06Sbostic const long t2; 168151034c06Sbostic { 168251034c06Sbostic register long t; 168351034c06Sbostic 168451034c06Sbostic t = t1 + t2; 168551034c06Sbostic if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { 168651034c06Sbostic error("time overflow"); 168751034c06Sbostic (void) exit(EXIT_FAILURE); 168851034c06Sbostic } 168951034c06Sbostic return t; 169051034c06Sbostic } 169151034c06Sbostic 169251034c06Sbostic static time_t 169351034c06Sbostic tadd(t1, t2) 169451034c06Sbostic const time_t t1; 169551034c06Sbostic const long t2; 169651034c06Sbostic { 169751034c06Sbostic register time_t t; 169851034c06Sbostic 169951034c06Sbostic if (t1 == max_time && t2 > 0) 170051034c06Sbostic return max_time; 170151034c06Sbostic if (t1 == min_time && t2 < 0) 170251034c06Sbostic return min_time; 170351034c06Sbostic t = t1 + t2; 170451034c06Sbostic if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { 170551034c06Sbostic error("time overflow"); 170651034c06Sbostic (void) exit(EXIT_FAILURE); 170751034c06Sbostic } 170851034c06Sbostic return t; 170951034c06Sbostic } 171051034c06Sbostic 171151034c06Sbostic /* 171251034c06Sbostic ** Given a rule, and a year, compute the date - in seconds since January 1, 171351034c06Sbostic ** 1970, 00:00 LOCAL time - in that year that the rule refers to. 171451034c06Sbostic */ 171551034c06Sbostic 171651034c06Sbostic static time_t 171751034c06Sbostic rpytime(rp, wantedy) 171851034c06Sbostic register const struct rule * const rp; 171951034c06Sbostic register const int wantedy; 172051034c06Sbostic { 172151034c06Sbostic register int y, m, i; 172251034c06Sbostic register long dayoff; /* with a nod to Margaret O. */ 172351034c06Sbostic register time_t t; 172451034c06Sbostic 172551034c06Sbostic dayoff = 0; 172651034c06Sbostic m = TM_JANUARY; 172751034c06Sbostic y = EPOCH_YEAR; 172851034c06Sbostic while (wantedy != y) { 172951034c06Sbostic if (wantedy > y) { 173051034c06Sbostic i = len_years[isleap(y)]; 173151034c06Sbostic ++y; 173251034c06Sbostic } else { 173351034c06Sbostic --y; 173451034c06Sbostic i = -len_years[isleap(y)]; 173551034c06Sbostic } 173651034c06Sbostic dayoff = oadd(dayoff, eitol(i)); 173751034c06Sbostic } 173851034c06Sbostic while (m != rp->r_month) { 173951034c06Sbostic i = len_months[isleap(y)][m]; 174051034c06Sbostic dayoff = oadd(dayoff, eitol(i)); 174151034c06Sbostic ++m; 174251034c06Sbostic } 174351034c06Sbostic i = rp->r_dayofmonth; 174451034c06Sbostic if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 174551034c06Sbostic if (rp->r_dycode == DC_DOWLEQ) 174651034c06Sbostic --i; 174751034c06Sbostic else { 174851034c06Sbostic error("use of 2/29 in non leap-year"); 174951034c06Sbostic (void) exit(EXIT_FAILURE); 175051034c06Sbostic } 175151034c06Sbostic } 175251034c06Sbostic --i; 175351034c06Sbostic dayoff = oadd(dayoff, eitol(i)); 175451034c06Sbostic if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 175551034c06Sbostic register long wday; 175651034c06Sbostic 175751034c06Sbostic #define LDAYSPERWEEK ((long) DAYSPERWEEK) 175851034c06Sbostic wday = eitol(EPOCH_WDAY); 175951034c06Sbostic /* 176051034c06Sbostic ** Don't trust mod of negative numbers. 176151034c06Sbostic */ 176251034c06Sbostic if (dayoff >= 0) 176351034c06Sbostic wday = (wday + dayoff) % LDAYSPERWEEK; 176451034c06Sbostic else { 176551034c06Sbostic wday -= ((-dayoff) % LDAYSPERWEEK); 176651034c06Sbostic if (wday < 0) 176751034c06Sbostic wday += LDAYSPERWEEK; 176851034c06Sbostic } 176951034c06Sbostic while (wday != eitol(rp->r_wday)) 177051034c06Sbostic if (rp->r_dycode == DC_DOWGEQ) { 177151034c06Sbostic dayoff = oadd(dayoff, (long) 1); 177251034c06Sbostic if (++wday >= LDAYSPERWEEK) 177351034c06Sbostic wday = 0; 177451034c06Sbostic ++i; 177551034c06Sbostic } else { 177651034c06Sbostic dayoff = oadd(dayoff, (long) -1); 177751034c06Sbostic if (--wday < 0) 1778*3044ec37Sbostic wday = LDAYSPERWEEK - 1; 177951034c06Sbostic --i; 178051034c06Sbostic } 178151034c06Sbostic if (i < 0 || i >= len_months[isleap(y)][m]) { 178251034c06Sbostic error("no day in month matches rule"); 178351034c06Sbostic (void) exit(EXIT_FAILURE); 178451034c06Sbostic } 178551034c06Sbostic } 178651034c06Sbostic if (dayoff < 0 && !tt_signed) { 178751034c06Sbostic if (wantedy == rp->r_loyear) 178851034c06Sbostic return min_time; 178951034c06Sbostic error("time before zero"); 179051034c06Sbostic (void) exit(EXIT_FAILURE); 179151034c06Sbostic } 179251034c06Sbostic t = (time_t) dayoff * SECSPERDAY; 179351034c06Sbostic /* 179451034c06Sbostic ** Cheap overflow check. 179551034c06Sbostic */ 179651034c06Sbostic if (t / SECSPERDAY != dayoff) { 179751034c06Sbostic if (wantedy == rp->r_hiyear) 179851034c06Sbostic return max_time; 179951034c06Sbostic if (wantedy == rp->r_loyear) 180051034c06Sbostic return min_time; 180151034c06Sbostic error("time overflow"); 180251034c06Sbostic (void) exit(EXIT_FAILURE); 180351034c06Sbostic } 180451034c06Sbostic return tadd(t, rp->r_tod); 180551034c06Sbostic } 180651034c06Sbostic 180751034c06Sbostic static void 180851034c06Sbostic newabbr(string) 180951034c06Sbostic const char * const string; 181051034c06Sbostic { 181151034c06Sbostic register int i; 181251034c06Sbostic 181351034c06Sbostic i = strlen(string) + 1; 181451034c06Sbostic if (charcnt + i >= TZ_MAX_CHARS) { 181551034c06Sbostic error("too many, or too long, time zone abbreviations"); 181651034c06Sbostic (void) exit(EXIT_FAILURE); 181751034c06Sbostic } 181851034c06Sbostic (void) strcpy(&chars[charcnt], string); 181951034c06Sbostic charcnt += eitol(i); 182051034c06Sbostic } 182151034c06Sbostic 182251034c06Sbostic static int 182351034c06Sbostic mkdirs(name) 182451034c06Sbostic char * const name; 182551034c06Sbostic { 182651034c06Sbostic register char * cp; 182751034c06Sbostic 182851034c06Sbostic if ((cp = name) == NULL || *cp == '\0') 182951034c06Sbostic return 0; 183051034c06Sbostic while ((cp = strchr(cp + 1, '/')) != 0) { 183151034c06Sbostic *cp = '\0'; 183251034c06Sbostic if (!itsdir(name)) { 183351034c06Sbostic /* 183451034c06Sbostic ** It doesn't seem to exist, so we try to create it. 183551034c06Sbostic */ 18366068c877Sbostic if (mkdir(name, 0755) != 0) { 183751034c06Sbostic (void) fprintf(stderr, 183851034c06Sbostic "%s: Can't create directory ", 183951034c06Sbostic progname); 184051034c06Sbostic (void) perror(name); 184151034c06Sbostic return -1; 184251034c06Sbostic } 184351034c06Sbostic } 184451034c06Sbostic *cp = '/'; 184551034c06Sbostic } 184651034c06Sbostic return 0; 184751034c06Sbostic } 184851034c06Sbostic 184951034c06Sbostic static long 185051034c06Sbostic eitol(i) 185151034c06Sbostic const int i; 185251034c06Sbostic { 185351034c06Sbostic long l; 185451034c06Sbostic 185551034c06Sbostic l = i; 185651034c06Sbostic if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) { 185751034c06Sbostic (void) fprintf(stderr, "%s: %d did not sign extend correctly\n", 185851034c06Sbostic progname, i); 185951034c06Sbostic (void) exit(EXIT_FAILURE); 186051034c06Sbostic } 186151034c06Sbostic return l; 186251034c06Sbostic } 186351034c06Sbostic 186451034c06Sbostic /* 186551034c06Sbostic ** UNIX is a registered trademark of AT&T. 186651034c06Sbostic */ 1867