summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdtime
diff options
context:
space:
mode:
authorstefanf <stefanf@FreeBSD.org>2004-06-14 10:31:52 +0000
committerstefanf <stefanf@FreeBSD.org>2004-06-14 10:31:52 +0000
commit819398b145715e5a4304dbc0fda51ccda8870f88 (patch)
treebc34b687aa5e1e885e5ec8f072d2774e97c05a1c /lib/libc/stdtime
parentc8eeaa3f96986892a586a683b030200986cd5900 (diff)
downloadFreeBSD-src-819398b145715e5a4304dbc0fda51ccda8870f88.zip
FreeBSD-src-819398b145715e5a4304dbc0fda51ccda8870f88.tar.gz
Merge changes from the tzcode2004a import. Wherever possible I tried to bring
us closer to the vendor branch. Requested by: wollman
Diffstat (limited to 'lib/libc/stdtime')
-rw-r--r--lib/libc/stdtime/asctime.c52
-rw-r--r--lib/libc/stdtime/difftime.c16
-rw-r--r--lib/libc/stdtime/localtime.c168
-rw-r--r--lib/libc/stdtime/private.h61
-rw-r--r--lib/libc/stdtime/strftime.c228
5 files changed, 374 insertions, 151 deletions
diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c
index 4fd130b..0f4212f 100644
--- a/lib/libc/stdtime/asctime.c
+++ b/lib/libc/stdtime/asctime.c
@@ -1,12 +1,12 @@
/*
** 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).
*/
#include <sys/cdefs.h>
#ifndef lint
#ifndef NOID
-static char elsieid[] __unused = "@(#)asctime.c 7.7";
+static char elsieid[] __unused = "@(#)asctime.c 7.9";
#endif /* !defined NOID */
#endif /* !defined lint */
__FBSDID("$FreeBSD$");
@@ -19,23 +19,13 @@ __FBSDID("$FreeBSD$");
#include "tzfile.h"
/*
-** A la X3J11, with core dump avoidance.
+** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12.
*/
-
-char *
-asctime(timeptr)
-const struct tm * timeptr;
-{
- static char result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +
- 3 + 2 + 1 + 1];
- return(asctime_r(timeptr, result));
-}
-
char *
-asctime_r(timeptr, result)
+asctime_r(timeptr, buf)
const struct tm * timeptr;
-char *result;
+char * buf;
{
static const char wday_name[][3] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
@@ -44,13 +34,6 @@ char *result;
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
- /*
- ** Big enough for something such as
- ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
- ** (two three-character abbreviations, five strings denoting integers,
- ** three explicit spaces, two explicit colons, a newline,
- ** and a trailing ASCII nul).
- */
const char * wn;
const char * mn;
@@ -65,10 +48,31 @@ char *result;
** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
** Since the .2 in 02.2d is ignored, we drop it.
*/
- (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
+ (void) sprintf(buf, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
wn, mn,
timeptr->tm_mday, timeptr->tm_hour,
timeptr->tm_min, timeptr->tm_sec,
TM_YEAR_BASE + timeptr->tm_year);
- return result;
+ return buf;
+}
+
+/*
+** A la X3J11, with core dump avoidance.
+*/
+
+char *
+asctime(timeptr)
+const struct tm * timeptr;
+{
+ /*
+ ** Big enough for something such as
+ ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n
+ ** (two three-character abbreviations, five strings denoting integers,
+ ** three explicit spaces, two explicit colons, a newline,
+ ** and a trailing ASCII nul).
+ */
+ static char result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) +
+ 3 + 2 + 1 + 1];
+
+ return asctime_r(timeptr, result);
}
diff --git a/lib/libc/stdtime/difftime.c b/lib/libc/stdtime/difftime.c
index c79891c..596ea82 100644
--- a/lib/libc/stdtime/difftime.c
+++ b/lib/libc/stdtime/difftime.c
@@ -6,7 +6,7 @@
#include <sys/cdefs.h>
#ifndef lint
#ifndef NOID
-static char elsieid[] __unused = "@(#)difftime.c 7.7";
+static char elsieid[] __unused = "@(#)difftime.c 7.9";
#endif /* !defined NOID */
#endif /* !defined lint */
__FBSDID("$FreeBSD$");
@@ -36,10 +36,16 @@ const time_t time0;
time_t delta;
time_t hibit;
- if (sizeof(time_t) < sizeof(double))
- return (double) time1 - (double) time0;
- if (sizeof(time_t) < sizeof(long_double))
- return (long_double) time1 - (long_double) time0;
+ {
+ time_t tt;
+ double d;
+ long_double ld;
+
+ if (sizeof tt < sizeof d)
+ return (double) time1 - (double) time0;
+ if (sizeof tt < sizeof ld)
+ return (long_double) time1 - (long_double) time0;
+ }
if (time1 < time0)
return -difftime(time0, time1);
/*
diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c
index fadb3ec..9efff47 100644
--- a/lib/libc/stdtime/localtime.c
+++ b/lib/libc/stdtime/localtime.c
@@ -1,12 +1,12 @@
/*
** 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).
*/
#include <sys/cdefs.h>
#ifndef lint
#ifndef NOID
-static char elsieid[] __unused = "@(#)localtime.c 7.57";
+static char elsieid[] __unused = "@(#)localtime.c 7.78";
#endif /* !defined NOID */
#endif /* !defined lint */
__FBSDID("$FreeBSD$");
@@ -77,12 +77,23 @@ static char wildabbr[] = "WILDABBR";
static const char gmt[] = "UTC";
+/*
+** 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 */
@@ -152,6 +163,10 @@ static time_t time2(struct tm *tmp,
void(*funcp) (const time_t *,
long, struct tm*),
long offset, int * okayp);
+static time_t time2sub(struct tm *tmp,
+ void(*funcp) (const time_t *,
+ long, struct tm*),
+ long offset, int * okayp, int do_norm_secs);
static void timesub(const time_t * timep, long offset,
const struct state * sp, struct tm * tmp);
static int tmcomp(const struct tm * atmp,
@@ -328,27 +343,23 @@ 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_magic) + (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 ||
@@ -356,7 +367,7 @@ 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 */
@@ -614,8 +625,8 @@ 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.
*/
@@ -701,10 +712,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;
}
@@ -766,6 +777,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;
@@ -828,8 +841,6 @@ const int lastditch;
if (*name != '\0')
return -1;
- if (load_result != 0)
- return -1;
/*
** Initial values of theirstdoffset and theirdstoffset.
*/
@@ -903,6 +914,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;
@@ -915,7 +927,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);
@@ -976,9 +988,9 @@ tzset_basic(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);
@@ -997,6 +1009,8 @@ tzset_basic(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);
@@ -1071,18 +1085,6 @@ struct tm * const tmp;
}
struct tm *
-localtime_r(timep, p_tm)
-const time_t * const timep;
-struct tm *p_tm;
-{
- _MUTEX_LOCK(&lcl_mutex);
- tzset_basic();
- localsub(timep, 0L, p_tm);
- _MUTEX_UNLOCK(&lcl_mutex);
- return(p_tm);
-}
-
-struct tm *
localtime(timep)
const time_t * const timep;
{
@@ -1119,6 +1121,22 @@ const time_t * const timep;
}
/*
+** Re-entrant version of localtime.
+*/
+
+struct tm *
+localtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
+{
+ _MUTEX_LOCK(&lcl_mutex);
+ tzset_basic();
+ localsub(timep, 0L, tm);
+ _MUTEX_UNLOCK(&lcl_mutex);
+ return tm;
+}
+
+/*
** gmtsub is to gmtime as localsub is to localtime.
*/
@@ -1142,7 +1160,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)
@@ -1197,11 +1215,17 @@ const time_t * const timep;
}
}
+/*
+* Re-entrant version of gmtime.
+*/
+
struct tm *
-gmtime_r(const time_t * timep, struct tm * tm)
+gmtime_r(timep, tm)
+const time_t * const timep;
+struct tm * tm;
{
gmtsub(timep, 0L, tm);
- return(tm);
+ return tm;
}
#ifdef STD_INSPIRED
@@ -1324,7 +1348,7 @@ 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))
*/
@@ -1334,9 +1358,10 @@ const time_t * const timep;
char *
ctime_r(timep, buf)
const time_t * const timep;
-char *buf;
+char * buf;
{
- struct tm tm;
+ struct tm tm;
+
return asctime_r(localtime_r(timep, &tm), buf);
}
@@ -1402,11 +1427,12 @@ 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)(const time_t*, long, struct tm*);
const long offset;
int * const okayp;
+const int do_norm_secs;
{
const struct state * sp;
int dir;
@@ -1419,6 +1445,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))
@@ -1551,6 +1582,24 @@ label:
}
static time_t
+time2(tmp, funcp, offset, okayp)
+struct tm * const tmp;
+void (* const funcp)(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)(const time_t *, long, struct tm *);
@@ -1559,6 +1608,11 @@ const long offset;
time_t t;
const struct state * sp;
int samei, otheri;
+ int sameind, otherind;
+ int i;
+ int nseen;
+ int seen[TZ_MAX_TYPES];
+ int types[TZ_MAX_TYPES];
int okay;
if (tmp->tm_isdst > 1)
@@ -1588,10 +1642,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 -
@@ -1677,7 +1741,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.
diff --git a/lib/libc/stdtime/private.h b/lib/libc/stdtime/private.h
index 214442c..a3c7778 100644
--- a/lib/libc/stdtime/private.h
+++ b/lib/libc/stdtime/private.h
@@ -1,9 +1,10 @@
#ifndef PRIVATE_H
#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).
+** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
**
** $FreeBSD$
*/
@@ -36,7 +37,7 @@
#ifndef lint
#ifndef NOID
/*
-static char privatehid[] = "@(#)private.h 7.43";
+static char privatehid[] = "@(#)private.h 7.53";
*/
#endif /* !defined NOID */
#endif /* !defined lint */
@@ -54,14 +55,30 @@ static char privatehid[] = "@(#)private.h 7.43";
#define HAVE_GETTEXT 0
#endif /* !defined HAVE_GETTEXT */
+#ifndef HAVE_INCOMPATIBLE_CTIME_R
+#define HAVE_INCOMPATIBLE_CTIME_R 0
+#endif /* !defined INCOMPATIBLE_CTIME_R */
+
#ifndef HAVE_SETTIMEOFDAY
#define HAVE_SETTIMEOFDAY 3
#endif /* !defined HAVE_SETTIMEOFDAY */
#ifndef HAVE_STRERROR
-#define HAVE_STRERROR 0
+#define HAVE_STRERROR 1
#endif /* !defined HAVE_STRERROR */
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK 1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H 1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H 1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
#ifndef HAVE_UNISTD_H
#define HAVE_UNISTD_H 1
#endif /* !defined HAVE_UNISTD_H */
@@ -74,6 +91,11 @@ static char privatehid[] = "@(#)private.h 7.43";
#define LOCALE_HOME "/usr/lib/locale"
#endif /* !defined LOCALE_HOME */
+#if HAVE_INCOMPATIBLE_CTIME_R
+#define asctime_r _incompatible_asctime_r
+#define ctime_r _incompatible_ctime_r
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
/*
** Nested includes
*/
@@ -90,6 +112,17 @@ static char privatehid[] = "@(#)private.h 7.43";
#include "libintl.h"
#endif /* HAVE_GETTEXT - 0 */
+#if HAVE_SYS_WAIT_H - 0
+#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H - 0 */
+
+#ifndef WIFEXITED
+#define WIFEXITED(status) (((status) & 0xff) == 0)
+#endif /* !defined WIFEXITED */
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
+#endif /* !defined WEXITSTATUS */
+
#if HAVE_UNISTD_H - 0
#include "unistd.h" /* for F_OK and R_OK */
#endif /* HAVE_UNISTD_H - 0 */
@@ -128,6 +161,19 @@ static char privatehid[] = "@(#)private.h 7.43";
#endif /* !defined FILENAME_MAX */
/*
+** Private function declarations.
+*/
+char * icalloc(int nelem, int elsize);
+char * icatalloc(char * old, const char * new);
+char * icpyalloc(const char * string);
+char * imalloc(int n);
+void * irealloc(void * pointer, int size);
+void icfree(char * pointer);
+void ifree(char * pointer);
+char * scheck(const char *string, const char *format);
+
+
+/*
** Finally, some convenience items.
*/
@@ -200,8 +246,15 @@ static char privatehid[] = "@(#)private.h 7.43";
#define TZ_DOMAIN "tz"
#endif /* !defined TZ_DOMAIN */
+#if HAVE_INCOMPATIBLE_CTIME_R
+#undef asctime_r
+#undef ctime_r
+char *asctime_r(struct tm const *, char *);
+char *ctime_r(time_t const *, char *);
+#endif /* HAVE_INCOMPATIBLE_CTIME_R */
+
/*
-** UNIX was a registered trademark of UNIX System Laboratories in 1993.
+** UNIX was a registered trademark of The Open Group in 2003.
*/
#endif /* !defined PRIVATE_H */
diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c
index 5869475..d55bb79 100644
--- a/lib/libc/stdtime/strftime.c
+++ b/lib/libc/stdtime/strftime.c
@@ -17,7 +17,7 @@
#ifndef lint
#ifndef NOID
-static const char elsieid[] = "@(#)strftime.c 7.38";
+static const char elsieid[] = "@(#)strftime.c 7.64";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain character".
@@ -42,21 +42,49 @@ __FBSDID("$FreeBSD$");
static char * _add(const char *, char *, const char *);
static char * _conv(int, const char *, char *, const char *);
-static char * _fmt(const char *, const struct tm *, char *, const char *);
+static char * _fmt(const char *, const struct tm *, char *, const char *, int *);
size_t strftime(char * __restrict, size_t, const char * __restrict,
const struct tm * __restrict);
extern char * tzname[];
+#ifndef YEAR_2000_NAME
+#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
+#endif /* !defined YEAR_2000_NAME */
+
+
+#define IN_NONE 0
+#define IN_SOME 1
+#define IN_THIS 2
+#define IN_ALL 3
+
size_t
strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
const struct tm * __restrict t)
{
- char *p;
+ char * p;
+ int warn;
tzset();
- p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize);
+ warn = IN_NONE;
+ p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
+#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
+ if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
+ (void) fprintf(stderr, "\n");
+ if (format == NULL)
+ (void) fprintf(stderr, "NULL strftime format ");
+ else (void) fprintf(stderr, "strftime format \"%s\" ",
+ format);
+ (void) fprintf(stderr, "yields only two digits of years in ");
+ if (warn == IN_SOME)
+ (void) fprintf(stderr, "some locales");
+ else if (warn == IN_THIS)
+ (void) fprintf(stderr, "the current locale");
+ else (void) fprintf(stderr, "all locales");
+ (void) fprintf(stderr, "\n");
+ }
+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
return 0;
*p = '\0';
@@ -64,11 +92,12 @@ strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
}
static char *
-_fmt(format, t, pt, ptlim)
- const char *format;
- const struct tm *const t;
- char *pt;
- const char *const ptlim;
+_fmt(format, t, pt, ptlim, warnp)
+const char * format;
+const struct tm * const t;
+char * pt;
+const char * const ptlim;
+int * warnp;
{
int Ealternative, Oalternative;
struct lc_time_T *tptr = __get_current_time_locale();
@@ -83,24 +112,28 @@ label:
--format;
break;
case 'A':
- pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
"?" : tptr->weekday[t->tm_wday],
pt, ptlim);
continue;
case 'a':
- pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
+ pt = _add((t->tm_wday < 0 ||
+ t->tm_wday >= DAYSPERWEEK) ?
"?" : tptr->wday[t->tm_wday],
pt, ptlim);
continue;
case 'B':
- pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
"?" : (Oalternative ? tptr->alt_month :
tptr->month)[t->tm_mon],
pt, ptlim);
continue;
case 'b':
case 'h':
- pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
+ pt = _add((t->tm_mon < 0 ||
+ t->tm_mon >= MONSPERYEAR) ?
"?" : tptr->mon[t->tm_mon],
pt, ptlim);
continue;
@@ -110,16 +143,24 @@ label:
** _fmt("%a %b %e %X %Y", t);
** ...whereas now POSIX 1003.2 calls for
** something completely different.
- ** (ado, 5/24/93)
+ ** (ado, 1993-05-24)
*/
pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
"%02d", pt, ptlim);
continue;
case 'c':
- pt = _fmt(tptr->c_fmt, t, pt, ptlim);
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->c_fmt, t, pt, ptlim, warnp);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
continue;
case 'D':
- pt = _fmt("%m/%d/%y", t, pt, ptlim);
+ pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
@@ -131,15 +172,13 @@ label:
goto label;
case 'O':
/*
- ** POSIX locale extensions, a la
- ** Arnold Robbins' strftime version 3.0.
+ ** C99 locale modifiers.
** The sequences
- ** %Ec %EC %Ex %EX %Ey %EY
+ ** %Ec %EC %Ex %EX %Ey %EY
** %Od %oe %OH %OI %Om %OM
** %OS %Ou %OU %OV %Ow %OW %Oy
** are supposed to provide alternate
** representations.
- ** (ado, 5/24/93)
**
** FreeBSD extension
** %OB
@@ -152,7 +191,7 @@ label:
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
- pt = _fmt("%Y-%m-%d", t, pt, ptlim);
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
@@ -174,7 +213,7 @@ label:
** match SunOS 4.1.1 and Arnold Robbins'
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
- ** (ado, 5/24/93)
+ ** (ado, 1993-05-24)
*/
pt = _conv(t->tm_hour, "%2d", pt, ptlim);
continue;
@@ -194,7 +233,7 @@ label:
** match SunOS 4.1.1 and Arnold Robbin's
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
- ** (ado, 5/24/93)
+ ** (ado, 1993-05-24)
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
@@ -210,16 +249,17 @@ label:
pt = _add("\n", pt, ptlim);
continue;
case 'p':
- pt = _add((t->tm_hour >= 12) ?
+ pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
tptr->pm :
tptr->am,
pt, ptlim);
continue;
case 'R':
- pt = _fmt("%H:%M", t, pt, ptlim);
+ pt = _fmt("%H:%M", t, pt, ptlim, warnp);
continue;
case 'r':
- pt = _fmt(tptr->ampm_fmt, t, pt, ptlim);
+ pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
+ warnp);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
@@ -242,13 +282,14 @@ label:
}
continue;
case 'T':
- pt = _fmt("%H:%M:%S", t, pt, ptlim);
+ pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
continue;
case 't':
pt = _add("\t", pt, ptlim);
continue;
case 'U':
- pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
+ t->tm_wday) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'u':
@@ -256,9 +297,10 @@ label:
** From Arnold Robbins' strftime version 3.0:
** "ISO 8601: Weekday as a decimal number
** [1 (Monday) - 7]"
- ** (ado, 5/24/93)
+ ** (ado, 1993-05-24)
*/
- pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
+ pt = _conv((t->tm_wday == 0) ?
+ DAYSPERWEEK : t->tm_wday,
"%d", pt, ptlim);
continue;
case 'V': /* ISO 8601 week number */
@@ -340,6 +382,7 @@ label:
pt = _conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
+ *warnp = IN_ALL;
pt = _conv(year % 100, "%02d",
pt, ptlim);
} else pt = _conv(year, "%04d",
@@ -350,26 +393,36 @@ label:
/*
** From Arnold Robbins' strftime version 3.0:
** "date as dd-bbb-YYYY"
- ** (ado, 5/24/93)
+ ** (ado, 1993-05-24)
*/
- pt = _fmt("%e-%b-%Y", t, pt, ptlim);
+ pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
continue;
case 'W':
- pt = _conv((t->tm_yday + 7 -
+ pt = _conv((t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
- (t->tm_wday - 1) : 6)) / 7,
+ (t->tm_wday - 1) :
+ (DAYSPERWEEK - 1))) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
- pt = _fmt(tptr->X_fmt, t, pt, ptlim);
+ pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp);
continue;
case 'x':
- pt = _fmt(tptr->x_fmt, t, pt, ptlim);
+ {
+ int warn2 = IN_SOME;
+
+ pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2);
+ if (warn2 == IN_ALL)
+ warn2 = IN_THIS;
+ if (warn2 > *warnp)
+ *warnp = warn2;
+ }
continue;
case 'y':
+ *warnp = IN_ALL;
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
"%02d", pt, ptlim);
continue;
@@ -378,39 +431,82 @@ label:
pt, ptlim);
continue;
case 'Z':
- if (t->tm_zone != NULL)
- pt = _add(t->tm_zone, pt, ptlim);
+#ifdef TM_ZONE
+ if (t->TM_ZONE != NULL)
+ pt = _add(t->TM_ZONE, pt, ptlim);
else
- if (t->tm_isdst == 0 || t->tm_isdst == 1) {
- pt = _add(tzname[t->tm_isdst],
+#endif /* defined TM_ZONE */
+ if (t->tm_isdst >= 0)
+ pt = _add(tzname[t->tm_isdst != 0],
pt, ptlim);
- } else pt = _add("?", pt, ptlim);
+ /*
+ ** C99 says that %Z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable.
+ */
continue;
case 'z':
{
- long absoff;
- if (t->tm_gmtoff >= 0) {
- absoff = t->tm_gmtoff;
- pt = _add("+", pt, ptlim);
- } else {
- absoff = -t->tm_gmtoff;
- pt = _add("-", pt, ptlim);
- }
- pt = _conv(absoff / 3600, "%02d",
- pt, ptlim);
- pt = _conv((absoff % 3600) / 60, "%02d",
- pt, ptlim);
- };
+ int diff;
+ char const * sign;
+
+ if (t->tm_isdst < 0)
+ continue;
+#ifdef TM_GMTOFF
+ diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+ /*
+ ** C99 says that the UTC offset must
+ ** be computed by looking only at
+ ** tm_isdst. This requirement is
+ ** incorrect, since it means the code
+ ** must rely on magic (in this case
+ ** altzone and timezone), and the
+ ** magic might not have the correct
+ ** offset. Doing things correctly is
+ ** tricky and requires disobeying C99;
+ ** see GNU C strftime for details.
+ ** For now, punt and conform to the
+ ** standard, even though it's incorrect.
+ **
+ ** C99 says that %z must be replaced by the
+ ** empty string if the time zone is not
+ ** determinable, so output nothing if the
+ ** appropriate variables are not available.
+ */
+ if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+ diff = -timezone;
+#else /* !defined USG_COMPAT */
+ continue;
+#endif /* !defined USG_COMPAT */
+ else
+#ifdef ALTZONE
+ diff = -altzone;
+#else /* !defined ALTZONE */
+ continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+ if (diff < 0) {
+ sign = "-";
+ diff = -diff;
+ } else sign = "+";
+ pt = _add(sign, pt, ptlim);
+ diff /= 60;
+ pt = _conv((diff/60)*100 + diff%60,
+ "%04d", pt, ptlim);
+ }
continue;
case '+':
- pt = _fmt(tptr->date_fmt, t, pt, ptlim);
+ pt = _fmt(tptr->date_fmt, t, pt, ptlim,
+ warnp);
continue;
case '%':
/*
- * X311J/88-090 (4.12.3.5): if conversion char is
- * undefined, behavior is undefined. Print out the
- * character itself as printf(3) also does.
- */
+ ** X311J/88-090 (4.12.3.5): if conversion char is
+ ** undefined, behavior is undefined. Print out the
+ ** character itself as printf(3) also does.
+ */
default:
break;
}
@@ -424,10 +520,10 @@ label:
static char *
_conv(n, format, pt, ptlim)
- const int n;
- const char *const format;
- char *const pt;
- const char *const ptlim;
+const int n;
+const char * const format;
+char * const pt;
+const char * const ptlim;
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
@@ -437,9 +533,9 @@ _conv(n, format, pt, ptlim)
static char *
_add(str, pt, ptlim)
- const char *str;
- char *pt;
- const char *const ptlim;
+const char * str;
+char * pt;
+const char * const ptlim;
{
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
OpenPOWER on IntegriCloud