summaryrefslogtreecommitdiff
path: root/lib/libc/stdtime/localtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/stdtime/localtime.c')
-rw-r--r--lib/libc/stdtime/localtime.c174
1 files changed, 132 insertions, 42 deletions
diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c
index 541f49ffdfe9..33dcd5d052c3 100644
--- a/lib/libc/stdtime/localtime.c
+++ b/lib/libc/stdtime/localtime.c
@@ -1,11 +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).
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
#ifndef lint
#ifndef NOID
-static char elsieid[] = "@(#)localtime.c 7.57";
+static char elsieid[] = "@(#)localtime.c 7.78";
#endif /* !defined NOID */
#endif /* !defined lint */
@@ -59,12 +59,23 @@ static char wildabbr[] = "WILDABBR";
static const char gmt[] = "GMT";
+/*
+** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
+** We default to US rules as of 1999-08-17.
+** POSIX 1003.1 section 8.1.1 says that the default DST rules are
+** implementation dependent; for historical reasons, US rules are a
+** common default.
+*/
+#ifndef TZDEFRULESTRING
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#endif /* !defined TZDEFDST */
+
struct ttinfo { /* time type information */
- long tt_gmtoff; /* GMT offset in seconds */
+ long tt_gmtoff; /* UTC 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 */
+ int tt_ttisgmt; /* TRUE if transition is UTC */
};
struct lsinfo { /* leap second information */
@@ -134,6 +145,10 @@ static time_t time2 P((struct tm *tmp,
void(*funcp) P((const time_t *,
long, struct tm*)),
long offset, int * okayp));
+static time_t time2sub P((struct tm *tmp,
+ void(*funcp) P((const time_t *,
+ long, struct tm*)),
+ long offset, int * okayp, int do_norm_secs));
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,
@@ -267,7 +282,7 @@ register struct state * const sp;
/*
** 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
+ ** that is the size needed for an array of char large enough
** to hold the longest file name string that the implementation
** guarantees can be opened."
*/
@@ -298,27 +313,23 @@ register struct state * const sp;
}
{
struct tzhead * tzhp;
- char buf[sizeof *sp + sizeof *tzhp];
+ union {
+ struct tzhead tzhead;
+ char buf[sizeof *sp + sizeof *tzhp];
+ } u;
int ttisstdcnt;
int ttisgmtcnt;
- i = read(fid, buf, sizeof buf);
+ i = read(fid, u.buf, sizeof u.buf);
if (close(fid) != 0)
return -1;
- 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;
+ ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
+ ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
+ sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
+ sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
+ sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
+ sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
+ p = u.tzhead.tzh_charcnt + sizeof u.tzhead.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 ||
@@ -326,7 +337,7 @@ register struct state * const sp;
(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
return -1;
- if (i - (p - buf) < sp->timecnt * 4 + /* ats */
+ if (i - (p - u.buf) < sp->timecnt * 4 + /* ats */
sp->timecnt + /* types */
sp->typecnt * (4 + 2) + /* ttinfos */
sp->charcnt + /* chars */
@@ -584,8 +595,8 @@ register struct rule * const rulep;
}
/*
-** 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,
+** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
+** year, a rule, and the offset from UTC at the time that rule takes effect,
** calculate the Epoch-relative time that rule takes effect.
*/
@@ -671,10 +682,10 @@ const long offset;
}
/*
- ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
+ ** "value" is the Epoch-relative time of 00:00:00 UTC 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.
+ ** from UTC.
*/
return value + rulep->r_time + offset;
}
@@ -708,15 +719,14 @@ const int lastditch;
name += stdlen;
if (stdlen >= sizeof sp->chars)
stdlen = (sizeof sp->chars) - 1;
+ stdoffset = 0;
} else {
name = getzname(name);
stdlen = name - stdname;
if (stdlen < 3)
return -1;
- }
- if (*name == '\0')
- return -1; /* was "stdoffset = 0;" */
- else {
+ if (*name == '\0')
+ return -1;
name = getoffset(name, &stdoffset);
if (name == NULL)
return -1;
@@ -735,6 +745,8 @@ const int lastditch;
if (name == NULL)
return -1;
} else dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0' && load_result != 0)
+ name = TZDEFRULESTRING;
if (*name == ',' || *name == ';') {
struct rule start;
struct rule end;
@@ -797,8 +809,6 @@ const int lastditch;
if (*name != '\0')
return -1;
- if (load_result != 0)
- return -1;
/*
** Initial values of theirstdoffset and theirdstoffset.
*/
@@ -872,6 +882,7 @@ const int lastditch;
sp->ttis[1].tt_gmtoff = -dstoffset;
sp->ttis[1].tt_isdst = TRUE;
sp->ttis[1].tt_abbrind = stdlen + 1;
+ sp->typecnt = 2;
}
} else {
dstlen = 0;
@@ -884,7 +895,7 @@ const int lastditch;
sp->charcnt = stdlen + 1;
if (dstlen != 0)
sp->charcnt += dstlen + 1;
- if (sp->charcnt > sizeof sp->chars)
+ if ((size_t) sp->charcnt > sizeof sp->chars)
return -1;
cp = sp->chars;
(void) strncpy(cp, stdname, stdlen);
@@ -944,9 +955,9 @@ tzset P((void))
return;
}
- if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
+ if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
return;
- lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
+ lcl_is_set = strlen(name) < sizeof lcl_TZname;
if (lcl_is_set)
(void) strcpy(lcl_TZname, name);
@@ -965,6 +976,8 @@ tzset P((void))
*/
lclptr->leapcnt = 0; /* so, we're off a little */
lclptr->timecnt = 0;
+ lclptr->typecnt = 0;
+ lclptr->ttis[0].tt_isdst = 0;
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
(void) strcpy(lclptr->chars, gmt);
@@ -1040,6 +1053,19 @@ const time_t * const timep;
}
/*
+** Re-entrant version of localtime.
+*/
+
+struct tm *
+localtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
+{
+ localsub(timep, 0L, tm);
+ return tm;
+}
+
+/*
** gmtsub is to gmtime as localsub is to localtime.
*/
@@ -1061,7 +1087,7 @@ struct tm * const tmp;
#ifdef TM_ZONE
/*
** Could get fancy here and deliver something such as
- ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
+ ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
** but this is no time for a treasure hunt.
*/
if (offset != 0)
@@ -1087,6 +1113,19 @@ const time_t * const timep;
return &tm;
}
+/*
+* Re-entrant version of gmtime.
+*/
+
+struct tm *
+gmtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
+{
+ gmtsub(timep, 0L, tm);
+ return tm;
+}
+
#ifdef STD_INSPIRED
struct tm *
@@ -1207,13 +1246,23 @@ 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
+** The ctime function 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));
}
+char *
+ctime_r(timep, buf)
+const time_t * const timep;
+char * buf;
+{
+ struct tm tm;
+
+ return asctime_r(localtime_r(timep, &tm), buf);
+}
+
/*
** Adapted from code provided by Robert Elz, who writes:
** The "best" way to do mktime I think is based on an idea of Bob
@@ -1276,11 +1325,12 @@ register const struct tm * const btmp;
}
static time_t
-time2(tmp, funcp, offset, okayp)
+time2sub(tmp, funcp, offset, okayp, do_norm_secs)
struct tm * const tmp;
void (* const funcp) P((const time_t*, long, struct tm*));
const long offset;
int * const okayp;
+const int do_norm_secs;
{
register const struct state * sp;
register int dir;
@@ -1293,6 +1343,11 @@ int * const okayp;
*okayp = FALSE;
yourtm = *tmp;
+ if (do_norm_secs) {
+ if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
+ SECSPERMIN))
+ return WRONG;
+ }
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
return WRONG;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
@@ -1330,7 +1385,9 @@ int * const okayp;
}
if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
return WRONG;
- if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
+ if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
+ saved_seconds = 0;
+ else 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.
@@ -1422,6 +1479,24 @@ label:
}
static time_t
+time2(tmp, funcp, offset, okayp)
+struct tm * const tmp;
+void (* const funcp) P((const time_t*, long, struct tm*));
+const long offset;
+int * const okayp;
+{
+ time_t t;
+
+ /*
+ ** First try without normalization of seconds
+ ** (in case tm_sec contains a value associated with a leap second).
+ ** If that fails, try with normalization of seconds.
+ */
+ t = time2sub(tmp, funcp, offset, okayp, FALSE);
+ return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
+}
+
+static time_t
time1(tmp, funcp, offset)
struct tm * const tmp;
void (* const funcp) P((const time_t *, long, struct tm *));
@@ -1430,6 +1505,11 @@ const long offset;
register time_t t;
register const struct state * sp;
register int samei, otheri;
+ register int sameind, otherind;
+ register int i;
+ register int nseen;
+ int seen[TZ_MAX_TYPES];
+ int types[TZ_MAX_TYPES];
int okay;
if (tmp->tm_isdst > 1)
@@ -1463,10 +1543,20 @@ const long offset;
if (sp == NULL)
return WRONG;
#endif /* defined ALL_STATE */
- for (samei = sp->typecnt - 1; samei >= 0; --samei) {
+ for (i = 0; i < sp->typecnt; ++i)
+ seen[i] = FALSE;
+ nseen = 0;
+ for (i = sp->timecnt - 1; i >= 0; --i)
+ if (!seen[sp->types[i]]) {
+ seen[sp->types[i]] = TRUE;
+ types[nseen++] = sp->types[i];
+ }
+ for (sameind = 0; sameind < nseen; ++sameind) {
+ samei = types[sameind];
if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
continue;
- for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
+ for (otherind = 0; otherind < nseen; ++otherind) {
+ otheri = types[otherind];
if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
continue;
tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
@@ -1548,7 +1638,7 @@ struct tm * const tmp;
/*
** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
-** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
+** shall correspond to "Wed Dec 31 23:59:59 UTC 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.