From 542c33e9fdb0405c01581eb0834f8be96eeef47a Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 30 Dec 1995 19:02:48 +0000 Subject: recording cvs-1.6 file death --- lib/libc/stdtime/localtime.c.ORIG | 1530 ------------------------------------- 1 file changed, 1530 deletions(-) delete mode 100644 lib/libc/stdtime/localtime.c.ORIG diff --git a/lib/libc/stdtime/localtime.c.ORIG b/lib/libc/stdtime/localtime.c.ORIG deleted file mode 100644 index 5403147..0000000 --- a/lib/libc/stdtime/localtime.c.ORIG +++ /dev/null @@ -1,1530 +0,0 @@ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)localtime.c 7.19"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - -/* -** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu). -** POSIX-style TZ environment variable handling from Guy Harris -** (guy@auspex.com). -*/ - -/*LINTLIBRARY*/ - -#include "private.h" -#include "tzfile.h" -#include "fcntl.h" - -#define ACCESS_MODE O_RDONLY - -#ifdef O_BINARY -#define OPEN_MODE (O_RDONLY | O_BINARY) -#endif /* defined O_BINARY */ -#ifndef O_BINARY -#define OPEN_MODE O_RDONLY -#endif /* !defined O_BINARY */ - -#ifndef WILDABBR -/* -** Someone might make incorrect use of a time zone abbreviation: -** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). -** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). -** 3. They might reference tzname[1] after setting to a time zone -** in which Daylight Saving Time is never observed. -** 4. They might reference tzname[0] after setting to a time zone -** in which Standard Time is never observed. -** 5. They might reference tm.TM_ZONE after calling offtime. -** What's best to do in the above cases is open to debate; -** for now, we just set things up so that in any of the five cases -** WILDABBR is used. Another possibility: initialize tzname[0] to the -** string "tzname[0] used before set", and similarly for the other cases. -** And another: initialize tzname[0] to "ERA", with an explanation in the -** manual page of what this "time zone abbreviation" means (doing this so -** that tzname[0] has the "normal" length of three characters). -*/ -#define WILDABBR " " -#endif /* !defined WILDABBR */ - -static const char GMT[] = "GMT"; - -struct ttinfo { /* time type information */ - long tt_gmtoff; /* GMT offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* TRUE if transition is std time */ -}; - -struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ -}; - -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - -#ifdef TZNAME_MAX -#define MY_TZNAME_MAX TZNAME_MAX -#endif /* defined TZNAME_MAX */ -#ifndef TZNAME_MAX -#define MY_TZNAME_MAX 255 -#endif /* !defined TZNAME_MAX */ - -struct state { - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - time_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; - struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof GMT), - (2 * (MY_TZNAME_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; -}; - -struct rule { - int r_type; /* type of rule--see below */ - int r_day; /* day number of rule */ - int r_week; /* week number of rule */ - int r_mon; /* month number of rule */ - long r_time; /* transition time of rule */ -}; - -#define JULIAN_DAY 0 /* Jn - Julian day */ -#define DAY_OF_YEAR 1 /* n - day of year */ -#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ - -/* -** Prototypes for static functions. -*/ - -static long detzcode P((const char * codep)); -static const char * getzname P((const char * strp)); -static const char * getnum P((const char * strp, int * nump, int min, - int max)); -static const char * getsecs P((const char * strp, long * secsp)); -static const char * getoffset P((const char * strp, long * offsetp)); -static const char * getrule P((const char * strp, struct rule * rulep)); -static void gmtload P((struct state * sp)); -static void gmtsub P((const time_t * timep, long offset, - struct tm * tmp)); -static void localsub P((const time_t * timep, long offset, - struct tm * tmp)); -static int increment_overflow P((int * number, int delta)); -static int normalize_overflow P((int * tensptr, int * unitsptr, - int base)); -static void settzname P((void)); -static time_t time1 P((struct tm * tmp, void (* funcp)(), - long offset)); -static time_t time2 P((struct tm *tmp, void (* funcp)(), - long offset, int * okayp)); -static void timesub P((const time_t * timep, long offset, - const struct state * sp, struct tm * tmp)); -static int tmcomp P((const struct tm * atmp, - const struct tm * btmp)); -static time_t transtime P((time_t janfirst, int year, - const struct rule * rulep, long offset)); -static int tzload P((const char * name, struct state * sp)); -static int tzparse P((const char * name, struct state * sp, - int lastditch)); - -#ifdef ALL_STATE -static struct state * lclptr; -static struct state * gmtptr; -#endif /* defined ALL_STATE */ - -#ifndef ALL_STATE -static struct state lclmem; -static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) -#endif /* State Farm */ - -static int lcl_is_set; -static int gmt_is_set; - -char * tzname[2] = { - WILDABBR, - WILDABBR -}; - -#ifdef USG_COMPAT -time_t timezone = 0; -int daylight = 0; -#endif /* defined USG_COMPAT */ - -#ifdef ALTZONE -time_t altzone = 0; -#endif /* defined ALTZONE */ - -static long -detzcode(codep) -const char * const codep; -{ - register long result; - register int i; - - result = 0; - for (i = 0; i < 4; ++i) - result = (result << 8) | (codep[i] & 0xff); - return result; -} - -static void -settzname() -{ - register const struct state * const sp = lclptr; - register int i; - - tzname[0] = WILDABBR; - tzname[1] = WILDABBR; -#ifdef USG_COMPAT - daylight = 0; - timezone = 0; -#endif /* defined USG_COMPAT */ -#ifdef ALTZONE - altzone = 0; -#endif /* defined ALTZONE */ -#ifdef ALL_STATE - if (sp == NULL) { - tzname[0] = tzname[1] = GMT; - return; - } -#endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - - tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; -#ifdef USG_COMPAT - if (ttisp->tt_isdst) - daylight = 1; - if (i == 0 || !ttisp->tt_isdst) - timezone = -(ttisp->tt_gmtoff); -#endif /* defined USG_COMPAT */ -#ifdef ALTZONE - if (i == 0 || ttisp->tt_isdst) - altzone = -(ttisp->tt_gmtoff); -#endif /* defined ALTZONE */ - } - /* - ** And to get the latest zone names into tzname. . . - */ - for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * const ttisp = - &sp->ttis[ - sp->types[i]]; - - tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; - } -} - -static int -tzload(name, sp) -register const char * name; -register struct state * const sp; -{ - register const char * p; - register int i; - register int fid; - - if (name == NULL && (name = TZDEFAULT) == NULL) - return -1; - { - register int doaccess; - char fullname[FILENAME_MAX + 1]; - - if (name[0] == ':') - ++name; - doaccess = name[0] == '/'; - if (!doaccess) { - if ((p = TZDIR) == NULL) - return -1; - if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) - return -1; - (void) strcpy(fullname, p); - (void) strcat(fullname, "/"); - (void) strcat(fullname, name); - /* - ** Set doaccess if '.' (as in "../") shows up in name. - */ - if (strchr(name, '.') != NULL) - doaccess = TRUE; - name = fullname; - } - if (doaccess && access(name, ACCESS_MODE) != 0) - return -1; - if ((fid = open(name, OPEN_MODE)) == -1) - return -1; - } - { - register const struct tzhead * tzhp; - char buf[sizeof *sp + sizeof *tzhp]; - int ttisstdcnt; - - i = read(fid, buf, sizeof buf); - if (close(fid) != 0 || i < sizeof *tzhp) - return -1; - tzhp = (struct tzhead *) buf; - ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); - sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); - sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); - sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); - sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); - if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || - sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || - sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || - sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || - (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) - return -1; - if (i < sizeof *tzhp + - sp->timecnt * (4 + sizeof (char)) + - sp->typecnt * (4 + 2 * sizeof (char)) + - sp->charcnt * sizeof (char) + - sp->leapcnt * 2 * 4 + - ttisstdcnt * sizeof (char)) - return -1; - p = buf + sizeof *tzhp; - for (i = 0; i < sp->timecnt; ++i) { - sp->ats[i] = detzcode(p); - p += 4; - } - for (i = 0; i < sp->timecnt; ++i) { - sp->types[i] = (unsigned char) *p++; - if (sp->types[i] >= sp->typecnt) - return -1; - } - for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - ttisp->tt_gmtoff = detzcode(p); - p += 4; - ttisp->tt_isdst = (unsigned char) *p++; - if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) - return -1; - ttisp->tt_abbrind = (unsigned char) *p++; - if (ttisp->tt_abbrind < 0 || - ttisp->tt_abbrind > sp->charcnt) - return -1; - } - for (i = 0; i < sp->charcnt; ++i) - sp->chars[i] = *p++; - sp->chars[i] = '\0'; /* ensure '\0' at end */ - for (i = 0; i < sp->leapcnt; ++i) { - register struct lsinfo * lsisp; - - lsisp = &sp->lsis[i]; - lsisp->ls_trans = detzcode(p); - p += 4; - lsisp->ls_corr = detzcode(p); - p += 4; - } - for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; - - ttisp = &sp->ttis[i]; - if (ttisstdcnt == 0) - ttisp->tt_ttisstd = FALSE; - else { - ttisp->tt_ttisstd = *p++; - if (ttisp->tt_ttisstd != TRUE && - ttisp->tt_ttisstd != FALSE) - return -1; - } - } - } - return 0; -} - -static const int mon_lengths[2][MONSPERYEAR] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -static const int year_lengths[2] = { - DAYSPERNYEAR, DAYSPERLYEAR -}; - -/* -** Given a pointer into a time zone string, scan until a character that is not -** a valid character in a zone name is found. Return a pointer to that -** character. -*/ - -static const char * -getzname(strp) -register const char * strp; -{ - register char c; - - while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && - c != '+') - ++strp; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a number from that string. -** Check that the number is within a specified range; if it is not, return -** NULL. -** Otherwise, return a pointer to the first character not part of the number. -*/ - -static const char * -getnum(strp, nump, min, max) -register const char * strp; -int * const nump; -const int min; -const int max; -{ - register char c; - register int num; - - if (strp == NULL || !isdigit(*strp)) - return NULL; - num = 0; - while ((c = *strp) != '\0' && isdigit(c)) { - num = num * 10 + (c - '0'); - if (num > max) - return NULL; /* illegal value */ - ++strp; - } - if (num < min) - return NULL; /* illegal value */ - *nump = num; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a number of seconds, -** in hh[:mm[:ss]] form, from the string. -** If any error occurs, return NULL. -** Otherwise, return a pointer to the first character not part of the number -** of seconds. -*/ - -static const char * -getsecs(strp, secsp) -register const char * strp; -long * const secsp; -{ - int num; - - strp = getnum(strp, &num, 0, HOURSPERDAY); - if (strp == NULL) - return NULL; - *secsp = num * SECSPERHOUR; - if (*strp == ':') { - ++strp; - strp = getnum(strp, &num, 0, MINSPERHOUR - 1); - if (strp == NULL) - return NULL; - *secsp += num * SECSPERMIN; - if (*strp == ':') { - ++strp; - strp = getnum(strp, &num, 0, SECSPERMIN - 1); - if (strp == NULL) - return NULL; - *secsp += num; - } - } - return strp; -} - -/* -** Given a pointer into a time zone string, extract an offset, in -** [+-]hh[:mm[:ss]] form, from the string. -** If any error occurs, return NULL. -** Otherwise, return a pointer to the first character not part of the time. -*/ - -static const char * -getoffset(strp, offsetp) -register const char * strp; -long * const offsetp; -{ - register int neg; - - if (*strp == '-') { - neg = 1; - ++strp; - } else if (isdigit(*strp) || *strp++ == '+') - neg = 0; - else return NULL; /* illegal offset */ - strp = getsecs(strp, offsetp); - if (strp == NULL) - return NULL; /* illegal time */ - if (neg) - *offsetp = -*offsetp; - return strp; -} - -/* -** Given a pointer into a time zone string, extract a rule in the form -** date[/time]. See POSIX section 8 for the format of "date" and "time". -** If a valid rule is not found, return NULL. -** Otherwise, return a pointer to the first character not part of the rule. -*/ - -static const char * -getrule(strp, rulep) -const char * strp; -register struct rule * const rulep; -{ - if (*strp == 'J') { - /* - ** Julian day. - */ - rulep->r_type = JULIAN_DAY; - ++strp; - strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); - } else if (*strp == 'M') { - /* - ** Month, week, day. - */ - rulep->r_type = MONTH_NTH_DAY_OF_WEEK; - ++strp; - strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_week, 1, 5); - if (strp == NULL) - return NULL; - if (*strp++ != '.') - return NULL; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (isdigit(*strp)) { - /* - ** Day of year. - */ - rulep->r_type = DAY_OF_YEAR; - strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); - } else return NULL; /* invalid format */ - if (strp == NULL) - return NULL; - if (*strp == '/') { - /* - ** Time specified. - */ - ++strp; - strp = getsecs(strp, &rulep->r_time); - } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ - return strp; -} - -/* -** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the -** year, a rule, and the offset from GMT at the time that rule takes effect, -** calculate the Epoch-relative time that rule takes effect. -*/ - -static time_t -transtime(janfirst, year, rulep, offset) -const time_t janfirst; -const int year; -register const struct rule * const rulep; -const long offset; -{ - register int leapyear; - register time_t value; - register int i; - int d, m1, yy0, yy1, yy2, dow; - - leapyear = isleap(year); - switch (rulep->r_type) { - - case JULIAN_DAY: - /* - ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap - ** years. - ** In non-leap years, or if the day number is 59 or less, just - ** add SECSPERDAY times the day number-1 to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + (rulep->r_day - 1) * SECSPERDAY; - if (leapyear && rulep->r_day >= 60) - value += SECSPERDAY; - break; - - case DAY_OF_YEAR: - /* - ** n - day of year. - ** Just add SECSPERDAY times the day number to the time of - ** January 1, midnight, to get the day. - */ - value = janfirst + rulep->r_day * SECSPERDAY; - break; - - case MONTH_NTH_DAY_OF_WEEK: - /* - ** Mm.n.d - nth "dth day" of month m. - */ - value = janfirst; - for (i = 0; i < rulep->r_mon - 1; ++i) - value += mon_lengths[leapyear][i] * SECSPERDAY; - - /* - ** Use Zeller's Congruence to get day-of-week of first day of - ** month. - */ - m1 = (rulep->r_mon + 9) % 12 + 1; - yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; - yy1 = yy0 / 100; - yy2 = yy0 % 100; - dow = ((26 * m1 - 2) / 10 + - 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; - if (dow < 0) - dow += DAYSPERWEEK; - - /* - ** "dow" is the day-of-week of the first day of the month. Get - ** the day-of-month (zero-origin) of the first "dow" day of the - ** month. - */ - d = rulep->r_day - dow; - if (d < 0) - d += DAYSPERWEEK; - for (i = 1; i < rulep->r_week; ++i) { - if (d + DAYSPERWEEK >= - mon_lengths[leapyear][rulep->r_mon - 1]) - break; - d += DAYSPERWEEK; - } - - /* - ** "d" is the day-of-month (zero-origin) of the day we want. - */ - value += d * SECSPERDAY; - break; - } - - /* - ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in - ** question. To get the Epoch-relative time of the specified local - ** time on that day, add the transition time and the current offset - ** from GMT. - */ - return value + rulep->r_time + offset; -} - -/* -** Given a POSIX section 8-style TZ string, fill in the rule tables as -** appropriate. -*/ - -static int -tzparse(name, sp, lastditch) -const char * name; -register struct state * const sp; -const int lastditch; -{ - const char * stdname; - const char * dstname; - int stdlen; - int dstlen; - long stdoffset; - long dstoffset; - register time_t * atp; - register unsigned char * typep; - register char * cp; - register int load_result; - - stdname = name; - if (lastditch) { - stdlen = strlen(name); /* length of standard zone name */ - name += stdlen; - if (stdlen >= sizeof sp->chars) - stdlen = (sizeof sp->chars) - 1; - } else { - name = getzname(name); - stdlen = name - stdname; - if (stdlen < 3) - return -1; - } - if (*name == '\0') - return -1; /* was "stdoffset = 0;" */ - else { - name = getoffset(name, &stdoffset); - if (name == NULL) - return -1; - } - load_result = tzload(TZDEFRULES, sp); - if (load_result != 0) - sp->leapcnt = 0; /* so, we're off a little */ - if (*name != '\0') { - dstname = name; - name = getzname(name); - dstlen = name - dstname; /* length of DST zone name */ - if (dstlen < 3) - return -1; - if (*name != '\0' && *name != ',' && *name != ';') { - name = getoffset(name, &dstoffset); - if (name == NULL) - return -1; - } else dstoffset = stdoffset - SECSPERHOUR; - if (*name == ',' || *name == ';') { - struct rule start; - struct rule end; - register int year; - register time_t janfirst; - time_t starttime; - time_t endtime; - - ++name; - if ((name = getrule(name, &start)) == NULL) - return -1; - if (*name++ != ',') - return -1; - if ((name = getrule(name, &end)) == NULL) - return -1; - if (*name != '\0') - return -1; - sp->typecnt = 2; /* standard time and DST */ - /* - ** Two transitions per year, from EPOCH_YEAR to 2037. - */ - sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); - if (sp->timecnt > TZ_MAX_TIMES) - return -1; - sp->ttis[0].tt_gmtoff = -dstoffset; - sp->ttis[0].tt_isdst = 1; - sp->ttis[0].tt_abbrind = stdlen + 1; - sp->ttis[1].tt_gmtoff = -stdoffset; - sp->ttis[1].tt_isdst = 0; - sp->ttis[1].tt_abbrind = 0; - atp = sp->ats; - typep = sp->types; - janfirst = 0; - for (year = EPOCH_YEAR; year <= 2037; ++year) { - starttime = transtime(janfirst, year, &start, - stdoffset); - endtime = transtime(janfirst, year, &end, - dstoffset); - if (starttime > endtime) { - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - } else { - *atp++ = starttime; - *typep++ = 0; /* DST begins */ - *atp++ = endtime; - *typep++ = 1; /* DST ends */ - } - janfirst += year_lengths[isleap(year)] * - SECSPERDAY; - } - } else { - int sawstd; - int sawdst; - long stdfix; - long dstfix; - long oldfix; - int isdst; - register int i; - - if (*name != '\0') - return -1; - if (load_result != 0) - return -1; - /* - ** Compute the difference between the real and - ** prototype standard and summer time offsets - ** from GMT, and put the real standard and summer - ** time offsets into the rules in place of the - ** prototype offsets. - */ - sawstd = FALSE; - sawdst = FALSE; - stdfix = 0; - dstfix = 0; - for (i = 0; i < sp->typecnt; ++i) { - if (sp->ttis[i].tt_isdst) { - oldfix = dstfix; - dstfix = sp->ttis[i].tt_gmtoff + - dstoffset; - if (sawdst && (oldfix != dstfix)) - return -1; - sp->ttis[i].tt_gmtoff = -dstoffset; - sp->ttis[i].tt_abbrind = stdlen + 1; - sawdst = TRUE; - } else { - oldfix = stdfix; - stdfix = sp->ttis[i].tt_gmtoff + - stdoffset; - if (sawstd && (oldfix != stdfix)) - return -1; - sp->ttis[i].tt_gmtoff = -stdoffset; - sp->ttis[i].tt_abbrind = 0; - sawstd = TRUE; - } - } - /* - ** Make sure we have both standard and summer time. - */ - if (!sawdst || !sawstd) - return -1; - /* - ** Now correct the transition times by shifting - ** them by the difference between the real and - ** prototype offsets. Note that this difference - ** can be different in standard and summer time; - ** the prototype probably has a 1-hour difference - ** between standard and summer time, but a different - ** difference can be specified in TZ. - */ - isdst = FALSE; /* we start in standard time */ - for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * ttisp; - - /* - ** If summer time is in effect, and the - ** transition time was not specified as - ** standard time, add the summer time - ** offset to the transition time; - ** otherwise, add the standard time offset - ** to the transition time. - */ - ttisp = &sp->ttis[sp->types[i]]; - sp->ats[i] += - (isdst && !ttisp->tt_ttisstd) ? - dstfix : stdfix; - isdst = ttisp->tt_isdst; - } - } - } else { - dstlen = 0; - sp->typecnt = 1; /* only standard time */ - sp->timecnt = 0; - sp->ttis[0].tt_gmtoff = -stdoffset; - sp->ttis[0].tt_isdst = 0; - sp->ttis[0].tt_abbrind = 0; - } - sp->charcnt = stdlen + 1; - if (dstlen != 0) - sp->charcnt += dstlen + 1; - if (sp->charcnt > sizeof sp->chars) - return -1; - cp = sp->chars; - (void) strncpy(cp, stdname, stdlen); - cp += stdlen; - *cp++ = '\0'; - if (dstlen != 0) { - (void) strncpy(cp, dstname, dstlen); - *(cp + dstlen) = '\0'; - } - return 0; -} - -static void -gmtload(sp) -struct state * const sp; -{ - if (tzload(GMT, sp) != 0) - (void) tzparse(GMT, sp, TRUE); -} - -#ifndef STD_INSPIRED -static -#endif /* !defined STD_INSPIRED */ -void -tzsetwall() -{ - lcl_is_set = TRUE; -#ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - return; - } - } -#endif /* defined ALL_STATE */ - if (tzload((char *) NULL, lclptr) != 0) - gmtload(lclptr); - settzname(); -} - -void -tzset() -{ - register const char * name; - - name = getenv("TZ"); - if (name == NULL) { - tzsetwall(); - return; - } - lcl_is_set = TRUE; -#ifdef ALL_STATE - if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); - if (lclptr == NULL) { - settzname(); /* all we can do */ - return; - } - } -#endif /* defined ALL_STATE */ - if (*name == '\0') { - /* - ** User wants it fast rather than right. - */ - lclptr->leapcnt = 0; /* so, we're off a little */ - lclptr->timecnt = 0; - lclptr->ttis[0].tt_gmtoff = 0; - lclptr->ttis[0].tt_abbrind = 0; - (void) strcpy(lclptr->chars, GMT); - } else if (tzload(name, lclptr) != 0) - if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) - (void) gmtload(lclptr); - settzname(); -} - -/* -** The easy way to behave "as if no library function calls" localtime -** is to not call it--so we drop its guts into "localsub", which can be -** freely called. (And no, the PANS doesn't require the above behavior-- -** but it *is* desirable.) -** -** The unused offset argument is for the benefit of mktime variants. -*/ - -/*ARGSUSED*/ -static void -localsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; -{ - register const struct state * sp; - register const struct ttinfo * ttisp; - register int i; - const time_t t = *timep; - - if (!lcl_is_set) - tzset(); - sp = lclptr; -#ifdef ALL_STATE - if (sp == NULL) { - gmtsub(timep, offset, tmp); - return; - } -#endif /* defined ALL_STATE */ - if (sp->timecnt == 0 || t < sp->ats[0]) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } - } else { - for (i = 1; i < sp->timecnt; ++i) - if (t < sp->ats[i]) - break; - i = sp->types[i - 1]; - } - ttisp = &sp->ttis[i]; - /* - ** To get (wrong) behavior that's compatible with System V Release 2.0 - ** you'd replace the statement below with - ** t += ttisp->tt_gmtoff; - ** timesub(&t, 0L, sp, tmp); - */ - timesub(&t, ttisp->tt_gmtoff, sp, tmp); - tmp->tm_isdst = ttisp->tt_isdst; - tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; -#ifdef TM_ZONE - tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; -#endif /* defined TM_ZONE */ -} - -struct tm * -localtime(timep) -const time_t * const timep; -{ - static struct tm tm; - - localsub(timep, 0L, &tm); - return &tm; -} - -/* -** gmtsub is to gmtime as localsub is to localtime. -*/ - -static void -gmtsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; -{ - if (!gmt_is_set) { - gmt_is_set = TRUE; -#ifdef ALL_STATE - gmtptr = (struct state *) malloc(sizeof *gmtptr); - if (gmtptr != NULL) -#endif /* defined ALL_STATE */ - gmtload(gmtptr); - } - timesub(timep, offset, gmtptr, tmp); -#ifdef TM_ZONE - /* - ** Could get fancy here and deliver something such as - ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, - ** but this is no time for a treasure hunt. - */ - if (offset != 0) - tmp->TM_ZONE = WILDABBR; - else { -#ifdef ALL_STATE - if (gmtptr == NULL) - tmp->TM_ZONE = GMT; - else tmp->TM_ZONE = gmtptr->chars; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - tmp->TM_ZONE = gmtptr->chars; -#endif /* State Farm */ - } -#endif /* defined TM_ZONE */ -} - -struct tm * -gmtime(timep) -const time_t * const timep; -{ - static struct tm tm; - - gmtsub(timep, 0L, &tm); - return &tm; -} - -#ifdef STD_INSPIRED - -struct tm * -offtime(timep, offset) -const time_t * const timep; -const long offset; -{ - static struct tm tm; - - gmtsub(timep, offset, &tm); - return &tm; -} - -#endif /* defined STD_INSPIRED */ - -static void -timesub(timep, offset, sp, tmp) -const time_t * const timep; -const long offset; -register const struct state * const sp; -register struct tm * const tmp; -{ - register const struct lsinfo * lp; - register long days; - register long rem; - register int y; - register int yleap; - register const int * ip; - register long corr; - register int hit; - register int i; - - corr = 0; - hit = 0; -#ifdef ALL_STATE - i = (sp == NULL) ? 0 : sp->leapcnt; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - i = sp->leapcnt; -#endif /* State Farm */ - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) { - if (*timep == lp->ls_trans) { - hit = ((i == 0 && lp->ls_corr > 0) || - lp->ls_corr > sp->lsis[i - 1].ls_corr); - if (hit) - while (i > 0 && - sp->lsis[i].ls_trans == - sp->lsis[i - 1].ls_trans + 1 && - sp->lsis[i].ls_corr == - sp->lsis[i - 1].ls_corr + 1) { - ++hit; - --i; - } - } - corr = lp->ls_corr; - break; - } - } - days = *timep / SECSPERDAY; - rem = *timep % SECSPERDAY; -#ifdef mc68k - if (*timep == 0x80000000) { - /* - ** A 3B1 muffs the division on the most negative number. - */ - days = -24855; - rem = -11648; - } -#endif /* mc68k */ - rem += (offset - corr); - while (rem < 0) { - rem += SECSPERDAY; - --days; - } - while (rem >= SECSPERDAY) { - rem -= SECSPERDAY; - ++days; - } - tmp->tm_hour = (int) (rem / SECSPERHOUR); - rem = rem % SECSPERHOUR; - tmp->tm_min = (int) (rem / SECSPERMIN); - tmp->tm_sec = (int) (rem % SECSPERMIN); - if (hit) - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec += hit; - tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); - if (tmp->tm_wday < 0) - tmp->tm_wday += DAYSPERWEEK; - y = EPOCH_YEAR; - if (days >= 0) - for ( ; ; ) { - yleap = isleap(y); - if (days < (long) year_lengths[yleap]) - break; - ++y; - days = days - (long) year_lengths[yleap]; - } - else do { - --y; - yleap = isleap(y); - days = days + (long) year_lengths[yleap]; - } while (days < 0); - tmp->tm_year = y - TM_YEAR_BASE; - tmp->tm_yday = (int) days; - ip = mon_lengths[yleap]; - for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) - days = days - (long) ip[tmp->tm_mon]; - tmp->tm_mday = (int) (days + 1); - tmp->tm_isdst = 0; -#ifdef TM_GMTOFF - tmp->TM_GMTOFF = offset; -#endif /* defined TM_GMTOFF */ -} - -char * -ctime(timep) -const time_t * const timep; -{ - return asctime(localtime(timep)); -} - -/* -** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). -** It does a binary search of the time_t space. Since time_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). -*/ - -#ifndef WRONG -#define WRONG (-1) -#endif /* !defined WRONG */ - -/* -** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com). -*/ - -static int -increment_overflow(number, delta) -int * number; -int delta; -{ - int number0; - - number0 = *number; - *number += delta; - return (*number < number0) != (delta < 0); -} - -static int -normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); -} - -static int -tmcomp(atmp, btmp) -register const struct tm * const atmp; -register const struct tm * const btmp; -{ - register int result; - - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; -} - -static time_t -time2(tmp, funcp, offset, okayp) -struct tm * const tmp; -void (* const funcp)(); -const long offset; -int * const okayp; -{ - register const struct state * sp; - register int dir; - register int bits; - register int i, j ; - register int saved_seconds; - time_t newt; - time_t t; - struct tm yourtm, mytm; - - *okayp = FALSE; - yourtm = *tmp; - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; - if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; - /* - ** Turn yourtm.tm_year into an actual year number for now. - ** It is converted back to an offset from TM_YEAR_BASE later. - */ - if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (increment_overflow(&yourtm.tm_year, -1)) - return WRONG; - yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)]; - } - while (yourtm.tm_mday > DAYSPERLYEAR) { - yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)]; - if (increment_overflow(&yourtm.tm_year, 1)) - return WRONG; - } - for ( ; ; ) { - i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; - if (yourtm.tm_mday <= i) - break; - yourtm.tm_mday -= i; - if (++yourtm.tm_mon >= MONSPERYEAR) { - yourtm.tm_mon = 0; - if (increment_overflow(&yourtm.tm_year, 1)) - return WRONG; - } - } - if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) - return WRONG; - if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { - /* - ** We can't set tm_sec to 0, because that might push the - ** time below the minimum representable time. - ** Set tm_sec to 59 instead. - ** This assumes that the minimum representable time is - ** not in the same minute that a leap second was deleted from, - ** which is a safer assumption than using 58 would be. - */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = SECSPERMIN - 1; - } else { - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - } - /* - ** Calculate the number of magnitude bits in a time_t - ** (this works regardless of whether time_t is - ** signed or unsigned, though lint complains if unsigned). - */ - for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) - continue; - /* - ** If time_t is signed, then 0 is the median value, - ** if time_t is unsigned, then 1 << bits is median. - */ - t = (t < 0) ? 0 : ((time_t) 1 << bits); - for ( ; ; ) { - (*funcp)(&t, offset, &mytm); - dir = tmcomp(&mytm, &yourtm); - if (dir != 0) { - if (bits-- < 0) - return WRONG; - if (bits < 0) - --t; - else if (dir > 0) - t -= (time_t) 1 << bits; - else t += (time_t) 1 << bits; - continue; - } - if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) - break; - /* - ** Right time, wrong type. - ** Hunt for right time, right type. - ** It's okay to guess wrong since the guess - ** gets checked. - */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) - (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); -#ifdef ALL_STATE - if (sp == NULL) - return WRONG; -#endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { - if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) - continue; - for (j = 0; j < sp->typecnt; ++j) { - if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) - continue; - newt = t + sp->ttis[j].tt_gmtoff - - sp->ttis[i].tt_gmtoff; - (*funcp)(&newt, offset, &mytm); - if (tmcomp(&mytm, &yourtm) != 0) - continue; - if (mytm.tm_isdst != yourtm.tm_isdst) - continue; - /* - ** We have a match. - */ - t = newt; - goto label; - } - } - return WRONG; - } -label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) - return WRONG; - t = newt; - (*funcp)(&t, offset, tmp); - *okayp = TRUE; - return t; -} - -static time_t -time1(tmp, funcp, offset) -struct tm * const tmp; -void (* const funcp)(); -const long offset; -{ - register time_t t; - register const struct state * sp; - register int samei, otheri; - int okay; - - if (tmp->tm_isdst > 1) - tmp->tm_isdst = 1; - t = time2(tmp, funcp, offset, &okay); -#ifdef PCTS - /* - ** PCTS code courtesy Grant Sullivan (grant@osf.org). - */ - if (okay) - return t; - if (tmp->tm_isdst < 0) - tmp->tm_isdst = 0; /* reset to std and try again */ -#endif /* defined PCTS */ -#ifndef PCTS - if (okay || tmp->tm_isdst < 0) - return t; -#endif /* !defined PCTS */ - /* - ** We're supposed to assume that somebody took a time of one type - ** and did some math on it that yielded a "struct tm" that's bad. - ** We try to divine the type they started from and adjust to the - ** type they need. - */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ - sp = (const struct state *) (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); -#ifdef ALL_STATE - if (sp == NULL) - return WRONG; -#endif /* defined ALL_STATE */ - for (samei = 0; samei < sp->typecnt; ++samei) { - if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) - continue; - for (otheri = 0; otheri < sp->typecnt; ++otheri) { - if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) - continue; - tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - t = time2(tmp, funcp, offset, &okay); - if (okay) - return t; - tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - } - } - return WRONG; -} - -time_t -mktime(tmp) -struct tm * const tmp; -{ - return time1(tmp, localsub, 0L); -} - -#ifdef STD_INSPIRED - -time_t -timelocal(tmp) -struct tm * const tmp; -{ - tmp->tm_isdst = -1; /* in case it wasn't initialized */ - return mktime(tmp); -} - -time_t -timegm(tmp) -struct tm * const tmp; -{ - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, 0L); -} - -time_t -timeoff(tmp, offset) -struct tm * const tmp; -const long offset; -{ - tmp->tm_isdst = 0; - return time1(tmp, gmtsub, offset); -} - -#endif /* defined STD_INSPIRED */ - -#ifdef CMUCS - -/* -** The following is supplied for compatibility with -** previous versions of the CMUCS runtime library. -*/ - -long -gtime(tmp) -struct tm * const tmp; -{ - const time_t t = mktime(tmp); - - if (t == WRONG) - return -1; - return t; -} - -#endif /* defined CMUCS */ - -/* -** XXX--is the below the right way to conditionalize?? -*/ - -#ifdef STD_INSPIRED - -/* -** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599 -** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which -** is not the case if we are accounting for leap seconds. -** So, we provide the following conversion routines for use -** when exchanging timestamps with POSIX conforming systems. -*/ - -static long -leapcorr(timep) -time_t * timep; -{ - register struct state * sp; - register struct lsinfo * lp; - register int i; - - if (!lcl_is_set) - (void) tzset(); - sp = lclptr; - i = sp->leapcnt; - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) - return lp->ls_corr; - } - return 0; -} - -time_t -time2posix(t) -time_t t; -{ - return t - leapcorr(&t); -} - -time_t -posix2time(t) -time_t t; -{ - time_t x; - time_t y; - - /* - ** For a positive leap second hit, the result - ** is not unique. For a negative leap second - ** hit, the corresponding time doesn't exist, - ** so we return an adjacent second. - */ - x = t + leapcorr(&t); - y = x - leapcorr(&x); - if (y < t) { - do { - x++; - y = x - leapcorr(&x); - } while (y < t); - if (t != y) - return x - 1; - } else if (y > t) { - do { - --x; - y = x - leapcorr(&x); - } while (y > t); - if (t != y) - return x + 1; - } - return x; -} - -#endif /* defined STD_INSPIRED */ -- cgit v1.1 From 432bfd150d5fcef2195e57491d1659bc73708bf9 Mon Sep 17 00:00:00 2001 From: wollman Date: Thu, 18 Jul 1996 18:05:09 +0000 Subject: Import the 96h release of ADO's timezone code. This release is primarily bugfixes, but is also contains a disclaimer of copyright. As we are completely off the vendor branch here, this import has no effect on the source tree. --- lib/libc/stdtime/asctime.c | 7 +- lib/libc/stdtime/difftime.c | 15 +- lib/libc/stdtime/localtime.c | 443 +++++++++++++++++++++++---------------- lib/libc/stdtime/private.h | 255 +++++++++++++--------- lib/libc/stdtime/strftime.c | 487 +++++++++++++++++++++++++++++++------------ lib/libc/stdtime/tzfile.h | 23 +- 6 files changed, 809 insertions(+), 421 deletions(-) diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c index 6087702..a1834b6 100644 --- a/lib/libc/stdtime/asctime.c +++ b/lib/libc/stdtime/asctime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)asctime.c 7.5"; +static char elsieid[] = "@(#)asctime.c 7.7"; #endif /* !defined NOID */ #endif /* !defined lint */ diff --git a/lib/libc/stdtime/difftime.c b/lib/libc/stdtime/difftime.c index 68f9d7e..f178524 100644 --- a/lib/libc/stdtime/difftime.c +++ b/lib/libc/stdtime/difftime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)difftime.c 7.4"; +static char elsieid[] = "@(#)difftime.c 7.7"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -43,9 +48,7 @@ const time_t time0; /* ** Repair delta overflow. */ - hibit = 1; - while ((hibit <<= 1) > 0) - continue; + hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1); /* ** The following expression rounds twice, which means ** the result may not be the closest to the true answer. @@ -65,10 +68,10 @@ const time_t time0; ** This problem occurs only with very large differences. ** It's too painful to fix this portably. ** We are not alone in this problem; - ** many C compilers round twice when converting + ** some C compilers round twice when converting ** large unsigned types to small floating types, ** so if time_t is unsigned the "return delta" above - ** has the same double-rounding problem. + ** has the same double-rounding problem with those compilers. */ return delta - 2 * (long_double) hibit; } diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index 5403147..541f49f 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)localtime.c 7.19"; +static char elsieid[] = "@(#)localtime.c 7.57"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -16,7 +21,9 @@ static char elsieid[] = "@(#)localtime.c 7.19"; #include "tzfile.h" #include "fcntl.h" -#define ACCESS_MODE O_RDONLY +/* +** SunOS 4.1.1 headers lack O_BINARY. +*/ #ifdef O_BINARY #define OPEN_MODE (O_RDONLY | O_BINARY) @@ -29,9 +36,9 @@ static char elsieid[] = "@(#)localtime.c 7.19"; /* ** Someone might make incorrect use of a time zone abbreviation: ** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). +** or implicitly). ** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). +** or implicitly). ** 3. They might reference tzname[1] after setting to a time zone ** in which Daylight Saving Time is never observed. ** 4. They might reference tzname[0] after setting to a time zone @@ -48,13 +55,16 @@ static char elsieid[] = "@(#)localtime.c 7.19"; #define WILDABBR " " #endif /* !defined WILDABBR */ -static const char GMT[] = "GMT"; +static char wildabbr[] = "WILDABBR"; + +static const char gmt[] = "GMT"; struct ttinfo { /* time type information */ long tt_gmtoff; /* GMT offset in seconds */ int tt_isdst; /* used to set tm_isdst */ int tt_abbrind; /* abbreviation list index */ int tt_ttisstd; /* TRUE if transition is std time */ + int tt_ttisgmt; /* TRUE if transition is GMT */ }; struct lsinfo { /* leap second information */ @@ -79,7 +89,7 @@ struct state { time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof GMT), + char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; }; @@ -116,9 +126,13 @@ static int increment_overflow P((int * number, int delta)); static int normalize_overflow P((int * tensptr, int * unitsptr, int base)); static void settzname P((void)); -static time_t time1 P((struct tm * tmp, void (* funcp)(), +static time_t time1 P((struct tm * tmp, + void(*funcp) P((const time_t *, + long, struct tm *)), long offset)); -static time_t time2 P((struct tm *tmp, void (* funcp)(), +static time_t time2 P((struct tm *tmp, + void(*funcp) P((const time_t *, + long, struct tm*)), long offset, int * okayp)); static void timesub P((const time_t * timep, long offset, const struct state * sp, struct tm * tmp)); @@ -142,14 +156,29 @@ static struct state gmtmem; #define gmtptr (&gmtmem) #endif /* State Farm */ +#ifndef TZ_STRLEN_MAX +#define TZ_STRLEN_MAX 255 +#endif /* !defined TZ_STRLEN_MAX */ + +static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; static int gmt_is_set; char * tzname[2] = { - WILDABBR, - WILDABBR + wildabbr, + wildabbr }; +/* +** Section 4.12.3 of X3.159-1989 requires that +** Except for the strftime function, these functions [asctime, +** ctime, gmtime, localtime] return values in one of two static +** objects: a broken-down time structure and an array of char. +** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. +*/ + +static struct tm tm; + #ifdef USG_COMPAT time_t timezone = 0; int daylight = 0; @@ -166,20 +195,20 @@ const char * const codep; register long result; register int i; - result = 0; + result = (codep[0] & 0x80) ? ~0L : 0L; for (i = 0; i < 4; ++i) result = (result << 8) | (codep[i] & 0xff); return result; } static void -settzname() +settzname P((void)) { - register const struct state * const sp = lclptr; - register int i; + register struct state * const sp = lclptr; + register int i; - tzname[0] = WILDABBR; - tzname[1] = WILDABBR; + tzname[0] = wildabbr; + tzname[1] = wildabbr; #ifdef USG_COMPAT daylight = 0; timezone = 0; @@ -189,7 +218,7 @@ settzname() #endif /* defined ALTZONE */ #ifdef ALL_STATE if (sp == NULL) { - tzname[0] = tzname[1] = GMT; + tzname[0] = tzname[1] = gmt; return; } #endif /* defined ALL_STATE */ @@ -197,7 +226,7 @@ settzname() register const struct ttinfo * const ttisp = &sp->ttis[i]; tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; + &sp->chars[ttisp->tt_abbrind]; #ifdef USG_COMPAT if (ttisp->tt_isdst) daylight = 1; @@ -218,7 +247,7 @@ settzname() sp->types[i]]; tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; + &sp->chars[ttisp->tt_abbrind]; } } @@ -234,7 +263,14 @@ register struct state * const sp; if (name == NULL && (name = TZDEFAULT) == NULL) return -1; { - register int doaccess; + register int doaccess; + /* + ** Section 4.9.1 of the C standard says that + ** "FILENAME_MAX expands to an integral constant expression + ** that is the sie needed for an array of char large enough + ** to hold the longest file name string that the implementation + ** guarantees can be opened." + */ char fullname[FILENAME_MAX + 1]; if (name[0] == ':') @@ -255,39 +291,49 @@ register struct state * const sp; doaccess = TRUE; name = fullname; } - if (doaccess && access(name, ACCESS_MODE) != 0) + if (doaccess && access(name, R_OK) != 0) return -1; if ((fid = open(name, OPEN_MODE)) == -1) return -1; } { - register const struct tzhead * tzhp; - char buf[sizeof *sp + sizeof *tzhp]; - int ttisstdcnt; + struct tzhead * tzhp; + char buf[sizeof *sp + sizeof *tzhp]; + int ttisstdcnt; + int ttisgmtcnt; i = read(fid, buf, sizeof buf); - if (close(fid) != 0 || i < sizeof *tzhp) + if (close(fid) != 0) return -1; - tzhp = (struct tzhead *) buf; - ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); - sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); - sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); - sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); - sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); + p = buf; + p += sizeof tzhp->tzh_reserved; + ttisstdcnt = (int) detzcode(p); + p += 4; + ttisgmtcnt = (int) detzcode(p); + p += 4; + sp->leapcnt = (int) detzcode(p); + p += 4; + sp->timecnt = (int) detzcode(p); + p += 4; + sp->typecnt = (int) detzcode(p); + p += 4; + sp->charcnt = (int) detzcode(p); + p += 4; if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || - (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) + (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || + (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) return -1; - if (i < sizeof *tzhp + - sp->timecnt * (4 + sizeof (char)) + - sp->typecnt * (4 + 2 * sizeof (char)) + - sp->charcnt * sizeof (char) + - sp->leapcnt * 2 * 4 + - ttisstdcnt * sizeof (char)) + if (i - (p - buf) < sp->timecnt * 4 + /* ats */ + sp->timecnt + /* types */ + sp->typecnt * (4 + 2) + /* ttinfos */ + sp->charcnt + /* chars */ + sp->leapcnt * (4 + 4) + /* lsinfos */ + ttisstdcnt + /* ttisstds */ + ttisgmtcnt) /* ttisgmts */ return -1; - p = buf + sizeof *tzhp; for (i = 0; i < sp->timecnt; ++i) { sp->ats[i] = detzcode(p); p += 4; @@ -336,6 +382,19 @@ register struct state * const sp; return -1; } } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisgmtcnt == 0) + ttisp->tt_ttisgmt = FALSE; + else { + ttisp->tt_ttisgmt = *p++; + if (ttisp->tt_ttisgmt != TRUE && + ttisp->tt_ttisgmt != FALSE) + return -1; + } + } } return 0; } @@ -361,7 +420,7 @@ register const char * strp; { register char c; - while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && + while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') ++strp; return strp; @@ -384,15 +443,15 @@ const int max; register char c; register int num; - if (strp == NULL || !isdigit(*strp)) + if (strp == NULL || !is_digit(c = *strp)) return NULL; num = 0; - while ((c = *strp) != '\0' && isdigit(c)) { + do { num = num * 10 + (c - '0'); if (num > max) return NULL; /* illegal value */ - ++strp; - } + c = *++strp; + } while (is_digit(c)); if (num < min) return NULL; /* illegal value */ *nump = num; @@ -414,10 +473,16 @@ long * const secsp; { int num; - strp = getnum(strp, &num, 0, HOURSPERDAY); + /* + ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like + ** "M10.4.6/26", which does not conform to Posix, + ** but which specifies the equivalent of + ** ``02:00 on the first Sunday on or after 23 Oct''. + */ + strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); if (strp == NULL) return NULL; - *secsp = num * SECSPERHOUR; + *secsp = num * (long) SECSPERHOUR; if (*strp == ':') { ++strp; strp = getnum(strp, &num, 0, MINSPERHOUR - 1); @@ -426,7 +491,8 @@ long * const secsp; *secsp += num * SECSPERMIN; if (*strp == ':') { ++strp; - strp = getnum(strp, &num, 0, SECSPERMIN - 1); + /* `SECSPERMIN' allows for leap seconds. */ + strp = getnum(strp, &num, 0, SECSPERMIN); if (strp == NULL) return NULL; *secsp += num; @@ -447,14 +513,13 @@ getoffset(strp, offsetp) register const char * strp; long * const offsetp; { - register int neg; + register int neg = 0; if (*strp == '-') { neg = 1; ++strp; - } else if (isdigit(*strp) || *strp++ == '+') - neg = 0; - else return NULL; /* illegal offset */ + } else if (*strp == '+') + ++strp; strp = getsecs(strp, offsetp); if (strp == NULL) return NULL; /* illegal time */ @@ -499,7 +564,7 @@ register struct rule * const rulep; if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (isdigit(*strp)) { + } else if (is_digit(*strp)) { /* ** Day of year. */ @@ -536,6 +601,7 @@ const long offset; register int i; int d, m1, yy0, yy1, yy2, dow; + INITIALIZE(value); leapyear = isleap(year); switch (rulep->r_type) { @@ -626,8 +692,8 @@ const int lastditch; { const char * stdname; const char * dstname; - int stdlen; - int dstlen; + size_t stdlen; + size_t dstlen; long stdoffset; long dstoffset; register time_t * atp; @@ -635,6 +701,7 @@ const int lastditch; register char * cp; register int load_result; + INITIALIZE(dstname); stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ @@ -721,82 +788,90 @@ const int lastditch; SECSPERDAY; } } else { - int sawstd; - int sawdst; - long stdfix; - long dstfix; - long oldfix; - int isdst; + register long theirstdoffset; + register long theirdstoffset; + register long theiroffset; + register int isdst; register int i; + register int j; if (*name != '\0') return -1; if (load_result != 0) return -1; /* - ** Compute the difference between the real and - ** prototype standard and summer time offsets - ** from GMT, and put the real standard and summer - ** time offsets into the rules in place of the - ** prototype offsets. + ** Initial values of theirstdoffset and theirdstoffset. */ - sawstd = FALSE; - sawdst = FALSE; - stdfix = 0; - dstfix = 0; - for (i = 0; i < sp->typecnt; ++i) { - if (sp->ttis[i].tt_isdst) { - oldfix = dstfix; - dstfix = sp->ttis[i].tt_gmtoff + - dstoffset; - if (sawdst && (oldfix != dstfix)) - return -1; - sp->ttis[i].tt_gmtoff = -dstoffset; - sp->ttis[i].tt_abbrind = stdlen + 1; - sawdst = TRUE; - } else { - oldfix = stdfix; - stdfix = sp->ttis[i].tt_gmtoff + - stdoffset; - if (sawstd && (oldfix != stdfix)) - return -1; - sp->ttis[i].tt_gmtoff = -stdoffset; - sp->ttis[i].tt_abbrind = 0; - sawstd = TRUE; + theirstdoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (!sp->ttis[j].tt_isdst) { + theirstdoffset = + -sp->ttis[j].tt_gmtoff; + break; + } + } + theirdstoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (sp->ttis[j].tt_isdst) { + theirdstoffset = + -sp->ttis[j].tt_gmtoff; + break; } } /* - ** Make sure we have both standard and summer time. + ** Initially we're assumed to be in standard time. */ - if (!sawdst || !sawstd) - return -1; + isdst = FALSE; + theiroffset = theirstdoffset; /* - ** Now correct the transition times by shifting - ** them by the difference between the real and - ** prototype offsets. Note that this difference - ** can be different in standard and summer time; - ** the prototype probably has a 1-hour difference - ** between standard and summer time, but a different - ** difference can be specified in TZ. + ** Now juggle transition times and types + ** tracking offsets as you do. */ - isdst = FALSE; /* we start in standard time */ for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * ttisp; - - /* - ** If summer time is in effect, and the - ** transition time was not specified as - ** standard time, add the summer time - ** offset to the transition time; - ** otherwise, add the standard time offset - ** to the transition time. - */ - ttisp = &sp->ttis[sp->types[i]]; - sp->ats[i] += - (isdst && !ttisp->tt_ttisstd) ? - dstfix : stdfix; - isdst = ttisp->tt_isdst; + j = sp->types[i]; + sp->types[i] = sp->ttis[j].tt_isdst; + if (sp->ttis[j].tt_ttisgmt) { + /* No adjustment to transition time */ + } else { + /* + ** If summer time is in effect, and the + ** transition time was not specified as + ** standard time, add the summer time + ** offset to the transition time; + ** otherwise, add the standard time + ** offset to the transition time. + */ + /* + ** Transitions from DST to DDST + ** will effectively disappear since + ** POSIX provides for only one DST + ** offset. + */ + if (isdst && !sp->ttis[j].tt_ttisstd) { + sp->ats[i] += dstoffset - + theirdstoffset; + } else { + sp->ats[i] += stdoffset - + theirstdoffset; + } + } + theiroffset = -sp->ttis[j].tt_gmtoff; + if (sp->ttis[j].tt_isdst) + theirdstoffset = theiroffset; + else theirstdoffset = theiroffset; } + /* + ** Finally, fill in ttis. + ** ttisstd and ttisgmt need not be handled. + */ + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = FALSE; + sp->ttis[0].tt_abbrind = 0; + sp->ttis[1].tt_gmtoff = -dstoffset; + sp->ttis[1].tt_isdst = TRUE; + sp->ttis[1].tt_abbrind = stdlen + 1; } } else { dstlen = 0; @@ -826,17 +901,24 @@ static void gmtload(sp) struct state * const sp; { - if (tzload(GMT, sp) != 0) - (void) tzparse(GMT, sp, TRUE); + if (tzload(gmt, sp) != 0) + (void) tzparse(gmt, sp, TRUE); } #ifndef STD_INSPIRED +/* +** A non-static declaration of tzsetwall in a system header file +** may cause a warning about this upcoming static declaration... +*/ static #endif /* !defined STD_INSPIRED */ void -tzsetwall() +tzsetwall P((void)) { - lcl_is_set = TRUE; + if (lcl_is_set < 0) + return; + lcl_is_set = -1; + #ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); @@ -852,7 +934,7 @@ tzsetwall() } void -tzset() +tzset P((void)) { register const char * name; @@ -861,7 +943,13 @@ tzset() tzsetwall(); return; } - lcl_is_set = TRUE; + + if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) + return; + lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); + if (lcl_is_set) + (void) strcpy(lcl_TZname, name); + #ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); @@ -879,7 +967,7 @@ tzset() lclptr->timecnt = 0; lclptr->ttis[0].tt_gmtoff = 0; lclptr->ttis[0].tt_abbrind = 0; - (void) strcpy(lclptr->chars, GMT); + (void) strcpy(lclptr->chars, gmt); } else if (tzload(name, lclptr) != 0) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) gmtload(lclptr); @@ -902,13 +990,11 @@ const time_t * const timep; const long offset; struct tm * const tmp; { - register const struct state * sp; + register struct state * sp; register const struct ttinfo * ttisp; register int i; const time_t t = *timep; - if (!lcl_is_set) - tzset(); sp = lclptr; #ifdef ALL_STATE if (sp == NULL) { @@ -938,7 +1024,7 @@ struct tm * const tmp; */ timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; - tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; + tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ @@ -948,8 +1034,7 @@ struct tm * localtime(timep) const time_t * const timep; { - static struct tm tm; - + tzset(); localsub(timep, 0L, &tm); return &tm; } @@ -980,11 +1065,11 @@ struct tm * const tmp; ** but this is no time for a treasure hunt. */ if (offset != 0) - tmp->TM_ZONE = WILDABBR; + tmp->TM_ZONE = wildabbr; else { #ifdef ALL_STATE if (gmtptr == NULL) - tmp->TM_ZONE = GMT; + tmp->TM_ZONE = gmt; else tmp->TM_ZONE = gmtptr->chars; #endif /* defined ALL_STATE */ #ifndef ALL_STATE @@ -998,8 +1083,6 @@ struct tm * gmtime(timep) const time_t * const timep; { - static struct tm tm; - gmtsub(timep, 0L, &tm); return &tm; } @@ -1011,8 +1094,6 @@ offtime(timep, offset) const time_t * const timep; const long offset; { - static struct tm tm; - gmtsub(timep, offset, &tm); return &tm; } @@ -1074,7 +1155,7 @@ register struct tm * const tmp; days = -24855; rem = -11648; } -#endif /* mc68k */ +#endif /* defined mc68k */ rem += (offset - corr); while (rem < 0) { rem += SECSPERDAY; @@ -1087,30 +1168,27 @@ register struct tm * const tmp; tmp->tm_hour = (int) (rem / SECSPERHOUR); rem = rem % SECSPERHOUR; tmp->tm_min = (int) (rem / SECSPERMIN); - tmp->tm_sec = (int) (rem % SECSPERMIN); - if (hit) - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec += hit; + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60" et seq. + */ + tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; - if (days >= 0) - for ( ; ; ) { - yleap = isleap(y); - if (days < (long) year_lengths[yleap]) - break; - ++y; - days = days - (long) year_lengths[yleap]; - } - else do { - --y; - yleap = isleap(y); - days = days + (long) year_lengths[yleap]; - } while (days < 0); +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { + register int newy; + + newy = y + days / DAYSPERNYEAR; + if (days < 0) + --newy; + days -= (newy - y) * DAYSPERNYEAR + + LEAPS_THRU_END_OF(newy - 1) - + LEAPS_THRU_END_OF(y - 1); + y = newy; + } tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; @@ -1127,13 +1205,20 @@ char * ctime(timep) const time_t * const timep; { +/* +** Section 4.12.3.2 of X3.159-1989 requires that +** The ctime funciton converts the calendar time pointed to by timer +** to local time in the form of a string. It is equivalent to +** asctime(localtime(timer)) +*/ return asctime(localtime(timep)); } /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +** Kridle's (so its said...) from a long time ago. +** [kridle@xinet.com as of 1996-01-16.] ** It does a binary search of the time_t space. Since time_t's are ** just 32 bits, its a max of 32 iterations (even at 64 bits it ** would still be very reasonable). @@ -1152,8 +1237,8 @@ increment_overflow(number, delta) int * number; int delta; { - int number0; - + int number0; + number0 = *number; *number += delta; return (*number < number0) != (delta < 0); @@ -1193,7 +1278,7 @@ register const struct tm * const btmp; static time_t time2(tmp, funcp, offset, okayp) struct tm * const tmp; -void (* const funcp)(); +void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; { @@ -1223,10 +1308,12 @@ int * const okayp; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) return WRONG; - yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)]; + i = yourtm.tm_year + (1 < yourtm.tm_mon); + yourtm.tm_mday += year_lengths[isleap(i)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { - yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)]; + i = yourtm.tm_year + (1 < yourtm.tm_mon); + yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } @@ -1261,17 +1348,16 @@ int * const okayp; yourtm.tm_sec = 0; } /* - ** Calculate the number of magnitude bits in a time_t - ** (this works regardless of whether time_t is - ** signed or unsigned, though lint complains if unsigned). + ** Divide the search space in half + ** (this works whether time_t is signed or unsigned). */ - for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) - continue; + bits = TYPE_BIT(time_t) - 1; /* - ** If time_t is signed, then 0 is the median value, - ** if time_t is unsigned, then 1 << bits is median. + ** If time_t is signed, then 0 is just above the median, + ** assuming two's complement arithmetic. + ** If time_t is unsigned, then (1 << bits) is just above the median. */ - t = (t < 0) ? 0 : ((time_t) 1 << bits); + t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); for ( ; ; ) { (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); @@ -1279,10 +1365,10 @@ int * const okayp; if (bits-- < 0) return WRONG; if (bits < 0) - --t; + --t; /* may be needed if new t is minimal */ else if (dir > 0) - t -= (time_t) 1 << bits; - else t += (time_t) 1 << bits; + t -= ((time_t) 1) << bits; + else t += ((time_t) 1) << bits; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) @@ -1303,10 +1389,10 @@ int * const okayp; if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { + for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; - for (j = 0; j < sp->typecnt; ++j) { + for (j = sp->typecnt - 1; j >= 0; --j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - @@ -1338,7 +1424,7 @@ label: static time_t time1(tmp, funcp, offset) struct tm * const tmp; -void (* const funcp)(); +void (* const funcp) P((const time_t *, long, struct tm *)); const long offset; { register time_t t; @@ -1377,10 +1463,10 @@ const long offset; if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ - for (samei = 0; samei < sp->typecnt; ++samei) { + for (samei = sp->typecnt - 1; samei >= 0; --samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; - for (otheri = 0; otheri < sp->typecnt; ++otheri) { + for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - @@ -1401,6 +1487,7 @@ time_t mktime(tmp) struct tm * const tmp; { + tzset(); return time1(tmp, localsub, 0L); } @@ -1475,8 +1562,6 @@ time_t * timep; register struct lsinfo * lp; register int i; - if (!lcl_is_set) - (void) tzset(); sp = lclptr; i = sp->leapcnt; while (--i >= 0) { @@ -1491,6 +1576,7 @@ time_t time2posix(t) time_t t; { + tzset(); return t - leapcorr(&t); } @@ -1501,6 +1587,7 @@ time_t t; time_t x; time_t y; + tzset(); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second diff --git a/lib/libc/stdtime/private.h b/lib/libc/stdtime/private.h index 5af259c..f81bf48 100644 --- a/lib/libc/stdtime/private.h +++ b/lib/libc/stdtime/private.h @@ -3,6 +3,11 @@ #define PRIVATE_H /* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + +/* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. @@ -16,36 +21,91 @@ #ifndef lint #ifndef NOID -static char privatehid[] = "@(#)private.h 7.5"; +static char privatehid[] = "@(#)private.h 7.43"; #endif /* !defined NOID */ #endif /* !defined lint */ /* -** const +** Defaults for preprocessor symbols. +** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. */ -#ifndef const -#ifndef __STDC__ -#define const -#endif /* !defined __STDC__ */ -#endif /* !defined const */ +#ifndef HAVE_ADJTIME +#define HAVE_ADJTIME 1 +#endif /* !defined HAVE_ADJTIME */ + +#ifndef HAVE_GETTEXT +#define HAVE_GETTEXT 0 +#endif /* !defined HAVE_GETTEXT */ + +#ifndef HAVE_SETTIMEOFDAY +#define HAVE_SETTIMEOFDAY 3 +#endif /* !defined HAVE_SETTIMEOFDAY */ + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR 0 +#endif /* !defined HAVE_STRERROR */ + +#ifndef HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 +#endif /* !defined HAVE_UNISTD_H */ + +#ifndef HAVE_UTMPX_H +#define HAVE_UTMPX_H 0 +#endif /* !defined HAVE_UTMPX_H */ + +#ifndef LOCALE_HOME +#define LOCALE_HOME "/usr/lib/locale" +#endif /* !defined LOCALE_HOME */ + +/* +** Nested includes +*/ + +#include "sys/types.h" /* for time_t */ +#include "stdio.h" +#include "errno.h" +#include "string.h" +#include "limits.h" /* for CHAR_BIT */ +#include "time.h" +#include "stdlib.h" + +#if HAVE_GETTEXT - 0 +#include "libintl.h" +#endif /* HAVE_GETTEXT - 0 */ + +#if HAVE_UNISTD_H - 0 +#include "unistd.h" /* for F_OK and R_OK */ +#endif /* HAVE_UNISTD_H - 0 */ + +#if !(HAVE_UNISTD_H - 0) +#ifndef F_OK +#define F_OK 0 +#endif /* !defined F_OK */ +#ifndef R_OK +#define R_OK 4 +#endif /* !defined R_OK */ +#endif /* !(HAVE_UNISTD_H - 0) */ + +/* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ +#define is_digit(c) ((unsigned)(c) - '0' <= 9) /* -** void +** Workarounds for compilers/systems. */ -#ifndef void +/* +** SunOS 4.1.1 cc lacks const. +*/ + +#ifndef const #ifndef __STDC__ -#ifndef vax -#ifndef sun -#define void char -#endif /* !defined sun */ -#endif /* !defined vax */ +#define const #endif /* !defined __STDC__ */ -#endif /* !defined void */ +#endif /* !defined const */ /* -** P((args)) +** SunOS 4.1.1 cc lacks prototypes. */ #ifndef P @@ -53,36 +113,29 @@ static char privatehid[] = "@(#)private.h 7.5"; #define P(x) x #endif /* defined __STDC__ */ #ifndef __STDC__ -#define ASTERISK * -#define P(x) ( /ASTERISK x ASTERISK/ ) +#define P(x) () #endif /* !defined __STDC__ */ #endif /* !defined P */ /* -** genericptr_t +** SunOS 4.1.1 headers lack EXIT_SUCCESS. */ -#ifdef __STDC__ -typedef void * genericptr_t; -#endif /* defined __STDC__ */ -#ifndef __STDC__ -typedef char * genericptr_t; -#endif /* !defined __STDC__ */ +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif /* !defined EXIT_SUCCESS */ -#include "sys/types.h" /* for time_t */ -#include "stdio.h" -#include "ctype.h" -#include "errno.h" -#include "string.h" -#include "limits.h" /* for CHAR_BIT */ -#ifndef _TIME_ -#include "time.h" -#endif /* !defined _TIME_ */ +/* +** SunOS 4.1.1 headers lack EXIT_FAILURE. +*/ -#ifndef remove -extern int unlink P((const char * filename)); -#define remove unlink -#endif /* !defined remove */ +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif /* !defined EXIT_FAILURE */ + +/* +** SunOS 4.1.1 headers lack FILENAME_MAX. +*/ #ifndef FILENAME_MAX @@ -101,62 +154,27 @@ extern int unlink P((const char * filename)); #endif /* !defined FILENAME_MAX */ -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif /* !defined EXIT_SUCCESS */ - -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif /* !defined EXIT_FAILURE */ - -#ifdef __STDC__ - -#define alloc_size_t size_t -#define qsort_size_t size_t -#define fwrite_size_t size_t - -#endif /* defined __STDC__ */ -#ifndef __STDC__ - -#ifndef alloc_size_t -#define alloc_size_t unsigned -#endif /* !defined alloc_size_t */ - -#ifndef qsort_size_t -#ifdef USG -#define qsort_size_t unsigned -#endif /* defined USG */ -#ifndef USG -#define qsort_size_t int -#endif /* !defined USG */ -#endif /* !defined qsort_size_t */ - -#ifndef fwrite_size_t -#define fwrite_size_t int -#endif /* !defined fwrite_size_t */ - -#ifndef USG -extern char * sprintf P((char * buf, const char * format, ...)); -#endif /* !defined USG */ +/* +** SunOS 4.1.1 libraries lack remove. +*/ -#endif /* !defined __STDC__ */ +#ifndef remove +extern int unlink P((const char * filename)); +#define remove unlink +#endif /* !defined remove */ /* -** Ensure that these are declared--redundantly declaring them shouldn't hurt. +** Some ancient errno.h implementations don't declare errno. +** But some newer errno.h implementations define it as a macro. +** Fix the former without affecting the latter. */ +#ifndef errno +extern int errno; +#endif /* !defined errno */ -extern char * getenv P((const char * name)); -extern genericptr_t malloc P((alloc_size_t size)); -extern genericptr_t calloc P((alloc_size_t nelem, alloc_size_t elsize)); -extern genericptr_t realloc P((genericptr_t oldptr, alloc_size_t newsize)); - -#ifdef USG -extern void exit P((int s)); -extern void qsort P((genericptr_t base, qsort_size_t nelem, - qsort_size_t elsize, int (*comp)())); -extern void perror P((const char * string)); -extern void free P((char * buf)); -#endif /* defined USG */ +/* +** Finally, some convenience items. +*/ #ifndef TRUE #define TRUE 1 @@ -166,20 +184,69 @@ extern void free P((char * buf)); #define FALSE 0 #endif /* !defined FALSE */ +#ifndef TYPE_BIT +#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) +#endif /* !defined TYPE_BIT */ + +#ifndef TYPE_SIGNED +#define TYPE_SIGNED(type) (((type) -1) < 0) +#endif /* !defined TYPE_SIGNED */ + #ifndef INT_STRLEN_MAXIMUM /* ** 302 / 1000 is log10(2.0) rounded up. -** Subtract one for the sign bit; +** Subtract one for the sign bit if the type is signed; ** add one for integer division truncation; -** add one more for a minus sign. +** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ - ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2) + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 100 + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ /* -** UNIX is a registered trademark of AT&T. -** VAX is a trademark of Digital Equipment Corporation. +** INITIALIZE(x) +*/ + +#ifndef GNUC_or_lint +#ifdef lint +#define GNUC_or_lint +#endif /* defined lint */ +#ifndef lint +#ifdef __GNUC__ +#define GNUC_or_lint +#endif /* defined __GNUC__ */ +#endif /* !defined lint */ +#endif /* !defined GNUC_or_lint */ + +#ifndef INITIALIZE +#ifdef GNUC_or_lint +#define INITIALIZE(x) ((x) = 0) +#endif /* defined GNUC_or_lint */ +#ifndef GNUC_or_lint +#define INITIALIZE(x) +#endif /* !defined GNUC_or_lint */ +#endif /* !defined INITIALIZE */ + +/* +** For the benefit of GNU folk... +** `_(MSGID)' uses the current locale's message library string for MSGID. +** The default is to use gettext if available, and use MSGID otherwise. +*/ + +#ifndef _ +#if HAVE_GETTEXT - 0 +#define _(msgid) gettext(msgid) +#else /* !(HAVE_GETTEXT - 0) */ +#define _(msgid) msgid +#endif /* !(HAVE_GETTEXT - 0) */ +#endif /* !defined _ */ + +#ifndef TZ_DOMAIN +#define TZ_DOMAIN "tz" +#endif /* !defined TZ_DOMAIN */ + +/* +** UNIX was a registered trademark of UNIX System Laboratories in 1993. */ #endif /* !defined PRIVATE_H */ diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c index 821bc79..a5ba85c 100644 --- a/lib/libc/stdtime/strftime.c +++ b/lib/libc/stdtime/strftime.c @@ -1,10 +1,9 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)strftime.c 7.19"; +static char elsieid[] = "@(#)strftime.c 7.47"; /* ** Based on the UCB version with the ID appearing below. -** This is ANSIish only when time is treated identically in all locales and -** when "multibyte character == plain character". +** This is ANSIish only when "multibyte character == plain character". */ #endif /* !defined NOID */ #endif /* !defined lint */ @@ -12,64 +11,122 @@ static char elsieid[] = "@(#)strftime.c 7.19"; #include "private.h" /* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ +** Copyright (c) 1989 The Regents of the University of California. +** All rights reserved. +** +** Redistribution and use in source and binary forms are permitted +** provided that the above copyright notice and this paragraph are +** duplicated in all such forms and that any documentation, +** advertising materials, and other materials related to such +** distribution and use acknowledge that the software was developed +** by the University of California, Berkeley. The name of the +** University may not be used to endorse or promote products derived +** from this software without specific prior written permission. +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +*/ #ifndef LIBC_SCCS #ifndef lint -static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; +static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #endif /* !defined lint */ #endif /* !defined LIBC_SCCS */ #include "tzfile.h" +#include "fcntl.h" +#include "locale.h" -static const char afmt[][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; -static const char Afmt[][10] = { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", - "Saturday" +struct lc_time_T { + const char * mon[12]; + const char * month[12]; + const char * wday[7]; + const char * weekday[7]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; }; -static const char bfmt[][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec" -}; -static const char Bfmt[][10] = { - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" + +#ifdef LOCALE_HOME +#include "sys/stat.h" +static struct lc_time_T localebuf; +static struct lc_time_T * _loc P((void)); +#define Locale _loc() +#endif /* defined LOCALE_HOME */ +#ifndef LOCALE_HOME +#define Locale (&C_time_locale) +#endif /* !defined LOCALE_HOME */ + +static const struct lc_time_T C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** Since the C language standard calls for + ** "date, using locale's date format," anything goes. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%D %X", /* %m/%d/%y %H:%M:%S */ + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %H:%M:%S %Z %Y" }; -static char *_add P((const char *, char *, const char *)); -static char *_conv P((int, const char *, char *, const char *)); -static char *_fmt P((const char *, const struct tm *, char *, const char *)); +static char * _add P((const char *, char *, const char *)); +static char * _conv P((int, const char *, char *, const char *)); +static char * _fmt P((const char *, const struct tm *, char *, const char *)); size_t strftime P((char *, size_t, const char *, const struct tm *)); -extern char *tzname[]; +extern char * tzname[]; size_t strftime(s, maxsize, format, t) - char *s; - size_t maxsize; - const char *format; - const struct tm *t; +char * const s; +const size_t maxsize; +const char * const format; +const struct tm * const t; { - char *p; + char * p; - p = _fmt(format, t, s, s + maxsize); + tzset(); +#ifdef LOCALE_HOME + localebuf.mon[0] = 0; +#endif /* defined LOCALE_HOME */ + p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize); if (p == s + maxsize) return 0; *p = '\0'; @@ -78,37 +135,38 @@ strftime(s, maxsize, format, t) static char * _fmt(format, t, pt, ptlim) - const char *format; - const struct tm *t; - char *pt; - const char *ptlim; +const char * format; +const struct tm * const t; +char * pt; +const char * const ptlim; { - for (; *format; ++format) { + for ( ; *format; ++format) { if (*format == '%') { label: - switch(*++format) { + switch (*++format) { case '\0': --format; break; case 'A': pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? - "?" : Afmt[t->tm_wday], pt, ptlim); + "?" : Locale->weekday[t->tm_wday], + pt, ptlim); continue; case 'a': pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? - "?" : afmt[t->tm_wday], pt, ptlim); + "?" : Locale->wday[t->tm_wday], + pt, ptlim); continue; case 'B': pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? - "?" : Bfmt[t->tm_mon], pt, ptlim); + "?" : Locale->month[t->tm_mon], + pt, ptlim); continue; case 'b': case 'h': pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? - "?" : bfmt[t->tm_mon], pt, ptlim); - continue; - case 'c': - pt = _fmt("%D %X", t, pt, ptlim); + "?" : Locale->mon[t->tm_mon], + pt, ptlim); continue; case 'C': /* @@ -121,27 +179,10 @@ label: pt = _conv((t->tm_year + TM_YEAR_BASE) / 100, "%02d", pt, ptlim); continue; - case 'D': - pt = _fmt("%m/%d/%y", t, pt, ptlim); + case 'c': + pt = _fmt(Locale->c_fmt, t, pt, ptlim); continue; - case 'x': - /* - ** Version 3.0 of strftime from Arnold Robbins - ** (arnold@skeeve.atl.ga.us) does the - ** equivalent of... - ** _fmt("%a %b %e %Y"); - ** ...for %x; since the X3J11 C language - ** standard calls for "date, using locale's - ** date format," anything goes. Using just - ** numbers (as here) makes Quakers happier. - ** Word from Paul Eggert (eggert@twinsun.com) - ** is that %Y-%m-%d is the ISO standard date - ** format, specified in ISO 2014 and later - ** ISO 8601:1988, with a summary available in - ** pub/doc/ISO/english/ISO8601.ps.Z on - ** ftp.uni-erlangen.de. - ** (ado, 5/30/93) - */ + case 'D': pt = _fmt("%m/%d/%y", t, pt, ptlim); continue; case 'd': @@ -220,7 +261,9 @@ label: pt = _add("\n", pt, ptlim); continue; case 'p': - pt = _add(t->tm_hour >= 12 ? "PM" : "AM", + pt = _add((t->tm_hour >= 12) ? + Locale->pm : + Locale->am, pt, ptlim); continue; case 'R': @@ -232,8 +275,24 @@ label: case 'S': pt = _conv(t->tm_sec, "%02d", pt, ptlim); continue; + case 's': + { + struct tm tm; + char buf[INT_STRLEN_MAXIMUM( + time_t) + 1]; + time_t mkt; + + tm = *t; + mkt = mktime(&tm); + if (TYPE_SIGNED(time_t)) + (void) sprintf(buf, "%ld", + (long) mkt); + else (void) sprintf(buf, "%lu", + (unsigned long) mkt); + pt = _add(buf, pt, ptlim); + } + continue; case 'T': - case 'X': pt = _fmt("%H:%M:%S", t, pt, ptlim); continue; case 't': @@ -253,66 +312,86 @@ label: pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday, "%d", pt, ptlim); continue; - case 'V': - /* - ** From Arnold Robbins' strftime version 3.0: - ** "the week number of the year (the first - ** Monday as the first day of week 1) as a - ** decimal number (01-53). The method for - ** determining the week number is as specified - ** by ISO 8601 (to wit: if the week containing - ** January 1 has four or more days in the new - ** year, then it is week 1, otherwise it is - ** week 53 of the previous year and the next - ** week is week 1)." - ** (ado, 5/24/93) - */ - /* - ** XXX--If January 1 falls on a Friday, - ** January 1-3 are part of week 53 of the - ** previous year. By analogy, if January - ** 1 falls on a Thursday, are December 29-31 - ** of the PREVIOUS year part of week 1??? - ** (ado 5/24/93) - ** - ** You are understood not to expect this. - */ + case 'V': /* ISO 8601 week number */ + case 'G': /* ISO 8601 year (four digits) */ + case 'g': /* ISO 8601 year (two digits) */ +/* +** From Arnold Robbins' strftime version 3.0: "the week number of the +** year (the first Monday as the first day of week 1) as a decimal number +** (01-53)." +** (ado, 1993-05-24) +** +** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn: +** "Week 01 of a year is per definition the first week which has the +** Thursday in this year, which is equivalent to the week which contains +** the fourth day of January. In other words, the first week of a new year +** is the week which has the majority of its days in the new year. Week 01 +** might also contain days from the previous year and the week before week +** 01 of a year is the last week (52 or 53) of the previous year even if +** it contains days from the new year. A week starts with Monday (day 1) +** and ends with Sunday (day 7). For example, the first week of the year +** 1997 lasts from 1996-12-30 to 1997-01-05..." +** (ado, 1996-01-02) +*/ { - int i; + int year; + int yday; + int wday; + int w; - i = (t->tm_yday + 10 - (t->tm_wday ? - (t->tm_wday - 1) : 6)) / 7; - if (i == 0) { + year = t->tm_year + TM_YEAR_BASE; + yday = t->tm_yday; + wday = t->tm_wday; + for ( ; ; ) { + int len; + int bot; + int top; + + len = isleap(year) ? + DAYSPERLYEAR : + DAYSPERNYEAR; /* - ** What day of the week does - ** January 1 fall on? + ** What yday (-3 ... 3) does + ** the ISO year begin on? */ - i = t->tm_wday - - (t->tm_yday - 1); + bot = ((yday + 11 - wday) % + DAYSPERWEEK) - 3; /* - ** Fri Jan 1: 53 - ** Sun Jan 1: 52 - ** Sat Jan 1: 53 if previous - ** year a leap - ** year, else 52 + ** What yday does the NEXT + ** ISO year begin on? */ - if (i == TM_FRIDAY) - i = 53; - else if (i == TM_SUNDAY) - i = 52; - else i = isleap(t->tm_year + - TM_YEAR_BASE) ? - 53 : 52; + top = bot - + (len % DAYSPERWEEK); + if (top < -3) + top += DAYSPERWEEK; + top += len; + if (yday >= top) { + ++year; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / + DAYSPERWEEK); + break; + } + --year; + yday += isleap(year) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + } #ifdef XPG4_1994_04_09 - /* - ** As of 4/9/94, though, - ** XPG4 calls for 53 - ** unconditionally. - */ - i = 53; + if (w == 52 && t->tm_mon == TM_JANUARY) + w = 53; #endif /* defined XPG4_1994_04_09 */ - } - pt = _conv(i, "%02d", pt, ptlim); + if (*format == 'V') + pt = _conv(w, "%02d", + pt, ptlim); + else if (*format == 'G') + pt = _conv(year, "%02d", + pt, ptlim); + else pt = _conv(year, "%04d", + pt, ptlim); } continue; case 'v': @@ -332,6 +411,12 @@ label: case 'w': pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; + case 'X': + pt = _fmt(Locale->X_fmt, t, pt, ptlim); + continue; + case 'x': + pt = _fmt(Locale->x_fmt, t, pt, ptlim); + continue; case 'y': pt = _conv((t->tm_year + TM_YEAR_BASE) % 100, "%02d", pt, ptlim); @@ -342,7 +427,7 @@ label: continue; case 'Z': #ifdef TM_ZONE - if (t->TM_ZONE) + if (t->TM_ZONE != NULL) pt = _add(t->TM_ZONE, pt, ptlim); else #endif /* defined TM_ZONE */ @@ -351,6 +436,9 @@ label: pt, ptlim); } else pt = _add("?", pt, ptlim); continue; + case '+': + pt = _fmt(Locale->date_fmt, t, pt, ptlim); + continue; case '%': /* * X311J/88-090 (4.12.3.5): if conversion char is @@ -370,12 +458,12 @@ label: static char * _conv(n, format, pt, ptlim) - int n; - const char *format; - char *pt; - const char *ptlim; +const int n; +const char * const format; +char * const pt; +const char * const ptlim; { - char buf[INT_STRLEN_MAXIMUM(int) + 1]; + char buf[INT_STRLEN_MAXIMUM(int) + 1]; (void) sprintf(buf, format, n); return _add(buf, pt, ptlim); @@ -383,11 +471,134 @@ _conv(n, format, pt, ptlim) static char * _add(str, pt, ptlim) - const char *str; - char *pt; - const char *ptlim; +const char * str; +char * pt; +const char * const ptlim; { while (pt < ptlim && (*pt = *str++) != '\0') ++pt; return pt; } + +#ifdef LOCALE_HOME +static struct lc_time_T * +_loc P((void)) +{ + static const char locale_home[] = LOCALE_HOME; + static const char lc_time[] = "LC_TIME"; + static char * locale_buf; + static char locale_buf_C[] = "C"; + + int fd; + int oldsun; /* "...ain't got nothin' to do..." */ + char * lbuf; + char * name; + char * p; + const char ** ap; + const char * plim; + char filename[FILENAME_MAX]; + struct stat st; + size_t namesize; + size_t bufsize; + + /* + ** Use localebuf.mon[0] to signal whether locale is already set up. + */ + if (localebuf.mon[0]) + return &localebuf; + name = setlocale(LC_TIME, (char *) NULL); + if (name == NULL || *name == '\0') + goto no_locale; + /* + ** If the locale name is the same as our cache, use the cache. + */ + lbuf = locale_buf; + if (lbuf != NULL && strcmp(name, lbuf) == 0) { + p = lbuf; + for (ap = (const char **) &localebuf; + ap < (const char **) (&localebuf + 1); + ++ap) + *ap = p += strlen(p) + 1; + return &localebuf; + } + /* + ** Slurp the locale file into the cache. + */ + namesize = strlen(name) + 1; + if (sizeof(filename) < + sizeof(locale_home) + namesize + sizeof(lc_time)) + goto no_locale; + oldsun = 0; + (void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time); + fd = open(filename, O_RDONLY); + if (fd < 0) { + /* + ** Old Sun systems have a different naming and data convention. + */ + oldsun = 1; + (void) sprintf(filename, "%s/%s/%s", locale_home, + lc_time, name); + fd = open(filename, O_RDONLY); + if (fd < 0) + goto no_locale; + } + if (fstat(fd, &st) != 0) + goto bad_locale; + if (st.st_size <= 0) + goto bad_locale; + bufsize = namesize + st.st_size; + locale_buf = NULL; + lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? + malloc(bufsize) : realloc(lbuf, bufsize); + if (lbuf == NULL) + goto bad_locale; + (void) strcpy(lbuf, name); + p = lbuf + namesize; + plim = p + st.st_size; + if (read(fd, p, (size_t) st.st_size) != st.st_size) + goto bad_lbuf; + if (close(fd) != 0) + goto bad_lbuf; + /* + ** Parse the locale file into localebuf. + */ + if (plim[-1] != '\n') + goto bad_lbuf; + for (ap = (const char **) &localebuf; + ap < (const char **) (&localebuf + 1); + ++ap) { + if (p == plim) + goto bad_lbuf; + *ap = p; + while (*p != '\n') + ++p; + *p++ = '\0'; + } + if (oldsun) { + /* + ** SunOS 4 used an obsolescent format; see localdtconv(3). + ** c_fmt had the ``short format for dates and times together'' + ** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale); + ** date_fmt had the ``long format for dates'' + ** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale). + ** Discard the latter in favor of the former. + */ + localebuf.date_fmt = localebuf.c_fmt; + } + /* + ** Record the successful parse in the cache. + */ + locale_buf = lbuf; + + return &localebuf; + +bad_lbuf: + free(lbuf); +bad_locale: + (void) close(fd); +no_locale: + localebuf = C_time_locale; + locale_buf = locale_buf_C; + return &localebuf; +} +#endif /* defined LOCALE_HOME */ diff --git a/lib/libc/stdtime/tzfile.h b/lib/libc/stdtime/tzfile.h index 45b4d7d..cb9b6a1 100644 --- a/lib/libc/stdtime/tzfile.h +++ b/lib/libc/stdtime/tzfile.h @@ -3,6 +3,11 @@ #define TZFILE_H /* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + +/* ** This header is for use ONLY with the time conversion code. ** There is no guarantee that it will remain unchanged, ** or that it will remain at all. @@ -16,7 +21,7 @@ #ifndef lint #ifndef NOID -static char tzfilehid[] = "@(#)tzfile.h 7.4"; +static char tzfilehid[] = "@(#)tzfile.h 7.8"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -41,7 +46,8 @@ static char tzfilehid[] = "@(#)tzfile.h 7.4"; */ struct tzhead { - char tzh_reserved[24]; /* reserved for future use */ + char tzh_reserved[20]; /* reserved for future use */ + char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ char tzh_leapcnt[4]; /* coded number of leap seconds */ char tzh_timecnt[4]; /* coded number of transition times */ @@ -67,6 +73,11 @@ struct tzhead { ** transition time is wall clock time ** if absent, transition times are ** assumed to be wall clock time +** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition +** time is GMT, if FALSE, +** transition time is local time +** if absent, transition times are +** assumed to be local time */ /* @@ -89,7 +100,11 @@ struct tzhead { #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined NOSOLAR */ #ifdef NOSOLAR -#define TZ_MAX_TYPES 10 /* Maximum number of local time types */ +/* +** Must be at least 14 for Europe/Riga as of Jan 12 1995, +** as noted by Earl Chew . +*/ +#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* !defined NOSOLAR */ #endif /* !defined TZ_MAX_TYPES */ @@ -143,7 +158,7 @@ struct tzhead { ** that will probably do. */ -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #ifndef USG -- cgit v1.1 From aff84ecc8f819a5f1134a83c067f8d7abf813138 Mon Sep 17 00:00:00 2001 From: wollman Date: Thu, 18 Jul 1996 19:40:52 +0000 Subject: Second part of the timezone code import for version 96h. This includes a number of bug fixes to the compiler (which bugs would previously have caused undesirable behavior during transition times). --- usr.sbin/zic/Music | 81 ++++++ usr.sbin/zic/README | 16 +- usr.sbin/zic/Theory | 20 +- usr.sbin/zic/WWW | 71 +++++ usr.sbin/zic/ialloc.c | 41 +-- usr.sbin/zic/scheck.c | 12 +- usr.sbin/zic/zdump.8 | 5 +- usr.sbin/zic/zdump.c | 149 +++++++--- usr.sbin/zic/zic.8 | 34 +-- usr.sbin/zic/zic.c | 758 ++++++++++++++++++++++++++++++++------------------ 10 files changed, 791 insertions(+), 396 deletions(-) create mode 100644 usr.sbin/zic/Music create mode 100644 usr.sbin/zic/WWW diff --git a/usr.sbin/zic/Music b/usr.sbin/zic/Music new file mode 100644 index 0000000..9fb0cec --- /dev/null +++ b/usr.sbin/zic/Music @@ -0,0 +1,81 @@ +@(#)Music 7.4 + +Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI: +-------------------------------------------------------------------------- +Artist: Karrin Allyson +CD: I Didn't Know About You +Copyright Date: 1993 +Label: Concord Jazz, Inc. +ID: CCD-4543 +Track Time: 3:44 +Personnel: Karrin Allyson, vocal + Russ Long, piano + Gerald Spaits, bass + Todd Strait, drums +Notes: CD notes "additional lyric by Karrin Allyson; + arranged by Russ Long and Karrin Allyson" +Rating: 1 star +-------------------------------------------------------------------------- +Artist: Kevin Mahogany +CD: Double Rainbow +Copyright Date: 1993 +Label: Enja Records +ID: ENJ-7097 2 +Track Time: 6:27 +Personnel: Kevin Mahogany, vocal + Kenny Barron, piano + Ray Drummond, bss + Ralph Moore, tenor saxophone + Lewis Nash, drums +Rating: 1.5 stars +-------------------------------------------------------------------------- +Artist: Joe Williams +CD: Here's to Life +Copyright Date: 1994 +Label: Telarc International Corporation +ID: CD-83357 +Track Time: 3:58 +Personnel: Joe Williams, vocal + The Robert Farnon [39 piece] Orchestra +Rating: black dot +-------------------------------------------------------------------------- +Artist: Charles Fambrough +CD: Keeper of the Spirit +Copyright Date: 1995 +Label: AudioQuest Music +ID: AQ-CD1033 +Track Time: 7:07 +Personnel: Charles Fambrough, bass + Joel Levine, tenor recorder + Edward Simon, piano + Lenny White, drums + Marion Simon, percussion +Rating: 2 stars +========================================================================== +Also of note: +Artist: Milt Hinton +CD: Old Man Time +Date: 1993 +Label: Chiaroscuro +ID: CR(D) 310 +Total Time: 149:38 (two CDs) +Personnel: Milt Hinton, bass + Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet + Al Grey, trombone + Eddier Barefield, Joe Camel (Flip Phillips), Buddy Tate, + clarinet and saxophone + John Bunch, Red Richards, Norman Simmons, Derek Smith, + Ralph Sutton, piano + Danny Barker, Al Casey, guitar + Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams, + drums + Lionel Hampton, vibraphone + Cab Calloway, Joe Williams, vocal + Buck Clayton, arrangements +Notes: tunes include Old Man Time, Time After Time, + Sometimes I'm Happy, + A Hot Time in the Old Town Tonight, + Four or Five Times, Now's the Time, + Time on My Hands, This Time It's Us, + and Good Time Charlie +Rating: 3 stars diff --git a/usr.sbin/zic/README b/usr.sbin/zic/README index 5eea1a2..3ca53ca 100644 --- a/usr.sbin/zic/README +++ b/usr.sbin/zic/README @@ -1,4 +1,4 @@ -@(#)README 7.5 +@(#)README 7.8 "What time is it?" -- Richard Deacon as The King "Any time you want it to be." -- Frank Baxter as The Scientist @@ -22,13 +22,6 @@ and as "part of the application" in others, there's no good way to name functions, such as timegm, that are not part of the proposed ANSI C standard; such functions have kept their old, underscore-free names in this update.) -Support for the tz_abbr variable has been eliminated from this version -(to forestall "kitchen sink" complaints from certain quarters :-). - -Support for Turbo C compilation has also been eliminated; it was present to -allow checking in an ANSI-style environment, and such checking is now done with -gcc. - And the "dysize" function has disappeared; it was present to allow compilation of the "date" command on old BSD systems, and a version of "date" is now provided in the package. The "date" command is not created when you "make all" @@ -64,9 +57,10 @@ Thanks to these Timezone Caballeros who've made major contributions to the time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz; Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales -for testing work. None of them are responsible for remaining errors. +for testing work, and to Gwillim Law for checking local mean time data. +None of them are responsible for remaining errors. -Look in the ~ftp/pub directory of elsie.nci.nih.gov (128.231.16.1) +Look in the ~ftp/pub directory of elsie.nci.nih.gov for updated versions of these files. -Please send comments or information to ado@elsie.nci.nih.gov. +Please send comments or information to tz@elsie.nci.nih.gov. diff --git a/usr.sbin/zic/Theory b/usr.sbin/zic/Theory index 93a07c0..2e34663 100644 --- a/usr.sbin/zic/Theory +++ b/usr.sbin/zic/Theory @@ -1,4 +1,4 @@ -@(#)Theory 7.2 +@(#)Theory 7.4 These time and date functions are much like the System V Release 2.0 (SVR2) time and date functions; there are a few additions and changes to extend @@ -47,7 +47,7 @@ These are the changes that have been made to the SVR2 functions: abbreviations are used. It was recognized that allowing the "TZ" environment variable to - take on values such as "US/Eastern" might cause "old" programs + take on values such as "America/New_York" might cause "old" programs (that expect "TZ" to have a certain form) to operate incorrectly; consideration was given to using some other environment variable (for example, "TIMEZONE") to hold the string used to generate the @@ -79,8 +79,8 @@ These are the changes that have been made to the SVR2 functions: best approximation to local wall clock time to be delivered by subsequent calls to "localtime." Source code for portable applications that "must" run on local wall clock time should call - "tzsetwall();" if such code is moved to "old" systems that don't provide - tzsetwall, you won't be able to generate an executable program. + "tzsetwall();" if such code is moved to "old" systems that don't + provide tzsetwall, you won't be able to generate an executable program. (These time zone functions also arrange for local wall clock time to be used if tzset is called--directly or indirectly--and there's no "TZ" environment variable; portable applications should not, however, rely @@ -94,8 +94,8 @@ Points of interest to folks with Version 7 or BSD systems: time zone abbreviation, and we refuse to guess. Programs that in the past used the timezone function may now examine tzname[localtime(&clock)->tm_isdst] to learn the correct time - zone abbreviation to use. Alternatively, use localtime(&clock)->tm_zone - if this has been enabled. + zone abbreviation to use. Alternatively, use + localtime(&clock)->tm_zone if this has been enabled. * The BSD gettimeofday function is not used in this package; this lets users control the time zone used in doing time conversions. @@ -104,10 +104,10 @@ Points of interest to folks with Version 7 or BSD systems: file "/etc/zoneinfo/localtime"; see the time zone compiler writeup for information on how to initialize this file. -The functions that are conditionally compiled if STD_INSPIRED is defined should, -at this point, be looked on primarily as food for thought. They are not in -any sense "standard compatible"--some are not, in fact, specified in *any* -standard. They do, however, represent responses of various authors to +The functions that are conditionally compiled if STD_INSPIRED is defined +should, at this point, be looked on primarily as food for thought. They are +not in any sense "standard compatible"--some are not, in fact, specified in +*any* standard. They do, however, represent responses of various authors to standardization proposals. Other time conversion proposals, in particular the one developed by folks at diff --git a/usr.sbin/zic/WWW b/usr.sbin/zic/WWW new file mode 100644 index 0000000..d2fd684 --- /dev/null +++ b/usr.sbin/zic/WWW @@ -0,0 +1,71 @@ +# '@(#)WWW 7.3' + +# From Paul Eggert (1995-11-03) +# +# The Web has several other sources for time zone and daylight savings data. +# Here are some recent links that may be of interest. +# +# Date and Time Gateway +# http://www.bsdi.com/date +# A text-based source for tables of current time throughout the world. +# Its point-and-click interface accesses a recent version of the tz data. +# +# Local Times Around the World +# http://www.hilink.com.au/times/ +# This text-based system contains links to local time servers +# throughout the world, and though the coverage is limited, +# the live data provide a nice way to check one's tables. +# +# World Time Zones +# http://tycho.usno.navy.mil/tzones.html +# US Naval Observatory data, used as the source for `usno1995'. +# +# Standard Time Zones of the World +# http://www.odci.gov/cia/publications/95fact/802389.gif [54 kB] +# http://www.odci.gov/cia/publications/95fact/802389h.gif [1317 kB] +# A static time zone map, available in both low-resolution and +# high-resolution versions. The quality is good, but the map does not +# indicate summer time, and parts of the data are a few years out of date. +# +# VIBE's World Map +# http://pathfinder.com/vibe/vibeworld +# An active time zone map. You can point to the map and find out what +# time it is at that location. The map and data are not as good as +# other sources. + +############################################################################### + +# From Manavendra Thakur (1995-11-06) +# +# To Paul's list of time zone information on the web, I would add the +# following URL: +# http://www.dhl.com/dhl/dhlinfo/1bb.html +# or more simply: +# http://www.dhl.com/ +# +# This is run by DHL (the courier company), and it presents a list of the +# countries served by that company. If you then click on a particular +# country, here's an example of what you'll see (graphics stripped out): +# +# United Kingdom +# +# HOLIDAYS: Jan 1, 2, Apr 14, 17, May 1, 29, Aug 28, Dec 25, 26 +# +# INTERNATIONAL DIALING CODE: +44 +# +# CURRENT LOCAL TIME: 09:41 Monday 6 November 1995 +# +# I find this rather handy, and given that DHL covers 217 countries and +# territories, it's pretty comprehensive coverage. +# +# (I have no idea what system DHL is using to calculate the local time, but +# it's been accurate so far.) + +############################################################################### + + +# From Arthur David Olson (1996-01-04) +# +# A good source of information about ISO 8601 seems to be +# http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html +# maintained by Markus Kuhn. diff --git a/usr.sbin/zic/ialloc.c b/usr.sbin/zic/ialloc.c index 7dc2f2b..5631947 100644 --- a/usr.sbin/zic/ialloc.c +++ b/usr.sbin/zic/ialloc.c @@ -1,6 +1,6 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)ialloc.c 8.21"; +static char elsieid[] = "@(#)ialloc.c 8.28"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -8,35 +8,20 @@ static char elsieid[] = "@(#)ialloc.c 8.21"; #include "private.h" -#ifdef MAL -#define NULLMAL(x) ((x) == NULL || (x) == MAL) -#endif /* defined MAL */ -#ifndef MAL -#define NULLMAL(x) ((x) == NULL) -#endif /* !defined MAL */ - #define nonzero(n) (((n) == 0) ? 1 : (n)) char * icalloc P((int nelem, int elsize)); char * icatalloc P((char * old, const char * new)); char * icpyalloc P((const char * string)); char * imalloc P((int n)); -char * irealloc P((char * pointer, int size)); +void * irealloc P((void * pointer, int size)); void ifree P((char * pointer)); char * imalloc(n) const int n; { -#ifdef MAL - register char * result; - - result = malloc((alloc_size_t) nonzero(n)); - return NULLMAL(result) ? NULL : result; -#endif /* defined MAL */ -#ifndef MAL - return malloc((alloc_size_t) nonzero(n)); -#endif /* !defined MAL */ + return malloc((size_t) nonzero(n)); } char * @@ -46,17 +31,17 @@ int elsize; { if (nelem == 0 || elsize == 0) nelem = elsize = 1; - return calloc((alloc_size_t) nelem, (alloc_size_t) elsize); + return calloc((size_t) nelem, (size_t) elsize); } -char * +void * irealloc(pointer, size) -char * const pointer; +void * const pointer; const int size; { - if (NULLMAL(pointer)) + if (pointer == NULL) return imalloc(size); - return realloc((genericptr_t) pointer, (alloc_size_t) nonzero(size)); + return realloc((void *) pointer, (size_t) nonzero(size)); } char * @@ -67,14 +52,14 @@ const char * const new; register char * result; register int oldsize, newsize; - newsize = NULLMAL(new) ? 0 : strlen(new); - if (NULLMAL(old)) + newsize = (new == NULL) ? 0 : strlen(new); + if (old == NULL) oldsize = 0; else if (newsize == 0) return old; else oldsize = strlen(old); if ((result = irealloc(old, oldsize + newsize + 1)) != NULL) - if (!NULLMAL(new)) + if (new != NULL) (void) strcpy(result + oldsize, new); return result; } @@ -90,7 +75,7 @@ void ifree(p) char * const p; { - if (!NULLMAL(p)) + if (p != NULL) (void) free(p); } @@ -98,6 +83,6 @@ void icfree(p) char * const p; { - if (!NULLMAL(p)) + if (p != NULL) (void) free(p); } diff --git a/usr.sbin/zic/scheck.c b/usr.sbin/zic/scheck.c index 4d9616d..64f2507 100644 --- a/usr.sbin/zic/scheck.c +++ b/usr.sbin/zic/scheck.c @@ -1,6 +1,6 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)scheck.c 8.11"; +static char elsieid[] = "@(#)scheck.c 8.13"; #endif /* !defined lint */ #endif /* !defined NOID */ @@ -14,7 +14,7 @@ extern void ifree P((char * p)); char * scheck(string, format) const char * const string; -const char * const format; +char * const format; { register char * fbuf; register const char * fp; @@ -22,12 +22,12 @@ const char * const format; register int c; register char * result; char dummy; - static char nada[1]; + static char nada; - result = nada; + result = &nada; if (string == NULL || format == NULL) return result; - fbuf = imalloc(2 * strlen(format) + 4); + fbuf = imalloc((int) (2 * strlen(format) + 4)); if (fbuf == NULL) return result; fp = format; @@ -42,7 +42,7 @@ const char * const format; *tp++ = '*'; if (*fp == '*') ++fp; - while (isascii(*fp) && isdigit(*fp)) + while (is_digit(*fp)) *tp++ = *fp++; if (*fp == 'l' || *fp == 'h') *tp++ = *fp++; diff --git a/usr.sbin/zic/zdump.8 b/usr.sbin/zic/zdump.8 index 23f4946..3323129 100644 --- a/usr.sbin/zic/zdump.8 +++ b/usr.sbin/zic/zdump.8 @@ -20,8 +20,7 @@ These options are available: For each .I zonename on the command line, -print the current time, -the time at the lowest possible time value, +print the time at the lowest possible time value, the time one day after the lowest possible time value, the times both one second before and exactly at each detected time discontinuity, @@ -37,4 +36,4 @@ otherwise. Cut off the verbose output near the start of the given year. .SH "SEE ALSO" newctime(3), tzfile(5), zic(8) -.\" @(#)zdump.8 7.2 +.\" @(#)zdump.8 7.3 diff --git a/usr.sbin/zic/zdump.c b/usr.sbin/zic/zdump.c index 1e44d4a..1058a84 100644 --- a/usr.sbin/zic/zdump.c +++ b/usr.sbin/zic/zdump.c @@ -1,6 +1,6 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)zdump.c 7.10"; +static char elsieid[] = "@(#)zdump.c 7.24"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -10,10 +10,11 @@ static char elsieid[] = "@(#)zdump.c 7.10"; ** You can use this code to help in verifying other implementations. */ -#include "stdio.h" /* for stdout, stderr */ +#include "stdio.h" /* for stdout, stderr, perror */ #include "string.h" /* for strcpy */ #include "sys/types.h" /* for time_t */ #include "time.h" /* for struct tm */ +#include "stdlib.h" /* for exit, malloc, atoi */ #ifndef MAX_STRING_LENGTH #define MAX_STRING_LENGTH 1024 @@ -67,18 +68,55 @@ static char elsieid[] = "@(#)zdump.c 7.10"; #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) #endif /* !defined isleap */ +#if HAVE_GETTEXT - 0 +#include "locale.h" /* for setlocale */ +#include "libintl.h" +#endif /* HAVE_GETTEXT - 0 */ + +#ifndef GNUC_or_lint +#ifdef lint +#define GNUC_or_lint +#endif /* defined lint */ +#ifndef lint +#ifdef __GNUC__ +#define GNUC_or_lint +#endif /* defined __GNUC__ */ +#endif /* !defined lint */ +#endif /* !defined GNUC_or_lint */ + +#ifndef INITIALIZE +#ifdef GNUC_or_lint +#define INITIALIZE(x) ((x) = 0) +#endif /* defined GNUC_or_lint */ +#ifndef GNUC_or_lint +#define INITIALIZE(x) +#endif /* !defined GNUC_or_lint */ +#endif /* !defined INITIALIZE */ + +/* +** For the benefit of GNU folk... +** `_(MSGID)' uses the current locale's message library string for MSGID. +** The default is to use gettext if available, and use MSGID otherwise. +*/ + +#ifndef _ +#if HAVE_GETTEXT - 0 +#define _(msgid) gettext(msgid) +#else /* !(HAVE_GETTEXT - 0) */ +#define _(msgid) msgid +#endif /* !(HAVE_GETTEXT - 0) */ +#endif /* !defined _ */ + +#ifndef TZ_DOMAIN +#define TZ_DOMAIN "tz" +#endif /* !defined TZ_DOMAIN */ + extern char ** environ; extern int getopt(); extern char * optarg; extern int optind; extern time_t time(); extern char * tzname[2]; -extern void tzset(); - -#ifdef USG -extern void exit(); -extern void perror(); -#endif /* defined USG */ static char * abbr(); static long delta(); @@ -92,16 +130,28 @@ main(argc, argv) int argc; char * argv[]; { - register int i, c; - register int vflag; - register char * cutoff; - register int cutyear; - register long cuttime; - time_t now; - time_t t, newt; - time_t hibit; - struct tm tm, newtm; - + register int i; + register int c; + register int vflag; + register char * cutoff; + register int cutyear; + register long cuttime; + char ** fakeenv; + time_t now; + time_t t; + time_t newt; + time_t hibit; + struct tm tm; + struct tm newtm; + + INITIALIZE(cuttime); +#if HAVE_GETTEXT - 0 + (void) setlocale(LC_MESSAGES, ""); +#ifdef TZ_DOMAINDIR + (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); +#endif /* defined(TEXTDOMAINDIR) */ + (void) textdomain(TZ_DOMAIN); +#endif /* HAVE_GETTEXT - 0 */ progname = argv[0]; vflag = 0; cutoff = NULL; @@ -112,7 +162,7 @@ char * argv[]; if (c != EOF || (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { (void) fprintf(stderr, -"%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n", +_("%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n"), argv[0], argv[0]); (void) exit(EXIT_FAILURE); } @@ -132,28 +182,36 @@ char * argv[]; longest = strlen(argv[i]); for (hibit = 1; (hibit << 1) != 0; hibit <<= 1) continue; - for (i = optind; i < argc; ++i) { - register char ** saveenv; - static char buf[MAX_STRING_LENGTH]; - char * fakeenv[2]; - - if (strlen(argv[i]) + 4 > sizeof buf) { - (void) fflush(stdout); - (void) fprintf(stderr, "%s: argument too long -- %s\n", - progname, argv[i]); - (void) exit(EXIT_FAILURE); + { + register int from; + register int to; + + for (i = 0; environ[i] != NULL; ++i) + continue; + fakeenv = (char **) malloc((size_t) ((i + 2) * + sizeof *fakeenv)); + if (fakeenv == NULL || + (fakeenv[0] = (char *) malloc((size_t) (longest + + 4))) == NULL) { + (void) perror(progname); + (void) exit(EXIT_FAILURE); } - (void) strcpy(buf, "TZ="); - (void) strcat(buf, argv[i]); - fakeenv[0] = buf; - fakeenv[1] = NULL; - saveenv = environ; + to = 0; + (void) strcpy(fakeenv[to++], "TZ="); + for (from = 0; environ[from] != NULL; ++from) + if (strncmp(environ[from], "TZ=", 3) != 0) + fakeenv[to++] = environ[from]; + fakeenv[to] = NULL; environ = fakeenv; - (void) tzset(); - environ = saveenv; - show(argv[i], now, FALSE); - if (!vflag) + } + for (i = optind; i < argc; ++i) { + static char buf[MAX_STRING_LENGTH]; + + (void) strcpy(&fakeenv[0][3], argv[i]); + if (!vflag) { + show(argv[i], now, FALSE); continue; + } /* ** Get lowest value of t. */ @@ -197,9 +255,9 @@ char * argv[]; show(argv[i], t, TRUE); } if (fflush(stdout) || ferror(stdout)) { - (void) fprintf(stderr, "%s: Error writing standard output ", + (void) fprintf(stderr, _("%s: Error writing standard output "), argv[0]); - (void) perror("standard output"); + (void) perror(_("standard output")); (void) exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); @@ -268,14 +326,15 @@ struct tm * oldp; return result; } +extern struct tm * localtime(); + static void show(zone, t, v) char * zone; time_t t; int v; { - struct tm * tmp; - extern struct tm * localtime(); + struct tm * tmp; (void) printf("%-*s ", longest, zone); if (v) @@ -298,10 +357,10 @@ abbr(tmp) struct tm * tmp; { register char * result; - static char nada[1]; + static char nada; if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) - return nada; + return &nada; result = tzname[tmp->tm_isdst]; - return (result == NULL) ? nada : result; + return (result == NULL) ? &nada : result; } diff --git a/usr.sbin/zic/zic.8 b/usr.sbin/zic/zic.8 index 6972d0e..979f4fa 100644 --- a/usr.sbin/zic/zic.8 +++ b/usr.sbin/zic/zic.8 @@ -154,17 +154,7 @@ then the rule applies in all years between .B FROM and .B TO -inclusive; -if -.B TYPE -is -.BR uspres , -the rule applies in U.S. Presidential election years; -if -.B TYPE -is -.BR nonpres , -the rule applies in years other than U.S. Presidential election years. +inclusive. If .B TYPE is something else, then @@ -219,14 +209,18 @@ Any of these forms may be followed by the letter .B w if the given time is local .q "wall clock" -time or +time, .B s if the given time is local .q standard -time; in the absence of -.B w +time, or +.B u +(or +.B g or -.BR s , +.BR z ) +if the given time is universal time; +in the absence of an indicator, wall clock time is assumed. .TP .B SAVE @@ -300,6 +294,9 @@ The pair of characters is used to show where the .q "variable part" of the time zone abbreviation goes. +Alternately, +a slash (/) +separates standard and daylight abbreviations. .TP .B UNTIL The time at which the GMT offset or the rule(s) change for a location. @@ -326,14 +323,13 @@ A link line has the form .sp .nf .ti +.5i -.if t .ta \w'Link\0\0'u +\w'LINK-FROM\0\0'u -.if n .ta \w'Link\0\0'u +\w'US/Eastern\0\0'u +.ta \w'Link\0\0'u +\w'Europe/Istanbul\0\0'u Link LINK-FROM LINK-TO .sp For example: .sp .ti +.5i -Link US/Eastern EST5EDT +Link Europe/Istanbul Asia/Istanbul .sp .fi The @@ -409,4 +405,4 @@ the earliest transition time recorded in the compiled file is correct. /usr/local/etc/zoneinfo standard directory used for created files .SH "SEE ALSO" newctime(3), tzfile(5), zdump(8) -.\" @(#)zic.8 7.7 +.\" @(#)zic.8 7.12 diff --git a/usr.sbin/zic/zic.c b/usr.sbin/zic/zic.c index a0dc5f6..0cec893 100644 --- a/usr.sbin/zic/zic.c +++ b/usr.sbin/zic/zic.c @@ -1,11 +1,28 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)zic.c 7.22"; +static char elsieid[] = "@(#)zic.c 7.77"; #endif /* !defined NOID */ #endif /* !defined lint */ #include "private.h" +#include "locale.h" #include "tzfile.h" +#ifdef unix +#include "sys/stat.h" /* for umask manifest constants */ +#endif /* defined unix */ + +/* +** On some ancient hosts, predicates like `isspace(C)' are defined +** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, +** which says they are defined only if C == ((unsigned char) C) || C == EOF. +** Neither the C Standard nor Posix require that `isascii' exist. +** For portability, we check both ancient and modern requirements. +** If isascii is not defined, the isascii check succeeds trivially. +*/ +#include "ctype.h" +#ifndef isascii +#define isascii(x) 1 +#endif struct rule { const char * r_filename; @@ -25,6 +42,8 @@ struct rule { long r_tod; /* time from midnight */ int r_todisstd; /* above is standard time if TRUE */ /* or wall clock time if FALSE */ + int r_todisgmt; /* above is GMT if TRUE */ + /* or local time if FALSE */ long r_stdoff; /* offset from standard time */ const char * r_abbrvar; /* variable part of abbreviation */ @@ -58,13 +77,13 @@ struct zone { time_t z_untiltime; }; -extern int emkdir P((const char * name, int mode)); -extern int getopt P((int argc, char * argv[], const char * options)); +extern int getopt P((int argc, char * const argv[], + const char * options)); extern char * icatalloc P((char * old, const char * new)); extern char * icpyalloc P((const char * string)); extern void ifree P((char * p)); extern char * imalloc P((int n)); -extern char * irealloc P((char * old, int n)); +extern void * irealloc P((void * old, int n)); extern int link P((const char * fromname, const char * toname)); extern char * optarg; extern int optind; @@ -72,13 +91,15 @@ extern char * scheck P((const char * string, const char * format)); static void addtt P((time_t starttime, int type)); static int addtype P((long gmtoff, const char * abbr, int isdst, - int ttisstd)); + int ttisstd, int ttisgmt)); static void leapadd P((time_t t, int positive, int rolling, int count)); static void adjleap P((void)); static void associate P((void)); static int ciequal P((const char * ap, const char * bp)); static void convert P((long val, char * buf)); static void dolink P((const char * fromfile, const char * tofile)); +static void doabbr P((char * abbr, const char * format, + const char * letters, int isdst)); static void eat P((const char * name, int num)); static void eats P((const char * name, int num, const char * rname, int rnum)); @@ -103,27 +124,29 @@ static void newabbr P((const char * abbr)); static long oadd P((long t1, long t2)); static void outzone P((const struct zone * zp, int ntzones)); static void puttzcode P((long code, FILE * fp)); -static int rcomp P((const genericptr_t leftp, const genericptr_t rightp)); +static int rcomp P((const void * leftp, const void * rightp)); static time_t rpytime P((const struct rule * rp, int wantedy)); static void rulesub P((struct rule * rp, - char * loyearp, char * hiyearp, - char * typep, char * monthp, - char * dayp, char * timep)); + const char * loyearp, const char * hiyearp, + const char * typep, const char * monthp, + const char * dayp, const char * timep)); static void setboundaries P((void)); static time_t tadd P((time_t t1, long t2)); static void usage P((void)); static void writezone P((const char * name)); static int yearistype P((int year, const char * type)); +#if !HAVE_STRERROR +static char * strerror P((int)); +#endif /* !HAVE_STRERROR */ + static int charcnt; static int errors; static const char * filename; static int leapcnt; static int linenum; -static int max_int; static time_t max_time; static int max_year; -static int min_int; static time_t min_time; static int min_year; static int noise; @@ -132,7 +155,6 @@ static int rlinenum; static const char * progname; static int timecnt; static int typecnt; -static int tt_signed; /* ** Line codes. @@ -313,12 +335,15 @@ static const int len_years[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; -static time_t ats[TZ_MAX_TIMES]; -static unsigned char types[TZ_MAX_TIMES]; +static struct attype { + time_t at; + unsigned char type; +} attypes[TZ_MAX_TIMES]; static long gmtoffs[TZ_MAX_TYPES]; static char isdsts[TZ_MAX_TYPES]; static unsigned char abbrinds[TZ_MAX_TYPES]; static char ttisstds[TZ_MAX_TYPES]; +static char ttisgmts[TZ_MAX_TYPES]; static char chars[TZ_MAX_CHARS]; static time_t trans[TZ_MAX_LEAPS]; static long corr[TZ_MAX_LEAPS]; @@ -333,21 +358,37 @@ memcheck(ptr) char * const ptr; { if (ptr == NULL) { - (void) perror(progname); + const char *e = strerror(errno); + (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"), + progname, e); (void) exit(EXIT_FAILURE); } return ptr; } #define emalloc(size) memcheck(imalloc(size)) -#define erealloc(ptr, size) memcheck(irealloc(ptr, size)) +#define erealloc(ptr, size) memcheck(irealloc((ptr), (size))) #define ecpyalloc(ptr) memcheck(icpyalloc(ptr)) -#define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp)) +#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp))) /* ** Error handling. */ +#if ! HAVE_STRERROR +static char * +strerror(errnum) +int errnum; +{ + extern char *sys_errlist[]; + extern int sys_nerr; + + if (errnum > 0 && errnum <= sys_nerr) + return sys_errlist[errnum]; + return "Unknown system error"; +} +#endif /* ! HAVE_STRERROR */ + static void eats(name, num, rname, rnum) const char * const name; @@ -375,24 +416,35 @@ const char * const string; { /* ** Match the format of "cc" to allow sh users to - ** zic ... 2>&1 | error -t "*" -v + ** zic ... 2>&1 | error -t "*" -v ** on BSD systems. */ - (void) fprintf(stderr, "\"%s\", line %d: %s", + (void) fprintf(stderr, _("\"%s\", line %d: %s"), filename, linenum, string); if (rfilename != NULL) - (void) fprintf(stderr, " (rule from \"%s\", line %d)", + (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"), rfilename, rlinenum); (void) fprintf(stderr, "\n"); ++errors; } static void -usage() +warning(string) +const char * const string; { - (void) fprintf(stderr, -"%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ] \n\ -\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n", + char * cp; + + cp = ecpyalloc("warning: "); + cp = ecatalloc(cp, string); + error(string); + ifree(cp); + --errors; +} + +static void +usage P((void)) +{ + (void) fprintf(stderr, _("%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"), progname, progname); (void) exit(EXIT_FAILURE); } @@ -409,12 +461,20 @@ main(argc, argv) int argc; char * argv[]; { - register int i, j; + register int i; + register int j; register int c; #ifdef unix - (void) umask(umask(022) | 022); + (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH)); #endif /* defined unix */ +#if HAVE_GETTEXT - 0 + (void) setlocale(LC_MESSAGES, ""); +#ifdef TZ_DOMAINDIR + (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); +#endif /* defined TEXTDOMAINDIR */ + (void) textdomain(TZ_DOMAIN); +#endif /* HAVE_GETTEXT - 0 */ progname = argv[0]; while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF) switch (c) { @@ -425,7 +485,7 @@ char * argv[]; directory = optarg; else { (void) fprintf(stderr, -"%s: More than one -d option specified\n", +_("%s: More than one -d option specified\n"), progname); (void) exit(EXIT_FAILURE); } @@ -435,7 +495,7 @@ char * argv[]; lcltime = optarg; else { (void) fprintf(stderr, -"%s: More than one -l option specified\n", +_("%s: More than one -l option specified\n"), progname); (void) exit(EXIT_FAILURE); } @@ -445,7 +505,7 @@ char * argv[]; psxrules = optarg; else { (void) fprintf(stderr, -"%s: More than one -p option specified\n", +_("%s: More than one -p option specified\n"), progname); (void) exit(EXIT_FAILURE); } @@ -455,7 +515,7 @@ char * argv[]; yitcommand = optarg; else { (void) fprintf(stderr, -"%s: More than one -y option specified\n", +_("%s: More than one -y option specified\n"), progname); (void) exit(EXIT_FAILURE); } @@ -465,7 +525,7 @@ char * argv[]; leapsec = optarg; else { (void) fprintf(stderr, -"%s: More than one -L option specified\n", +_("%s: More than one -L option specified\n"), progname); (void) exit(EXIT_FAILURE); } @@ -491,9 +551,6 @@ char * argv[]; adjleap(); } - zones = (struct zone *) emalloc(0); - rules = (struct rule *) emalloc(0); - links = (struct link *) emalloc(0); for (i = optind; i < argc; ++i) infile(argv[i]); if (errors) @@ -528,14 +585,14 @@ const char * const tofile; register char * toname; if (fromfile[0] == '/') - fromname = fromfile; + fromname = ecpyalloc(fromfile); else { fromname = ecpyalloc(directory); fromname = ecatalloc(fromname, "/"); fromname = ecatalloc(fromname, fromfile); } if (tofile[0] == '/') - toname = tofile; + toname = ecpyalloc(tofile); else { toname = ecpyalloc(directory); toname = ecatalloc(toname, "/"); @@ -551,48 +608,52 @@ const char * const tofile; if (mkdirs(toname) != 0) (void) exit(EXIT_FAILURE); if (link(fromname, toname) != 0) { - (void) fprintf(stderr, "%s: Can't link from %s to ", - progname, fromname); - (void) perror(toname); + const char *e = strerror(errno); + (void) fprintf(stderr, + _("%s: Can't link from %s to %s: %s\n"), + progname, fromname, toname, e); (void) exit(EXIT_FAILURE); } } - if (fromname != fromfile) - ifree(fromname); - if (toname != tofile) - ifree(toname); + ifree(fromname); + ifree(toname); } +#ifndef INT_MAX +#define INT_MAX ((int) (((unsigned)~0)>>1)) +#endif /* !defined INT_MAX */ + +#ifndef INT_MIN +#define INT_MIN ((int) ~(((unsigned)~0)>>1)) +#endif /* !defined INT_MIN */ + +/* +** The tz file format currently allows at most 32-bit quantities. +** This restriction should be removed before signed 32-bit values +** wrap around in 2038, but unfortunately this will require a +** change to the tz file format. +*/ + +#define MAX_BITS_IN_FILE 32 +#define TIME_T_BITS_IN_FILE ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE) + static void -setboundaries() +setboundaries P((void)) { - register time_t bit; - register int bii; - - for (bit = 1; bit > 0; bit <<= 1) - continue; - if (bit == 0) { /* time_t is an unsigned type */ - tt_signed = FALSE; - min_time = 0; - max_time = ~(time_t) 0; - if (sflag) - max_time >>= 1; - } else { - tt_signed = TRUE; - min_time = bit; - max_time = bit; - ++max_time; - max_time = -max_time; + if (TYPE_SIGNED(time_t)) { + min_time = ~ (time_t) 0; + min_time <<= TIME_T_BITS_IN_FILE - 1; + max_time = ~ (time_t) 0 - min_time; if (sflag) min_time = 0; + } else { + min_time = 0; + max_time = 2 - sflag; + max_time <<= TIME_T_BITS_IN_FILE - 1; + --max_time; } min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year; max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year; - - for (bii = 1; bii > 0; bii <<= 1) - continue; - min_int = bii; - max_int = -1 - bii; } static int @@ -604,7 +665,7 @@ const char * const name; myname = ecpyalloc(name); myname = ecatalloc(myname, "/."); - accres = access(myname, 0); + accres = access(myname, F_OK); ifree(myname); return accres == 0; } @@ -619,25 +680,50 @@ const char * const name; static int rcomp(cp1, cp2) -const genericptr_t cp1; -const genericptr_t cp2; +const void * cp1; +const void * cp2; { - return strcmp(((struct rule *) cp1)->r_name, - ((struct rule *) cp2)->r_name); + return strcmp(((const struct rule *) cp1)->r_name, + ((const struct rule *) cp2)->r_name); } static void -associate() +associate P((void)) { register struct zone * zp; register struct rule * rp; register int base, out; - register int i; + register int i, j; - if (nrules != 0) - (void) qsort((genericptr_t) rules, - (qsort_size_t) nrules, - (qsort_size_t) sizeof *rules, rcomp); + if (nrules != 0) { + (void) qsort((void *) rules, (size_t) nrules, + (size_t) sizeof *rules, rcomp); + for (i = 0; i < nrules - 1; ++i) { + if (strcmp(rules[i].r_name, + rules[i + 1].r_name) != 0) + continue; + if (strcmp(rules[i].r_filename, + rules[i + 1].r_filename) == 0) + continue; + eat(rules[i].r_filename, rules[i].r_linenum); + warning(_("same rule name in multiple files")); + eat(rules[i + 1].r_filename, rules[i + 1].r_linenum); + warning(_("same rule name in multiple files")); + for (j = i + 2; j < nrules; ++j) { + if (strcmp(rules[i].r_name, + rules[j].r_name) != 0) + break; + if (strcmp(rules[i].r_filename, + rules[j].r_filename) == 0) + continue; + if (strcmp(rules[i + 1].r_filename, + rules[j].r_filename) == 0) + continue; + break; + } + i = j - 1; + } + } for (i = 0; i < nzones; ++i) { zp = &zones[i]; zp->z_rules = NULL; @@ -663,13 +749,14 @@ associate() ** Maybe we have a local standard time offset. */ eat(zp->z_filename, zp->z_linenum); - zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE); + zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"), + TRUE); /* ** Note, though, that if there's no rule, ** a '%s' in the format is a bad thing. */ if (strchr(zp->z_format, '%') != 0) - error("%s in ruleless zone"); + error(_("%s in ruleless zone")); } } if (errors) @@ -690,11 +777,12 @@ const char * name; char buf[BUFSIZ]; if (strcmp(name, "-") == 0) { - name = "standard input"; + name = _("standard input"); fp = stdin; } else if ((fp = fopen(name, "r")) == NULL) { - (void) fprintf(stderr, "%s: Can't open ", progname); - (void) perror(name); + const char *e = strerror(errno); + (void) fprintf(stderr, _("%s: Can't open %s: %s\n"), + progname, name, e); (void) exit(EXIT_FAILURE); } wantcont = FALSE; @@ -704,17 +792,17 @@ const char * name; break; cp = strchr(buf, '\n'); if (cp == NULL) { - error("line too long"); + error(_("line too long")); (void) exit(EXIT_FAILURE); } *cp = '\0'; fields = getfields(buf); nfields = 0; while (fields[nfields] != NULL) { - static char nada[1]; + static char nada; - if (ciequal(fields[nfields], "-")) - fields[nfields] = nada; + if (strcmp(fields[nfields], "-") == 0) + fields[nfields] = &nada; ++nfields; } if (nfields == 0) { @@ -724,7 +812,7 @@ const char * name; } else { lp = byword(fields[0], line_codes); if (lp == NULL) - error("input line of unknown type"); + error(_("input line of unknown type")); else switch ((int) (lp->l_value)) { case LC_RULE: inrule(fields, nfields); @@ -740,14 +828,14 @@ const char * name; case LC_LEAP: if (name != leapsec) (void) fprintf(stderr, -"%s: Leap line in non leap seconds file %s\n", +_("%s: Leap line in non leap seconds file %s\n"), progname, name); else inleap(fields, nfields); wantcont = FALSE; break; default: /* "cannot happen" */ (void) fprintf(stderr, -"%s: panic: Invalid l_value %d\n", +_("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) exit(EXIT_FAILURE); } @@ -755,22 +843,23 @@ const char * name; ifree((char *) fields); } if (ferror(fp)) { - (void) fprintf(stderr, "%s: Error reading ", progname); - (void) perror(filename); + (void) fprintf(stderr, _("%s: Error reading %s\n"), + progname, filename); (void) exit(EXIT_FAILURE); } if (fp != stdin && fclose(fp)) { - (void) fprintf(stderr, "%s: Error closing ", progname); - (void) perror(filename); + const char *e = strerror(errno); + (void) fprintf(stderr, _("%s: Error closing %s: %s\n"), + progname, filename, e); (void) exit(EXIT_FAILURE); } if (wantcont) - error("expected continuation line not found"); + error(_("expected continuation line not found")); } /* ** Convert a string of one of the forms -** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss +** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss ** into a number of seconds. ** A null string maps to zero. ** Call error with errstring and return zero on errors. @@ -820,21 +909,21 @@ const int nfields; static struct rule r; if (nfields != RULE_FIELDS) { - error("wrong number of fields on Rule line"); + error(_("wrong number of fields on Rule line")); return; } if (*fields[RF_NAME] == '\0') { - error("nameless rule"); + error(_("nameless rule")); return; } r.r_filename = filename; r.r_linenum = linenum; - r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE); + r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE); rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]); r.r_name = ecpyalloc(fields[RF_NAME]); r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]); - rules = (struct rule *) erealloc((char *) rules, + rules = (struct rule *) (void *) erealloc((char *) rules, (int) ((nrules + 1) * sizeof *rules)); rules[nrules++] = r; } @@ -848,21 +937,21 @@ const int nfields; static char * buf; if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) { - error("wrong number of fields on Zone line"); + error(_("wrong number of fields on Zone line")); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) { - buf = erealloc(buf, 132 + strlen(TZDEFAULT)); + buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT))); (void) sprintf(buf, -"\"Zone %s\" line and -l option are mutually exclusive", +_("\"Zone %s\" line and -l option are mutually exclusive"), TZDEFAULT); error(buf); return FALSE; } if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) { - buf = erealloc(buf, 132 + strlen(TZDEFRULES)); + buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES))); (void) sprintf(buf, -"\"Zone %s\" line and -p option are mutually exclusive", +_("\"Zone %s\" line and -p option are mutually exclusive"), TZDEFRULES); error(buf); return FALSE; @@ -870,11 +959,11 @@ const int nfields; for (i = 0; i < nzones; ++i) if (zones[i].z_name != NULL && strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) { - buf = erealloc(buf, 132 + + buf = erealloc(buf, (int) (132 + strlen(fields[ZF_NAME]) + - strlen(zones[i].z_filename)); + strlen(zones[i].z_filename))); (void) sprintf(buf, -"duplicate zone name %s (file \"%s\", line %d)", +_("duplicate zone name %s (file \"%s\", line %d)"), fields[ZF_NAME], zones[i].z_filename, zones[i].z_linenum); @@ -890,7 +979,7 @@ register char ** const fields; const int nfields; { if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) { - error("wrong number of fields on Zone continuation line"); + error(_("wrong number of fields on Zone continuation line")); return FALSE; } return inzsub(fields, nfields, TRUE); @@ -930,10 +1019,10 @@ const int iscont; } z.z_filename = filename; z.z_linenum = linenum; - z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE); + z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid GMT offset"), TRUE); if ((cp = strchr(fields[i_format], '%')) != 0) { if (*++cp != 's' || strchr(cp, '%') != 0) { - error("invalid abbreviation format"); + error(_("invalid abbreviation format")); return FALSE; } } @@ -959,11 +1048,11 @@ const int iscont; zones[nzones - 1].z_untiltime > min_time && zones[nzones - 1].z_untiltime < max_time && zones[nzones - 1].z_untiltime >= z.z_untiltime) { -error("Zone continuation line end time is not after end time of previous line"); + error(_("Zone continuation line end time is not after end time of previous line")); return FALSE; } } - zones = (struct zone *) erealloc((char *) zones, + zones = (struct zone *) (void *) erealloc((char *) zones, (int) ((nzones + 1) * sizeof *zones)); zones[nzones++] = z; /* @@ -986,7 +1075,7 @@ const int nfields; time_t t; if (nfields != LEAP_FIELDS) { - error("wrong number of fields on Leap line"); + error(_("wrong number of fields on Leap line")); return; } dayoff = 0; @@ -995,7 +1084,7 @@ const int nfields; /* * Leapin' Lizards! */ - error("invalid leaping year"); + error(_("invalid leaping year")); return; } j = EPOCH_YEAR; @@ -1010,7 +1099,7 @@ const int nfields; dayoff = oadd(dayoff, eitol(i)); } if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) { - error("invalid month name"); + error(_("invalid month name")); return; } month = lp->l_value; @@ -1023,12 +1112,12 @@ const int nfields; cp = fields[LP_DAY]; if (sscanf(cp, scheck(cp, "%d"), &day) != 1 || day <= 0 || day > len_months[isleap(year)][month]) { - error("invalid day of month"); + error(_("invalid day of month")); return; } dayoff = oadd(dayoff, eitol(day - 1)); - if (dayoff < 0 && !tt_signed) { - error("time before zero"); + if (dayoff < 0 && !TYPE_SIGNED(time_t)) { + error(_("time before zero")); return; } t = (time_t) dayoff * SECSPERDAY; @@ -1036,10 +1125,10 @@ const int nfields; ** Cheap overflow check. */ if (t / SECSPERDAY != dayoff) { - error("time overflow"); + error(_("time overflow")); return; } - tod = gethms(fields[LP_TIME], "invalid time of day", FALSE); + tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE); cp = fields[LP_CORR]; { register int positive; @@ -1058,11 +1147,11 @@ const int nfields; positive = TRUE; count = 2; } else { - error("illegal CORRECTION field on Leap line"); + error(_("illegal CORRECTION field on Leap line")); return; } if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) { - error("illegal Rolling/Stationary field on Leap line"); + error(_("illegal Rolling/Stationary field on Leap line")); return; } leapadd(tadd(t, tod), positive, lp->l_value, count); @@ -1077,22 +1166,22 @@ const int nfields; struct link l; if (nfields != LINK_FIELDS) { - error("wrong number of fields on Link line"); + error(_("wrong number of fields on Link line")); return; } if (*fields[LF_FROM] == '\0') { - error("blank FROM field on Link line"); + error(_("blank FROM field on Link line")); return; } if (*fields[LF_TO] == '\0') { - error("blank TO field on Link line"); + error(_("blank TO field on Link line")); return; } l.l_filename = filename; l.l_linenum = linenum; l.l_from = ecpyalloc(fields[LF_FROM]); l.l_to = ecpyalloc(fields[LF_TO]); - links = (struct link *) erealloc((char *) links, + links = (struct link *) (void *) erealloc((char *) links, (int) ((nlinks + 1) * sizeof *links)); links[nlinks++] = l; } @@ -1100,86 +1189,99 @@ const int nfields; static void rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep) register struct rule * const rp; -char * const loyearp; -char * const hiyearp; -char * const typep; -char * const monthp; -char * const dayp; -char * const timep; +const char * const loyearp; +const char * const hiyearp; +const char * const typep; +const char * const monthp; +const char * const dayp; +const char * const timep; { - register struct lookup const * lp; - register char * cp; + register const struct lookup * lp; + register const char * cp; + register char * dp; + register char * ep; if ((lp = byword(monthp, mon_names)) == NULL) { - error("invalid month name"); + error(_("invalid month name")); return; } rp->r_month = lp->l_value; rp->r_todisstd = FALSE; - cp = timep; - if (*cp != '\0') { - cp += strlen(cp) - 1; - switch (lowerit(*cp)) { - case 's': + rp->r_todisgmt = FALSE; + dp = ecpyalloc(timep); + if (*dp != '\0') { + ep = dp + strlen(dp) - 1; + switch (lowerit(*ep)) { + case 's': /* Standard */ rp->r_todisstd = TRUE; - *cp = '\0'; + rp->r_todisgmt = FALSE; + *ep = '\0'; break; - case 'w': + case 'w': /* Wall */ rp->r_todisstd = FALSE; - *cp = '\0'; + rp->r_todisgmt = FALSE; + *ep = '\0'; + case 'g': /* Greenwich */ + case 'u': /* Universal */ + case 'z': /* Zulu */ + rp->r_todisstd = TRUE; + rp->r_todisgmt = TRUE; + *ep = '\0'; break; } } - rp->r_tod = gethms(timep, "invalid time of day", FALSE); + rp->r_tod = gethms(dp, _("invalid time of day"), FALSE); + ifree(dp); /* ** Year work. */ cp = loyearp; - if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) { + lp = byword(cp, begin_years); + if (lp != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: - rp->r_loyear = min_int; + rp->r_loyear = INT_MIN; break; case YR_MAXIMUM: - rp->r_loyear = max_int; + rp->r_loyear = INT_MAX; break; default: /* "cannot happen" */ (void) fprintf(stderr, - "%s: panic: Invalid l_value %d\n", + _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) exit(EXIT_FAILURE); } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) { - error("invalid starting year"); + error(_("invalid starting year")); return; } cp = hiyearp; if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) { case YR_MINIMUM: - rp->r_hiyear = min_int; + rp->r_hiyear = INT_MIN; break; case YR_MAXIMUM: - rp->r_hiyear = max_int; + rp->r_hiyear = INT_MAX; break; case YR_ONLY: rp->r_hiyear = rp->r_loyear; break; default: /* "cannot happen" */ (void) fprintf(stderr, - "%s: panic: Invalid l_value %d\n", + _("%s: panic: Invalid l_value %d\n"), progname, lp->l_value); (void) exit(EXIT_FAILURE); } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) { - error("invalid ending year"); + error(_("invalid ending year")); return; } if (rp->r_loyear > rp->r_hiyear) { - error("starting year greater than ending year"); + error(_("starting year greater than ending year")); return; } if (*typep == '\0') rp->r_yrtype = NULL; else { if (rp->r_loyear == rp->r_hiyear) { - error("typed single year"); + error(_("typed single year")); return; } rp->r_yrtype = ecpyalloc(typep); @@ -1192,38 +1294,43 @@ char * const timep; ** Sun<=20 ** Sun>=7 */ - if ((lp = byword(dayp, lasts)) != NULL) { + dp = ecpyalloc(dayp); + if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { - if ((cp = strchr(dayp, '<')) != 0) + if ((ep = strchr(dp, '<')) != 0) rp->r_dycode = DC_DOWLEQ; - else if ((cp = strchr(dayp, '>')) != 0) + else if ((ep = strchr(dp, '>')) != 0) rp->r_dycode = DC_DOWGEQ; else { - cp = dayp; + ep = dp; rp->r_dycode = DC_DOM; } if (rp->r_dycode != DC_DOM) { - *cp++ = 0; - if (*cp++ != '=') { - error("invalid day of month"); + *ep++ = 0; + if (*ep++ != '=') { + error(_("invalid day of month")); + ifree(dp); return; } - if ((lp = byword(dayp, wday_names)) == NULL) { - error("invalid weekday name"); + if ((lp = byword(dp, wday_names)) == NULL) { + error(_("invalid weekday name")); + ifree(dp); return; } rp->r_wday = lp->l_value; } - if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 || + if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 || rp->r_dayofmonth <= 0 || (rp->r_dayofmonth > len_months[1][rp->r_month])) { - error("invalid day of month"); + error(_("invalid day of month")); + ifree(dp); return; } } + ifree(dp); } static void @@ -1246,9 +1353,19 @@ FILE * const fp; char buf[4]; convert(val, buf); - (void) fwrite((genericptr_t) buf, - (fwrite_size_t) sizeof buf, - (fwrite_size_t) 1, fp); + (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp); +} + +static int +atcomp(avp, bvp) +void * avp; +void * bvp; +{ + if (((struct attype *) avp)->at < ((struct attype *) bvp)->at) + return -1; + else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at) + return 1; + else return 0; } static void @@ -1259,27 +1376,78 @@ const char * const name; register int i, j; static char * fullname; static struct tzhead tzh; + time_t ats[TZ_MAX_TIMES]; + unsigned char types[TZ_MAX_TIMES]; + /* + ** Sort. + */ + if (timecnt > 1) + (void) qsort((void *) attypes, (size_t) timecnt, + (size_t) sizeof *attypes, atcomp); + /* + ** Optimize. + */ + { + int fromi; + int toi; + + toi = 0; + fromi = 0; + if (isdsts[0] == 0) + while (attypes[fromi].type == 0) + ++fromi; /* handled by default rule */ + for ( ; fromi < timecnt; ++fromi) { + if (toi != 0 + && ((attypes[fromi].at + + gmtoffs[attypes[toi - 1].type]) + <= (attypes[toi - 1].at + + gmtoffs[toi == 1 ? 0 + : attypes[toi - 2].type]))) { + attypes[toi - 1].type = attypes[fromi].type; + continue; + } + if (toi == 0 || + attypes[toi - 1].type != attypes[fromi].type) + attypes[toi++] = attypes[fromi]; + } + timecnt = toi; + } + /* + ** Transfer. + */ + for (i = 0; i < timecnt; ++i) { + ats[i] = attypes[i].at; + types[i] = attypes[i].type; + } fullname = erealloc(fullname, - strlen(directory) + 1 + strlen(name) + 1); + (int) (strlen(directory) + 1 + strlen(name) + 1)); (void) sprintf(fullname, "%s/%s", directory, name); if ((fp = fopen(fullname, "wb")) == NULL) { if (mkdirs(fullname) != 0) (void) exit(EXIT_FAILURE); if ((fp = fopen(fullname, "wb")) == NULL) { - (void) fprintf(stderr, "%s: Can't create ", progname); - (void) perror(fullname); + const char *e = strerror(errno); + (void) fprintf(stderr, _("%s: Can't create %s: %s\n"), + progname, fullname, e); (void) exit(EXIT_FAILURE); } } + convert(eitol(typecnt), tzh.tzh_ttisgmtcnt); convert(eitol(typecnt), tzh.tzh_ttisstdcnt); convert(eitol(leapcnt), tzh.tzh_leapcnt); convert(eitol(timecnt), tzh.tzh_timecnt); convert(eitol(typecnt), tzh.tzh_typecnt); convert(eitol(charcnt), tzh.tzh_charcnt); - (void) fwrite((genericptr_t) &tzh, - (fwrite_size_t) sizeof tzh, - (fwrite_size_t) 1, fp); +#define DO(field) (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp) + DO(tzh_reserved); + DO(tzh_ttisgmtcnt); + DO(tzh_ttisstdcnt); + DO(tzh_leapcnt); + DO(tzh_timecnt); + DO(tzh_typecnt); + DO(tzh_charcnt); +#undef DO for (i = 0; i < timecnt; ++i) { j = leapcnt; while (--j >= 0) @@ -1290,18 +1458,16 @@ const char * const name; puttzcode((long) ats[i], fp); } if (timecnt > 0) - (void) fwrite((genericptr_t) types, - (fwrite_size_t) sizeof types[0], - (fwrite_size_t) timecnt, fp); + (void) fwrite((void *) types, (size_t) sizeof types[0], + (size_t) timecnt, fp); for (i = 0; i < typecnt; ++i) { puttzcode((long) gmtoffs[i], fp); (void) putc(isdsts[i], fp); (void) putc(abbrinds[i], fp); } if (charcnt != 0) - (void) fwrite((genericptr_t) chars, - (fwrite_size_t) sizeof chars[0], - (fwrite_size_t) charcnt, fp); + (void) fwrite((void *) chars, (size_t) sizeof chars[0], + (size_t) charcnt, fp); for (i = 0; i < leapcnt; ++i) { if (roll[i]) { if (timecnt == 0 || trans[i] < ats[0]) { @@ -1323,14 +1489,35 @@ const char * const name; } for (i = 0; i < typecnt; ++i) (void) putc(ttisstds[i], fp); + for (i = 0; i < typecnt; ++i) + (void) putc(ttisgmts[i], fp); if (ferror(fp) || fclose(fp)) { - (void) fprintf(stderr, "%s: Write error on ", progname); - (void) perror(fullname); + (void) fprintf(stderr, _("%s: Error writing %s\n"), + progname, fullname); (void) exit(EXIT_FAILURE); } } static void +doabbr(abbr, format, letters, isdst) +char * const abbr; +const char * const format; +const char * const letters; +const int isdst; +{ + if (strchr(format, '/') == NULL) { + if (letters == NULL) + (void) strcpy(abbr, format); + else (void) sprintf(abbr, format, letters); + } else if (isdst) + (void) strcpy(abbr, strchr(format, '/') + 1); + else { + (void) strcpy(abbr, format); + *strchr(abbr, '/') = '\0'; + } +} + +static void outzone(zpfirst, zonecount) const struct zone * const zpfirst; const int zonecount; @@ -1344,11 +1531,13 @@ const int zonecount; register long stdoff; register int year; register long startoff; - register int startisdst; register int startttisstd; + register int startttisgmt; register int type; char startbuf[BUFSIZ]; + INITIALIZE(untiltime); + INITIALIZE(starttime); /* ** Now. . .finally. . .generate some useful data! */ @@ -1364,9 +1553,7 @@ const int zonecount; ** for noting the need to unconditionally initialize startttisstd. */ startttisstd = FALSE; -#ifdef lint - starttime = 0; -#endif /* defined lint */ + startttisgmt = FALSE; for (i = 0; i < zonecount; ++i) { zp = &zpfirst[i]; usestart = i > 0 && (zp - 1)->z_untiltime > min_time; @@ -1375,14 +1562,19 @@ const int zonecount; continue; gmtoff = zp->z_gmtoff; eat(zp->z_filename, zp->z_linenum); - startisdst = -1; + *startbuf = '\0'; + startoff = zp->z_gmtoff; if (zp->z_nrules == 0) { stdoff = zp->z_stdoff; - (void) strcpy(startbuf, zp->z_format); + doabbr(startbuf, zp->z_format, + (char *) NULL, stdoff != 0); type = addtype(oadd(zp->z_gmtoff, stdoff), - startbuf, stdoff != 0, startttisstd); - if (usestart) + startbuf, stdoff != 0, startttisstd, + startttisgmt); + if (usestart) { addtt(starttime, type); + usestart = FALSE; + } else if (stdoff != 0) addtt(min_time, type); } else for (year = min_year; year <= max_year; ++year) { @@ -1408,14 +1600,17 @@ const int zonecount; register long offset; char buf[BUFSIZ]; + INITIALIZE(ktime); if (useuntil) { /* ** Turn untiltime into GMT ** assuming the current gmtoff and ** stdoff values. */ - untiltime = tadd(zp->z_untiltime, - -gmtoff); + untiltime = zp->z_untiltime; + if (!zp->z_untilrule.r_todisgmt) + untiltime = tadd(untiltime, + -gmtoff); if (!zp->z_untilrule.r_todisstd) untiltime = tadd(untiltime, -stdoff); @@ -1425,16 +1620,13 @@ const int zonecount; ** that takes effect earliest in the year. */ k = -1; -#ifdef lint - ktime = 0; -#endif /* defined lint */ for (j = 0; j < zp->z_nrules; ++j) { rp = &zp->z_rules[j]; if (!rp->r_todo) continue; eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); - offset = gmtoff; + offset = rp->r_todisgmt ? 0 : gmtoff; if (!rp->r_todisstd) offset = oadd(offset, stdoff); jtime = rp->r_temp; @@ -1453,54 +1645,62 @@ const int zonecount; rp->r_todo = FALSE; if (useuntil && ktime >= untiltime) break; + stdoff = rp->r_stdoff; + if (usestart && ktime == starttime) + usestart = FALSE; if (usestart) { - if (ktime < starttime) { - stdoff = rp->r_stdoff; - startoff = oadd(zp->z_gmtoff, - rp->r_stdoff); - (void) sprintf(startbuf, zp->z_format, - rp->r_abbrvar); - startisdst = rp->r_stdoff != 0; - continue; - } - usestart = FALSE; - if (ktime != starttime) { - if (startisdst < 0 && - zp->z_gmtoff != - (zp - 1)->z_gmtoff) { - type = (timecnt == 0) ? 0 : - types[timecnt - 1]; - startoff = oadd(gmtoffs[type], - -(zp - 1)->z_gmtoff); - startisdst = startoff != 0; - startoff = oadd(startoff, - zp->z_gmtoff); - (void) strcpy(startbuf, - &chars[abbrinds[type]]); + if (ktime < starttime) { + startoff = oadd(zp->z_gmtoff, + stdoff); + doabbr(startbuf, zp->z_format, + rp->r_abbrvar, + rp->r_stdoff != 0); + continue; + } + if (*startbuf == '\0' && + startoff == oadd(zp->z_gmtoff, + stdoff)) { + doabbr(startbuf, zp->z_format, + rp->r_abbrvar, + rp->r_stdoff != 0); } - if (startisdst >= 0) -addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd)); - } } eats(zp->z_filename, zp->z_linenum, rp->r_filename, rp->r_linenum); - (void) sprintf(buf, zp->z_format, - rp->r_abbrvar); + doabbr(buf, zp->z_format, rp->r_abbrvar, + rp->r_stdoff != 0); offset = oadd(zp->z_gmtoff, rp->r_stdoff); type = addtype(offset, buf, rp->r_stdoff != 0, - rp->r_todisstd); + rp->r_todisstd, rp->r_todisgmt); addtt(ktime, type); - stdoff = rp->r_stdoff; } } + if (usestart) { + if (*startbuf == '\0' && + zp->z_format != NULL && + strchr(zp->z_format, '%') == NULL && + strchr(zp->z_format, '/') == NULL) + (void) strcpy(startbuf, zp->z_format); + eat(zp->z_filename, zp->z_linenum); + if (*startbuf == '\0') +error(_("can't determine time zone abbrevation to use just after until time")); + else addtt(starttime, + addtype(startoff, startbuf, + startoff != zp->z_gmtoff, + startttisstd, + startttisgmt)); + } /* ** Now we may get to set starttime for the next zone line. */ if (useuntil) { - starttime = tadd(zp->z_untiltime, -gmtoff); startttisstd = zp->z_untilrule.r_todisstd; + startttisgmt = zp->z_untilrule.r_todisgmt; + starttime = zp->z_untiltime; if (!startttisstd) starttime = tadd(starttime, -stdoff); + if (!startttisgmt) + starttime = tadd(starttime, -gmtoff); } } writezone(zpfirst->z_name); @@ -1511,28 +1711,37 @@ addtt(starttime, type) const time_t starttime; const int type; { - if (timecnt != 0 && type == types[timecnt - 1]) - return; /* easy enough! */ - if (timecnt == 0 && type == 0 && isdsts[0] == 0) - return; /* handled by default rule */ if (timecnt >= TZ_MAX_TIMES) { - error("too many transitions?!"); + error(_("too many transitions?!")); (void) exit(EXIT_FAILURE); } - ats[timecnt] = starttime; - types[timecnt] = type; + attypes[timecnt].at = starttime; + attypes[timecnt].type = type; ++timecnt; } static int -addtype(gmtoff, abbr, isdst, ttisstd) +addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt) const long gmtoff; const char * const abbr; const int isdst; const int ttisstd; +const int ttisgmt; { register int i, j; + if (isdst != TRUE && isdst != FALSE) { + error(_("internal error - addtype called with bad isdst")); + (void) exit(EXIT_FAILURE); + } + if (ttisstd != TRUE && ttisstd != FALSE) { + error(_("internal error - addtype called with bad ttisstd")); + (void) exit(EXIT_FAILURE); + } + if (ttisgmt != TRUE && ttisgmt != FALSE) { + error(_("internal error - addtype called with bad ttisgmt")); + (void) exit(EXIT_FAILURE); + } /* ** See if there's already an entry for this zone type. ** If so, just return its index. @@ -1540,7 +1749,8 @@ const int ttisstd; for (i = 0; i < typecnt; ++i) { if (gmtoff == gmtoffs[i] && isdst == isdsts[i] && strcmp(abbr, &chars[abbrinds[i]]) == 0 && - ttisstd == ttisstds[i]) + ttisstd == ttisstds[i] && + ttisgmt == ttisgmts[i]) return i; } /* @@ -1548,12 +1758,13 @@ const int ttisstd; ** many. */ if (typecnt >= TZ_MAX_TYPES) { - error("too many local time types"); + error(_("too many local time types")); (void) exit(EXIT_FAILURE); } gmtoffs[i] = gmtoff; isdsts[i] = isdst; ttisstds[i] = ttisstd; + ttisgmts[i] = ttisgmt; for (j = 0; j < charcnt; ++j) if (strcmp(&chars[j], abbr) == 0) @@ -1575,13 +1786,13 @@ int count; register int i, j; if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) { - error("too many leap seconds"); + error(_("too many leap seconds")); (void) exit(EXIT_FAILURE); } for (i = 0; i < leapcnt; ++i) if (t <= trans[i]) { if (t == trans[i]) { - error("repeated leap second moment"); + error(_("repeated leap second moment")); (void) exit(EXIT_FAILURE); } break; @@ -1600,7 +1811,7 @@ int count; } static void -adjleap() +adjleap P((void)) { register int i; register long last = 0; @@ -1624,19 +1835,15 @@ const char * const type; if (type == NULL || *type == '\0') return TRUE; - if (strcmp(type, "uspres") == 0) - return (year % 4) == 0; - if (strcmp(type, "nonpres") == 0) - return (year % 4) != 0; - buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type)); + buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type))); (void) sprintf(buf, "%s %d %s", yitcommand, year, type); result = system(buf); if (result == 0) return TRUE; if (result == (1 << 8)) return FALSE; - error("Wild result from command execution"); - (void) fprintf(stderr, "%s: command was '%s', result was %d\n", + error(_("Wild result from command execution")); + (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"), progname, buf, result); for ( ; ; ) (void) exit(EXIT_FAILURE); @@ -1644,8 +1851,9 @@ const char * const type; static int lowerit(a) -const int a; +int a; { + a = (unsigned char) a; return (isascii(a) && isupper(a)) ? tolower(a) : a; } @@ -1669,9 +1877,10 @@ register const char * word; return FALSE; ++word; while (*++abbr != '\0') - do if (*word == '\0') - return FALSE; - while (lowerit(*word++) != lowerit(*abbr)); + do { + if (*word == '\0') + return FALSE; + } while (lowerit(*word++) != lowerit(*abbr)); return TRUE; } @@ -1713,10 +1922,11 @@ register char * cp; if (cp == NULL) return NULL; - array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array)); + array = (char **) (void *) + emalloc((int) ((strlen(cp) + 1) * sizeof *array)); nsubs = 0; for ( ; ; ) { - while (isascii(*cp) && isspace(*cp)) + while (isascii(*cp) && isspace((unsigned char) *cp)) ++cp; if (*cp == '\0' || *cp == '#') break; @@ -1727,10 +1937,10 @@ register char * cp; else while ((*dp = *cp++) != '"') if (*dp != '\0') ++dp; - else error("Odd number of quotation marks"); + else error(_("Odd number of quotation marks")); } while (*cp != '\0' && *cp != '#' && - (!isascii(*cp) || !isspace(*cp))); - if (isascii(*cp) && isspace(*cp)) + (!isascii(*cp) || !isspace((unsigned char) *cp))); + if (isascii(*cp) && isspace((unsigned char) *cp)) ++cp; *dp = '\0'; } @@ -1747,7 +1957,7 @@ const long t2; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { - error("time overflow"); + error(_("time overflow")); (void) exit(EXIT_FAILURE); } return t; @@ -1766,7 +1976,7 @@ const long t2; return min_time; t = t1 + t2; if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) { - error("time overflow"); + error(_("time overflow")); (void) exit(EXIT_FAILURE); } return t; @@ -1786,9 +1996,9 @@ register const int wantedy; register long dayoff; /* with a nod to Margaret O. */ register time_t t; - if (wantedy == min_int) + if (wantedy == INT_MIN) return min_time; - if (wantedy == max_int) + if (wantedy == INT_MAX) return max_time; dayoff = 0; m = TM_JANUARY; @@ -1813,7 +2023,7 @@ register const int wantedy; if (rp->r_dycode == DC_DOWLEQ) --i; else { - error("use of 2/29 in non leap-year"); + error(_("use of 2/29 in non leap-year")); (void) exit(EXIT_FAILURE); } } @@ -1847,11 +2057,11 @@ register const int wantedy; --i; } if (i < 0 || i >= len_months[isleap(y)][m]) { - error("no day in month matches rule"); + error(_("no day in month matches rule")); (void) exit(EXIT_FAILURE); } } - if (dayoff < 0 && !tt_signed) + if (dayoff < 0 && !TYPE_SIGNED(time_t)) return min_time; t = (time_t) dayoff * SECSPERDAY; /* @@ -1870,7 +2080,7 @@ const char * const string; i = strlen(string) + 1; if (charcnt + i > TZ_MAX_CHARS) { - error("too many, or too long, time zone abbreviations"); + error(_("too many, or too long, time zone abbreviations")); (void) exit(EXIT_FAILURE); } (void) strcpy(&chars[charcnt], string); @@ -1891,10 +2101,10 @@ char * const argname; *cp = '\0'; #ifndef unix /* - ** MS-DOS drive specifier? + ** DOS drive specifier? */ - if (strlen(name) == 2 && isascii(name[0]) && - isalpha(name[0]) && name[1] == ':') { + if (isalpha((unsigned char) name[0]) && + name[1] == ':' && name[2] == '\0') { *cp = '/'; continue; } @@ -1903,11 +2113,11 @@ char * const argname; /* ** It doesn't seem to exist, so we try to create it. */ - if (emkdir(name, 0755) != 0) { + if (mkdir(name, 0755) != 0) { + const char *e = strerror(errno); (void) fprintf(stderr, - "%s: Can't create directory ", - progname); - (void) perror(name); + _("%s: Can't create directory %s: %s\n"), + progname, name, e); ifree(name); return -1; } @@ -1927,7 +2137,7 @@ const int i; l = i; if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) { (void) fprintf(stderr, - "%s: %d did not sign extend correctly\n", + _("%s: %d did not sign extend correctly\n"), progname, i); (void) exit(EXIT_FAILURE); } @@ -1935,5 +2145,5 @@ const int i; } /* -** UNIX is a registered trademark of AT&T. +** UNIX was a registered trademark of UNIX System Laboratories in 1993. */ -- cgit v1.1