17c478bd9Sstevel@tonic-gate /* 2*a68d064cSrobbin * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 380868c53Srobbin * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 67c478bd9Sstevel@tonic-gate 7*a68d064cSrobbin static char elsieid[] = "@(#)zic.c 7.128.1"; 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* 107c478bd9Sstevel@tonic-gate * #define LEAPSECOND_SUPPORT 117c478bd9Sstevel@tonic-gate */ 127c478bd9Sstevel@tonic-gate 1380868c53Srobbin /* 1480868c53Srobbin * Regardless of the type of time_t, we do our work using this type. 1580868c53Srobbin */ 1680868c53Srobbin 1780868c53Srobbin typedef int zic_t; 1880868c53Srobbin 197c478bd9Sstevel@tonic-gate #include "private.h" 207c478bd9Sstevel@tonic-gate #include <tzfile.h> /* this is in system headers at Sun */ 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate #include <sys/stat.h> /* for umask manifest constants */ 237c478bd9Sstevel@tonic-gate #include <ctype.h> 247c478bd9Sstevel@tonic-gate #include <locale.h> 257c478bd9Sstevel@tonic-gate #include <stdlib.h> /* for getopt */ 267c478bd9Sstevel@tonic-gate 2780868c53Srobbin #ifndef ZIC_MAX_ABBR_LEN_WO_WARN 2880868c53Srobbin #define ZIC_MAX_ABBR_LEN_WO_WARN 6 2980868c53Srobbin #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */ 3080868c53Srobbin 3180868c53Srobbin #ifdef S_IRUSR 3280868c53Srobbin #define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 3380868c53Srobbin #else 3480868c53Srobbin #define MKDIR_UMASK 0755 3580868c53Srobbin #endif 3680868c53Srobbin 377c478bd9Sstevel@tonic-gate struct rule { 387c478bd9Sstevel@tonic-gate const char *r_filename; 397c478bd9Sstevel@tonic-gate int r_linenum; 407c478bd9Sstevel@tonic-gate const char *r_name; 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate int r_loyear; /* for example, 1986 */ 437c478bd9Sstevel@tonic-gate int r_hiyear; /* for example, 1986 */ 447c478bd9Sstevel@tonic-gate const char *r_yrtype; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate int r_month; /* 0..11 */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate int r_dycode; /* see below */ 497c478bd9Sstevel@tonic-gate int r_dayofmonth; 507c478bd9Sstevel@tonic-gate int r_wday; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate long r_tod; /* time from midnight */ 537c478bd9Sstevel@tonic-gate int r_todisstd; /* above is standard time if TRUE */ 547c478bd9Sstevel@tonic-gate /* or wall clock time if FALSE */ 557c478bd9Sstevel@tonic-gate int r_todisgmt; /* above is GMT if TRUE */ 567c478bd9Sstevel@tonic-gate /* or local time if FALSE */ 577c478bd9Sstevel@tonic-gate long r_stdoff; /* offset from standard time */ 587c478bd9Sstevel@tonic-gate const char *r_abbrvar; /* variable part of abbreviation */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate int r_todo; /* a rule to do (used in outzone) */ 6180868c53Srobbin zic_t r_temp; /* used in outzone */ 627c478bd9Sstevel@tonic-gate }; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * r_dycode r_dayofmonth r_wday 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #define DC_DOM 0 /* 1..31 */ /* unused */ 697c478bd9Sstevel@tonic-gate #define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ 707c478bd9Sstevel@tonic-gate #define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate struct zone { 737c478bd9Sstevel@tonic-gate const char *z_filename; 747c478bd9Sstevel@tonic-gate int z_linenum; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate const char *z_name; 777c478bd9Sstevel@tonic-gate long z_gmtoff; 787c478bd9Sstevel@tonic-gate const char *z_rule; 797c478bd9Sstevel@tonic-gate const char *z_format; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate long z_stdoff; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate struct rule *z_rules; 847c478bd9Sstevel@tonic-gate int z_nrules; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate struct rule z_untilrule; 8780868c53Srobbin zic_t z_untiltime; 887c478bd9Sstevel@tonic-gate }; 897c478bd9Sstevel@tonic-gate 9080868c53Srobbin static void addtt(zic_t starttime, int type); 917c478bd9Sstevel@tonic-gate static int addtype(long gmtoff, const char *abbr, int isdst, 927c478bd9Sstevel@tonic-gate int ttisstd, int ttisgmt); 937c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 9480868c53Srobbin static void leapadd(zic_t t, int positive, int rolling, int count); 957c478bd9Sstevel@tonic-gate static void adjleap(void); 967c478bd9Sstevel@tonic-gate #endif 977c478bd9Sstevel@tonic-gate static void associate(void); 987c478bd9Sstevel@tonic-gate static int ciequal(const char *ap, const char *bp); 997c478bd9Sstevel@tonic-gate static void convert(long val, char *buf); 100*a68d064cSrobbin static void dolink(const char *fromfield, const char *tofield); 1017c478bd9Sstevel@tonic-gate static void doabbr(char *abbr, const char *format, 1027c478bd9Sstevel@tonic-gate const char *letters, int isdst); 1037c478bd9Sstevel@tonic-gate static void eat(const char *name, int num); 1047c478bd9Sstevel@tonic-gate static void eats(const char *name, int num, 1057c478bd9Sstevel@tonic-gate const char *rname, int rnum); 1067c478bd9Sstevel@tonic-gate static long eitol(int i); 1077c478bd9Sstevel@tonic-gate static void error(const char *message); 1087c478bd9Sstevel@tonic-gate static char **getfields(char *buf); 1097c478bd9Sstevel@tonic-gate static long gethms(const char *string, const char *errstrng, int signable); 1107c478bd9Sstevel@tonic-gate static void infile(const char *filename); 1117c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 1127c478bd9Sstevel@tonic-gate static void inleap(char **fields, int nfields); 1137c478bd9Sstevel@tonic-gate #endif 1147c478bd9Sstevel@tonic-gate static void inlink(char **fields, int nfields); 1157c478bd9Sstevel@tonic-gate static void inrule(char **fields, int nfields); 1167c478bd9Sstevel@tonic-gate static int inzcont(char **fields, int nfields); 1177c478bd9Sstevel@tonic-gate static int inzone(char **fields, int nfields); 1187c478bd9Sstevel@tonic-gate static int inzsub(char **fields, int nfields, int iscont); 1197c478bd9Sstevel@tonic-gate static int itsabbr(const char *abbr, const char *word); 1207c478bd9Sstevel@tonic-gate static int itsdir(const char *name); 1217c478bd9Sstevel@tonic-gate static int lowerit(int c); 1227c478bd9Sstevel@tonic-gate static char *memcheck(char *tocheck); 1237c478bd9Sstevel@tonic-gate static int mkdirs(char *filename); 1247c478bd9Sstevel@tonic-gate static void newabbr(const char *abbr); 1257c478bd9Sstevel@tonic-gate static long oadd(long t1, long t2); 1267c478bd9Sstevel@tonic-gate static void outzone(const struct zone *zp, int ntzones); 1277c478bd9Sstevel@tonic-gate static void puttzcode(long code, FILE *fp); 1287c478bd9Sstevel@tonic-gate static int rcomp(const void *leftp, const void *rightp); 12980868c53Srobbin static zic_t rpytime(const struct rule *rp, int wantedy); 1307c478bd9Sstevel@tonic-gate static void rulesub(struct rule *rp, 1317c478bd9Sstevel@tonic-gate const char *loyearp, const char *hiyearp, 1327c478bd9Sstevel@tonic-gate const char *typep, const char *monthp, 1337c478bd9Sstevel@tonic-gate const char *dayp, const char *timep); 1347c478bd9Sstevel@tonic-gate static void setboundaries(void); 13580868c53Srobbin static zic_t tadd(zic_t t1, long t2); 1367c478bd9Sstevel@tonic-gate static void usage(void); 1377c478bd9Sstevel@tonic-gate static void writezone(const char *name); 1387c478bd9Sstevel@tonic-gate static int yearistype(int year, const char *type); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate static int charcnt; 1417c478bd9Sstevel@tonic-gate static int errors; 1427c478bd9Sstevel@tonic-gate static const char *filename; 1437c478bd9Sstevel@tonic-gate static int leapcnt; 1447c478bd9Sstevel@tonic-gate static int linenum; 14580868c53Srobbin static zic_t max_time; 1467c478bd9Sstevel@tonic-gate static int max_year; 1477c478bd9Sstevel@tonic-gate static int max_year_representable; 14880868c53Srobbin static zic_t min_time; 1497c478bd9Sstevel@tonic-gate static int min_year; 1507c478bd9Sstevel@tonic-gate static int min_year_representable; 1517c478bd9Sstevel@tonic-gate static int noise; 1527c478bd9Sstevel@tonic-gate static const char *rfilename; 1537c478bd9Sstevel@tonic-gate static int rlinenum; 1547c478bd9Sstevel@tonic-gate static const char *progname; 1557c478bd9Sstevel@tonic-gate static int timecnt; 1567c478bd9Sstevel@tonic-gate static int typecnt; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Line codes. 1607c478bd9Sstevel@tonic-gate */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate #define LC_RULE 0 1637c478bd9Sstevel@tonic-gate #define LC_ZONE 1 1647c478bd9Sstevel@tonic-gate #define LC_LINK 2 1657c478bd9Sstevel@tonic-gate #define LC_LEAP 3 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Which fields are which on a Zone line. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate #define ZF_NAME 1 1727c478bd9Sstevel@tonic-gate #define ZF_GMTOFF 2 1737c478bd9Sstevel@tonic-gate #define ZF_RULE 3 1747c478bd9Sstevel@tonic-gate #define ZF_FORMAT 4 1757c478bd9Sstevel@tonic-gate #define ZF_TILYEAR 5 1767c478bd9Sstevel@tonic-gate #define ZF_TILMONTH 6 1777c478bd9Sstevel@tonic-gate #define ZF_TILDAY 7 1787c478bd9Sstevel@tonic-gate #define ZF_TILTIME 8 1797c478bd9Sstevel@tonic-gate #define ZONE_MINFIELDS 5 1807c478bd9Sstevel@tonic-gate #define ZONE_MAXFIELDS 9 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * Which fields are which on a Zone continuation line. 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate #define ZFC_GMTOFF 0 1877c478bd9Sstevel@tonic-gate #define ZFC_RULE 1 1887c478bd9Sstevel@tonic-gate #define ZFC_FORMAT 2 1897c478bd9Sstevel@tonic-gate #define ZFC_TILYEAR 3 1907c478bd9Sstevel@tonic-gate #define ZFC_TILMONTH 4 1917c478bd9Sstevel@tonic-gate #define ZFC_TILDAY 5 1927c478bd9Sstevel@tonic-gate #define ZFC_TILTIME 6 1937c478bd9Sstevel@tonic-gate #define ZONEC_MINFIELDS 3 1947c478bd9Sstevel@tonic-gate #define ZONEC_MAXFIELDS 7 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Which files are which on a Rule line. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate #define RF_NAME 1 2017c478bd9Sstevel@tonic-gate #define RF_LOYEAR 2 2027c478bd9Sstevel@tonic-gate #define RF_HIYEAR 3 2037c478bd9Sstevel@tonic-gate #define RF_COMMAND 4 2047c478bd9Sstevel@tonic-gate #define RF_MONTH 5 2057c478bd9Sstevel@tonic-gate #define RF_DAY 6 2067c478bd9Sstevel@tonic-gate #define RF_TOD 7 2077c478bd9Sstevel@tonic-gate #define RF_STDOFF 8 2087c478bd9Sstevel@tonic-gate #define RF_ABBRVAR 9 2097c478bd9Sstevel@tonic-gate #define RULE_FIELDS 10 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Which fields are which on a Link line. 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate #define LF_FROM 1 2167c478bd9Sstevel@tonic-gate #define LF_TO 2 2177c478bd9Sstevel@tonic-gate #define LINK_FIELDS 3 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Which fields are which on a Leap line. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate #define LP_YEAR 1 2247c478bd9Sstevel@tonic-gate #define LP_MONTH 2 2257c478bd9Sstevel@tonic-gate #define LP_DAY 3 2267c478bd9Sstevel@tonic-gate #define LP_TIME 4 2277c478bd9Sstevel@tonic-gate #define LP_CORR 5 2287c478bd9Sstevel@tonic-gate #define LP_ROLL 6 2297c478bd9Sstevel@tonic-gate #define LEAP_FIELDS 7 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * Year synonyms. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate #define YR_MINIMUM 0 2367c478bd9Sstevel@tonic-gate #define YR_MAXIMUM 1 2377c478bd9Sstevel@tonic-gate #define YR_ONLY 2 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static struct rule *rules; 2407c478bd9Sstevel@tonic-gate static int nrules; /* number of rules */ 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate static struct zone *zones; 2437c478bd9Sstevel@tonic-gate static int nzones; /* number of zones */ 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate struct link { 2467c478bd9Sstevel@tonic-gate const char *l_filename; 2477c478bd9Sstevel@tonic-gate int l_linenum; 2487c478bd9Sstevel@tonic-gate const char *l_from; 2497c478bd9Sstevel@tonic-gate const char *l_to; 2507c478bd9Sstevel@tonic-gate }; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate static struct link *links; 2537c478bd9Sstevel@tonic-gate static int nlinks; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate struct lookup { 2567c478bd9Sstevel@tonic-gate const char *l_word; 2577c478bd9Sstevel@tonic-gate const int l_value; 2587c478bd9Sstevel@tonic-gate }; 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static struct lookup const *byword(const char *string, 2617c478bd9Sstevel@tonic-gate const struct lookup *lp); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static struct lookup const line_codes[] = { 2647c478bd9Sstevel@tonic-gate { "Rule", LC_RULE }, 2657c478bd9Sstevel@tonic-gate { "Zone", LC_ZONE }, 2667c478bd9Sstevel@tonic-gate { "Link", LC_LINK }, 2677c478bd9Sstevel@tonic-gate { "Leap", LC_LEAP }, 2687c478bd9Sstevel@tonic-gate { NULL, 0} 2697c478bd9Sstevel@tonic-gate }; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate static struct lookup const mon_names[] = { 2727c478bd9Sstevel@tonic-gate { "January", TM_JANUARY }, 2737c478bd9Sstevel@tonic-gate { "February", TM_FEBRUARY }, 2747c478bd9Sstevel@tonic-gate { "March", TM_MARCH }, 2757c478bd9Sstevel@tonic-gate { "April", TM_APRIL }, 2767c478bd9Sstevel@tonic-gate { "May", TM_MAY }, 2777c478bd9Sstevel@tonic-gate { "June", TM_JUNE }, 2787c478bd9Sstevel@tonic-gate { "July", TM_JULY }, 2797c478bd9Sstevel@tonic-gate { "August", TM_AUGUST }, 2807c478bd9Sstevel@tonic-gate { "September", TM_SEPTEMBER }, 2817c478bd9Sstevel@tonic-gate { "October", TM_OCTOBER }, 2827c478bd9Sstevel@tonic-gate { "November", TM_NOVEMBER }, 2837c478bd9Sstevel@tonic-gate { "December", TM_DECEMBER }, 2847c478bd9Sstevel@tonic-gate { NULL, 0 } 2857c478bd9Sstevel@tonic-gate }; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate static struct lookup const wday_names[] = { 2887c478bd9Sstevel@tonic-gate { "Sunday", TM_SUNDAY }, 2897c478bd9Sstevel@tonic-gate { "Monday", TM_MONDAY }, 2907c478bd9Sstevel@tonic-gate { "Tuesday", TM_TUESDAY }, 2917c478bd9Sstevel@tonic-gate { "Wednesday", TM_WEDNESDAY }, 2927c478bd9Sstevel@tonic-gate { "Thursday", TM_THURSDAY }, 2937c478bd9Sstevel@tonic-gate { "Friday", TM_FRIDAY }, 2947c478bd9Sstevel@tonic-gate { "Saturday", TM_SATURDAY }, 2957c478bd9Sstevel@tonic-gate { NULL, 0 } 2967c478bd9Sstevel@tonic-gate }; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate static struct lookup const lasts[] = { 2997c478bd9Sstevel@tonic-gate { "last-Sunday", TM_SUNDAY }, 3007c478bd9Sstevel@tonic-gate { "last-Monday", TM_MONDAY }, 3017c478bd9Sstevel@tonic-gate { "last-Tuesday", TM_TUESDAY }, 3027c478bd9Sstevel@tonic-gate { "last-Wednesday", TM_WEDNESDAY }, 3037c478bd9Sstevel@tonic-gate { "last-Thursday", TM_THURSDAY }, 3047c478bd9Sstevel@tonic-gate { "last-Friday", TM_FRIDAY }, 3057c478bd9Sstevel@tonic-gate { "last-Saturday", TM_SATURDAY }, 3067c478bd9Sstevel@tonic-gate { NULL, 0 } 3077c478bd9Sstevel@tonic-gate }; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate static struct lookup const begin_years[] = { 3107c478bd9Sstevel@tonic-gate { "minimum", YR_MINIMUM }, 3117c478bd9Sstevel@tonic-gate { "maximum", YR_MAXIMUM }, 3127c478bd9Sstevel@tonic-gate { NULL, 0 } 3137c478bd9Sstevel@tonic-gate }; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static struct lookup const end_years[] = { 3167c478bd9Sstevel@tonic-gate { "minimum", YR_MINIMUM }, 3177c478bd9Sstevel@tonic-gate { "maximum", YR_MAXIMUM }, 3187c478bd9Sstevel@tonic-gate { "only", YR_ONLY }, 3197c478bd9Sstevel@tonic-gate { NULL, 0 } 3207c478bd9Sstevel@tonic-gate }; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate static struct lookup const leap_types[] = { 3237c478bd9Sstevel@tonic-gate { "Rolling", TRUE }, 3247c478bd9Sstevel@tonic-gate { "Stationary", FALSE }, 3257c478bd9Sstevel@tonic-gate { NULL, 0 } 3267c478bd9Sstevel@tonic-gate }; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate static const int len_months[2][MONSPERYEAR] = { 3297c478bd9Sstevel@tonic-gate { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 3307c478bd9Sstevel@tonic-gate { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 3317c478bd9Sstevel@tonic-gate }; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate static const int len_years[2] = { 3347c478bd9Sstevel@tonic-gate DAYSPERNYEAR, DAYSPERLYEAR 3357c478bd9Sstevel@tonic-gate }; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate static struct attype { 33880868c53Srobbin zic_t at; 3397c478bd9Sstevel@tonic-gate unsigned char type; 3407c478bd9Sstevel@tonic-gate } attypes[TZ_MAX_TIMES]; 3417c478bd9Sstevel@tonic-gate static long gmtoffs[TZ_MAX_TYPES]; 3427c478bd9Sstevel@tonic-gate static char isdsts[TZ_MAX_TYPES]; 3437c478bd9Sstevel@tonic-gate static unsigned char abbrinds[TZ_MAX_TYPES]; 3447c478bd9Sstevel@tonic-gate static char ttisstds[TZ_MAX_TYPES]; 3457c478bd9Sstevel@tonic-gate static char ttisgmts[TZ_MAX_TYPES]; 3467c478bd9Sstevel@tonic-gate static char chars[TZ_MAX_CHARS]; 34780868c53Srobbin static zic_t trans[TZ_MAX_LEAPS]; 3487c478bd9Sstevel@tonic-gate static long corr[TZ_MAX_LEAPS]; 3497c478bd9Sstevel@tonic-gate static char roll[TZ_MAX_LEAPS]; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Memory allocation. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate static char * 3567c478bd9Sstevel@tonic-gate memcheck(ptr) 3577c478bd9Sstevel@tonic-gate char * const ptr; 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate if (ptr == NULL) { 3607c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 3617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Memory exhausted: %s\n"), 3627c478bd9Sstevel@tonic-gate progname, e); 36380868c53Srobbin exit(EXIT_FAILURE); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate return (ptr); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate #define emalloc(size) memcheck(imalloc(size)) 3697c478bd9Sstevel@tonic-gate #define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) 3707c478bd9Sstevel@tonic-gate #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) 3717c478bd9Sstevel@tonic-gate #define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * Error handling. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate static void 3787c478bd9Sstevel@tonic-gate eats(name, num, rname, rnum) 3797c478bd9Sstevel@tonic-gate const char * const name; 3807c478bd9Sstevel@tonic-gate const int num; 3817c478bd9Sstevel@tonic-gate const char * const rname; 3827c478bd9Sstevel@tonic-gate const int rnum; 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate filename = name; 3857c478bd9Sstevel@tonic-gate linenum = num; 3867c478bd9Sstevel@tonic-gate rfilename = rname; 3877c478bd9Sstevel@tonic-gate rlinenum = rnum; 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate static void 3917c478bd9Sstevel@tonic-gate eat(name, num) 3927c478bd9Sstevel@tonic-gate const char * const name; 3937c478bd9Sstevel@tonic-gate const int num; 3947c478bd9Sstevel@tonic-gate { 3957c478bd9Sstevel@tonic-gate eats(name, num, (char *)NULL, -1); 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate static void 3997c478bd9Sstevel@tonic-gate error(string) 4007c478bd9Sstevel@tonic-gate const char * const string; 4017c478bd9Sstevel@tonic-gate { 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * Match the format of "cc" to allow sh users to 4047c478bd9Sstevel@tonic-gate * zic ... 2>&1 | error -t "*" -v 4057c478bd9Sstevel@tonic-gate * on BSD systems. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\"%s\", line %d: %s"), 4087c478bd9Sstevel@tonic-gate filename, linenum, string); 4097c478bd9Sstevel@tonic-gate if (rfilename != NULL) 4107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(" (rule from \"%s\", line %d)"), 4117c478bd9Sstevel@tonic-gate rfilename, rlinenum); 4127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 4137c478bd9Sstevel@tonic-gate ++errors; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate static void 4177c478bd9Sstevel@tonic-gate warning(string) 4187c478bd9Sstevel@tonic-gate const char * const string; 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate char *cp; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate cp = ecpyalloc(gettext("warning: ")); 4237c478bd9Sstevel@tonic-gate cp = ecatalloc(cp, string); 4247c478bd9Sstevel@tonic-gate error(cp); 4257c478bd9Sstevel@tonic-gate ifree(cp); 4267c478bd9Sstevel@tonic-gate --errors; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate static void 4307c478bd9Sstevel@tonic-gate usage(void) 4317c478bd9Sstevel@tonic-gate { 4327c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 43380868c53Srobbin (void) fprintf(stderr, gettext("%s: usage is %s " 43480868c53Srobbin "[ --version ] [ -s ] [ -v ] [ -l localtime ] " 43580868c53Srobbin "\n\t[ -p posixrules ] [ -d directory ] [ -L leapseconds ] " 43680868c53Srobbin "[ -y yearistype ] [ filename ... ]\n"), progname, progname); 4377c478bd9Sstevel@tonic-gate #else /* ! LEAPSECOND_SUPPORT */ 43880868c53Srobbin (void) fprintf(stderr, gettext("%s: usage is %s " 43980868c53Srobbin "[ --version ] [ -s ] [ -v ] [ -l localtime ]" 44080868c53Srobbin "\n\t[ -p posixrules ] [ -d directory ] [ -y yearistype ] " 44180868c53Srobbin "[ filename ... ]\n"), progname, progname); 4427c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate static const char *psxrules; 4467c478bd9Sstevel@tonic-gate static const char *lcltime; 4477c478bd9Sstevel@tonic-gate static const char *directory; 4487c478bd9Sstevel@tonic-gate static const char *leapsec; 4497c478bd9Sstevel@tonic-gate static const char *yitcommand; 4507c478bd9Sstevel@tonic-gate static int sflag = FALSE; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate int 4537c478bd9Sstevel@tonic-gate main(argc, argv) 4547c478bd9Sstevel@tonic-gate int argc; 4557c478bd9Sstevel@tonic-gate char *argv[]; 4567c478bd9Sstevel@tonic-gate { 4577c478bd9Sstevel@tonic-gate register int i; 4587c478bd9Sstevel@tonic-gate register int j; 4597c478bd9Sstevel@tonic-gate register int c; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4647c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 4657c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 4667c478bd9Sstevel@tonic-gate #endif 4677c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate progname = argv[0]; 47080868c53Srobbin for (i = 1; i < argc; ++i) 47180868c53Srobbin if (strcmp(argv[i], "--version") == 0) { 47280868c53Srobbin (void) printf("%s\n", elsieid); 47380868c53Srobbin exit(EXIT_SUCCESS); 47480868c53Srobbin } 47580868c53Srobbin 4767c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 4777c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) 4787c478bd9Sstevel@tonic-gate #else 4797c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d:l:p:vsy:")) != EOF) 4807c478bd9Sstevel@tonic-gate #endif 4817c478bd9Sstevel@tonic-gate switch (c) { 4827c478bd9Sstevel@tonic-gate default: 4837c478bd9Sstevel@tonic-gate usage(); 4847c478bd9Sstevel@tonic-gate case 'd': 4857c478bd9Sstevel@tonic-gate if (directory == NULL) 4867c478bd9Sstevel@tonic-gate directory = optarg; 4877c478bd9Sstevel@tonic-gate else { 4887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4897c478bd9Sstevel@tonic-gate "%s: More than one -d option specified\n"), 4907c478bd9Sstevel@tonic-gate progname); 49180868c53Srobbin exit(EXIT_FAILURE); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate break; 4947c478bd9Sstevel@tonic-gate case 'l': 4957c478bd9Sstevel@tonic-gate if (lcltime == NULL) 4967c478bd9Sstevel@tonic-gate lcltime = optarg; 4977c478bd9Sstevel@tonic-gate else { 4987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 4997c478bd9Sstevel@tonic-gate "%s: More than one -l option specified\n"), 5007c478bd9Sstevel@tonic-gate progname); 50180868c53Srobbin exit(EXIT_FAILURE); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate case 'p': 5057c478bd9Sstevel@tonic-gate if (psxrules == NULL) 5067c478bd9Sstevel@tonic-gate psxrules = optarg; 5077c478bd9Sstevel@tonic-gate else { 5087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5097c478bd9Sstevel@tonic-gate "%s: More than one -p option specified\n"), 5107c478bd9Sstevel@tonic-gate progname); 51180868c53Srobbin exit(EXIT_FAILURE); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate break; 5147c478bd9Sstevel@tonic-gate case 'y': 5157c478bd9Sstevel@tonic-gate if (yitcommand == NULL) 5167c478bd9Sstevel@tonic-gate yitcommand = optarg; 5177c478bd9Sstevel@tonic-gate else { 5187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5197c478bd9Sstevel@tonic-gate "%s: More than one -y option specified\n"), 5207c478bd9Sstevel@tonic-gate progname); 52180868c53Srobbin exit(EXIT_FAILURE); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate break; 5247c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 5257c478bd9Sstevel@tonic-gate case 'L': 5267c478bd9Sstevel@tonic-gate if (leapsec == NULL) 5277c478bd9Sstevel@tonic-gate leapsec = optarg; 5287c478bd9Sstevel@tonic-gate else { 5297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5307c478bd9Sstevel@tonic-gate "%s: More than one -L option specified\n"), 5317c478bd9Sstevel@tonic-gate progname); 53280868c53Srobbin exit(EXIT_FAILURE); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate break; 5357c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 5367c478bd9Sstevel@tonic-gate case 'v': 5377c478bd9Sstevel@tonic-gate noise = TRUE; 5387c478bd9Sstevel@tonic-gate break; 5397c478bd9Sstevel@tonic-gate case 's': 5407c478bd9Sstevel@tonic-gate sflag = TRUE; 5417c478bd9Sstevel@tonic-gate break; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) 5447c478bd9Sstevel@tonic-gate usage(); /* usage message by request */ 5457c478bd9Sstevel@tonic-gate if (directory == NULL) 5467c478bd9Sstevel@tonic-gate directory = TZDIR; 5477c478bd9Sstevel@tonic-gate if (yitcommand == NULL) 5487c478bd9Sstevel@tonic-gate yitcommand = "yearistype"; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate setboundaries(); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 5537c478bd9Sstevel@tonic-gate if (optind < argc && leapsec != NULL) { 5547c478bd9Sstevel@tonic-gate infile(leapsec); 5557c478bd9Sstevel@tonic-gate adjleap(); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) 5607c478bd9Sstevel@tonic-gate infile(argv[i]); 5617c478bd9Sstevel@tonic-gate if (errors) 56280868c53Srobbin exit(EXIT_FAILURE); 5637c478bd9Sstevel@tonic-gate associate(); 5647c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; i = j) { 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * Find the next non-continuation zone entry. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) 5697c478bd9Sstevel@tonic-gate continue; 5707c478bd9Sstevel@tonic-gate outzone(&zones[i], j - i); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * Make links. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate for (i = 0; i < nlinks; ++i) { 5767c478bd9Sstevel@tonic-gate eat(links[i].l_filename, links[i].l_linenum); 5777c478bd9Sstevel@tonic-gate dolink(links[i].l_from, links[i].l_to); 57880868c53Srobbin if (noise) 57980868c53Srobbin for (j = 0; j < nlinks; ++j) 58080868c53Srobbin if (strcmp(links[i].l_to, links[j].l_from) == 0) 58180868c53Srobbin warning(gettext("link to link")); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate if (lcltime != NULL) { 5847c478bd9Sstevel@tonic-gate eat("command line", 1); 5857c478bd9Sstevel@tonic-gate dolink(lcltime, TZDEFAULT); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate if (psxrules != NULL) { 5887c478bd9Sstevel@tonic-gate eat("command line", 1); 5897c478bd9Sstevel@tonic-gate dolink(psxrules, TZDEFRULES); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate return ((errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate static void 595*a68d064cSrobbin dolink(fromfield, tofield) 596*a68d064cSrobbin const char * const fromfield; 597*a68d064cSrobbin const char * const tofield; 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate register char *fromname; 6007c478bd9Sstevel@tonic-gate register char *toname; 6017c478bd9Sstevel@tonic-gate 602*a68d064cSrobbin if (fromfield[0] == '/') 603*a68d064cSrobbin fromname = ecpyalloc(fromfield); 6047c478bd9Sstevel@tonic-gate else { 6057c478bd9Sstevel@tonic-gate fromname = ecpyalloc(directory); 6067c478bd9Sstevel@tonic-gate fromname = ecatalloc(fromname, "/"); 607*a68d064cSrobbin fromname = ecatalloc(fromname, fromfield); 6087c478bd9Sstevel@tonic-gate } 609*a68d064cSrobbin if (tofield[0] == '/') 610*a68d064cSrobbin toname = ecpyalloc(tofield); 6117c478bd9Sstevel@tonic-gate else { 6127c478bd9Sstevel@tonic-gate toname = ecpyalloc(directory); 6137c478bd9Sstevel@tonic-gate toname = ecatalloc(toname, "/"); 614*a68d064cSrobbin toname = ecatalloc(toname, tofield); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * We get to be careful here since 6187c478bd9Sstevel@tonic-gate * there's a fair chance of root running us. 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate if (!itsdir(toname)) 6217c478bd9Sstevel@tonic-gate (void) remove(toname); 6227c478bd9Sstevel@tonic-gate if (link(fromname, toname) != 0) { 6237c478bd9Sstevel@tonic-gate int result; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (mkdirs(toname) != 0) 62680868c53Srobbin exit(EXIT_FAILURE); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate result = link(fromname, toname); 6297c478bd9Sstevel@tonic-gate 63080868c53Srobbin if (result != 0 && access(fromname, F_OK) == 0 && 63180868c53Srobbin !itsdir(fromname)) { 632*a68d064cSrobbin const char *s = tofield; 6337c478bd9Sstevel@tonic-gate register char *symlinkcontents = NULL; 63480868c53Srobbin 6357c478bd9Sstevel@tonic-gate while ((s = strchr(s+1, '/')) != NULL) 6367c478bd9Sstevel@tonic-gate symlinkcontents = ecatalloc(symlinkcontents, 6377c478bd9Sstevel@tonic-gate "../"); 638*a68d064cSrobbin symlinkcontents = ecatalloc(symlinkcontents, fromname); 6397c478bd9Sstevel@tonic-gate result = symlink(symlinkcontents, toname); 6407c478bd9Sstevel@tonic-gate if (result == 0) 6417c478bd9Sstevel@tonic-gate warning(gettext( 6427c478bd9Sstevel@tonic-gate "hard link failed, symbolic link used")); 6437c478bd9Sstevel@tonic-gate ifree(symlinkcontents); 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (result != 0) { 6477c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6507c478bd9Sstevel@tonic-gate "%s: Can't link from %s to %s: %s\n"), 6517c478bd9Sstevel@tonic-gate progname, fromname, toname, e); 65280868c53Srobbin exit(EXIT_FAILURE); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate ifree(fromname); 6567c478bd9Sstevel@tonic-gate ifree(toname); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate #ifndef INT_MAX 6607c478bd9Sstevel@tonic-gate #define INT_MAX ((int)(((unsigned)~0)>>1)) 6617c478bd9Sstevel@tonic-gate #endif /* !defined INT_MAX */ 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate #ifndef INT_MIN 6647c478bd9Sstevel@tonic-gate #define INT_MIN ((int)~(((unsigned)~0)>>1)) 6657c478bd9Sstevel@tonic-gate #endif /* !defined INT_MIN */ 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * The tz file format currently allows at most 32-bit quantities. 6697c478bd9Sstevel@tonic-gate * This restriction should be removed before signed 32-bit values 6707c478bd9Sstevel@tonic-gate * wrap around in 2038, but unfortunately this will require a 6717c478bd9Sstevel@tonic-gate * change to the tz file format. 6727c478bd9Sstevel@tonic-gate */ 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate #define MAX_BITS_IN_FILE 32 6757c478bd9Sstevel@tonic-gate /* CSTYLED */ 67680868c53Srobbin #define TIME_T_BITS_IN_FILE ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \ 67780868c53Srobbin TYPE_BIT(zic_t): MAX_BITS_IN_FILE) 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate static void 6807c478bd9Sstevel@tonic-gate setboundaries(void) 6817c478bd9Sstevel@tonic-gate { 68280868c53Srobbin register int i; 68380868c53Srobbin 68480868c53Srobbin if (TYPE_SIGNED(zic_t)) { 68580868c53Srobbin min_time = -1; 68680868c53Srobbin for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) 68780868c53Srobbin min_time *= 2; 68880868c53Srobbin max_time = -(min_time + 1); 6897c478bd9Sstevel@tonic-gate if (sflag) 6907c478bd9Sstevel@tonic-gate min_time = 0; 6917c478bd9Sstevel@tonic-gate } else { 6927c478bd9Sstevel@tonic-gate min_time = 0; 6937c478bd9Sstevel@tonic-gate max_time = 2 - sflag; 69480868c53Srobbin for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i) 69580868c53Srobbin max_time *= 2; 6967c478bd9Sstevel@tonic-gate --max_time; 6977c478bd9Sstevel@tonic-gate } 69880868c53Srobbin { 69980868c53Srobbin time_t t; 70080868c53Srobbin 70180868c53Srobbin t = (time_t)min_time; 70280868c53Srobbin min_year = TM_YEAR_BASE + gmtime(&t)->tm_year; 70380868c53Srobbin t = (time_t)max_time; 70480868c53Srobbin max_year = TM_YEAR_BASE + gmtime(&t)->tm_year; 70580868c53Srobbin } 7067c478bd9Sstevel@tonic-gate min_year_representable = min_year; 7077c478bd9Sstevel@tonic-gate max_year_representable = max_year; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate static int 7117c478bd9Sstevel@tonic-gate itsdir(name) 7127c478bd9Sstevel@tonic-gate const char * const name; 7137c478bd9Sstevel@tonic-gate { 7147c478bd9Sstevel@tonic-gate register char *myname; 7157c478bd9Sstevel@tonic-gate register int accres; 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate myname = ecpyalloc(name); 7187c478bd9Sstevel@tonic-gate myname = ecatalloc(myname, "/."); 7197c478bd9Sstevel@tonic-gate accres = access(myname, F_OK); 7207c478bd9Sstevel@tonic-gate ifree(myname); 7217c478bd9Sstevel@tonic-gate return (accres == 0); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * Associate sets of rules with zones. 7267c478bd9Sstevel@tonic-gate */ 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * Sort by rule name. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate static int 7337c478bd9Sstevel@tonic-gate rcomp(cp1, cp2) 7347c478bd9Sstevel@tonic-gate const void * cp1; 7357c478bd9Sstevel@tonic-gate const void * cp2; 7367c478bd9Sstevel@tonic-gate { 7377c478bd9Sstevel@tonic-gate return (strcmp(((const struct rule *) cp1)->r_name, 7387c478bd9Sstevel@tonic-gate ((const struct rule *) cp2)->r_name)); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate static void 7427c478bd9Sstevel@tonic-gate associate(void) 7437c478bd9Sstevel@tonic-gate { 7447c478bd9Sstevel@tonic-gate register struct zone *zp; 7457c478bd9Sstevel@tonic-gate register struct rule *rp; 7467c478bd9Sstevel@tonic-gate register int base, out; 7477c478bd9Sstevel@tonic-gate register int i, j; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate if (nrules != 0) { 7507c478bd9Sstevel@tonic-gate (void) qsort((void *)rules, (size_t)nrules, 7517c478bd9Sstevel@tonic-gate (size_t)sizeof (*rules), rcomp); 7527c478bd9Sstevel@tonic-gate for (i = 0; i < nrules - 1; ++i) { 7537c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_name, 7547c478bd9Sstevel@tonic-gate rules[i + 1].r_name) != 0) 7557c478bd9Sstevel@tonic-gate continue; 7567c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_filename, 7577c478bd9Sstevel@tonic-gate rules[i + 1].r_filename) == 0) 7587c478bd9Sstevel@tonic-gate continue; 7597c478bd9Sstevel@tonic-gate eat(rules[i].r_filename, rules[i].r_linenum); 7607c478bd9Sstevel@tonic-gate warning(gettext("same rule name in multiple files")); 7617c478bd9Sstevel@tonic-gate eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); 7627c478bd9Sstevel@tonic-gate warning(gettext("same rule name in multiple files")); 7637c478bd9Sstevel@tonic-gate for (j = i + 2; j < nrules; ++j) { 7647c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_name, 7657c478bd9Sstevel@tonic-gate rules[j].r_name) != 0) 7667c478bd9Sstevel@tonic-gate break; 7677c478bd9Sstevel@tonic-gate if (strcmp(rules[i].r_filename, 7687c478bd9Sstevel@tonic-gate rules[j].r_filename) == 0) 7697c478bd9Sstevel@tonic-gate continue; 7707c478bd9Sstevel@tonic-gate if (strcmp(rules[i + 1].r_filename, 7717c478bd9Sstevel@tonic-gate rules[j].r_filename) == 0) 7727c478bd9Sstevel@tonic-gate continue; 7737c478bd9Sstevel@tonic-gate break; 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate i = j - 1; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 7797c478bd9Sstevel@tonic-gate zp = &zones[i]; 7807c478bd9Sstevel@tonic-gate zp->z_rules = NULL; 7817c478bd9Sstevel@tonic-gate zp->z_nrules = 0; 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate for (base = 0; base < nrules; base = out) { 7847c478bd9Sstevel@tonic-gate rp = &rules[base]; 7857c478bd9Sstevel@tonic-gate for (out = base + 1; out < nrules; ++out) 7867c478bd9Sstevel@tonic-gate if (strcmp(rp->r_name, rules[out].r_name) != 0) 7877c478bd9Sstevel@tonic-gate break; 7887c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 7897c478bd9Sstevel@tonic-gate zp = &zones[i]; 7907c478bd9Sstevel@tonic-gate if (strcmp(zp->z_rule, rp->r_name) != 0) 7917c478bd9Sstevel@tonic-gate continue; 7927c478bd9Sstevel@tonic-gate zp->z_rules = rp; 7937c478bd9Sstevel@tonic-gate zp->z_nrules = out - base; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) { 7977c478bd9Sstevel@tonic-gate zp = &zones[i]; 7987c478bd9Sstevel@tonic-gate if (zp->z_nrules == 0) { 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * Maybe we have a local standard time offset. 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 8037c478bd9Sstevel@tonic-gate zp->z_stdoff = gethms(zp->z_rule, 8047c478bd9Sstevel@tonic-gate gettext("unruly zone"), TRUE); 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * Note, though, that if there's no rule, 8077c478bd9Sstevel@tonic-gate * a '%s' in the format is a bad thing. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate if (strchr(zp->z_format, '%') != 0) 8107c478bd9Sstevel@tonic-gate error(gettext("%s in ruleless zone")); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate if (errors) 81480868c53Srobbin exit(EXIT_FAILURE); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate static void 8187c478bd9Sstevel@tonic-gate infile(name) 8197c478bd9Sstevel@tonic-gate const char *name; 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate register FILE *fp; 8227c478bd9Sstevel@tonic-gate register char **fields; 8237c478bd9Sstevel@tonic-gate register char *cp; 8247c478bd9Sstevel@tonic-gate register const struct lookup *lp; 8257c478bd9Sstevel@tonic-gate register int nfields; 8267c478bd9Sstevel@tonic-gate register int wantcont; 8277c478bd9Sstevel@tonic-gate register int num; 8287c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate if (strcmp(name, "-") == 0) { 8317c478bd9Sstevel@tonic-gate name = gettext("standard input"); 8327c478bd9Sstevel@tonic-gate fp = stdin; 8337c478bd9Sstevel@tonic-gate } else if ((fp = fopen(name, "r")) == NULL) { 8347c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Can't open %s: %s\n"), 8377c478bd9Sstevel@tonic-gate progname, name, e); 83880868c53Srobbin exit(EXIT_FAILURE); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate wantcont = FALSE; 8417c478bd9Sstevel@tonic-gate for (num = 1; ; ++num) { 8427c478bd9Sstevel@tonic-gate eat(name, num); 8437c478bd9Sstevel@tonic-gate if (fgets(buf, (int)sizeof (buf), fp) != buf) 8447c478bd9Sstevel@tonic-gate break; 8457c478bd9Sstevel@tonic-gate cp = strchr(buf, '\n'); 8467c478bd9Sstevel@tonic-gate if (cp == NULL) { 8477c478bd9Sstevel@tonic-gate error(gettext("line too long")); 84880868c53Srobbin exit(EXIT_FAILURE); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate *cp = '\0'; 8517c478bd9Sstevel@tonic-gate fields = getfields(buf); 8527c478bd9Sstevel@tonic-gate nfields = 0; 8537c478bd9Sstevel@tonic-gate while (fields[nfields] != NULL) { 8547c478bd9Sstevel@tonic-gate static char nada; 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate if (strcmp(fields[nfields], "-") == 0) 8577c478bd9Sstevel@tonic-gate fields[nfields] = &nada; 8587c478bd9Sstevel@tonic-gate ++nfields; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate if (nfields == 0) { 8617c478bd9Sstevel@tonic-gate /* nothing to do */ 8627c478bd9Sstevel@tonic-gate } else if (wantcont) { 8637c478bd9Sstevel@tonic-gate wantcont = inzcont(fields, nfields); 8647c478bd9Sstevel@tonic-gate } else { 8657c478bd9Sstevel@tonic-gate lp = byword(fields[0], line_codes); 8667c478bd9Sstevel@tonic-gate if (lp == NULL) 8677c478bd9Sstevel@tonic-gate error(gettext("input line of unknown type")); 8687c478bd9Sstevel@tonic-gate else switch ((int)(lp->l_value)) { 8697c478bd9Sstevel@tonic-gate case LC_RULE: 8707c478bd9Sstevel@tonic-gate inrule(fields, nfields); 8717c478bd9Sstevel@tonic-gate wantcont = FALSE; 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate case LC_ZONE: 8747c478bd9Sstevel@tonic-gate wantcont = inzone(fields, nfields); 8757c478bd9Sstevel@tonic-gate break; 8767c478bd9Sstevel@tonic-gate case LC_LINK: 8777c478bd9Sstevel@tonic-gate inlink(fields, nfields); 8787c478bd9Sstevel@tonic-gate wantcont = FALSE; 8797c478bd9Sstevel@tonic-gate break; 8807c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 8817c478bd9Sstevel@tonic-gate case LC_LEAP: 8827c478bd9Sstevel@tonic-gate if (name != leapsec) 8837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 8847c478bd9Sstevel@tonic-gate "%s: Leap line in non leap seconds file %s\n"), 8857c478bd9Sstevel@tonic-gate progname, name); 8867c478bd9Sstevel@tonic-gate else inleap(fields, nfields); 8877c478bd9Sstevel@tonic-gate wantcont = FALSE; 8887c478bd9Sstevel@tonic-gate break; 8897c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 8907c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 8917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 8927c478bd9Sstevel@tonic-gate "%s: panic: Invalid l_value %d\n"), 8937c478bd9Sstevel@tonic-gate progname, lp->l_value); 89480868c53Srobbin exit(EXIT_FAILURE); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate ifree((char *)fields); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate if (ferror(fp)) { 9007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error reading %s\n"), 9017c478bd9Sstevel@tonic-gate progname, filename); 90280868c53Srobbin exit(EXIT_FAILURE); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate if (fp != stdin && fclose(fp)) { 9057c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 9067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error closing %s: %s\n"), 9077c478bd9Sstevel@tonic-gate progname, filename, e); 90880868c53Srobbin exit(EXIT_FAILURE); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate if (wantcont) 9117c478bd9Sstevel@tonic-gate error(gettext("expected continuation line not found")); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * Convert a string of one of the forms 9167c478bd9Sstevel@tonic-gate * h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss 9177c478bd9Sstevel@tonic-gate * into a number of seconds. 9187c478bd9Sstevel@tonic-gate * A null string maps to zero. 9197c478bd9Sstevel@tonic-gate * Call error with errstring and return zero on errors. 9207c478bd9Sstevel@tonic-gate */ 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate static long 9237c478bd9Sstevel@tonic-gate gethms(string, errstring, signable) 9247c478bd9Sstevel@tonic-gate const char *string; 9257c478bd9Sstevel@tonic-gate const char * const errstring; 9267c478bd9Sstevel@tonic-gate const int signable; 9277c478bd9Sstevel@tonic-gate { 928*a68d064cSrobbin long hh; 929*a68d064cSrobbin int mm, ss, sign; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (string == NULL || *string == '\0') 9327c478bd9Sstevel@tonic-gate return (0); 9337c478bd9Sstevel@tonic-gate if (!signable) 9347c478bd9Sstevel@tonic-gate sign = 1; 9357c478bd9Sstevel@tonic-gate else if (*string == '-') { 9367c478bd9Sstevel@tonic-gate sign = -1; 9377c478bd9Sstevel@tonic-gate ++string; 9387c478bd9Sstevel@tonic-gate } else sign = 1; 939*a68d064cSrobbin if (sscanf(string, scheck(string, "%ld"), &hh) == 1) 9407c478bd9Sstevel@tonic-gate mm = ss = 0; 941*a68d064cSrobbin else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) 9427c478bd9Sstevel@tonic-gate ss = 0; 943*a68d064cSrobbin else if (sscanf(string, scheck(string, "%ld:%d:%d"), 9447c478bd9Sstevel@tonic-gate &hh, &mm, &ss) != 3) { 9457c478bd9Sstevel@tonic-gate error(errstring); 9467c478bd9Sstevel@tonic-gate return (0); 9477c478bd9Sstevel@tonic-gate } 948*a68d064cSrobbin if (hh < 0 || 9497c478bd9Sstevel@tonic-gate mm < 0 || mm >= MINSPERHOUR || 950*a68d064cSrobbin ss < 0 || ss > SECSPERMIN) { 9517c478bd9Sstevel@tonic-gate error(errstring); 9527c478bd9Sstevel@tonic-gate return (0); 9537c478bd9Sstevel@tonic-gate } 954*a68d064cSrobbin if (LONG_MAX / SECSPERHOUR < hh) { 955*a68d064cSrobbin error(gettext("time overflow")); 956*a68d064cSrobbin return (0); 957*a68d064cSrobbin } 958*a68d064cSrobbin if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) 95980868c53Srobbin warning( 96080868c53Srobbin gettext("24:00 not handled by pre-1998 versions of zic")); 961*a68d064cSrobbin if (noise && (hh > HOURSPERDAY || 962*a68d064cSrobbin (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) 963*a68d064cSrobbin warning(gettext("values over 24 hours not handled by " 964*a68d064cSrobbin "pre-2007 versions of zic")); 965*a68d064cSrobbin 966*a68d064cSrobbin return (oadd(eitol(sign) * hh * eitol(SECSPERHOUR), 967*a68d064cSrobbin eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)))); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate static void 9717c478bd9Sstevel@tonic-gate inrule(fields, nfields) 9727c478bd9Sstevel@tonic-gate register char ** const fields; 9737c478bd9Sstevel@tonic-gate const int nfields; 9747c478bd9Sstevel@tonic-gate { 9757c478bd9Sstevel@tonic-gate static struct rule r; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate if (nfields != RULE_FIELDS) { 9787c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Rule line")); 9797c478bd9Sstevel@tonic-gate return; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate if (*fields[RF_NAME] == '\0') { 9827c478bd9Sstevel@tonic-gate error(gettext("nameless rule")); 9837c478bd9Sstevel@tonic-gate return; 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate r.r_filename = filename; 9867c478bd9Sstevel@tonic-gate r.r_linenum = linenum; 9877c478bd9Sstevel@tonic-gate r.r_stdoff = gethms(fields[RF_STDOFF], gettext("invalid saved time"), 9887c478bd9Sstevel@tonic-gate TRUE); 9897c478bd9Sstevel@tonic-gate rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], 9907c478bd9Sstevel@tonic-gate fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); 9917c478bd9Sstevel@tonic-gate r.r_name = ecpyalloc(fields[RF_NAME]); 9927c478bd9Sstevel@tonic-gate r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); 9937c478bd9Sstevel@tonic-gate rules = (struct rule *)(void *)erealloc((char *)rules, 9947c478bd9Sstevel@tonic-gate (int)((nrules + 1) * sizeof (*rules))); 9957c478bd9Sstevel@tonic-gate rules[nrules++] = r; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate static int 9997c478bd9Sstevel@tonic-gate inzone(fields, nfields) 10007c478bd9Sstevel@tonic-gate register char ** const fields; 10017c478bd9Sstevel@tonic-gate const int nfields; 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate register int i; 10047c478bd9Sstevel@tonic-gate static char *buf; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { 10077c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Zone line")); 10087c478bd9Sstevel@tonic-gate return (FALSE); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { 10117c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(TZDEFAULT))); 10127c478bd9Sstevel@tonic-gate (void) sprintf(buf, 10137c478bd9Sstevel@tonic-gate gettext("\"Zone %s\" line and -l option are mutually exclusive"), 10147c478bd9Sstevel@tonic-gate TZDEFAULT); 10157c478bd9Sstevel@tonic-gate error(buf); 10167c478bd9Sstevel@tonic-gate return (FALSE); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { 10197c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(TZDEFRULES))); 10207c478bd9Sstevel@tonic-gate (void) sprintf(buf, 10217c478bd9Sstevel@tonic-gate gettext("\"Zone %s\" line and -p option are mutually exclusive"), 10227c478bd9Sstevel@tonic-gate TZDEFRULES); 10237c478bd9Sstevel@tonic-gate error(buf); 10247c478bd9Sstevel@tonic-gate return (FALSE); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate for (i = 0; i < nzones; ++i) 10277c478bd9Sstevel@tonic-gate if (zones[i].z_name != NULL && 10287c478bd9Sstevel@tonic-gate strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { 10297c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + 10307c478bd9Sstevel@tonic-gate strlen(fields[ZF_NAME]) + 10317c478bd9Sstevel@tonic-gate strlen(zones[i].z_filename))); 10327c478bd9Sstevel@tonic-gate (void) sprintf(buf, 10337c478bd9Sstevel@tonic-gate gettext("duplicate zone name %s (file \"%s\", line %d)"), 10347c478bd9Sstevel@tonic-gate fields[ZF_NAME], 10357c478bd9Sstevel@tonic-gate zones[i].z_filename, 10367c478bd9Sstevel@tonic-gate zones[i].z_linenum); 10377c478bd9Sstevel@tonic-gate error(buf); 10387c478bd9Sstevel@tonic-gate return (FALSE); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate return (inzsub(fields, nfields, FALSE)); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate static int 10447c478bd9Sstevel@tonic-gate inzcont(fields, nfields) 10457c478bd9Sstevel@tonic-gate register char ** const fields; 10467c478bd9Sstevel@tonic-gate const int nfields; 10477c478bd9Sstevel@tonic-gate { 10487c478bd9Sstevel@tonic-gate if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { 10497c478bd9Sstevel@tonic-gate error(gettext( 10507c478bd9Sstevel@tonic-gate "wrong number of fields on Zone continuation line")); 10517c478bd9Sstevel@tonic-gate return (FALSE); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate return (inzsub(fields, nfields, TRUE)); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate static int 10577c478bd9Sstevel@tonic-gate inzsub(fields, nfields, iscont) 10587c478bd9Sstevel@tonic-gate register char ** const fields; 10597c478bd9Sstevel@tonic-gate const int nfields; 10607c478bd9Sstevel@tonic-gate const int iscont; 10617c478bd9Sstevel@tonic-gate { 10627c478bd9Sstevel@tonic-gate register char *cp; 10637c478bd9Sstevel@tonic-gate static struct zone z; 10647c478bd9Sstevel@tonic-gate register int i_gmtoff, i_rule, i_format; 10657c478bd9Sstevel@tonic-gate register int i_untilyear, i_untilmonth; 10667c478bd9Sstevel@tonic-gate register int i_untilday, i_untiltime; 10677c478bd9Sstevel@tonic-gate register int hasuntil; 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if (iscont) { 10707c478bd9Sstevel@tonic-gate i_gmtoff = ZFC_GMTOFF; 10717c478bd9Sstevel@tonic-gate i_rule = ZFC_RULE; 10727c478bd9Sstevel@tonic-gate i_format = ZFC_FORMAT; 10737c478bd9Sstevel@tonic-gate i_untilyear = ZFC_TILYEAR; 10747c478bd9Sstevel@tonic-gate i_untilmonth = ZFC_TILMONTH; 10757c478bd9Sstevel@tonic-gate i_untilday = ZFC_TILDAY; 10767c478bd9Sstevel@tonic-gate i_untiltime = ZFC_TILTIME; 10777c478bd9Sstevel@tonic-gate z.z_name = NULL; 10787c478bd9Sstevel@tonic-gate } else { 10797c478bd9Sstevel@tonic-gate i_gmtoff = ZF_GMTOFF; 10807c478bd9Sstevel@tonic-gate i_rule = ZF_RULE; 10817c478bd9Sstevel@tonic-gate i_format = ZF_FORMAT; 10827c478bd9Sstevel@tonic-gate i_untilyear = ZF_TILYEAR; 10837c478bd9Sstevel@tonic-gate i_untilmonth = ZF_TILMONTH; 10847c478bd9Sstevel@tonic-gate i_untilday = ZF_TILDAY; 10857c478bd9Sstevel@tonic-gate i_untiltime = ZF_TILTIME; 10867c478bd9Sstevel@tonic-gate z.z_name = ecpyalloc(fields[ZF_NAME]); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate z.z_filename = filename; 10897c478bd9Sstevel@tonic-gate z.z_linenum = linenum; 10907c478bd9Sstevel@tonic-gate z.z_gmtoff = gethms(fields[i_gmtoff], gettext("invalid UTC offset"), 10917c478bd9Sstevel@tonic-gate TRUE); 10927c478bd9Sstevel@tonic-gate if ((cp = strchr(fields[i_format], '%')) != 0) { 10937c478bd9Sstevel@tonic-gate if (*++cp != 's' || strchr(cp, '%') != 0) { 10947c478bd9Sstevel@tonic-gate error(gettext("invalid abbreviation format")); 10957c478bd9Sstevel@tonic-gate return (FALSE); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate z.z_rule = ecpyalloc(fields[i_rule]); 10997c478bd9Sstevel@tonic-gate z.z_format = ecpyalloc(fields[i_format]); 11007c478bd9Sstevel@tonic-gate hasuntil = nfields > i_untilyear; 11017c478bd9Sstevel@tonic-gate if (hasuntil) { 11027c478bd9Sstevel@tonic-gate z.z_untilrule.r_filename = filename; 11037c478bd9Sstevel@tonic-gate z.z_untilrule.r_linenum = linenum; 11047c478bd9Sstevel@tonic-gate rulesub(&z.z_untilrule, 11057c478bd9Sstevel@tonic-gate fields[i_untilyear], 11067c478bd9Sstevel@tonic-gate "only", 11077c478bd9Sstevel@tonic-gate "", 11087c478bd9Sstevel@tonic-gate (nfields > i_untilmonth) ? 11097c478bd9Sstevel@tonic-gate fields[i_untilmonth] : "Jan", 11107c478bd9Sstevel@tonic-gate (nfields > i_untilday) ? fields[i_untilday] : "1", 11117c478bd9Sstevel@tonic-gate (nfields > i_untiltime) ? fields[i_untiltime] : "0"); 11127c478bd9Sstevel@tonic-gate z.z_untiltime = rpytime(&z.z_untilrule, 11137c478bd9Sstevel@tonic-gate z.z_untilrule.r_loyear); 11147c478bd9Sstevel@tonic-gate if (iscont && nzones > 0 && 11157c478bd9Sstevel@tonic-gate z.z_untiltime > min_time && 11167c478bd9Sstevel@tonic-gate z.z_untiltime < max_time && 11177c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime > min_time && 11187c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime < max_time && 11197c478bd9Sstevel@tonic-gate zones[nzones - 1].z_untiltime >= z.z_untiltime) { 11207c478bd9Sstevel@tonic-gate error(gettext( 11217c478bd9Sstevel@tonic-gate "Zone continuation line end time is not after end time of previous line")); 11227c478bd9Sstevel@tonic-gate return (FALSE); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate zones = (struct zone *)(void *)erealloc((char *)zones, 11267c478bd9Sstevel@tonic-gate (int)((nzones + 1) * sizeof (*zones))); 11277c478bd9Sstevel@tonic-gate zones[nzones++] = z; 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * If there was an UNTIL field on this line, 11307c478bd9Sstevel@tonic-gate * there's more information about the zone on the next line. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate return (hasuntil); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 11367c478bd9Sstevel@tonic-gate static void 11377c478bd9Sstevel@tonic-gate inleap(fields, nfields) 11387c478bd9Sstevel@tonic-gate register char ** const fields; 11397c478bd9Sstevel@tonic-gate const int nfields; 11407c478bd9Sstevel@tonic-gate { 11417c478bd9Sstevel@tonic-gate register const char *cp; 11427c478bd9Sstevel@tonic-gate register const struct lookup *lp; 11437c478bd9Sstevel@tonic-gate register int i, j; 11447c478bd9Sstevel@tonic-gate int year, month, day; 11457c478bd9Sstevel@tonic-gate long dayoff, tod; 114680868c53Srobbin zic_t t; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate if (nfields != LEAP_FIELDS) { 11497c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Leap line")); 11507c478bd9Sstevel@tonic-gate return; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate dayoff = 0; 11537c478bd9Sstevel@tonic-gate cp = fields[LP_YEAR]; 11547c478bd9Sstevel@tonic-gate if (sscanf(cp, scheck(cp, "%d"), &year) != 1) { 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * Leapin' Lizards! 11577c478bd9Sstevel@tonic-gate */ 11587c478bd9Sstevel@tonic-gate error(gettext("invalid leaping year")); 11597c478bd9Sstevel@tonic-gate return; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate j = EPOCH_YEAR; 11627c478bd9Sstevel@tonic-gate while (j != year) { 11637c478bd9Sstevel@tonic-gate if (year > j) { 11647c478bd9Sstevel@tonic-gate i = len_years[isleap(j)]; 11657c478bd9Sstevel@tonic-gate ++j; 11667c478bd9Sstevel@tonic-gate } else { 11677c478bd9Sstevel@tonic-gate --j; 11687c478bd9Sstevel@tonic-gate i = -len_years[isleap(j)]; 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { 11737c478bd9Sstevel@tonic-gate error(gettext("invalid month name")); 11747c478bd9Sstevel@tonic-gate return; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate month = lp->l_value; 11777c478bd9Sstevel@tonic-gate j = TM_JANUARY; 11787c478bd9Sstevel@tonic-gate while (j != month) { 11797c478bd9Sstevel@tonic-gate i = len_months[isleap(year)][j]; 11807c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 11817c478bd9Sstevel@tonic-gate ++j; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate cp = fields[LP_DAY]; 11847c478bd9Sstevel@tonic-gate if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || 11857c478bd9Sstevel@tonic-gate day <= 0 || day > len_months[isleap(year)][month]) { 11867c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 11877c478bd9Sstevel@tonic-gate return; 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(day - 1)); 119080868c53Srobbin if (dayoff < 0 && !TYPE_SIGNED(zic_t)) { 11917c478bd9Sstevel@tonic-gate error(gettext("time before zero")); 11927c478bd9Sstevel@tonic-gate return; 11937c478bd9Sstevel@tonic-gate } 119480868c53Srobbin if (dayoff < min_time / SECSPERDAY) { 119580868c53Srobbin error(gettext("time too small")); 11967c478bd9Sstevel@tonic-gate return; 11977c478bd9Sstevel@tonic-gate } 119880868c53Srobbin if (dayoff > max_time / SECSPERDAY) { 119980868c53Srobbin error(gettext("time too large")); 120080868c53Srobbin return; 120180868c53Srobbin } 120280868c53Srobbin t = (zic_t)dayoff * SECSPERDAY; 12037c478bd9Sstevel@tonic-gate tod = gethms(fields[LP_TIME], gettext("invalid time of day"), FALSE); 12047c478bd9Sstevel@tonic-gate cp = fields[LP_CORR]; 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate register int positive; 12077c478bd9Sstevel@tonic-gate int count; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */ 12107c478bd9Sstevel@tonic-gate positive = FALSE; 12117c478bd9Sstevel@tonic-gate count = 1; 12127c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "--") == 0) { 12137c478bd9Sstevel@tonic-gate positive = FALSE; 12147c478bd9Sstevel@tonic-gate count = 2; 12157c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "+") == 0) { 12167c478bd9Sstevel@tonic-gate positive = TRUE; 12177c478bd9Sstevel@tonic-gate count = 1; 12187c478bd9Sstevel@tonic-gate } else if (strcmp(cp, "++") == 0) { 12197c478bd9Sstevel@tonic-gate positive = TRUE; 12207c478bd9Sstevel@tonic-gate count = 2; 12217c478bd9Sstevel@tonic-gate } else { 12227c478bd9Sstevel@tonic-gate error(gettext("illegal CORRECTION field on Leap line")); 12237c478bd9Sstevel@tonic-gate return; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { 12267c478bd9Sstevel@tonic-gate error(gettext( 12277c478bd9Sstevel@tonic-gate "illegal Rolling/Stationary field on Leap line")); 12287c478bd9Sstevel@tonic-gate return; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate leapadd(tadd(t, tod), positive, lp->l_value, count); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate static void 12367c478bd9Sstevel@tonic-gate inlink(fields, nfields) 12377c478bd9Sstevel@tonic-gate register char ** const fields; 12387c478bd9Sstevel@tonic-gate const int nfields; 12397c478bd9Sstevel@tonic-gate { 12407c478bd9Sstevel@tonic-gate struct link l; 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate if (nfields != LINK_FIELDS) { 12437c478bd9Sstevel@tonic-gate error(gettext("wrong number of fields on Link line")); 12447c478bd9Sstevel@tonic-gate return; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate if (*fields[LF_FROM] == '\0') { 12477c478bd9Sstevel@tonic-gate error(gettext("blank FROM field on Link line")); 12487c478bd9Sstevel@tonic-gate return; 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate if (*fields[LF_TO] == '\0') { 12517c478bd9Sstevel@tonic-gate error(gettext("blank TO field on Link line")); 12527c478bd9Sstevel@tonic-gate return; 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate l.l_filename = filename; 12557c478bd9Sstevel@tonic-gate l.l_linenum = linenum; 12567c478bd9Sstevel@tonic-gate l.l_from = ecpyalloc(fields[LF_FROM]); 12577c478bd9Sstevel@tonic-gate l.l_to = ecpyalloc(fields[LF_TO]); 12587c478bd9Sstevel@tonic-gate links = (struct link *)(void *)erealloc((char *)links, 12597c478bd9Sstevel@tonic-gate (int)((nlinks + 1) * sizeof (*links))); 12607c478bd9Sstevel@tonic-gate links[nlinks++] = l; 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate static void 12647c478bd9Sstevel@tonic-gate rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) 12657c478bd9Sstevel@tonic-gate register struct rule * const rp; 12667c478bd9Sstevel@tonic-gate const char * const loyearp; 12677c478bd9Sstevel@tonic-gate const char * const hiyearp; 12687c478bd9Sstevel@tonic-gate const char * const typep; 12697c478bd9Sstevel@tonic-gate const char * const monthp; 12707c478bd9Sstevel@tonic-gate const char * const dayp; 12717c478bd9Sstevel@tonic-gate const char * const timep; 12727c478bd9Sstevel@tonic-gate { 12737c478bd9Sstevel@tonic-gate register const struct lookup *lp; 12747c478bd9Sstevel@tonic-gate register const char *cp; 12757c478bd9Sstevel@tonic-gate register char *dp; 12767c478bd9Sstevel@tonic-gate register char *ep; 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate if ((lp = byword(monthp, mon_names)) == NULL) { 12797c478bd9Sstevel@tonic-gate error(gettext("invalid month name")); 12807c478bd9Sstevel@tonic-gate return; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate rp->r_month = lp->l_value; 12837c478bd9Sstevel@tonic-gate rp->r_todisstd = FALSE; 12847c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 12857c478bd9Sstevel@tonic-gate dp = ecpyalloc(timep); 12867c478bd9Sstevel@tonic-gate if (*dp != '\0') { 12877c478bd9Sstevel@tonic-gate ep = dp + strlen(dp) - 1; 12887c478bd9Sstevel@tonic-gate switch (lowerit(*ep)) { 12897c478bd9Sstevel@tonic-gate case 's': /* Standard */ 12907c478bd9Sstevel@tonic-gate rp->r_todisstd = TRUE; 12917c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 12927c478bd9Sstevel@tonic-gate *ep = '\0'; 12937c478bd9Sstevel@tonic-gate break; 12947c478bd9Sstevel@tonic-gate case 'w': /* Wall */ 12957c478bd9Sstevel@tonic-gate rp->r_todisstd = FALSE; 12967c478bd9Sstevel@tonic-gate rp->r_todisgmt = FALSE; 12977c478bd9Sstevel@tonic-gate *ep = '\0'; 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate case 'g': /* Greenwich */ 13007c478bd9Sstevel@tonic-gate case 'u': /* Universal */ 13017c478bd9Sstevel@tonic-gate case 'z': /* Zulu */ 13027c478bd9Sstevel@tonic-gate rp->r_todisstd = TRUE; 13037c478bd9Sstevel@tonic-gate rp->r_todisgmt = TRUE; 13047c478bd9Sstevel@tonic-gate *ep = '\0'; 13057c478bd9Sstevel@tonic-gate break; 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate rp->r_tod = gethms(dp, gettext("invalid time of day"), FALSE); 13097c478bd9Sstevel@tonic-gate ifree(dp); 13107c478bd9Sstevel@tonic-gate /* 13117c478bd9Sstevel@tonic-gate * Year work. 13127c478bd9Sstevel@tonic-gate */ 13137c478bd9Sstevel@tonic-gate cp = loyearp; 13147c478bd9Sstevel@tonic-gate lp = byword(cp, begin_years); 13157c478bd9Sstevel@tonic-gate if (lp != NULL) { 13167c478bd9Sstevel@tonic-gate switch ((int)lp->l_value) { 13177c478bd9Sstevel@tonic-gate case YR_MINIMUM: 13187c478bd9Sstevel@tonic-gate rp->r_loyear = INT_MIN; 13197c478bd9Sstevel@tonic-gate break; 13207c478bd9Sstevel@tonic-gate case YR_MAXIMUM: 13217c478bd9Sstevel@tonic-gate rp->r_loyear = INT_MAX; 13227c478bd9Sstevel@tonic-gate break; 13237c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 13247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 13257c478bd9Sstevel@tonic-gate gettext("%s: panic: Invalid l_value %d\n"), 13267c478bd9Sstevel@tonic-gate progname, lp->l_value); 132780868c53Srobbin exit(EXIT_FAILURE); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { 13307c478bd9Sstevel@tonic-gate error(gettext("invalid starting year")); 13317c478bd9Sstevel@tonic-gate return; 13327c478bd9Sstevel@tonic-gate } else if (noise) { 13337c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year_representable) 13347c478bd9Sstevel@tonic-gate warning(gettext( 13357c478bd9Sstevel@tonic-gate "starting year too low to be represented")); 13367c478bd9Sstevel@tonic-gate else if (rp->r_loyear > max_year_representable) 13377c478bd9Sstevel@tonic-gate warning(gettext( 13387c478bd9Sstevel@tonic-gate "starting year too high to be represented")); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate cp = hiyearp; 13417c478bd9Sstevel@tonic-gate if ((lp = byword(cp, end_years)) != NULL) { 13427c478bd9Sstevel@tonic-gate switch ((int)lp->l_value) { 13437c478bd9Sstevel@tonic-gate case YR_MINIMUM: 13447c478bd9Sstevel@tonic-gate rp->r_hiyear = INT_MIN; 13457c478bd9Sstevel@tonic-gate break; 13467c478bd9Sstevel@tonic-gate case YR_MAXIMUM: 13477c478bd9Sstevel@tonic-gate rp->r_hiyear = INT_MAX; 13487c478bd9Sstevel@tonic-gate break; 13497c478bd9Sstevel@tonic-gate case YR_ONLY: 13507c478bd9Sstevel@tonic-gate rp->r_hiyear = rp->r_loyear; 13517c478bd9Sstevel@tonic-gate break; 13527c478bd9Sstevel@tonic-gate default: /* "cannot happen" */ 13537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 13547c478bd9Sstevel@tonic-gate gettext("%s: panic: Invalid l_value %d\n"), 13557c478bd9Sstevel@tonic-gate progname, lp->l_value); 135680868c53Srobbin exit(EXIT_FAILURE); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { 13597c478bd9Sstevel@tonic-gate error(gettext("invalid ending year")); 13607c478bd9Sstevel@tonic-gate return; 13617c478bd9Sstevel@tonic-gate } else if (noise) { 13627c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year_representable) 13637c478bd9Sstevel@tonic-gate warning(gettext( 136480868c53Srobbin "ending year too low to be represented")); 13657c478bd9Sstevel@tonic-gate else if (rp->r_loyear > max_year_representable) 13667c478bd9Sstevel@tonic-gate warning(gettext( 136780868c53Srobbin "ending year too high to be represented")); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate if (rp->r_loyear > rp->r_hiyear) { 13707c478bd9Sstevel@tonic-gate error(gettext("starting year greater than ending year")); 13717c478bd9Sstevel@tonic-gate return; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate if (*typep == '\0') 13747c478bd9Sstevel@tonic-gate rp->r_yrtype = NULL; 13757c478bd9Sstevel@tonic-gate else { 13767c478bd9Sstevel@tonic-gate if (rp->r_loyear == rp->r_hiyear) { 13777c478bd9Sstevel@tonic-gate error(gettext("typed single year")); 13787c478bd9Sstevel@tonic-gate return; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate rp->r_yrtype = ecpyalloc(typep); 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate if (rp->r_loyear < min_year && rp->r_loyear > 0) 13837c478bd9Sstevel@tonic-gate min_year = rp->r_loyear; 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * Day work. 13867c478bd9Sstevel@tonic-gate * Accept things such as: 13877c478bd9Sstevel@tonic-gate * 1 13887c478bd9Sstevel@tonic-gate * last-Sunday 13897c478bd9Sstevel@tonic-gate * Sun<=20 13907c478bd9Sstevel@tonic-gate * Sun>=7 13917c478bd9Sstevel@tonic-gate */ 13927c478bd9Sstevel@tonic-gate dp = ecpyalloc(dayp); 13937c478bd9Sstevel@tonic-gate if ((lp = byword(dp, lasts)) != NULL) { 13947c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWLEQ; 13957c478bd9Sstevel@tonic-gate rp->r_wday = lp->l_value; 13967c478bd9Sstevel@tonic-gate rp->r_dayofmonth = len_months[1][rp->r_month]; 13977c478bd9Sstevel@tonic-gate } else { 13987c478bd9Sstevel@tonic-gate if ((ep = strchr(dp, '<')) != 0) 13997c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWLEQ; 14007c478bd9Sstevel@tonic-gate else if ((ep = strchr(dp, '>')) != 0) 14017c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOWGEQ; 14027c478bd9Sstevel@tonic-gate else { 14037c478bd9Sstevel@tonic-gate ep = dp; 14047c478bd9Sstevel@tonic-gate rp->r_dycode = DC_DOM; 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate if (rp->r_dycode != DC_DOM) { 14077c478bd9Sstevel@tonic-gate *ep++ = 0; 14087c478bd9Sstevel@tonic-gate if (*ep++ != '=') { 14097c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 14107c478bd9Sstevel@tonic-gate ifree(dp); 14117c478bd9Sstevel@tonic-gate return; 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate if ((lp = byword(dp, wday_names)) == NULL) { 14147c478bd9Sstevel@tonic-gate error(gettext("invalid weekday name")); 14157c478bd9Sstevel@tonic-gate ifree(dp); 14167c478bd9Sstevel@tonic-gate return; 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate rp->r_wday = lp->l_value; 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || 14217c478bd9Sstevel@tonic-gate rp->r_dayofmonth <= 0 || 14227c478bd9Sstevel@tonic-gate (rp->r_dayofmonth > len_months[1][rp->r_month])) { 14237c478bd9Sstevel@tonic-gate error(gettext("invalid day of month")); 14247c478bd9Sstevel@tonic-gate ifree(dp); 14257c478bd9Sstevel@tonic-gate return; 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate ifree(dp); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate static void 14327c478bd9Sstevel@tonic-gate convert(val, buf) 14337c478bd9Sstevel@tonic-gate const long val; 14347c478bd9Sstevel@tonic-gate char * const buf; 14357c478bd9Sstevel@tonic-gate { 14367c478bd9Sstevel@tonic-gate register int i; 14377c478bd9Sstevel@tonic-gate register long shift; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate for (i = 0, shift = 24; i < 4; ++i, shift -= 8) 14407c478bd9Sstevel@tonic-gate buf[i] = val >> shift; 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate static void 14447c478bd9Sstevel@tonic-gate puttzcode(val, fp) 14457c478bd9Sstevel@tonic-gate const long val; 14467c478bd9Sstevel@tonic-gate FILE * const fp; 14477c478bd9Sstevel@tonic-gate { 14487c478bd9Sstevel@tonic-gate char buf[4]; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate convert(val, buf); 14517c478bd9Sstevel@tonic-gate (void) fwrite((void *)buf, (size_t)sizeof (buf), (size_t)1, fp); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate static int 14557c478bd9Sstevel@tonic-gate atcomp(avp, bvp) 14567c478bd9Sstevel@tonic-gate const void *avp; 14577c478bd9Sstevel@tonic-gate const void *bvp; 14587c478bd9Sstevel@tonic-gate { 14597c478bd9Sstevel@tonic-gate if (((struct attype *)avp)->at < ((struct attype *)bvp)->at) 14607c478bd9Sstevel@tonic-gate return (-1); 14617c478bd9Sstevel@tonic-gate else if (((struct attype *)avp)->at > ((struct attype *)bvp)->at) 14627c478bd9Sstevel@tonic-gate return (1); 14637c478bd9Sstevel@tonic-gate else return (0); 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate static void 14677c478bd9Sstevel@tonic-gate writezone(name) 14687c478bd9Sstevel@tonic-gate const char * const name; 14697c478bd9Sstevel@tonic-gate { 14707c478bd9Sstevel@tonic-gate register FILE *fp; 14717c478bd9Sstevel@tonic-gate register int i, j; 14727c478bd9Sstevel@tonic-gate static char *fullname; 14737c478bd9Sstevel@tonic-gate static struct tzhead tzh; 147480868c53Srobbin zic_t ats[TZ_MAX_TIMES]; 14757c478bd9Sstevel@tonic-gate unsigned char types[TZ_MAX_TIMES]; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate /* 14787c478bd9Sstevel@tonic-gate * Sort. 14797c478bd9Sstevel@tonic-gate */ 14807c478bd9Sstevel@tonic-gate if (timecnt > 1) 14817c478bd9Sstevel@tonic-gate (void) qsort((void *)attypes, (size_t)timecnt, 14827c478bd9Sstevel@tonic-gate (size_t)sizeof (*attypes), atcomp); 14837c478bd9Sstevel@tonic-gate /* 14847c478bd9Sstevel@tonic-gate * Optimize. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate { 14877c478bd9Sstevel@tonic-gate int fromi; 14887c478bd9Sstevel@tonic-gate int toi; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate toi = 0; 14917c478bd9Sstevel@tonic-gate fromi = 0; 14927c478bd9Sstevel@tonic-gate while (fromi < timecnt && attypes[fromi].at < min_time) 14937c478bd9Sstevel@tonic-gate ++fromi; 14947c478bd9Sstevel@tonic-gate if (isdsts[0] == 0) 14957c478bd9Sstevel@tonic-gate while (fromi < timecnt && attypes[fromi].type == 0) 14967c478bd9Sstevel@tonic-gate ++fromi; /* handled by default rule */ 14977c478bd9Sstevel@tonic-gate for (; fromi < timecnt; ++fromi) { 149880868c53Srobbin if (toi != 0 && ((attypes[fromi].at + 14997c478bd9Sstevel@tonic-gate gmtoffs[attypes[toi - 1].type]) <= 15007c478bd9Sstevel@tonic-gate (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0 15017c478bd9Sstevel@tonic-gate : attypes[toi - 2].type]))) { 150280868c53Srobbin attypes[toi - 1].type = 150380868c53Srobbin attypes[fromi].type; 15047c478bd9Sstevel@tonic-gate continue; 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate if (toi == 0 || 15077c478bd9Sstevel@tonic-gate attypes[toi - 1].type != attypes[fromi].type) 15087c478bd9Sstevel@tonic-gate attypes[toi++] = attypes[fromi]; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate timecnt = toi; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate /* 15137c478bd9Sstevel@tonic-gate * Transfer. 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate for (i = 0; i < timecnt; ++i) { 15167c478bd9Sstevel@tonic-gate ats[i] = attypes[i].at; 15177c478bd9Sstevel@tonic-gate types[i] = attypes[i].type; 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate fullname = erealloc(fullname, 15207c478bd9Sstevel@tonic-gate (int)(strlen(directory) + 1 + strlen(name) + 1)); 15217c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%s/%s", directory, name); 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * Remove old file, if any, to snap links. 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) { 15267c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Can't remove %s: %s\n"), 15297c478bd9Sstevel@tonic-gate progname, fullname, e); 153080868c53Srobbin exit(EXIT_FAILURE); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate if ((fp = fopen(fullname, "wb")) == NULL) { 15337c478bd9Sstevel@tonic-gate if (mkdirs(fullname) != 0) 153480868c53Srobbin exit(EXIT_FAILURE); 15357c478bd9Sstevel@tonic-gate if ((fp = fopen(fullname, "wb")) == NULL) { 15367c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 15377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 15387c478bd9Sstevel@tonic-gate "%s: Can't create %s: %s\n"), 15397c478bd9Sstevel@tonic-gate progname, fullname, e); 154080868c53Srobbin exit(EXIT_FAILURE); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); 15447c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_ttisstdcnt); 15457c478bd9Sstevel@tonic-gate convert(eitol(leapcnt), tzh.tzh_leapcnt); 15467c478bd9Sstevel@tonic-gate convert(eitol(timecnt), tzh.tzh_timecnt); 15477c478bd9Sstevel@tonic-gate convert(eitol(typecnt), tzh.tzh_typecnt); 15487c478bd9Sstevel@tonic-gate convert(eitol(charcnt), tzh.tzh_charcnt); 15497c478bd9Sstevel@tonic-gate (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof (tzh.tzh_magic)); 15507c478bd9Sstevel@tonic-gate #define DO(field) (void) fwrite((void *) tzh.field, \ 15517c478bd9Sstevel@tonic-gate (size_t)sizeof (tzh.field), (size_t)1, fp) 15527c478bd9Sstevel@tonic-gate DO(tzh_magic); 15537c478bd9Sstevel@tonic-gate DO(tzh_reserved); 15547c478bd9Sstevel@tonic-gate DO(tzh_ttisgmtcnt); 15557c478bd9Sstevel@tonic-gate DO(tzh_ttisstdcnt); 15567c478bd9Sstevel@tonic-gate DO(tzh_leapcnt); 15577c478bd9Sstevel@tonic-gate DO(tzh_timecnt); 15587c478bd9Sstevel@tonic-gate DO(tzh_typecnt); 15597c478bd9Sstevel@tonic-gate DO(tzh_charcnt); 15607c478bd9Sstevel@tonic-gate #undef DO 15617c478bd9Sstevel@tonic-gate for (i = 0; i < timecnt; ++i) { 15627c478bd9Sstevel@tonic-gate j = leapcnt; 15637c478bd9Sstevel@tonic-gate while (--j >= 0) 15647c478bd9Sstevel@tonic-gate if (ats[i] >= trans[j]) { 15657c478bd9Sstevel@tonic-gate ats[i] = tadd(ats[i], corr[j]); 15667c478bd9Sstevel@tonic-gate break; 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate puttzcode((long)ats[i], fp); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate if (timecnt > 0) 15717c478bd9Sstevel@tonic-gate (void) fwrite((void *)types, (size_t)sizeof (types[0]), 15727c478bd9Sstevel@tonic-gate (size_t)timecnt, fp); 15737c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) { 15747c478bd9Sstevel@tonic-gate puttzcode((long)gmtoffs[i], fp); 15757c478bd9Sstevel@tonic-gate (void) putc(isdsts[i], fp); 15767c478bd9Sstevel@tonic-gate (void) putc(abbrinds[i], fp); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate if (charcnt != 0) 15797c478bd9Sstevel@tonic-gate (void) fwrite((void *)chars, (size_t)sizeof (chars[0]), 15807c478bd9Sstevel@tonic-gate (size_t)charcnt, fp); 15817c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) { 15827c478bd9Sstevel@tonic-gate if (roll[i]) { 15837c478bd9Sstevel@tonic-gate if (timecnt == 0 || trans[i] < ats[0]) { 15847c478bd9Sstevel@tonic-gate j = 0; 15857c478bd9Sstevel@tonic-gate while (isdsts[j]) 15867c478bd9Sstevel@tonic-gate if (++j >= typecnt) { 15877c478bd9Sstevel@tonic-gate j = 0; 15887c478bd9Sstevel@tonic-gate break; 15897c478bd9Sstevel@tonic-gate } 15907c478bd9Sstevel@tonic-gate } else { 15917c478bd9Sstevel@tonic-gate j = 1; 15927c478bd9Sstevel@tonic-gate while (j < timecnt && trans[i] >= ats[j]) 15937c478bd9Sstevel@tonic-gate ++j; 15947c478bd9Sstevel@tonic-gate j = types[j - 1]; 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate puttzcode((long)tadd(trans[i], -gmtoffs[j]), fp); 15977c478bd9Sstevel@tonic-gate } else puttzcode((long)trans[i], fp); 15987c478bd9Sstevel@tonic-gate puttzcode((long)corr[i], fp); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) 16017c478bd9Sstevel@tonic-gate (void) putc(ttisstds[i], fp); 16027c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) 16037c478bd9Sstevel@tonic-gate (void) putc(ttisgmts[i], fp); 16047c478bd9Sstevel@tonic-gate if (ferror(fp) || fclose(fp)) { 16057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Error writing %s\n"), 16067c478bd9Sstevel@tonic-gate progname, fullname); 160780868c53Srobbin exit(EXIT_FAILURE); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate static void 16127c478bd9Sstevel@tonic-gate doabbr(abbr, format, letters, isdst) 16137c478bd9Sstevel@tonic-gate char * const abbr; 16147c478bd9Sstevel@tonic-gate const char * const format; 16157c478bd9Sstevel@tonic-gate const char * const letters; 16167c478bd9Sstevel@tonic-gate const int isdst; 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate if (strchr(format, '/') == NULL) { 16197c478bd9Sstevel@tonic-gate if (letters == NULL) 16207c478bd9Sstevel@tonic-gate (void) strcpy(abbr, format); 16217c478bd9Sstevel@tonic-gate else 16227c478bd9Sstevel@tonic-gate (void) sprintf(abbr, format, letters); 16237c478bd9Sstevel@tonic-gate } else if (isdst) 16247c478bd9Sstevel@tonic-gate (void) strcpy(abbr, strchr(format, '/') + 1); 16257c478bd9Sstevel@tonic-gate else { 16267c478bd9Sstevel@tonic-gate (void) strcpy(abbr, format); 16277c478bd9Sstevel@tonic-gate *strchr(abbr, '/') = '\0'; 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate static void 16327c478bd9Sstevel@tonic-gate outzone(zpfirst, zonecount) 16337c478bd9Sstevel@tonic-gate const struct zone * const zpfirst; 16347c478bd9Sstevel@tonic-gate const int zonecount; 16357c478bd9Sstevel@tonic-gate { 16367c478bd9Sstevel@tonic-gate register const struct zone *zp; 16377c478bd9Sstevel@tonic-gate register struct rule *rp; 16387c478bd9Sstevel@tonic-gate register int i, j; 16397c478bd9Sstevel@tonic-gate register int usestart, useuntil; 164080868c53Srobbin register zic_t starttime, untiltime; 16417c478bd9Sstevel@tonic-gate register long gmtoff; 16427c478bd9Sstevel@tonic-gate register long stdoff; 16437c478bd9Sstevel@tonic-gate register int year; 16447c478bd9Sstevel@tonic-gate register long startoff; 16457c478bd9Sstevel@tonic-gate register int startttisstd; 16467c478bd9Sstevel@tonic-gate register int startttisgmt; 16477c478bd9Sstevel@tonic-gate register int type; 16487c478bd9Sstevel@tonic-gate char startbuf[BUFSIZ]; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate INITIALIZE(untiltime); 16517c478bd9Sstevel@tonic-gate INITIALIZE(starttime); 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * Now. . .finally. . .generate some useful data! 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate timecnt = 0; 16567c478bd9Sstevel@tonic-gate typecnt = 0; 16577c478bd9Sstevel@tonic-gate charcnt = 0; 16587c478bd9Sstevel@tonic-gate /* 1659f430f59aSrobbin * Thanks to Earl Chew 16607c478bd9Sstevel@tonic-gate * for noting the need to unconditionally initialize startttisstd. 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate startttisstd = FALSE; 16637c478bd9Sstevel@tonic-gate startttisgmt = FALSE; 16647c478bd9Sstevel@tonic-gate for (i = 0; i < zonecount; ++i) { 16657c478bd9Sstevel@tonic-gate /* 16667c478bd9Sstevel@tonic-gate * A guess that may well be corrected later. 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate stdoff = 0; 16697c478bd9Sstevel@tonic-gate zp = &zpfirst[i]; 16707c478bd9Sstevel@tonic-gate usestart = i > 0 && (zp - 1)->z_untiltime > min_time; 16717c478bd9Sstevel@tonic-gate useuntil = i < (zonecount - 1); 16727c478bd9Sstevel@tonic-gate if (useuntil && zp->z_untiltime <= min_time) 16737c478bd9Sstevel@tonic-gate continue; 16747c478bd9Sstevel@tonic-gate gmtoff = zp->z_gmtoff; 16757c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 16767c478bd9Sstevel@tonic-gate *startbuf = '\0'; 16777c478bd9Sstevel@tonic-gate startoff = zp->z_gmtoff; 16787c478bd9Sstevel@tonic-gate if (zp->z_nrules == 0) { 16797c478bd9Sstevel@tonic-gate stdoff = zp->z_stdoff; 16807c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 16817c478bd9Sstevel@tonic-gate (char *)NULL, stdoff != 0); 16827c478bd9Sstevel@tonic-gate type = addtype(oadd(zp->z_gmtoff, stdoff), 16837c478bd9Sstevel@tonic-gate startbuf, stdoff != 0, startttisstd, 16847c478bd9Sstevel@tonic-gate startttisgmt); 16857c478bd9Sstevel@tonic-gate if (usestart) { 16867c478bd9Sstevel@tonic-gate addtt(starttime, type); 16877c478bd9Sstevel@tonic-gate usestart = FALSE; 168880868c53Srobbin } else if (stdoff != 0) 16897c478bd9Sstevel@tonic-gate addtt(min_time, type); 16907c478bd9Sstevel@tonic-gate } else 16917c478bd9Sstevel@tonic-gate for (year = min_year; year <= max_year; ++year) { 16927c478bd9Sstevel@tonic-gate if (useuntil && year > zp->z_untilrule.r_hiyear) 16937c478bd9Sstevel@tonic-gate break; 16947c478bd9Sstevel@tonic-gate /* 16957c478bd9Sstevel@tonic-gate * Mark which rules to do in the current year. 16967c478bd9Sstevel@tonic-gate * For those to do, calculate rpytime(rp, year); 16977c478bd9Sstevel@tonic-gate */ 16987c478bd9Sstevel@tonic-gate for (j = 0; j < zp->z_nrules; ++j) { 16997c478bd9Sstevel@tonic-gate rp = &zp->z_rules[j]; 17007c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 17017c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 17027c478bd9Sstevel@tonic-gate rp->r_todo = year >= rp->r_loyear && 17037c478bd9Sstevel@tonic-gate year <= rp->r_hiyear && 17047c478bd9Sstevel@tonic-gate yearistype(year, rp->r_yrtype); 17057c478bd9Sstevel@tonic-gate if (rp->r_todo) 17067c478bd9Sstevel@tonic-gate rp->r_temp = rpytime(rp, year); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate for (;;) { 17097c478bd9Sstevel@tonic-gate register int k; 171080868c53Srobbin register zic_t jtime, ktime; 17117c478bd9Sstevel@tonic-gate register long offset; 17127c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate INITIALIZE(ktime); 17157c478bd9Sstevel@tonic-gate if (useuntil) { 17167c478bd9Sstevel@tonic-gate /* 171780868c53Srobbin * Turn untiltime into UTC * assuming 171880868c53Srobbin * the current gmtoff and stdoff values. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate untiltime = zp->z_untiltime; 17217c478bd9Sstevel@tonic-gate if (!zp->z_untilrule.r_todisgmt) 17227c478bd9Sstevel@tonic-gate untiltime = tadd(untiltime, 17237c478bd9Sstevel@tonic-gate -gmtoff); 17247c478bd9Sstevel@tonic-gate if (!zp->z_untilrule.r_todisstd) 17257c478bd9Sstevel@tonic-gate untiltime = tadd(untiltime, 17267c478bd9Sstevel@tonic-gate -stdoff); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * Find the rule (of those to do, if any) 17307c478bd9Sstevel@tonic-gate * that takes effect earliest in the year. 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate k = -1; 17337c478bd9Sstevel@tonic-gate for (j = 0; j < zp->z_nrules; ++j) { 17347c478bd9Sstevel@tonic-gate rp = &zp->z_rules[j]; 17357c478bd9Sstevel@tonic-gate if (!rp->r_todo) 17367c478bd9Sstevel@tonic-gate continue; 17377c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 17387c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 17397c478bd9Sstevel@tonic-gate offset = rp->r_todisgmt ? 0 : gmtoff; 17407c478bd9Sstevel@tonic-gate if (!rp->r_todisstd) 17417c478bd9Sstevel@tonic-gate offset = oadd(offset, stdoff); 17427c478bd9Sstevel@tonic-gate jtime = rp->r_temp; 17437c478bd9Sstevel@tonic-gate if (jtime == min_time || 17447c478bd9Sstevel@tonic-gate jtime == max_time) 17457c478bd9Sstevel@tonic-gate continue; 17467c478bd9Sstevel@tonic-gate jtime = tadd(jtime, -offset); 17477c478bd9Sstevel@tonic-gate if (k < 0 || jtime < ktime) { 17487c478bd9Sstevel@tonic-gate k = j; 17497c478bd9Sstevel@tonic-gate ktime = jtime; 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate if (k < 0) 17537c478bd9Sstevel@tonic-gate break; /* go on to next year */ 17547c478bd9Sstevel@tonic-gate rp = &zp->z_rules[k]; 17557c478bd9Sstevel@tonic-gate rp->r_todo = FALSE; 17567c478bd9Sstevel@tonic-gate if (useuntil && ktime >= untiltime) 17577c478bd9Sstevel@tonic-gate break; 17587c478bd9Sstevel@tonic-gate stdoff = rp->r_stdoff; 17597c478bd9Sstevel@tonic-gate if (usestart && ktime == starttime) 17607c478bd9Sstevel@tonic-gate usestart = FALSE; 17617c478bd9Sstevel@tonic-gate if (usestart) { 17627c478bd9Sstevel@tonic-gate if (ktime < starttime) { 17637c478bd9Sstevel@tonic-gate startoff = oadd(zp->z_gmtoff, 17647c478bd9Sstevel@tonic-gate stdoff); 17657c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 17667c478bd9Sstevel@tonic-gate rp->r_abbrvar, 17677c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 17687c478bd9Sstevel@tonic-gate continue; 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate if (*startbuf == '\0' && 17717c478bd9Sstevel@tonic-gate startoff == oadd(zp->z_gmtoff, 17727c478bd9Sstevel@tonic-gate stdoff)) { 17737c478bd9Sstevel@tonic-gate doabbr(startbuf, zp->z_format, 17747c478bd9Sstevel@tonic-gate rp->r_abbrvar, 17757c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate eats(zp->z_filename, zp->z_linenum, 17797c478bd9Sstevel@tonic-gate rp->r_filename, rp->r_linenum); 17807c478bd9Sstevel@tonic-gate doabbr(buf, zp->z_format, rp->r_abbrvar, 17817c478bd9Sstevel@tonic-gate rp->r_stdoff != 0); 17827c478bd9Sstevel@tonic-gate offset = oadd(zp->z_gmtoff, rp->r_stdoff); 17837c478bd9Sstevel@tonic-gate type = addtype(offset, buf, rp->r_stdoff != 0, 17847c478bd9Sstevel@tonic-gate rp->r_todisstd, rp->r_todisgmt); 17857c478bd9Sstevel@tonic-gate addtt(ktime, type); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate if (usestart) { 17897c478bd9Sstevel@tonic-gate if (*startbuf == '\0' && 17907c478bd9Sstevel@tonic-gate zp->z_format != NULL && 17917c478bd9Sstevel@tonic-gate strchr(zp->z_format, '%') == NULL && 17927c478bd9Sstevel@tonic-gate strchr(zp->z_format, '/') == NULL) 17937c478bd9Sstevel@tonic-gate (void) strcpy(startbuf, zp->z_format); 17947c478bd9Sstevel@tonic-gate eat(zp->z_filename, zp->z_linenum); 17957c478bd9Sstevel@tonic-gate if (*startbuf == '\0') 17967c478bd9Sstevel@tonic-gate error(gettext( 17977c478bd9Sstevel@tonic-gate "can't determine time zone abbrevation to use just after until time")); 17987c478bd9Sstevel@tonic-gate else addtt(starttime, 17997c478bd9Sstevel@tonic-gate addtype(startoff, startbuf, 18007c478bd9Sstevel@tonic-gate startoff != zp->z_gmtoff, 18017c478bd9Sstevel@tonic-gate startttisstd, 18027c478bd9Sstevel@tonic-gate startttisgmt)); 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate /* 18057c478bd9Sstevel@tonic-gate * Now we may get to set starttime for the next zone line. 18067c478bd9Sstevel@tonic-gate */ 18077c478bd9Sstevel@tonic-gate if (useuntil) { 18087c478bd9Sstevel@tonic-gate startttisstd = zp->z_untilrule.r_todisstd; 18097c478bd9Sstevel@tonic-gate startttisgmt = zp->z_untilrule.r_todisgmt; 18107c478bd9Sstevel@tonic-gate starttime = zp->z_untiltime; 18117c478bd9Sstevel@tonic-gate if (!startttisstd) 18127c478bd9Sstevel@tonic-gate starttime = tadd(starttime, -stdoff); 18137c478bd9Sstevel@tonic-gate if (!startttisgmt) 18147c478bd9Sstevel@tonic-gate starttime = tadd(starttime, -gmtoff); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate writezone(zpfirst->z_name); 18187c478bd9Sstevel@tonic-gate } 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate static void 18217c478bd9Sstevel@tonic-gate addtt(starttime, type) 182280868c53Srobbin const zic_t starttime; 18237c478bd9Sstevel@tonic-gate int type; 18247c478bd9Sstevel@tonic-gate { 18257c478bd9Sstevel@tonic-gate if (starttime <= min_time || 18267c478bd9Sstevel@tonic-gate (timecnt == 1 && attypes[0].at < min_time)) { 18277c478bd9Sstevel@tonic-gate gmtoffs[0] = gmtoffs[type]; 18287c478bd9Sstevel@tonic-gate isdsts[0] = isdsts[type]; 18297c478bd9Sstevel@tonic-gate ttisstds[0] = ttisstds[type]; 18307c478bd9Sstevel@tonic-gate ttisgmts[0] = ttisgmts[type]; 18317c478bd9Sstevel@tonic-gate if (abbrinds[type] != 0) 18327c478bd9Sstevel@tonic-gate (void) strcpy(chars, &chars[abbrinds[type]]); 18337c478bd9Sstevel@tonic-gate abbrinds[0] = 0; 18347c478bd9Sstevel@tonic-gate charcnt = strlen(chars) + 1; 18357c478bd9Sstevel@tonic-gate typecnt = 1; 18367c478bd9Sstevel@tonic-gate timecnt = 0; 18377c478bd9Sstevel@tonic-gate type = 0; 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate if (timecnt >= TZ_MAX_TIMES) { 18407c478bd9Sstevel@tonic-gate error(gettext("too many transitions?!")); 184180868c53Srobbin exit(EXIT_FAILURE); 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate attypes[timecnt].at = starttime; 18447c478bd9Sstevel@tonic-gate attypes[timecnt].type = type; 18457c478bd9Sstevel@tonic-gate ++timecnt; 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate static int 18497c478bd9Sstevel@tonic-gate addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) 18507c478bd9Sstevel@tonic-gate const long gmtoff; 18517c478bd9Sstevel@tonic-gate const char * const abbr; 18527c478bd9Sstevel@tonic-gate const int isdst; 18537c478bd9Sstevel@tonic-gate const int ttisstd; 18547c478bd9Sstevel@tonic-gate const int ttisgmt; 18557c478bd9Sstevel@tonic-gate { 18567c478bd9Sstevel@tonic-gate register int i, j; 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate if (isdst != TRUE && isdst != FALSE) { 18597c478bd9Sstevel@tonic-gate error(gettext( 18607c478bd9Sstevel@tonic-gate "internal error - addtype called with bad isdst")); 186180868c53Srobbin exit(EXIT_FAILURE); 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate if (ttisstd != TRUE && ttisstd != FALSE) { 18647c478bd9Sstevel@tonic-gate error(gettext( 18657c478bd9Sstevel@tonic-gate "internal error - addtype called with bad ttisstd")); 186680868c53Srobbin exit(EXIT_FAILURE); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate if (ttisgmt != TRUE && ttisgmt != FALSE) { 18697c478bd9Sstevel@tonic-gate error(gettext( 18707c478bd9Sstevel@tonic-gate "internal error - addtype called with bad ttisgmt")); 187180868c53Srobbin exit(EXIT_FAILURE); 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate /* 18747c478bd9Sstevel@tonic-gate * See if there's already an entry for this zone type. 18757c478bd9Sstevel@tonic-gate * If so, just return its index. 18767c478bd9Sstevel@tonic-gate */ 18777c478bd9Sstevel@tonic-gate for (i = 0; i < typecnt; ++i) { 18787c478bd9Sstevel@tonic-gate if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && 18797c478bd9Sstevel@tonic-gate strcmp(abbr, &chars[abbrinds[i]]) == 0 && 18807c478bd9Sstevel@tonic-gate ttisstd == ttisstds[i] && 18817c478bd9Sstevel@tonic-gate ttisgmt == ttisgmts[i]) 18827c478bd9Sstevel@tonic-gate return (i); 18837c478bd9Sstevel@tonic-gate } 18847c478bd9Sstevel@tonic-gate /* 18857c478bd9Sstevel@tonic-gate * There isn't one; add a new one, unless there are already too 18867c478bd9Sstevel@tonic-gate * many. 18877c478bd9Sstevel@tonic-gate */ 18887c478bd9Sstevel@tonic-gate if (typecnt >= TZ_MAX_TYPES) { 18897c478bd9Sstevel@tonic-gate error(gettext("too many local time types")); 189080868c53Srobbin exit(EXIT_FAILURE); 18917c478bd9Sstevel@tonic-gate } 1892*a68d064cSrobbin if (!(-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { 1893*a68d064cSrobbin error(gettext("UTC offset out of range")); 1894*a68d064cSrobbin exit(EXIT_FAILURE); 1895*a68d064cSrobbin } 18967c478bd9Sstevel@tonic-gate gmtoffs[i] = gmtoff; 18977c478bd9Sstevel@tonic-gate isdsts[i] = isdst; 18987c478bd9Sstevel@tonic-gate ttisstds[i] = ttisstd; 18997c478bd9Sstevel@tonic-gate ttisgmts[i] = ttisgmt; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate for (j = 0; j < charcnt; ++j) 19027c478bd9Sstevel@tonic-gate if (strcmp(&chars[j], abbr) == 0) 19037c478bd9Sstevel@tonic-gate break; 19047c478bd9Sstevel@tonic-gate if (j == charcnt) 19057c478bd9Sstevel@tonic-gate newabbr(abbr); 19067c478bd9Sstevel@tonic-gate abbrinds[i] = j; 19077c478bd9Sstevel@tonic-gate ++typecnt; 19087c478bd9Sstevel@tonic-gate return (i); 19097c478bd9Sstevel@tonic-gate } 19107c478bd9Sstevel@tonic-gate 19117c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 19127c478bd9Sstevel@tonic-gate static void 19137c478bd9Sstevel@tonic-gate leapadd(t, positive, rolling, count) 191480868c53Srobbin const zic_t t; 19157c478bd9Sstevel@tonic-gate const int positive; 19167c478bd9Sstevel@tonic-gate const int rolling; 19177c478bd9Sstevel@tonic-gate int count; 19187c478bd9Sstevel@tonic-gate { 19197c478bd9Sstevel@tonic-gate register int i, j; 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { 19227c478bd9Sstevel@tonic-gate error(gettext("too many leap seconds")); 192380868c53Srobbin exit(EXIT_FAILURE); 19247c478bd9Sstevel@tonic-gate } 19257c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) 19267c478bd9Sstevel@tonic-gate if (t <= trans[i]) { 19277c478bd9Sstevel@tonic-gate if (t == trans[i]) { 19287c478bd9Sstevel@tonic-gate error(gettext("repeated leap second moment")); 192980868c53Srobbin exit(EXIT_FAILURE); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate break; 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate do { 19347c478bd9Sstevel@tonic-gate for (j = leapcnt; j > i; --j) { 19357c478bd9Sstevel@tonic-gate trans[j] = trans[j - 1]; 19367c478bd9Sstevel@tonic-gate corr[j] = corr[j - 1]; 19377c478bd9Sstevel@tonic-gate roll[j] = roll[j - 1]; 19387c478bd9Sstevel@tonic-gate } 19397c478bd9Sstevel@tonic-gate trans[i] = t; 19407c478bd9Sstevel@tonic-gate corr[i] = positive ? 1L : eitol(-count); 19417c478bd9Sstevel@tonic-gate roll[i] = rolling; 19427c478bd9Sstevel@tonic-gate ++leapcnt; 19437c478bd9Sstevel@tonic-gate } while (positive && --count != 0); 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate #ifdef LEAPSECOND_SUPPORT 19487c478bd9Sstevel@tonic-gate static void 19497c478bd9Sstevel@tonic-gate adjleap(void) 19507c478bd9Sstevel@tonic-gate { 19517c478bd9Sstevel@tonic-gate register int i; 19527c478bd9Sstevel@tonic-gate register long last = 0; 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate /* 19557c478bd9Sstevel@tonic-gate * propagate leap seconds forward 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate for (i = 0; i < leapcnt; ++i) { 19587c478bd9Sstevel@tonic-gate trans[i] = tadd(trans[i], last); 19597c478bd9Sstevel@tonic-gate last = corr[i] += last; 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate #endif /* LEAPSECOND_SUPPORT */ 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate static int 19657c478bd9Sstevel@tonic-gate yearistype(year, type) 19667c478bd9Sstevel@tonic-gate const int year; 19677c478bd9Sstevel@tonic-gate const char * const type; 19687c478bd9Sstevel@tonic-gate { 19697c478bd9Sstevel@tonic-gate static char *buf; 19707c478bd9Sstevel@tonic-gate int result; 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate if (type == NULL || *type == '\0') 19737c478bd9Sstevel@tonic-gate return (TRUE); 19747c478bd9Sstevel@tonic-gate #if defined(sun) 19757c478bd9Sstevel@tonic-gate if (strcmp(type, "uspres") == 0) 19767c478bd9Sstevel@tonic-gate return ((year % 4) == 0); 19777c478bd9Sstevel@tonic-gate if (strcmp(type, "nonpres") == 0) 19787c478bd9Sstevel@tonic-gate return ((year % 4) != 0); 19797c478bd9Sstevel@tonic-gate if (strcmp(type, "even") == 0) 19807c478bd9Sstevel@tonic-gate return ((year % 2) == 0); 19817c478bd9Sstevel@tonic-gate if (strcmp(type, "odd") == 0) 19827c478bd9Sstevel@tonic-gate return ((year % 2) != 0); 19837c478bd9Sstevel@tonic-gate #endif /* defined(sun) */ 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate buf = erealloc(buf, (int)(132 + strlen(yitcommand) + strlen(type))); 19867c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s %d %s", yitcommand, year, type); 19877c478bd9Sstevel@tonic-gate result = system(buf); 198880868c53Srobbin if (WIFEXITED(result)) { 198980868c53Srobbin switch (WEXITSTATUS(result)) { 199080868c53Srobbin case 0: 19917c478bd9Sstevel@tonic-gate return (TRUE); 199280868c53Srobbin case 1: 19937c478bd9Sstevel@tonic-gate return (FALSE); 199480868c53Srobbin } 199580868c53Srobbin } 19967c478bd9Sstevel@tonic-gate error(gettext("Wild result from command execution")); 19977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: command was '%s', result was %d\n"), 19987c478bd9Sstevel@tonic-gate progname, buf, result); 19997c478bd9Sstevel@tonic-gate for (;;) 200080868c53Srobbin exit(EXIT_FAILURE); 20017c478bd9Sstevel@tonic-gate } 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate static int 20047c478bd9Sstevel@tonic-gate lowerit(a) 20057c478bd9Sstevel@tonic-gate int a; 20067c478bd9Sstevel@tonic-gate { 20077c478bd9Sstevel@tonic-gate a = (unsigned char) a; 20087c478bd9Sstevel@tonic-gate return ((isascii(a) && isupper(a)) ? tolower(a) : a); 20097c478bd9Sstevel@tonic-gate } 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate static int 20127c478bd9Sstevel@tonic-gate ciequal(ap, bp) /* case-insensitive equality */ 20137c478bd9Sstevel@tonic-gate register const char *ap; 20147c478bd9Sstevel@tonic-gate register const char *bp; 20157c478bd9Sstevel@tonic-gate { 20167c478bd9Sstevel@tonic-gate while (lowerit(*ap) == lowerit(*bp++)) 20177c478bd9Sstevel@tonic-gate if (*ap++ == '\0') 20187c478bd9Sstevel@tonic-gate return (TRUE); 20197c478bd9Sstevel@tonic-gate return (FALSE); 20207c478bd9Sstevel@tonic-gate } 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate static int 20237c478bd9Sstevel@tonic-gate itsabbr(abbr, word) 20247c478bd9Sstevel@tonic-gate register const char *abbr; 20257c478bd9Sstevel@tonic-gate register const char *word; 20267c478bd9Sstevel@tonic-gate { 20277c478bd9Sstevel@tonic-gate if (lowerit(*abbr) != lowerit(*word)) 20287c478bd9Sstevel@tonic-gate return (FALSE); 20297c478bd9Sstevel@tonic-gate ++word; 20307c478bd9Sstevel@tonic-gate while (*++abbr != '\0') 20317c478bd9Sstevel@tonic-gate do { 20327c478bd9Sstevel@tonic-gate if (*word == '\0') 20337c478bd9Sstevel@tonic-gate return (FALSE); 20347c478bd9Sstevel@tonic-gate } while (lowerit(*word++) != lowerit(*abbr)); 20357c478bd9Sstevel@tonic-gate return (TRUE); 20367c478bd9Sstevel@tonic-gate } 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate static const struct lookup * 20397c478bd9Sstevel@tonic-gate byword(word, table) 20407c478bd9Sstevel@tonic-gate register const char * const word; 20417c478bd9Sstevel@tonic-gate register const struct lookup * const table; 20427c478bd9Sstevel@tonic-gate { 20437c478bd9Sstevel@tonic-gate register const struct lookup *foundlp; 20447c478bd9Sstevel@tonic-gate register const struct lookup *lp; 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate if (word == NULL || table == NULL) 20477c478bd9Sstevel@tonic-gate return (NULL); 20487c478bd9Sstevel@tonic-gate /* 20497c478bd9Sstevel@tonic-gate * Look for exact match. 20507c478bd9Sstevel@tonic-gate */ 20517c478bd9Sstevel@tonic-gate for (lp = table; lp->l_word != NULL; ++lp) 20527c478bd9Sstevel@tonic-gate if (ciequal(word, lp->l_word)) 20537c478bd9Sstevel@tonic-gate return (lp); 20547c478bd9Sstevel@tonic-gate /* 20557c478bd9Sstevel@tonic-gate * Look for inexact match. 20567c478bd9Sstevel@tonic-gate */ 20577c478bd9Sstevel@tonic-gate foundlp = NULL; 20587c478bd9Sstevel@tonic-gate for (lp = table; lp->l_word != NULL; ++lp) 20597c478bd9Sstevel@tonic-gate if (itsabbr(word, lp->l_word)) { 20607c478bd9Sstevel@tonic-gate if (foundlp == NULL) 20617c478bd9Sstevel@tonic-gate foundlp = lp; 20627c478bd9Sstevel@tonic-gate else return (NULL); /* multiple inexact matches */ 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate return (foundlp); 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate static char ** 20687c478bd9Sstevel@tonic-gate getfields(cp) 20697c478bd9Sstevel@tonic-gate register char *cp; 20707c478bd9Sstevel@tonic-gate { 20717c478bd9Sstevel@tonic-gate register char *dp; 20727c478bd9Sstevel@tonic-gate register char **array; 20737c478bd9Sstevel@tonic-gate register int nsubs; 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate if (cp == NULL) 20767c478bd9Sstevel@tonic-gate return (NULL); 20777c478bd9Sstevel@tonic-gate array = (char **)(void *) 20787c478bd9Sstevel@tonic-gate emalloc((int)((strlen(cp) + 1) * sizeof (*array))); 20797c478bd9Sstevel@tonic-gate nsubs = 0; 20807c478bd9Sstevel@tonic-gate for (;;) { 20817c478bd9Sstevel@tonic-gate while (isascii(*cp) && isspace((unsigned char) *cp)) 20827c478bd9Sstevel@tonic-gate ++cp; 20837c478bd9Sstevel@tonic-gate if (*cp == '\0' || *cp == '#') 20847c478bd9Sstevel@tonic-gate break; 20857c478bd9Sstevel@tonic-gate array[nsubs++] = dp = cp; 20867c478bd9Sstevel@tonic-gate do { 20877c478bd9Sstevel@tonic-gate if ((*dp = *cp++) != '"') 20887c478bd9Sstevel@tonic-gate ++dp; 20897c478bd9Sstevel@tonic-gate else while ((*dp = *cp++) != '"') 20907c478bd9Sstevel@tonic-gate if (*dp != '\0') 20917c478bd9Sstevel@tonic-gate ++dp; 2092*a68d064cSrobbin else { 20937c478bd9Sstevel@tonic-gate error(gettext( 20947c478bd9Sstevel@tonic-gate "Odd number of quotation marks")); 2095*a68d064cSrobbin exit(1); 2096*a68d064cSrobbin } 20977c478bd9Sstevel@tonic-gate } while (*cp != '\0' && *cp != '#' && 20987c478bd9Sstevel@tonic-gate (!isascii(*cp) || !isspace((unsigned char) *cp))); 20997c478bd9Sstevel@tonic-gate if (isascii(*cp) && isspace((unsigned char) *cp)) 21007c478bd9Sstevel@tonic-gate ++cp; 21017c478bd9Sstevel@tonic-gate *dp = '\0'; 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate array[nsubs] = NULL; 21047c478bd9Sstevel@tonic-gate return (array); 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate static long 21087c478bd9Sstevel@tonic-gate oadd(t1, t2) 21097c478bd9Sstevel@tonic-gate const long t1; 21107c478bd9Sstevel@tonic-gate const long t2; 21117c478bd9Sstevel@tonic-gate { 21127c478bd9Sstevel@tonic-gate register long t; 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate t = t1 + t2; 21157c478bd9Sstevel@tonic-gate if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 21167c478bd9Sstevel@tonic-gate error(gettext("time overflow")); 211780868c53Srobbin exit(EXIT_FAILURE); 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate return (t); 21207c478bd9Sstevel@tonic-gate } 21217c478bd9Sstevel@tonic-gate 212280868c53Srobbin static zic_t 21237c478bd9Sstevel@tonic-gate tadd(t1, t2) 212480868c53Srobbin const zic_t t1; 21257c478bd9Sstevel@tonic-gate const long t2; 21267c478bd9Sstevel@tonic-gate { 212780868c53Srobbin register zic_t t; 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate if (t1 == max_time && t2 > 0) 21307c478bd9Sstevel@tonic-gate return (max_time); 21317c478bd9Sstevel@tonic-gate if (t1 == min_time && t2 < 0) 21327c478bd9Sstevel@tonic-gate return (min_time); 21337c478bd9Sstevel@tonic-gate t = t1 + t2; 21347c478bd9Sstevel@tonic-gate if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { 21357c478bd9Sstevel@tonic-gate error(gettext("time overflow")); 213680868c53Srobbin exit(EXIT_FAILURE); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate return (t); 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate /* 21427c478bd9Sstevel@tonic-gate * Given a rule, and a year, compute the date - in seconds since January 1, 21437c478bd9Sstevel@tonic-gate * 1970, 00:00 LOCAL time - in that year that the rule refers to. 21447c478bd9Sstevel@tonic-gate */ 21457c478bd9Sstevel@tonic-gate 214680868c53Srobbin static zic_t 21477c478bd9Sstevel@tonic-gate rpytime(rp, wantedy) 21487c478bd9Sstevel@tonic-gate register const struct rule * const rp; 21497c478bd9Sstevel@tonic-gate register const int wantedy; 21507c478bd9Sstevel@tonic-gate { 21517c478bd9Sstevel@tonic-gate register int y, m, i; 21527c478bd9Sstevel@tonic-gate register long dayoff; /* with a nod to Margaret O. */ 215380868c53Srobbin register zic_t t; 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate if (wantedy == INT_MIN) 21567c478bd9Sstevel@tonic-gate return (min_time); 21577c478bd9Sstevel@tonic-gate if (wantedy == INT_MAX) 21587c478bd9Sstevel@tonic-gate return (max_time); 21597c478bd9Sstevel@tonic-gate dayoff = 0; 21607c478bd9Sstevel@tonic-gate m = TM_JANUARY; 21617c478bd9Sstevel@tonic-gate y = EPOCH_YEAR; 21627c478bd9Sstevel@tonic-gate while (wantedy != y) { 21637c478bd9Sstevel@tonic-gate if (wantedy > y) { 21647c478bd9Sstevel@tonic-gate i = len_years[isleap(y)]; 21657c478bd9Sstevel@tonic-gate ++y; 21667c478bd9Sstevel@tonic-gate } else { 21677c478bd9Sstevel@tonic-gate --y; 21687c478bd9Sstevel@tonic-gate i = -len_years[isleap(y)]; 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate while (m != rp->r_month) { 21737c478bd9Sstevel@tonic-gate i = len_months[isleap(y)][m]; 21747c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 21757c478bd9Sstevel@tonic-gate ++m; 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate i = rp->r_dayofmonth; 21787c478bd9Sstevel@tonic-gate if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { 21797c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWLEQ) 21807c478bd9Sstevel@tonic-gate --i; 21817c478bd9Sstevel@tonic-gate else { 21827c478bd9Sstevel@tonic-gate error(gettext("use of 2/29 in non leap-year")); 218380868c53Srobbin exit(EXIT_FAILURE); 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate --i; 21877c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, eitol(i)); 21887c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { 21897c478bd9Sstevel@tonic-gate register long wday; 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate #define LDAYSPERWEEK ((long)DAYSPERWEEK) 21927c478bd9Sstevel@tonic-gate wday = eitol(EPOCH_WDAY); 21937c478bd9Sstevel@tonic-gate /* 21947c478bd9Sstevel@tonic-gate * Don't trust mod of negative numbers. 21957c478bd9Sstevel@tonic-gate */ 21967c478bd9Sstevel@tonic-gate if (dayoff >= 0) 21977c478bd9Sstevel@tonic-gate wday = (wday + dayoff) % LDAYSPERWEEK; 21987c478bd9Sstevel@tonic-gate else { 21997c478bd9Sstevel@tonic-gate wday -= ((-dayoff) % LDAYSPERWEEK); 22007c478bd9Sstevel@tonic-gate if (wday < 0) 22017c478bd9Sstevel@tonic-gate wday += LDAYSPERWEEK; 22027c478bd9Sstevel@tonic-gate } 22037c478bd9Sstevel@tonic-gate while (wday != eitol(rp->r_wday)) 22047c478bd9Sstevel@tonic-gate if (rp->r_dycode == DC_DOWGEQ) { 22057c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, (long)1); 22067c478bd9Sstevel@tonic-gate if (++wday >= LDAYSPERWEEK) 22077c478bd9Sstevel@tonic-gate wday = 0; 22087c478bd9Sstevel@tonic-gate ++i; 22097c478bd9Sstevel@tonic-gate } else { 22107c478bd9Sstevel@tonic-gate dayoff = oadd(dayoff, (long)-1); 22117c478bd9Sstevel@tonic-gate if (--wday < 0) 22127c478bd9Sstevel@tonic-gate wday = LDAYSPERWEEK - 1; 22137c478bd9Sstevel@tonic-gate --i; 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate if (i < 0 || i >= len_months[isleap(y)][m]) { 221680868c53Srobbin if (noise) 221780868c53Srobbin warning(gettext("rule goes past start/end of " 221880868c53Srobbin "month--will not work with pre-2004 " 221980868c53Srobbin "versions of zic")); 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate } 222280868c53Srobbin if (dayoff < 0 && !TYPE_SIGNED(zic_t)) 22237c478bd9Sstevel@tonic-gate return (min_time); 222480868c53Srobbin if (dayoff < min_time / SECSPERDAY) 222580868c53Srobbin return (min_time); 222680868c53Srobbin if (dayoff > max_time / SECSPERDAY) 222780868c53Srobbin return (max_time); 222880868c53Srobbin t = (zic_t)dayoff * SECSPERDAY; 22297c478bd9Sstevel@tonic-gate return (tadd(t, rp->r_tod)); 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate 22327c478bd9Sstevel@tonic-gate static void 22337c478bd9Sstevel@tonic-gate newabbr(string) 22347c478bd9Sstevel@tonic-gate const char * const string; 22357c478bd9Sstevel@tonic-gate { 22367c478bd9Sstevel@tonic-gate register int i; 22377c478bd9Sstevel@tonic-gate 223880868c53Srobbin if (strcmp(string, GRANDPARENTED) != 0) { 223980868c53Srobbin register const char *cp; 224080868c53Srobbin register char *wp; 224180868c53Srobbin 224280868c53Srobbin /* 224380868c53Srobbin * Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics 224480868c53Srobbin * optionally followed by a + or - and a number from 1 to 14. 224580868c53Srobbin */ 224680868c53Srobbin cp = string; 224780868c53Srobbin wp = NULL; 224880868c53Srobbin while (isascii(*cp) && isalpha(*cp)) 224980868c53Srobbin ++cp; 225080868c53Srobbin if (cp - string == 0) 225180868c53Srobbin wp = gettext(("time zone abbreviation lacks " 225280868c53Srobbin "alphabetic at start")); 225380868c53Srobbin if (noise && cp - string > 3) 225480868c53Srobbin wp = gettext(("time zone abbreviation has more than 3 " 225580868c53Srobbin "alphabetics")); 225680868c53Srobbin if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN) 225780868c53Srobbin wp = gettext(("time zone abbreviation has too many " 225880868c53Srobbin "alphabetics")); 225980868c53Srobbin if (wp == NULL && (*cp == '+' || *cp == '-')) { 226080868c53Srobbin ++cp; 226180868c53Srobbin if (isascii(*cp) && isdigit(*cp)) 226280868c53Srobbin if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 226380868c53Srobbin ++cp; 226480868c53Srobbin } 226580868c53Srobbin if (*cp != '\0') 226680868c53Srobbin wp = gettext("time zone abbreviation differs from " 226780868c53Srobbin "POSIX standard"); 226880868c53Srobbin if (wp != NULL) { 226980868c53Srobbin wp = ecpyalloc(wp); 227080868c53Srobbin wp = ecatalloc(wp, " ("); 227180868c53Srobbin wp = ecatalloc(wp, string); 227280868c53Srobbin wp = ecatalloc(wp, ")"); 227380868c53Srobbin warning(wp); 227480868c53Srobbin ifree(wp); 227580868c53Srobbin } 227680868c53Srobbin } 22777c478bd9Sstevel@tonic-gate i = strlen(string) + 1; 22787c478bd9Sstevel@tonic-gate if (charcnt + i > TZ_MAX_CHARS) { 227980868c53Srobbin error(gettext("too many, or too long, time zone " 228080868c53Srobbin "abbreviations")); 228180868c53Srobbin exit(EXIT_FAILURE); 22827c478bd9Sstevel@tonic-gate } 22837c478bd9Sstevel@tonic-gate (void) strcpy(&chars[charcnt], string); 22847c478bd9Sstevel@tonic-gate charcnt += eitol(i); 22857c478bd9Sstevel@tonic-gate } 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate static int 22887c478bd9Sstevel@tonic-gate mkdirs(argname) 2289*a68d064cSrobbin char * argname; 22907c478bd9Sstevel@tonic-gate { 22917c478bd9Sstevel@tonic-gate register char *name; 22927c478bd9Sstevel@tonic-gate register char *cp; 22937c478bd9Sstevel@tonic-gate 22947c478bd9Sstevel@tonic-gate if (argname == NULL || *argname == '\0') 22957c478bd9Sstevel@tonic-gate return (0); 22967c478bd9Sstevel@tonic-gate cp = name = ecpyalloc(argname); 22977c478bd9Sstevel@tonic-gate while ((cp = strchr(cp + 1, '/')) != 0) { 22987c478bd9Sstevel@tonic-gate *cp = '\0'; 22997c478bd9Sstevel@tonic-gate if (!itsdir(name)) { 23007c478bd9Sstevel@tonic-gate /* 23017c478bd9Sstevel@tonic-gate * It doesn't seem to exist, so we try to create it. 23027c478bd9Sstevel@tonic-gate * Creation may fail because of the directory being 23037c478bd9Sstevel@tonic-gate * created by some other multiprocessor, so we get 23047c478bd9Sstevel@tonic-gate * to do extra checking. 23057c478bd9Sstevel@tonic-gate */ 230680868c53Srobbin if (mkdir(name, MKDIR_UMASK) != 0) { 23077c478bd9Sstevel@tonic-gate const char *e = strerror(errno); 23087c478bd9Sstevel@tonic-gate 23097c478bd9Sstevel@tonic-gate if (errno != EEXIST || !itsdir(name)) { 23107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 23117c478bd9Sstevel@tonic-gate "%s: Can't create directory %s: %s\n"), 23127c478bd9Sstevel@tonic-gate progname, name, e); 23137c478bd9Sstevel@tonic-gate ifree(name); 23147c478bd9Sstevel@tonic-gate return (-1); 23157c478bd9Sstevel@tonic-gate } 23167c478bd9Sstevel@tonic-gate } 23177c478bd9Sstevel@tonic-gate } 23187c478bd9Sstevel@tonic-gate *cp = '/'; 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate ifree(name); 23217c478bd9Sstevel@tonic-gate return (0); 23227c478bd9Sstevel@tonic-gate } 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate static long 23257c478bd9Sstevel@tonic-gate eitol(i) 23267c478bd9Sstevel@tonic-gate const int i; 23277c478bd9Sstevel@tonic-gate { 23287c478bd9Sstevel@tonic-gate long l; 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate l = i; 23317c478bd9Sstevel@tonic-gate if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { 23327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 23337c478bd9Sstevel@tonic-gate gettext("%s: %d did not sign extend correctly\n"), 23347c478bd9Sstevel@tonic-gate progname, i); 233580868c53Srobbin exit(EXIT_FAILURE); 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate return (l); 23387c478bd9Sstevel@tonic-gate } 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate /* 234180868c53Srobbin * UNIX was a registered trademark of The Open Group in 2003. 23427c478bd9Sstevel@tonic-gate */ 2343