aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGarrett Wollman <wollman@FreeBSD.org>1996-07-18 18:05:09 +0000
committerGarrett Wollman <wollman@FreeBSD.org>1996-07-18 18:05:09 +0000
commit979a211643ccba0ec4121184236acd4ffa1a8dea (patch)
tree556604079b0f29ac467efe87fa5772892d0018b8
parent89e2ea2b0f066d599b1e71a3e3844cdf1661d784 (diff)
downloadsrc-979a211643ccba0ec4121184236acd4ffa1a8dea.tar.gz
src-979a211643ccba0ec4121184236acd4ffa1a8dea.zip
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.
Notes
Notes: svn path=/vendor/tzcode/dist/; revision=17208
-rw-r--r--lib/libc/stdtime/asctime.c7
-rw-r--r--lib/libc/stdtime/difftime.c15
-rw-r--r--lib/libc/stdtime/localtime.c443
-rw-r--r--lib/libc/stdtime/private.h255
-rw-r--r--lib/libc/stdtime/strftime.c487
-rw-r--r--lib/libc/stdtime/tzfile.h23
6 files changed, 809 insertions, 421 deletions
diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c
index 60877028c74b..a1834b65a273 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 68f9d7eb96c5..f178524f5152 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 54031479f1dc..541f49ffdfe9 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 5af259c62604..f81bf4867bdb 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 <ctype.h>'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 821bc7957467..a5ba85c90473 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 45b4d7d606a7..cb9b6a1a11e1 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 <earl@hpato.aus.hp.com>.
+*/
+#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