echo x - "tzfile.h" 2>&1 sed "s/^X//" >"tzfile.h" <<'!The!End!' X#ifndef lint X#ifndef NOID Xstatic char tzfilehid[] = "@(#)tzfile.h 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X/* X** Information about time zone files. X*/ X X#ifndef TZDIR X#define TZDIR "/etc/zoneinfo" /* Time zone object file directory */ X#endif /* !TZDIR */ X X#ifndef TZDEFAULT X#define TZDEFAULT "localtime" X#endif /* !TZDEFAULT */ X X/* X** Each file begins with. . . X*/ X Xstruct tzhead { X char tzh_reserved[32]; /* reserved for future use */ X char tzh_timecnt[4]; /* coded number of transition times */ X char tzh_typecnt[4]; /* coded number of local time types */ X char tzh_charcnt[4]; /* coded number of abbr. chars */ X}; X X/* X** . . .followed by. . . X** X** tzh_timecnt (char [4])s coded transition times a la time(2) X** tzh_timecnt (unsigned char)s types of local time starting at above X** tzh_typecnt repetitions of X** one (char [4]) coded GMT offset in seconds X** one (unsigned char) used to set tm_isdt X** one (unsigned char) that's an abbreviation list index X** tzh_charcnt (char)s '\0'-terminated zone abbreviaton strings X*/ X X/* X** In the current implementation, "tzset()" refuses to deal with files that X** exceed any of the limits below. X*/ X X#ifndef TZ_MAX_TIMES X/* X** The TZ_MAX_TIMES value below is enough to handle a bit more than a X** year's worth of solar time (corrected daily to the nearest second) or X** 138 years of Pacific Presidential Election time X** (where there are three time zone transitions every fourth year). X*/ X#define TZ_MAX_TIMES 370 X#endif /* !TZ_MAX_TIMES */ X X#ifndef TZ_MAX_TYPES X#ifndef NOSOLAR X#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ X#else /* !NOSOLAR */ X#define TZ_MAX_TYPES 10 /* Maximum number of local time types */ X#endif /* !NOSOLAR */ X#endif /* !TZ_MAX_TYPES */ X X#ifndef TZ_MAX_CHARS X#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ X#endif /* !TZ_MAX_CHARS */ X X#define SECS_PER_MIN 60 X#define MINS_PER_HOUR 60 X#define HOURS_PER_DAY 24 X#define DAYS_PER_WEEK 7 X#define DAYS_PER_NYEAR 365 X#define DAYS_PER_LYEAR 366 X#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR) X#define SECS_PER_DAY ((long) SECS_PER_HOUR * HOURS_PER_DAY) X#define MONS_PER_YEAR 12 X X#define TM_SUNDAY 0 X#define TM_MONDAY 1 X#define TM_TUESDAY 2 X#define TM_WEDNESDAY 3 X#define TM_THURSDAY 4 X#define TM_FRIDAY 5 X#define TM_SATURDAY 6 X X#define TM_JANUARY 0 X#define TM_FEBRUARY 1 X#define TM_MARCH 2 X#define TM_APRIL 3 X#define TM_MAY 4 X#define TM_JUNE 5 X#define TM_JULY 6 X#define TM_AUGUST 7 X#define TM_SEPTEMBER 8 X#define TM_OCTOBER 9 X#define TM_NOVEMBER 10 X#define TM_DECEMBER 11 X#define TM_SUNDAY 0 X X#define TM_YEAR_BASE 1900 X X#define EPOCH_YEAR 1970 X#define EPOCH_WDAY TM_THURSDAY X X/* X** Accurate only for the past couple of centuries; X** that will probably do. X*/ X X#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) !The!End! echo x - "zic.c" 2>&1 sed "s/^X//" >"zic.c" <<'!The!End!' X# X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)zic.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#include "tzfile.h" X#include "ctype.h" X#include "sys/types.h" X#include "sys/stat.h" X#include "time.h" X X#ifndef BUFSIZ X#define BUFSIZ 1024 X#endif X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X Xextern char * icpyalloc(); Xextern char * imalloc(); Xextern char * irealloc(); Xextern char * optarg; Xextern int optind; Xextern FILE * popen(); Xextern char * scheck(); X#ifndef USG Xextern char * sprintf(); X#endif /* !USG */ Xextern char * strcat(); Xextern char * strchr(); Xextern char * strcpy(); X Xstatic addtt(); Xstatic addtype(); Xstatic associate(); Xstatic int charcnt; Xstatic ciequal(); Xstatic long eitol(); Xstatic int errors; Xstatic char * filename; Xstatic char ** getfields(); Xstatic long gethms(); Xstatic infile(); Xstatic inlink(); Xstatic inrule(); Xstatic inzcont(); Xstatic inzone(); Xstatic inzsub(); Xstatic int linenum; Xstatic lowerit(); Xstatic time_t max_time; Xstatic int max_year; Xstatic time_t min_time; Xstatic int min_year; Xstatic mkdirs(); Xstatic newabbr(); Xstatic int noise; Xstatic nondunlink(); Xstatic long oadd(); Xstatic outzone(); Xstatic char * progname; Xstatic char * rfilename; Xstatic int rlinenum; Xstatic time_t rpytime(); Xstatic rulesub(); Xstatic setboundaries(); Xstatic time_t tadd(); Xstatic int timecnt; Xstatic int tt_signed; Xstatic int typecnt; Xstatic yearistype(); X X/* X** Line codes. X*/ X X#define LC_RULE 0 X#define LC_ZONE 1 X#define LC_LINK 2 X X/* X** Which fields are which on a Zone line. X*/ X X#define ZF_NAME 1 X#define ZF_GMTOFF 2 X#define ZF_RULE 3 X#define ZF_FORMAT 4 X#define ZF_UNTILYEAR 5 X#define ZF_UNTILMONTH 6 X#define ZF_UNTILDAY 7 X#define ZF_UNTILTIME 8 X#define ZONE_MINFIELDS 5 X#define ZONE_MAXFIELDS 9 X X/* X** Which fields are which on a Zone continuation line. X*/ X X#define ZFC_GMTOFF 0 X#define ZFC_RULE 1 X#define ZFC_FORMAT 2 X#define ZFC_UNTILYEAR 3 X#define ZFC_UNTILMONTH 4 X#define ZFC_UNTILDAY 5 X#define ZFC_UNTILTIME 6 X#define ZONEC_MINFIELDS 3 X#define ZONEC_MAXFIELDS 7 X X/* X** Which files are which on a Rule line. X*/ X X#define RF_NAME 1 X#define RF_LOYEAR 2 X#define RF_HIYEAR 3 X#define RF_COMMAND 4 X#define RF_MONTH 5 X#define RF_DAY 6 X#define RF_TOD 7 X#define RF_STDOFF 8 X#define RF_ABBRVAR 9 X#define RULE_FIELDS 10 X X/* X** Which fields are which on a Link line. X*/ X X#define LF_FROM 1 X#define LF_TO 2 X#define LINK_FIELDS 3 X Xstruct rule { X char * r_filename; X int r_linenum; X char * r_name; X X int r_loyear; /* for example, 1986 */ X int r_hiyear; /* for example, 1986 */ X char * r_yrtype; X X int r_month; /* 0..11 */ X X int r_dycode; /* see below */ X int r_dayofmonth; X int r_wday; X X long r_tod; /* time from midnight */ X int r_todisstd; /* above is standard time if TRUE */ X /* above is wall clock time if FALSE */ X long r_stdoff; /* offset from standard time */ X char * r_abbrvar; /* variable part of time zone abbreviation */ X X int r_todo; /* a rule to do (used in outzone) */ X time_t r_temp; /* used in outzone */ X}; X X/* X** r_dycode r_dayofmonth r_wday X*/ X#define DC_DOM 0 /* 1..31 */ /* unused */ X#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */ X#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */ X X/* X** Year synonyms. X*/ X X#define YR_MINIMUM 0 X#define YR_MAXIMUM 1 X#define YR_ONLY 2 X Xstatic struct rule * rules; Xstatic int nrules; /* number of rules */ X Xstruct zone { X char * z_filename; X int z_linenum; X X char * z_name; X long z_gmtoff; X char * z_rule; X char * z_format; X X long z_stdoff; X X struct rule * z_rules; X int z_nrules; X X struct rule z_untilrule; X time_t z_untiltime; X}; X Xstatic struct zone * zones; Xstatic int nzones; /* number of zones */ X Xstruct link { X char * l_filename; X int l_linenum; X char * l_from; X char * l_to; X}; X Xstatic struct link * links; Xstatic int nlinks; X Xstruct lookup { X char * l_word; X int l_value; X}; X Xstatic struct lookup * byword(); X Xstatic struct lookup line_codes[] = { X "Rule", LC_RULE, X "Zone", LC_ZONE, X "Link", LC_LINK, X NULL, 0 X}; X Xstatic struct lookup mon_names[] = { X "January", TM_JANUARY, X "February", TM_FEBRUARY, X "March", TM_MARCH, X "April", TM_APRIL, X "May", TM_MAY, X "June", TM_JUNE, X "July", TM_JULY, X "August", TM_AUGUST, X "September", TM_SEPTEMBER, X "October", TM_OCTOBER, X "November", TM_NOVEMBER, X "December", TM_DECEMBER, X NULL, 0 X}; X Xstatic struct lookup wday_names[] = { X "Sunday", TM_SUNDAY, X "Monday", TM_MONDAY, X "Tuesday", TM_TUESDAY, X "Wednesday", TM_WEDNESDAY, X "Thursday", TM_THURSDAY, X "Friday", TM_FRIDAY, X "Saturday", TM_SATURDAY, X NULL, 0 X}; X Xstatic struct lookup lasts[] = { X "last-Sunday", TM_SUNDAY, X "last-Monday", TM_MONDAY, X "last-Tuesday", TM_TUESDAY, X "last-Wednesday", TM_WEDNESDAY, X "last-Thursday", TM_THURSDAY, X "last-Friday", TM_FRIDAY, X "last-Saturday", TM_SATURDAY, X NULL, 0 X}; X Xstatic struct lookup begin_years[] = { X "minimum", YR_MINIMUM, X "maximum", YR_MAXIMUM, X NULL, 0 X}; X Xstatic struct lookup end_years[] = { X "minimum", YR_MINIMUM, X "maximum", YR_MAXIMUM, X "only", YR_ONLY, X NULL, 0 X}; X Xstatic int len_months[2][MONS_PER_YEAR] = { X 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, X 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 X}; X Xstatic int len_years[2] = { X DAYS_PER_NYEAR, DAYS_PER_LYEAR X}; X Xstatic time_t ats[TZ_MAX_TIMES]; Xstatic unsigned char types[TZ_MAX_TIMES]; Xstatic long gmtoffs[TZ_MAX_TYPES]; Xstatic char isdsts[TZ_MAX_TYPES]; Xstatic char abbrinds[TZ_MAX_TYPES]; Xstatic char chars[TZ_MAX_CHARS]; X X/* X** Memory allocation. X*/ X Xstatic char * Xmemcheck(ptr) Xchar * ptr; X{ X if (ptr == NULL) { X perror(progname); X exit(1); X } X return ptr; X} X X#define emalloc(size) memcheck(imalloc(size)) X#define erealloc(ptr, size) memcheck(irealloc(ptr, size)) X#define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) X X/* X** Error handling. X*/ X Xstatic Xeats(name, num, rname, rnum) Xchar * name; Xchar * rname; X{ X filename = name; X linenum = num; X rfilename = rname; X rlinenum = rnum; X} X Xstatic Xeat(name, num) Xchar * name; X{ X eats(name, num, (char *) NULL, -1); X} X Xstatic Xerror(string) Xchar * string; X{ X /* X ** Match the format of "cc" to allow sh users to X ** zic ... 2>&1 | error -t "*" -v X ** on BSD systems. X */ X (void) fprintf(stderr, "\"%s\", line %d: %s", X filename, linenum, string); X if (rfilename != NULL) X (void) fprintf(stderr, " (rule from \"%s\", line %d)", X rfilename, rlinenum); X (void) fprintf(stderr, "\n"); X ++errors; X} X Xstatic Xusage() X{ X (void) fprintf(stderr, X"%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n", X progname, progname); X exit(1); X} X Xstatic char * lcltime = NULL; Xstatic char * directory = NULL; X Xmain(argc, argv) Xint argc; Xchar * argv[]; X{ X register int i, j; X register int c; X X#ifdef unix X umask(umask(022) | 022); X#endif X progname = argv[0]; X while ((c = getopt(argc, argv, "d:l:v")) != EOF) X switch (c) { X default: X usage(); X case 'd': X if (directory == NULL) X directory = optarg; X else { X (void) fprintf(stderr, X"%s: More than one -d option specified\n", X progname); X exit(1); X } X break; X case 'l': X if (lcltime == NULL) X lcltime = optarg; X else { X (void) fprintf(stderr, X"%s: More than one -l option specified\n", X progname); X exit(1); X } X break; X case 'v': X noise = TRUE; X break; X } X if (optind == argc - 1 && strcmp(argv[optind], "=") == 0) X usage(); /* usage message by request */ X if (directory == NULL) X directory = TZDIR; X X setboundaries(); X X zones = (struct zone *) emalloc(0); X rules = (struct rule *) emalloc(0); X links = (struct link *) emalloc(0); X for (i = optind; i < argc; ++i) X infile(argv[i]); X if (errors) X exit(1); X associate(); X for (i = 0; i < nzones; i = j) { X /* X * Find the next non-continuation zone entry. X */ X for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j) X ; X outzone(&zones[i], j - i); X } X /* X ** We'll take the easy way out on this last part. X */ X if (chdir(directory) != 0) { X (void) fprintf(stderr, "%s: Can't chdir to ", progname); X perror(directory); X exit(1); X } X for (i = 0; i < nlinks; ++i) { X nondunlink(links[i].l_to); X if (link(links[i].l_from, links[i].l_to) != 0) { X (void) fprintf(stderr, "%s: Can't link %s to ", X progname, links[i].l_from); X perror(links[i].l_to); X exit(1); X } X } X if (lcltime != NULL) { X nondunlink(TZDEFAULT); X if (link(lcltime, TZDEFAULT) != 0) { X (void) fprintf(stderr, "%s: Can't link %s to ", X progname, lcltime); X perror(TZDEFAULT); X exit(1); X } X } X exit((errors == 0) ? 0 : 1); X} X Xstatic Xsetboundaries() X{ X register time_t bit; X X for (bit = 1; bit > 0; bit <<= 1) X ; X if (bit == 0) { /* time_t is an unsigned type */ X tt_signed = FALSE; X min_time = 0; X max_time = ~(time_t) 0; X } else { X tt_signed = TRUE; X min_time = bit; X max_time = bit; X ++max_time; X max_time = -max_time; X } X min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; X max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; X} X X/* X** We get to be careful here since there's a fair chance of root running us. X*/ X Xstatic Xnondunlink(name) Xchar * name; X{ X struct stat s; X X if (stat(name, &s) != 0) X return; X if ((s.st_mode & S_IFMT) == S_IFDIR) X return; X (void) unlink(name); X} X X/* X** Associate sets of rules with zones. X*/ X X/* X** Sort by rule name. X*/ X Xstatic Xrcomp(cp1, cp2) Xchar * cp1; Xchar * cp2; X{ X return strcmp(((struct rule *) cp1)->r_name, X ((struct rule *) cp2)->r_name); X} X Xstatic Xassociate() X{ X register struct zone * zp; X register struct rule * rp; X register int base, out; X register int i; X X if (nrules != 0) X (void) qsort((char *) rules, nrules, sizeof *rules, rcomp); X for (i = 0; i < nzones; ++i) { X zp = &zones[i]; X zp->z_rules = NULL; X zp->z_nrules = 0; X } X for (base = 0; base < nrules; base = out) { X rp = &rules[base]; X for (out = base + 1; out < nrules; ++out) X if (strcmp(rp->r_name, rules[out].r_name) != 0) X break; X for (i = 0; i < nzones; ++i) { X zp = &zones[i]; X if (strcmp(zp->z_rule, rp->r_name) != 0) X continue; X zp->z_rules = rp; X zp->z_nrules = out - base; X } X } X for (i = 0; i < nzones; ++i) { X zp = &zones[i]; X if (zp->z_nrules == 0) { X /* X ** Maybe we have a local standard time offset. X */ X eat(zp->z_filename, zp->z_linenum); X zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE); X /* X ** Note, though, that if there's no rule, X ** a '%s' in the format is a bad thing. X */ X if (strchr(zp->z_format, '%') != 0) X error("%s in ruleless zone"); X } X } X if (errors) X exit(1); X} X Xstatic Xinfile(name) Xchar * name; X{ X register FILE * fp; X register char ** fields; X register char * cp; X register struct lookup * lp; X register int nfields; X register int wantcont; X register int num; X char buf[BUFSIZ]; X X if (strcmp(name, "-") == 0) { X name = "standard input"; X fp = stdin; X } else if ((fp = fopen(name, "r")) == NULL) { X (void) fprintf(stderr, "%s: Can't open ", progname); X perror(name); X exit(1); X } X wantcont = FALSE; X for (num = 1; ; ++num) { X eat(name, num); X if (fgets(buf, sizeof buf, fp) != buf) X break; X cp = strchr(buf, '\n'); X if (cp == NULL) { X error("line too long"); X exit(1); X } X *cp = '\0'; X fields = getfields(buf); X nfields = 0; X while (fields[nfields] != NULL) { X if (ciequal(fields[nfields], "-")) X fields[nfields] = ""; X ++nfields; X } X if (nfields == 0) { X /* nothing to do */ X } else if (wantcont) { X wantcont = inzcont(fields, nfields); X } else { X lp = byword(fields[0], line_codes); X if (lp == NULL) X error("input line of unknown type"); X else switch ((int) (lp->l_value)) { X case LC_RULE: X inrule(fields, nfields); X wantcont = FALSE; X break; X case LC_ZONE: X wantcont = inzone(fields, nfields); X break; X case LC_LINK: X inlink(fields, nfields); X wantcont = FALSE; X break; X default: /* "cannot happen" */ X (void) fprintf(stderr, X"%s: panic: Invalid l_value %d\n", X progname, lp->l_value); X exit(1); X } X } X free((char *) fields); X } X if (ferror(fp)) { X (void) fprintf(stderr, "%s: Error reading ", progname); X perror(filename); X exit(1); X } X if (fp != stdin && fclose(fp)) { X (void) fprintf(stderr, "%s: Error closing ", progname); X perror(filename); X exit(1); X } X if (wantcont) X error("expected continuation line not found"); X} X X/* X** Convert a string of one of the forms X** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss X** into a number of seconds. X** A null string maps to zero. X** Call error with errstring and return zero on errors. X*/ X Xstatic long Xgethms(string, errstring, signable) Xchar * string; Xchar * errstring; X{ X int hh, mm, ss, sign; X X if (string == NULL || *string == '\0') X return 0; X if (!signable) X sign = 1; X else if (*string == '-') { X sign = -1; X ++string; X } else sign = 1; X if (sscanf(string, scheck(string, "%d"), &hh) == 1) X mm = ss = 0; X else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) X ss = 0; X else if (sscanf(string, scheck(string, "%d:%d:%d"), X &hh, &mm, &ss) != 3) { X error(errstring); X return 0; X } X if (hh < 0 || hh >= HOURS_PER_DAY || X mm < 0 || mm >= MINS_PER_HOUR || X ss < 0 || ss >= SECS_PER_MIN) { X error(errstring); X return 0; X } X return eitol(sign) * X (eitol(hh * MINS_PER_HOUR + mm) * X eitol(SECS_PER_MIN) + eitol(ss)); X} X Xstatic Xinrule(fields, nfields) Xregister char ** fields; X{ X struct rule r; X X if (nfields != RULE_FIELDS) { X error("wrong number of fields on Rule line"); X return; X } X if (*fields[RF_NAME] == '\0') { X error("nameless rule"); X return; X } X r.r_filename = filename; X r.r_linenum = linenum; X r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); X rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], X fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); X r.r_name = ecpyalloc(fields[RF_NAME]); X r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); X rules = (struct rule *) erealloc((char *) rules, X (nrules + 1) * sizeof *rules); X rules[nrules++] = r; X} X Xstatic Xinzone(fields, nfields) Xregister char ** fields; X{ X register int i; X char buf[132]; X X if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { X error("wrong number of fields on Zone line"); X return FALSE; X } X if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { X (void) sprintf(buf, X "\"Zone %s\" line and -l option are mutually exclusive", X TZDEFAULT); X error(buf); X return FALSE; X } X for (i = 0; i < nzones; ++i) X if (zones[i].z_name != NULL && X strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { X (void) sprintf(buf, X"duplicate zone name %s (file \"%s\", line %d)", X fields[ZF_NAME], X zones[i].z_filename, X zones[i].z_linenum); X error(buf); X return FALSE; X } X return inzsub(fields, nfields, FALSE); X} X Xstatic Xinzcont(fields, nfields) Xregister char ** fields; X{ X if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { X error("wrong number of fields on Zone continuation line"); X return FALSE; X } X return inzsub(fields, nfields, TRUE); X} X Xstatic Xinzsub(fields, nfields, iscont) Xregister char ** fields; X{ X register char * cp; X struct zone z; X register int i_gmtoff, i_rule, i_format; X register int i_untilyear, i_untilmonth; X register int i_untilday, i_untiltime; X register int hasuntil; X X if (iscont) { X i_gmtoff = ZFC_GMTOFF; X i_rule = ZFC_RULE; X i_format = ZFC_FORMAT; X i_untilyear = ZFC_UNTILYEAR; X i_untilmonth = ZFC_UNTILMONTH; X i_untilday = ZFC_UNTILDAY; X i_untiltime = ZFC_UNTILTIME; X z.z_name = NULL; X } else { X i_gmtoff = ZF_GMTOFF; X i_rule = ZF_RULE; X i_format = ZF_FORMAT; X i_untilyear = ZF_UNTILYEAR; X i_untilmonth = ZF_UNTILMONTH; X i_untilday = ZF_UNTILDAY; X i_untiltime = ZF_UNTILTIME; X z.z_name = ecpyalloc(fields[ZF_NAME]); X } X z.z_filename = filename; X z.z_linenum = linenum; X z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); X if ((cp = strchr(fields[i_format], '%')) != 0) { X if (*++cp != 's' || strchr(cp, '%') != 0) { X error("invalid abbreviation format"); X return FALSE; X } X } X z.z_rule = ecpyalloc(fields[i_rule]); X z.z_format = ecpyalloc(fields[i_format]); X hasuntil = nfields > i_untilyear; X if (hasuntil) { X z.z_untilrule.r_filename = filename; X z.z_untilrule.r_linenum = linenum; X rulesub(&z.z_untilrule, X fields[i_untilyear], X "only", X "", X (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan", X (nfields > i_untilday) ? fields[i_untilday] : "1", X (nfields > i_untiltime) ? fields[i_untiltime] : "0"); X z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear); X if (iscont && nzones > 0 && z.z_untiltime < max_time && X z.z_untiltime > min_time && X zones[nzones - 1].z_untiltime >= z.z_untiltime) { Xerror("Zone continuation line end time is not after end time of previous line"); X return FALSE; X } X } X zones = (struct zone *) erealloc((char *) zones, X (nzones + 1) * sizeof *zones); X zones[nzones++] = z; X /* X ** If there was an UNTIL field on this line, X ** there's more information about the zone on the next line. X */ X return hasuntil; X} X Xstatic Xinlink(fields, nfields) Xregister char ** fields; X{ X struct link l; X X if (nfields != LINK_FIELDS) { X error("wrong number of fields on Link line"); X return; X } X if (*fields[LF_FROM] == '\0') { X error("blank FROM field on Link line"); X return; X } X if (*fields[LF_TO] == '\0') { X error("blank TO field on Link line"); X return; X } X l.l_filename = filename; X l.l_linenum = linenum; X l.l_from = ecpyalloc(fields[LF_FROM]); X l.l_to = ecpyalloc(fields[LF_TO]); X links = (struct link *) erealloc((char *) links, X (nlinks + 1) * sizeof *links); X links[nlinks++] = l; X} X Xstatic Xrulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) Xregister struct rule * rp; Xchar * loyearp; Xchar * hiyearp; Xchar * typep; Xchar * monthp; Xchar * dayp; Xchar * timep; X{ X register struct lookup * lp; X register char * cp; X X if ((lp = byword(monthp, mon_names)) == NULL) { X error("invalid month name"); X return; X } X rp->r_month = lp->l_value; X rp->r_todisstd = FALSE; X cp = timep; X if (*cp != '\0') { X cp += strlen(cp) - 1; X switch (lowerit(*cp)) { X case 's': X rp->r_todisstd = TRUE; X *cp = '\0'; X break; X case 'w': X rp->r_todisstd = FALSE; X *cp = '\0'; X break; X } X } X rp->r_tod = gethms(timep, "invalid time of day", FALSE); X /* X ** Year work. X */ X cp = loyearp; X if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { X case YR_MINIMUM: X rp->r_loyear = min_year; X break; X case YR_MAXIMUM: X rp->r_loyear = max_year; X break; X default: /* "cannot happen" */ X (void) fprintf(stderr, X "%s: panic: Invalid l_value %d\n", X progname, lp->l_value); X exit(1); X } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 || X rp->r_loyear < min_year || rp->r_loyear > max_year) { X if (noise) X error("invalid starting year"); X if (rp->r_loyear > max_year) X return; X } X cp = hiyearp; X if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { X case YR_MINIMUM: X rp->r_hiyear = min_year; X break; X case YR_MAXIMUM: X rp->r_hiyear = max_year; X break; X case YR_ONLY: X rp->r_hiyear = rp->r_loyear; X break; X default: /* "cannot happen" */ X (void) fprintf(stderr, X "%s: panic: Invalid l_value %d\n", X progname, lp->l_value); X exit(1); X } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 || X rp->r_hiyear < min_year || rp->r_hiyear > max_year) { X if (noise) X error("invalid ending year"); X if (rp->r_hiyear < min_year) X return; X } X if (rp->r_hiyear < min_year) X return; X if (rp->r_loyear < min_year) X rp->r_loyear = min_year; X if (rp->r_hiyear > max_year) X rp->r_hiyear = max_year; X if (rp->r_loyear > rp->r_hiyear) { X error("starting year greater than ending year"); X return; X } X if (*typep == '\0') X rp->r_yrtype = NULL; X else { X if (rp->r_loyear == rp->r_hiyear) { X error("typed single year"); X return; X } X rp->r_yrtype = ecpyalloc(typep); X } X /* X ** Day work. X ** Accept things such as: X ** 1 X ** last-Sunday X ** Sun<=20 X ** Sun>=7 X */ X if ((lp = byword(dayp, lasts)) != NULL) { X rp->r_dycode = DC_DOWLEQ; X rp->r_wday = lp->l_value; X rp->r_dayofmonth = len_months[1][rp->r_month]; X } else { X if ((cp = strchr(dayp, '<')) != 0) X rp->r_dycode = DC_DOWLEQ; X else if ((cp = strchr(dayp, '>')) != 0) X rp->r_dycode = DC_DOWGEQ; X else { X cp = dayp; X rp->r_dycode = DC_DOM; X } X if (rp->r_dycode != DC_DOM) { X *cp++ = 0; X if (*cp++ != '=') { X error("invalid day of month"); X return; X } X if ((lp = byword(dayp, wday_names)) == NULL) { X error("invalid weekday name"); X return; X } X rp->r_wday = lp->l_value; X } X if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || X rp->r_dayofmonth <= 0 || X (rp->r_dayofmonth > len_months[1][rp->r_month])) { X error("invalid day of month"); X return; X } X } X} X Xstatic Xputtzcode(val, fp) Xlong val; XFILE * fp; X{ X register int c; X register int shift; X X for (shift = 24; shift >= 0; shift -= 8) { X c = val >> shift; X (void) putc(c, fp); X } X} X Xstatic Xwritezone(name) Xchar * name; X{ X register FILE * fp; X register int i; X char fullname[BUFSIZ]; X X if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) { X (void) fprintf(stderr, X "%s: File name %s/%s too long\n", progname, X directory, name); X exit(1); X } X (void) sprintf(fullname, "%s/%s", directory, name); X if ((fp = fopen(fullname, "w")) == NULL) { X if (mkdirs(fullname) != 0) X exit(1); X if ((fp = fopen(fullname, "w")) == NULL) { X (void) fprintf(stderr, "%s: Can't create ", progname); X perror(fullname); X exit(1); X } X } X (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0); X puttzcode(eitol(timecnt), fp); X puttzcode(eitol(typecnt), fp); X puttzcode(eitol(charcnt), fp); X for (i = 0; i < timecnt; ++i) X puttzcode((long) ats[i], fp); X if (timecnt > 0) X (void) fwrite((char *) types, sizeof types[0], X (int) timecnt, fp); X for (i = 0; i < typecnt; ++i) { X puttzcode((long) gmtoffs[i], fp); X (void) putc(isdsts[i], fp); X (void) putc(abbrinds[i], fp); X } X if (charcnt != 0) X (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp); X if (ferror(fp) || fclose(fp)) { X (void) fprintf(stderr, "%s: Write error on ", progname); X perror(fullname); X exit(1); X } X} X Xstatic Xoutzone(zpfirst, zonecount) Xstruct zone * zpfirst; X{ X register struct zone * zp; X register struct rule * rp; X register int i, j; X register int usestart, useuntil; X register time_t starttime, untiltime; X register long gmtoff; X register long stdoff; X register int year; X register long startoff; X register int startisdst; X register int type; X char startbuf[BUFSIZ]; X X /* X ** Now. . .finally. . .generate some useful data! X */ X timecnt = 0; X typecnt = 0; X charcnt = 0; X /* X ** Two guesses. . .the second may well be corrected later. X */ X gmtoff = zpfirst->z_gmtoff; X stdoff = 0; X for (i = 0; i < zonecount; ++i) { X usestart = i > 0; X useuntil = i < (zonecount - 1); X zp = &zpfirst[i]; X eat(zp->z_filename, zp->z_linenum); X startisdst = -1; X if (zp->z_nrules == 0) { X type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff), X zp->z_format, zp->z_stdoff != 0); X if (usestart) X addtt(starttime, type); X gmtoff = zp->z_gmtoff; X stdoff = zp->z_stdoff; X } else for (year = min_year; year <= max_year; ++year) { X if (useuntil && year > zp->z_untilrule.r_hiyear) X break; X /* X ** Mark which rules to do in the current year. X ** For those to do, calculate rpytime(rp, year); X */ X for (j = 0; j < zp->z_nrules; ++j) { X rp = &zp->z_rules[j]; X eats(zp->z_filename, zp->z_linenum, X rp->r_filename, rp->r_linenum); X rp->r_todo = year >= rp->r_loyear && X year <= rp->r_hiyear && X yearistype(year, rp->r_yrtype); X if (rp->r_todo) X rp->r_temp = rpytime(rp, year); X } X for ( ; ; ) { X register int k; X register time_t jtime, ktime; X register long offset; X char buf[BUFSIZ]; X X if (useuntil) { X /* X ** Turn untiltime into GMT X ** assuming the current gmtoff and X ** stdoff values. X */ X offset = gmtoff; X if (!zp->z_untilrule.r_todisstd) X offset = oadd(offset, stdoff); X untiltime = tadd(zp->z_untiltime, X -offset); X } X /* X ** Find the rule (of those to do, if any) X ** that takes effect earliest in the year. X */ X k = -1; X for (j = 0; j < zp->z_nrules; ++j) { X rp = &zp->z_rules[j]; X if (!rp->r_todo) X continue; X eats(zp->z_filename, zp->z_linenum, X rp->r_filename, rp->r_linenum); X offset = gmtoff; X if (!rp->r_todisstd) X offset = oadd(offset, stdoff); X jtime = rp->r_temp; X if (jtime == min_time || X jtime == max_time) X continue; X jtime = tadd(jtime, -offset); X if (k < 0 || jtime < ktime) { X k = j; X ktime = jtime; X } X } X if (k < 0) X break; /* go on to next year */ X rp = &zp->z_rules[k]; X rp->r_todo = FALSE; X if (useuntil && ktime >= untiltime) X break; X if (usestart) { X if (ktime < starttime) { X stdoff = rp->r_stdoff; X startoff = oadd(zp->z_gmtoff, X rp->r_stdoff); X (void) sprintf(startbuf, X zp->z_format, X rp->r_abbrvar); X startisdst = X rp->r_stdoff != 0; X continue; X } X if (ktime != starttime && X startisdst >= 0) Xaddtt(starttime, addtype(startoff, startbuf, startisdst)); X usestart = FALSE; X } X eats(zp->z_filename, zp->z_linenum, X rp->r_filename, rp->r_linenum); X (void) sprintf(buf, zp->z_format, X rp->r_abbrvar); X offset = oadd(zp->z_gmtoff, rp->r_stdoff); X type = addtype(offset, buf, rp->r_stdoff != 0); X if (timecnt != 0 || rp->r_stdoff != 0) X addtt(ktime, type); X gmtoff = zp->z_gmtoff; X stdoff = rp->r_stdoff; X } X } X /* X ** Now we may get to set starttime for the next zone line. X */ X if (useuntil) X starttime = tadd(zp->z_untiltime, X -gmtoffs[types[timecnt - 1]]); X } X writezone(zpfirst->z_name); X} X Xstatic Xaddtt(starttime, type) Xtime_t starttime; X{ X if (timecnt != 0 && type == types[timecnt - 1]) X return; /* easy enough! */ X if (timecnt >= TZ_MAX_TIMES) { X error("too many transitions?!"); X exit(1); X } X ats[timecnt] = starttime; X types[timecnt] = type; X ++timecnt; X} X Xstatic Xaddtype(gmtoff, abbr, isdst) Xlong gmtoff; Xchar * abbr; X{ X register int i, j; X X /* X ** See if there's already an entry for this zone type. X ** If so, just return its index. X */ X for (i = 0; i < typecnt; ++i) { X if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && X strcmp(abbr, &chars[abbrinds[i]]) == 0) X return i; X } X /* X ** There isn't one; add a new one, unless there are already too X ** many. X */ X if (typecnt >= TZ_MAX_TYPES) { X error("too many local time types"); X exit(1); X } X gmtoffs[i] = gmtoff; X isdsts[i] = isdst; X X for (j = 0; j < charcnt; ++j) X if (strcmp(&chars[j], abbr) == 0) X break; X if (j == charcnt) X newabbr(abbr); X abbrinds[i] = j; X ++typecnt; X return i; X} X Xstatic Xyearistype(year, type) Xchar * type; X{ X char buf[BUFSIZ]; X int result; X X if (type == NULL || *type == '\0') X return TRUE; X if (strcmp(type, "uspres") == 0) X return (year % 4) == 0; X if (strcmp(type, "nonpres") == 0) X return (year % 4) != 0; X (void) sprintf(buf, "yearistype %d %s", year, type); X result = system(buf); X if (result == 0) X return TRUE; X if (result == 1 << 8) X return FALSE; X error("Wild result from command execution"); X (void) fprintf(stderr, "%s: command was '%s', result was %d\n", X progname, buf, result); X for ( ; ; ) X exit(1); X} X Xstatic Xlowerit(a) X{ X return (isascii(a) && isupper(a)) ? tolower(a) : a; X} X Xstatic Xciequal(ap, bp) /* case-insensitive equality */ Xregister char * ap; Xregister char * bp; X{ X while (lowerit(*ap) == lowerit(*bp++)) X if (*ap++ == '\0') X return TRUE; X return FALSE; X} X Xstatic Xisabbr(abbr, word) Xregister char * abbr; Xregister char * word; X{ X if (lowerit(*abbr) != lowerit(*word)) X return FALSE; X ++word; X while (*++abbr != '\0') X do if (*word == '\0') X return FALSE; X while (lowerit(*word++) != lowerit(*abbr)); X return TRUE; X} X Xstatic struct lookup * Xbyword(word, table) Xregister char * word; Xregister struct lookup * table; X{ X register struct lookup * foundlp; X register struct lookup * lp; X X if (word == NULL || table == NULL) X return NULL; X /* X ** Look for exact match. X */ X for (lp = table; lp->l_word != NULL; ++lp) X if (ciequal(word, lp->l_word)) X return lp; X /* X ** Look for inexact match. X */ X foundlp = NULL; X for (lp = table; lp->l_word != NULL; ++lp) X if (isabbr(word, lp->l_word)) X if (foundlp == NULL) X foundlp = lp; X else return NULL; /* multiple inexact matches */ X return foundlp; X} X Xstatic char ** Xgetfields(cp) Xregister char * cp; X{ X register char * dp; X register char ** array; X register int nsubs; X X if (cp == NULL) X return NULL; X array = (char **) emalloc((strlen(cp) + 1) * sizeof *array); X nsubs = 0; X for ( ; ; ) { X while (isascii(*cp) && isspace(*cp)) X ++cp; X if (*cp == '\0' || *cp == '#') X break; X array[nsubs++] = dp = cp; X do { X if ((*dp = *cp++) != '"') X ++dp; X else while ((*dp = *cp++) != '"') X if (*dp != '\0') X ++dp; X else error("Odd number of quotation marks"); X } while (*cp != '\0' && *cp != '#' && X (!isascii(*cp) || !isspace(*cp))); X if (isascii(*cp) && isspace(*cp)) X ++cp; X *dp = '\0'; X } X array[nsubs] = NULL; X return array; X} X Xstatic long Xoadd(t1, t2) Xlong t1; Xlong t2; X{ X register long t; X X t = t1 + t2; X if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { X error("time overflow"); X exit(1); X } X return t; X} X Xstatic time_t Xtadd(t1, t2) Xtime_t t1; Xlong t2; X{ X register time_t t; X X if (t1 == max_time && t2 > 0) X return max_time; X if (t1 == min_time && t2 < 0) X return min_time; X t = t1 + t2; X if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) { X error("time overflow"); X exit(1); X } X return t; X} X X/* X** Given a rule, and a year, compute the date - in seconds since January 1, X** 1970, 00:00 LOCAL time - in that year that the rule refers to. X*/ X Xstatic time_t Xrpytime(rp, wantedy) Xregister struct rule * rp; Xregister int wantedy; X{ X register int y, m, i; X register long dayoff; /* with a nod to Margaret O. */ X register time_t t; X X dayoff = 0; X m = TM_JANUARY; X y = EPOCH_YEAR; X while (wantedy != y) { X if (wantedy > y) { X i = len_years[isleap(y)]; X ++y; X } else { X --y; X i = -len_years[isleap(y)]; X } X dayoff = oadd(dayoff, eitol(i)); X } X while (m != rp->r_month) { X i = len_months[isleap(y)][m]; X dayoff = oadd(dayoff, eitol(i)); X ++m; X } X i = rp->r_dayofmonth; X if (m == TM_FEBRUARY && i == 29 && !isleap(y)) { X if (rp->r_dycode == DC_DOWLEQ) X --i; X else { X error("use of 2/29 in non leap-year"); X exit(1); X } X } X --i; X dayoff = oadd(dayoff, eitol(i)); X if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) { X register long wday; X X#define LDAYS_PER_WEEK ((long) DAYS_PER_WEEK) X wday = eitol(EPOCH_WDAY); X /* X ** Don't trust mod of negative numbers. X */ X if (dayoff >= 0) X wday = (wday + dayoff) % LDAYS_PER_WEEK; X else { X wday -= ((-dayoff) % LDAYS_PER_WEEK); X if (wday < 0) X wday += LDAYS_PER_WEEK; X } X while (wday != eitol(rp->r_wday)) X if (rp->r_dycode == DC_DOWGEQ) { X dayoff = oadd(dayoff, (long) 1); X if (++wday >= LDAYS_PER_WEEK) X wday = 0; X ++i; X } else { X dayoff = oadd(dayoff, (long) -1); X if (--wday < 0) X wday = LDAYS_PER_WEEK; X --i; X } X if (i < 0 || i >= len_months[isleap(y)][m]) { X error("no day in month matches rule"); X exit(1); X } X } X if (dayoff < 0 && !tt_signed) { X if (wantedy == rp->r_loyear) X return min_time; X error("time before zero"); X exit(1); X } X t = (time_t) dayoff * SECS_PER_DAY; X /* X ** Cheap overflow check. X */ X if (t / SECS_PER_DAY != dayoff) { X if (wantedy == rp->r_hiyear) X return max_time; X if (wantedy == rp->r_loyear) X return min_time; X error("time overflow"); X exit(1); X } X return tadd(t, rp->r_tod); X} X Xstatic Xnewabbr(string) Xchar * string; X{ X register int i; X X i = strlen(string) + 1; X if (charcnt + i >= TZ_MAX_CHARS) { X error("too many, or too long, time zone abbreviations"); X exit(1); X } X (void) strcpy(&chars[charcnt], string); X charcnt += eitol(i); X} X Xstatic Xmkdirs(name) Xchar * name; X{ X register char * cp; X X if ((cp = name) == NULL || *cp == '\0') X return 0; X while ((cp = strchr(cp + 1, '/')) != 0) { X *cp = '\0'; X if (access(name, 0) != 0) { X /* X * It doesn't seem to exist, so we try to create it. X */ X if (mkdir(name, 0755) != 0) { X (void) fprintf(stderr, X "%s: Can't create directory ", X progname); X perror(name); X return -1; X } X } X *cp = '/'; X } X return 0; X} X Xstatic long Xeitol(i) X{ X long l; X X l = i; X if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) { X (void) fprintf(stderr, "%s: %d did not sign extend correctly\n", X progname, i); X exit(1); X } X return l; X} X X/* X** UNIX is a registered trademark of AT&T. X*/ !The!End! echo x - "zdump.c" 2>&1 sed "s/^X//" >"zdump.c" <<'!The!End!' X# X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)zdump.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#include "sys/types.h" X#include "time.h" X#include "tzfile.h" X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X Xextern char * asctime(); Xextern char ** environ; Xextern struct tm * gmtime(); Xextern char * imalloc(); Xextern char * optarg; Xextern int optind; X#ifndef USG Xextern char * sprintf(); X#endif /* !USG */ Xextern long time(); Xextern char * tzname[2]; Xextern void tzset(); X X/* X** For the benefit of cyntax... X*/ X Xstatic long tzdecode(); Xstatic readerr(); Xstatic show(); X Xstatic int longest; X Xstatic long Xtzdecode(codep) Xchar * codep; X{ X register int i; X register long result; X X result = 0; X for (i = 0; i < 4; ++i) X result = (result << 8) | (codep[i] & 0xff); X return result; X} X Xmain(argc, argv) Xint argc; Xchar * argv[]; X{ X register FILE * fp; X register int i, j, c; X register int vflag; X register char * cutoff; X register int cutyear; X register long cuttime; X time_t now; X time_t t; X long timecnt; X char buf[BUFSIZ]; X X vflag = 0; X cutoff = NULL; X while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') X if (c == 'v') X vflag = 1; X else cutoff = optarg; X if (c != EOF || optind == argc - 1 && strcmp(argv[optind], "=") == 0) { X (void) fprintf(stderr, "%s: usage is %s [ -v ] zonename ...\n", X argv[0], argv[0]); X exit(1); X } X if (cutoff != NULL) X cutyear = atoi(cutoff); X /* X ** VERY approximate. X */ X cuttime = (long) (cutyear - EPOCH_YEAR) * X SECS_PER_HOUR * HOURS_PER_DAY * DAYS_PER_NYEAR; X (void) time(&now); X longest = 0; X for (i = optind; i < argc; ++i) X if (strlen(argv[i]) > longest) X longest = strlen(argv[i]); X for (i = optind; i < argc; ++i) { X register char ** saveenv; X char * tzequals; X char * fakeenv[2]; X X tzequals = imalloc(strlen(argv[i]) + 4); X if (tzequals == NULL) { X (void) fprintf(stderr, "%s: can't allocate memory\n", X argv[0]); X exit(1); X } X (void) sprintf(tzequals, "TZ=%s", argv[i]); X fakeenv[0] = tzequals; X fakeenv[1] = NULL; X saveenv = environ; X environ = fakeenv; X (void) tzset(); X environ = saveenv; X show(argv[i], now, FALSE); X if (!vflag) X continue; X if (argv[i][0] == '/') X fp = fopen(argv[i], "r"); X else { X j = strlen(TZDIR) + 1 + strlen(argv[i]) + 1; X if (j > sizeof buf) { X (void) fprintf(stderr, X "%s: timezone name %s/%s is too long\n", X argv[0], TZDIR, argv[i]); X exit(1); X } X (void) sprintf(buf, "%s/%s", TZDIR, argv[i]); X fp = fopen(buf, "r"); X } X if (fp == NULL) { X (void) fprintf(stderr, "%s: Can't open ", argv[0]); X perror(argv[i]); X exit(1); X } X { X char code[4]; X X(void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0); X if (fread((char *) code, sizeof code, 1, fp) != 1) X readerr(fp, argv[0], argv[i]); X timecnt = tzdecode(code); X (void) fseek(fp, (long) (2 * sizeof code), 1); X } X t = 0x80000000; X if (t > 0) /* time_t is unsigned */ X t = 0; X show(argv[i], t, TRUE); X t += SECS_PER_HOUR * HOURS_PER_DAY; X show(argv[i], t, TRUE); X while (timecnt-- > 0) { X char code[4]; X X if (fread((char *) code, sizeof code, 1, fp) != 1) X readerr(fp, argv[0], argv[i]); X t = tzdecode(code); X if (cutoff != NULL && t > cuttime) X break; X show(argv[i], t - 1, TRUE); X show(argv[i], t, TRUE); X } X if (fclose(fp)) { X (void) fprintf(stderr, "%s: Error closing ", argv[0]); X perror(argv[i]); X exit(1); X } X t = 0xffffffff; X if (t < 0) /* time_t is signed */ X t = 0x7fffffff ; X t -= SECS_PER_HOUR * HOURS_PER_DAY; X show(argv[i], t, TRUE); X t += SECS_PER_HOUR * HOURS_PER_DAY; X show(argv[i], t, TRUE); X free(tzequals); X } X if (fflush(stdout) || ferror(stdout)) { X (void) fprintf(stderr, "%s: Error writing standard output ", X argv[0]); X perror("standard output"); X exit(1); X } X return 0; X} X Xstatic Xshow(zone, t, v) Xchar * zone; Xtime_t t; X{ X struct tm * tmp; X extern struct tm * localtime(); X X (void) printf("%-*s ", longest, zone); X if (v) X (void) printf("%.24s GMT = ", asctime(gmtime(&t))); X tmp = localtime(&t); X (void) printf("%.24s", asctime(tmp)); X if (*tzname[tmp->tm_isdst] != '\0') X (void) printf(" %s", tzname[tmp->tm_isdst]); X if (v) { X (void) printf(" isdst=%d", tmp->tm_isdst); X#ifdef KRE_COMPAT X (void) printf(" gmtoff=%ld", tmp->tm_gmtoff); X#endif /* KRE_COMPAT */ X } X (void) printf("\n"); X} X Xstatic Xreaderr(fp, progname, filename) XFILE * fp; Xchar * progname; Xchar * filename; X{ X (void) fprintf(stderr, "%s: Error reading ", progname); X if (ferror(fp)) X perror(filename); X else (void) fprintf(stderr, "%s: Premature EOF\n", filename); X exit(1); X} !The!End! echo x - "localtime.c" 2>&1 sed "s/^X//" >"localtime.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X/* X** sys/types.h is included to get time_t. X*/ X X#include "sys/types.h" X#include "tzfile.h" X#include "time.h" X X#ifndef MAXPATHLEN X#include "sys/param.h" X#ifndef MAXPATHLEN X#define MAXPATHLEN 1024 X#endif /* !MAXPATHLEN */ X#endif /* !MAXPATHLEN */ X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)localtime.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif /* !TRUE */ X Xextern char * getenv(); Xextern char * strcpy(); Xextern char * strcat(); X#ifdef STD_INSPIRED Xstruct tm * offtime(); X#else /* !STD_INSPIRED */ Xstatic struct tm * offtime(); X#endif /* !STD_INSPIRED */ X Xstruct ttinfo { /* time type information */ X long tt_gmtoff; /* GMT offset in seconds */ X int tt_isdst; /* used to set tm_isdst */ X int tt_abbrind; /* abbreviation list index */ X}; X Xstruct state { X int timecnt; X int typecnt; X int charcnt; X time_t ats[TZ_MAX_TIMES]; X unsigned char types[TZ_MAX_TIMES]; X struct ttinfo ttis[TZ_MAX_TYPES]; X char chars[TZ_MAX_CHARS + 1]; X}; X Xstatic struct state s; X Xstatic int tz_is_set; X Xchar * tzname[2] = { X "GMT", X "GMT" X}; X X#ifdef USG_COMPAT Xtime_t timezone = 0; Xint daylight = 0; X#endif /* USG_COMPAT */ X X#ifdef TZA_COMPAT Xchar * tz_abbr; /* compatibility w/older versions */ X#endif /* TZA_COMPAT */ X Xstatic long Xdetzcode(codep) Xchar * codep; X{ X register long result; X register int i; X X result = 0; X for (i = 0; i < 4; ++i) X result = (result << 8) | (codep[i] & 0xff); X return result; X} X Xstatic Xtzload(name) Xregister char * name; X{ X register int i; X register int fid; X X if (name == 0 && (name = TZDEFAULT) == 0) X return -1; X { X register char * p; X register int doaccess; X char fullname[MAXPATHLEN]; X X doaccess = name[0] == '/'; X if (!doaccess) { X if ((p = TZDIR) == 0) X return -1; X if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) X return -1; X (void) strcpy(fullname, p); X (void) strcat(fullname, "/"); X (void) strcat(fullname, name); X /* X ** Set doaccess if '.' (as in "../") shows up in name. X */ X while (*name != '\0') X if (*name++ == '.') X doaccess = TRUE; X name = fullname; X } X if (doaccess && access(name, 4) != 0) X return -1; X if ((fid = open(name, 0)) == -1) X return -1; X } X { X register char * p; X register struct tzhead * tzhp; X char buf[sizeof s]; X X i = read(fid, buf, sizeof buf); X if (close(fid) != 0 || i < sizeof *tzhp) X return -1; X tzhp = (struct tzhead *) buf; X s.timecnt = (int) detzcode(tzhp->tzh_timecnt); X s.typecnt = (int) detzcode(tzhp->tzh_typecnt); X s.charcnt = (int) detzcode(tzhp->tzh_charcnt); X if (s.timecnt > TZ_MAX_TIMES || X s.typecnt == 0 || X s.typecnt > TZ_MAX_TYPES || X s.charcnt > TZ_MAX_CHARS) X return -1; X if (i < sizeof *tzhp + X s.timecnt * (4 + sizeof (char)) + X s.typecnt * (4 + 2 * sizeof (char)) + X s.charcnt * sizeof (char)) X return -1; X p = buf + sizeof *tzhp; X for (i = 0; i < s.timecnt; ++i) { X s.ats[i] = detzcode(p); X p += 4; X } X for (i = 0; i < s.timecnt; ++i) X s.types[i] = (unsigned char) *p++; X for (i = 0; i < s.typecnt; ++i) { X register struct ttinfo * ttisp; X X ttisp = &s.ttis[i]; X ttisp->tt_gmtoff = detzcode(p); X p += 4; X ttisp->tt_isdst = (unsigned char) *p++; X ttisp->tt_abbrind = (unsigned char) *p++; X } X for (i = 0; i < s.charcnt; ++i) X s.chars[i] = *p++; X s.chars[i] = '\0'; /* ensure '\0' at end */ X } X /* X ** Check that all the local time type indices are valid. X */ X for (i = 0; i < s.timecnt; ++i) X if (s.types[i] >= s.typecnt) X return -1; X /* X ** Check that all abbreviation indices are valid. X */ X for (i = 0; i < s.typecnt; ++i) X if (s.ttis[i].tt_abbrind >= s.charcnt) X return -1; X /* X ** Set tzname elements to initial values. X */ X tzname[0] = tzname[1] = &s.chars[0]; X#ifdef USG_COMPAT X timezone = s.ttis[0].tt_gmtoff; X daylight = 0; X#endif /* USG_COMPAT */ X for (i = 1; i < s.typecnt; ++i) { X register struct ttinfo * ttisp; X X ttisp = &s.ttis[i]; X if (ttisp->tt_isdst) { X tzname[1] = &s.chars[ttisp->tt_abbrind]; X#ifdef USG_COMPAT X daylight = 1; X#endif /* USG_COMPAT */ X } else { X tzname[0] = &s.chars[ttisp->tt_abbrind]; X#ifdef USG_COMPAT X timezone = ttisp->tt_gmtoff; X#endif /* USG_COMPAT */ X } X } X return 0; X} X Xstatic Xtzsetgmt() X{ X s.timecnt = 0; X s.ttis[0].tt_gmtoff = 0; X s.ttis[0].tt_abbrind = 0; X (void) strcpy(s.chars, "GMT"); X tzname[0] = tzname[1] = s.chars; X#ifdef USG_COMPAT X timezone = 0; X daylight = 0; X#endif /* USG_COMPAT */ X} X Xvoid Xtzset() X{ X register char * name; X X tz_is_set = TRUE; X name = getenv("TZ"); X if (name != 0 && *name == '\0') X tzsetgmt(); /* GMT by request */ X else if (tzload(name) != 0) X tzsetgmt(); X} X Xvoid Xtzsetwall() X{ X tz_is_set = TRUE; X if (tzload((char *) 0) != 0) X tzsetgmt(); X} X Xstruct tm * Xlocaltime(timep) Xtime_t * timep; X{ X register struct ttinfo * ttisp; X register struct tm * tmp; X register int i; X time_t t; X X if (!tz_is_set) X (void) tzset(); X t = *timep; X if (s.timecnt == 0 || t < s.ats[0]) { X i = 0; X while (s.ttis[i].tt_isdst) X if (++i >= s.timecnt) { X i = 0; X break; X } X } else { X for (i = 1; i < s.timecnt; ++i) X if (t < s.ats[i]) X break; X i = s.types[i - 1]; X } X ttisp = &s.ttis[i]; X /* X ** To get (wrong) behavior that's compatible with System V Release 2.0 X ** you'd replace the statement below with X ** tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L); X */ X tmp = offtime(&t, ttisp->tt_gmtoff); X tmp->tm_isdst = ttisp->tt_isdst; X tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind]; X#ifdef KRE_COMPAT X tmp->tm_zone = &s.chars[ttisp->tt_abbrind]; X#endif /* KRE_COMPAT */ X#ifdef TZA_COMPAT X tz_abbr = &s.chars[ttisp->tt_abbrind]; X#endif /* TZA_COMPAT */ X return tmp; X} X Xstruct tm * Xgmtime(clock) Xtime_t * clock; X{ X register struct tm * tmp; X X tmp = offtime(clock, 0L); X tzname[0] = "GMT"; X#ifdef KRE_COMPAT X tmp->tm_zone = "GMT"; /* UCT ? */ X#endif /* KRE_COMPAT */ X return tmp; X} X Xstatic int mon_lengths[2][MONS_PER_YEAR] = { X 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, X 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 X}; X Xstatic int year_lengths[2] = { X DAYS_PER_NYEAR, DAYS_PER_LYEAR X}; X X#ifdef STD_INSPIRED Xstruct tm * X#else /* !STD_INSPIRED */ Xstatic struct tm * X#endif /* !STD_INSPIRED */ Xofftime(clock, offset) Xtime_t * clock; Xlong offset; X{ X register struct tm * tmp; X register long days; X register long rem; X register int y; X register int yleap; X register int * ip; X static struct tm tm; X X tmp = &tm; X days = *clock / SECS_PER_DAY; X rem = *clock % SECS_PER_DAY; X rem += offset; X while (rem < 0) { X rem += SECS_PER_DAY; X --days; X } X while (rem >= SECS_PER_DAY) { X rem -= SECS_PER_DAY; X ++days; X } X tmp->tm_hour = (int) (rem / SECS_PER_HOUR); X rem = rem % SECS_PER_HOUR; X tmp->tm_min = (int) (rem / SECS_PER_MIN); X tmp->tm_sec = (int) (rem % SECS_PER_MIN); X tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK); X if (tmp->tm_wday < 0) X tmp->tm_wday += DAYS_PER_WEEK; X y = EPOCH_YEAR; X if (days >= 0) X for ( ; ; ) { X yleap = isleap(y); X if (days < (long) year_lengths[yleap]) X break; X ++y; X days = days - (long) year_lengths[yleap]; X } X else do { X --y; X yleap = isleap(y); X days = days + (long) year_lengths[yleap]; X } while (days < 0); X tmp->tm_year = y - TM_YEAR_BASE; X tmp->tm_yday = (int) days; X ip = mon_lengths[yleap]; X for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) X days = days - (long) ip[tmp->tm_mon]; X tmp->tm_mday = (int) (days + 1); X tmp->tm_isdst = 0; X#ifdef KRE_COMPAT X tmp->tm_zone = ""; X tmp->tm_gmtoff = offset; X#endif /* KRE_COMPAT */ X return tmp; X} X X#ifdef BSD_COMPAT X X/* X** If ctime and localtime aren't in the same file on 4.3BSD systems, X** you can run into compilation problems--take X** cc date.c -lz X** (please). X*/ X Xchar * Xctime(timep) Xtime_t * timep; X{ X return asctime(localtime(timep)); X} X X#endif /* BSD_COMPAT */ !The!End! echo x - "asctime.c" 2>&1 sed "s/^X//" >"asctime.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)asctime.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#include "time.h" X#include "tzfile.h" X X#ifndef USG Xextern char * sprintf(); X#endif /* !USG */ X X/* X** A la X3J11 X*/ X Xchar * Xasctime(timeptr) Xregister struct tm * timeptr; X{ X static char wday_name[DAYS_PER_WEEK][3] = { X "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" X }; X static char mon_name[MONS_PER_YEAR][3] = { X "Jan", "Feb", "Mar", "Apr", "May", "Jun", X "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" X }; X static char result[26]; X X (void) sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", X wday_name[timeptr->tm_wday], X mon_name[timeptr->tm_mon], X timeptr->tm_mday, timeptr->tm_hour, X timeptr->tm_min, timeptr->tm_sec, X TM_YEAR_BASE + timeptr->tm_year); X return result; X} !The!End! echo x - "ctime.c" 2>&1 sed "s/^X//" >"ctime.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)ctime.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#ifndef BSD_COMPAT X X/* X** On non-BSD systems, this can be a separate function (as is proper). X*/ X X#include "sys/types.h" X#include "time.h" X Xextern char * asctime(); Xextern struct tm * localtime(); X Xchar * Xctime(timep) Xtime_t * timep; X{ X return asctime(localtime(timep)); X} X X#endif /* !BSD_COMPAT */ !The!End! echo x - "dysize.c" 2>&1 sed "s/^X//" >"dysize.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)dysize.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#ifdef BSD_COMPAT X X#include "tzfile.h" X Xdysize(y) X{ X /* X ** The 4.[0123]BSD version of dysize behaves as if the return statement X ** below read X ** return ((y % 4) == 0) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR; X ** but since we'd rather be right than (strictly) compatible. . . X */ X return isleap(y) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR; X} X X#endif /* BSD_COMPAT */ !The!End! echo x - "timemk.c" 2>&1 sed "s/^X//" >"timemk.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)timemk.c 3.1"; X#endif /* !NOID */ X#endif /* !lint */ X X#ifdef STD_INSPIRED X X/* X** Code provided by Robert Elz, who writes: X** The "best" way to do mktime I think is based on an idea of Bob X** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). X** It does a binary search of the time_t space. Since time_t's are X** just 32 bits, its a max of 32 iterations (even at 64 bits it X** would still be very reasonable). X** X** This code does handle "out of bounds" values in the way described X** for "mktime" in the October, 1986 draft of the proposed ANSI C Standard; X** though this is an accident of the implementation and *cannot* be made to X** work correctly for the purposes there described. X** X** A warning applies if you try to use these functions with a version of X** "localtime" that has overflow problems (such as System V Release 2.0 X** or 4.3 BSD localtime). X** If you're not using GMT and feed a value to localtime X** that's near the minimum (or maximum) possible time_t value, localtime X** may return a struct that represents a time near the maximum (or minimum) X** possible time_t value (because of overflow). If such a returned struct tm X** is fed to timelocal, it will not return the value originally feed to X** localtime. X*/ X X#include "time.h" X#include "tzfile.h" X#include "sys/types.h" X X#ifndef WRONG X#define WRONG (-1) X#endif /* !WRONG */ X Xextern struct tm * localtime(); Xextern struct tm * gmtime(); Xextern struct tm * offtime(); X Xstatic time_t Xtimemk(timeptr, funcp, offset) Xstruct tm * timeptr; Xstruct tm * (* funcp)(); Xlong offset; X{ X register int direction; X register int bits; X time_t t; X struct tm yourtm, mytm; X X yourtm = *timeptr; X /* X ** Correct the tm supplied, in case some of its values are X ** out of range. X */ X while (yourtm.tm_sec >= SECS_PER_MIN) X ++yourtm.tm_min, yourtm.tm_sec -= SECS_PER_MIN; X while (yourtm.tm_sec < 0) X --yourtm.tm_min, yourtm.tm_sec += SECS_PER_MIN; X while (yourtm.tm_min >= MINS_PER_HOUR) X ++yourtm.tm_hour, yourtm.tm_min -= MINS_PER_HOUR; X while (yourtm.tm_min < 0) X --yourtm.tm_hour, yourtm.tm_min += MINS_PER_HOUR; X while (yourtm.tm_hour >= HOURS_PER_DAY) X ++yourtm.tm_mday, yourtm.tm_hour -= HOURS_PER_DAY; X while (yourtm.tm_hour < 0) X --yourtm.tm_mday, yourtm.tm_hour += HOURS_PER_DAY; X while (yourtm.tm_mday > 31) /* trust me [kre] */ X ++yourtm.tm_mon, yourtm.tm_mday -= 31; X while (yourtm.tm_mday <= 0) X --yourtm.tm_mon, yourtm.tm_mday += 31; X while (yourtm.tm_mon >= MONS_PER_YEAR) X ++yourtm.tm_year, yourtm.tm_mon -= MONS_PER_YEAR; X while (yourtm.tm_mon < 0) X --yourtm.tm_year, yourtm.tm_mon += MONS_PER_YEAR; X /* X ** Calcluate the number of magnitude bits in a time_t X ** (this works regardless of whether time_t is X ** signed or unsigned, though lint complains if unsigned). X */ X for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) X ; X /* X ** If time_t is signed, then 0 is the median value, X ** if time_t is unsigned, then 1 << bits is median. X */ X t = (t < 0) ? 0 : ((time_t) 1 << bits); X for ( ; ; ) { X mytm = (funcp == offtime) ? X *((*funcp)(&t, offset)) : *((*funcp)(&t)); X if ((direction = (mytm.tm_year - yourtm.tm_year)) == 0 && X (direction = (mytm.tm_mon - yourtm.tm_mon)) == 0 && X (direction = (mytm.tm_mday - yourtm.tm_mday)) == 0 && X (direction = (mytm.tm_hour - yourtm.tm_hour)) == 0 && X (direction = (mytm.tm_min - yourtm.tm_min)) == 0) X direction = mytm.tm_sec - yourtm.tm_sec; X if (direction == 0) { X *timeptr = mytm; X return t; X } X if (bits-- < 0) { X *timeptr = yourtm; /* restore "original" value */ X if (yourtm.tm_mday == 31) { X timeptr->tm_mday = 1; X ++(timeptr->tm_mon); X t = timemk(timeptr, funcp); X if (t != WRONG) X return t; X *timeptr = yourtm; X } else if (yourtm.tm_mon == TM_FEBRUARY && X yourtm.tm_mday > 28) { X timeptr->tm_mday -= 28; X ++(timeptr->tm_mon); X t = timemk(timeptr, funcp); X if (t != WRONG) X return t; X *timeptr = yourtm; X } X return WRONG; X } X if (bits < 0) X --t; X else if (direction > 0) X t -= (time_t) 1 << bits; X else t += (time_t) 1 << bits; X } X} X Xtime_t Xtimelocal(timeptr) Xstruct tm * timeptr; X{ X return timemk(timeptr, localtime, 0L); X} X Xtime_t Xtimegm(timeptr) Xstruct tm * timeptr; X{ X return timemk(timeptr, gmtime, 0L); X} X Xtime_t Xtimeoff(timeptr, offset) Xstruct tm * timeptr; Xlong offset; X{ X return timemk(timeptr, offtime, offset); X} X X#endif /* STD_INSPIRED */ !The!End! echo x - "scheck.c" 2>&1 sed "s/^X//" >"scheck.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)scheck.c 7.15"; X#endif /* !NOID */ X#endif /* !lint */ X X#include "ctype.h" X Xextern char * imalloc(); X Xchar * Xscheck(string, format) Xchar * string; Xchar * format; X{ X register char * fbuf; X register char * fp; X register char * tp; X register int c; X register char * result; X char dummy; X X result = ""; X if (string == NULL || format == NULL) X return result; X fbuf = imalloc(2 * strlen(format) + 4); X if (fbuf == NULL) X return result; X fp = format; X tp = fbuf; X while ((*tp++ = c = *fp++) != '\0') { X if (c != '%') X continue; X if (*fp == '%') { X *tp++ = *fp++; X continue; X } X *tp++ = '*'; X if (*fp == '*') X ++fp; X while (isascii(*fp) && isdigit(*fp)) X *tp++ = *fp++; X if (*fp == 'l' || *fp == 'h') X *tp++ = *fp++; X else if (*fp == '[') X do *tp++ = *fp++; X while (*fp != '\0' && *fp != ']'); X if ((*tp++ = *fp++) == '\0') X break; X } X *(tp - 1) = '%'; X *tp++ = 'c'; X *tp = '\0'; X if (sscanf(string, fbuf, &dummy) != 1) X result = format; X free(fbuf); X return result; X} !The!End! echo x - "ialloc.c" 2>&1 sed "s/^X//" >"ialloc.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)ialloc.c 7.13"; X#endif /* !NOID */ X#endif /* !lint */ X X#ifndef alloc_t X#define alloc_t unsigned X#endif /* !alloc_t */ X X#ifdef MAL X#define NULLMAL(x) ((x) == NULL || (x) == MAL) X#else /* !MAL */ X#define NULLMAL(x) ((x) == NULL) X#endif /* !MAL */ X Xextern char * calloc(); Xextern char * malloc(); Xextern char * realloc(); Xextern char * strcpy(); X Xchar * Ximalloc(n) X{ X#ifdef MAL X register char * result; X X if (n == 0) X n = 1; X result = malloc((alloc_t) n); X return (result == MAL) ? NULL : result; X#else /* !MAL */ X if (n == 0) X n = 1; X return malloc((alloc_t) n); X#endif /* !MAL */ X} X Xchar * Xicalloc(nelem, elsize) X{ X if (nelem == 0 || elsize == 0) X nelem = elsize = 1; X return calloc((alloc_t) nelem, (alloc_t) elsize); X} X Xchar * Xirealloc(pointer, size) Xchar * pointer; X{ X if (NULLMAL(pointer)) X return imalloc(size); X if (size == 0) X size = 1; X return realloc(pointer, (alloc_t) size); X} X Xchar * Xicatalloc(old, new) Xchar * old; Xchar * new; X{ X register char * result; X register oldsize, newsize; X X oldsize = NULLMAL(old) ? 0 : strlen(old); X newsize = NULLMAL(new) ? 0 : strlen(new); X if ((result = irealloc(old, oldsize + newsize + 1)) != NULL) X if (!NULLMAL(new)) X (void) strcpy(result + oldsize, new); X return result; X} X Xchar * Xicpyalloc(string) Xchar * string; X{ X return icatalloc((char *) NULL, string); X} X Xifree(p) Xchar * p; X{ X if (!NULLMAL(p)) X free(p); X} !The!End! echo x - "mkdir.c" 2>&1 sed "s/^X//" >"mkdir.c" <<'!The!End!' X# X X/*LINTLIBRARY*/ X X#include "stdio.h" X X#ifndef lint X#ifndef NOID Xstatic char sccsid[] = "@(#)mkdir.c 7.5"; X#endif /* !NOID */ X#endif /* !lint */ X Xextern FILE * popen(); X Xstatic Xquote(name, fp) Xregister char * name; Xregister FILE * fp; X{ X register int c; X X (void) fputc('\'', fp); X if (name != NULL) X while ((c = *name++) != '\0') X if (c == '\'') X (void) fprintf(fp, "'\\''"); X else (void) fputc(c, fp); X (void) fputc('\'', fp); X} X Xmkdir(name, mode) Xchar * name; X{ X register FILE * fp; X register int oops; X X if ((fp = popen("sh", "w")) == NULL) X return -1; X (void) fprintf(fp, "mkdir 2>&- "); X quote(name, fp); X (void) fprintf(fp, " && chmod 2>&- %o ", mode); X quote(name, fp); X (void) fputc('\n', fp); X (void) fflush(fp); X oops = ferror(fp); X return (pclose(fp) == 0 && !oops) ? 0 : -1; X} !The!End! exit