Compare commits

...

5 Commits

Author SHA1 Message Date
Jim Meyering
06d1a87e3b *** empty log message *** 1998-10-18 14:18:22 +00:00
Jim Meyering
f417e8b9d4 . 1998-10-18 14:14:09 +00:00
Jim Meyering
4fb556ee0e Don't invoke localtime_r or gmtime_r unless it's the GNU C
library's localtime_r and gmtime_r; there are too many buggy
	implementations of localtime_r and gmtime_r out there, and
	it's not worth keeping track of all the different bugs.

	* strftime.c (__EXTENSIONS__): Remove.
	(my_strftime_gmtime_r): Renamed from gmtime_r; all uses changed.
	(my_strftime_localtime_r): Renamed from localtime_r; all uses changed.
	Base them on localtime/gmtime if not _LIBC.
1998-10-18 14:09:48 +00:00
Jim Meyering
c850393032 Don't invoke localtime_r or gmtime_r unless it's the GNU C
library's localtime_r and gmtime_r; there are too many buggy
	implementations of localtime_r and gmtime_r out there, and
	it's not worth keeping track of all the different bugs.

	* mktime.c (__EXTENSIONS__, HAVE_LOCALTIME_R): Remove.
	(my_mktime_localtime_r): Renamed from localtime_r; all uses changed.
	Base it on localtime unless _LIBC.
1998-10-18 14:08:35 +00:00
Jim Meyering
61ece919c6 (jm_CHECK_DECL_LOCALTIME_R): Remove macro. 1998-10-18 14:08:09 +00:00
6 changed files with 168 additions and 173 deletions

View File

@@ -1,4 +1,4 @@
/* mktime: convert a `struct tm' to a time_t value zzzzzz
/* mktime: convert a `struct tm' to a time_t value
Copyright (C) 1993-1997, 1998 Free Software Foundation, Inc.
Contributed by Paul Eggert (eggert@twinsun.com).
@@ -28,14 +28,8 @@
# include <config.h>
#endif
/* Some systems need this in order to declare localtime_r properly. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define HAVE_LOCALTIME_R 1
# define STDC_HEADERS 1
#endif
@@ -49,11 +43,6 @@
#include <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
/* Provide a declaration of localtime_r on systems that lack it. */
#if ! defined HAVE_DECL_LOCALTIME_R
extern struct tm* localtime_r ();
#endif
#if HAVE_LIMITS_H
# include <limits.h>
#endif
@@ -130,35 +119,23 @@ time_t __mktime_internal __P ((struct tm *,
#ifdef _LIBC
# define localtime_r __localtime_r
# define my_mktime_localtime_r __localtime_r
#else
# if HAVE_LOCALTIME_R == defined localtime_r
/* Provide our own substitute for a missing or possibly broken localtime_r. */
/* If we're a mktime substitute in a GNU program, then prefer
localtime to localtime_r, since many localtime_r implementations
are buggy. */
static struct tm *my_mktime_localtime_r __P ((const time_t *, struct tm *));
static struct tm *
my_mktime_localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
# ifdef localtime_r
/* Digital Unix 4.0A and 4.0D have a macro localtime_r with the
standard meaning, along with an unwanted, nonstandard function
localtime_r. The placeholder function my_mktime_localtime_r
invokes the macro; use that instead of the system's bogus
localtime_r. */
return localtime_r (t, tp);
# undef localtime_r
# else /* ! defined (localtime_r) */
/* Approximate localtime_r as best we can in its absence. */
struct tm *l = localtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
# endif /* ! defined localtime_r */
}
# define localtime_r my_mktime_localtime_r
# endif /* HAVE_LOCALTIME_R == defined localtime_r */
#endif /* ! _LIBC */
@@ -213,7 +190,7 @@ mktime (tp)
__tzset ();
#endif
return __mktime_internal (tp, localtime_r, &localtime_offset);
return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
}
/* Use CONVERT to convert *T to a broken down time in *TP.
@@ -559,6 +536,6 @@ main (argc, argv)
/*
Local Variables:
compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
End:
*/

View File

@@ -22,11 +22,6 @@
# include <config.h>
#endif
/* Some systems need this in order to declare localtime_r properly. */
#ifndef _REENTRANT
# define _REENTRANT 1
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define HAVE_MBLEN 1
@@ -48,11 +43,6 @@
#include <ctype.h>
#include <sys/types.h> /* Some systems define `time_t' here. */
/* Provide a declaration of localtime_r on systems that lack it. */
#if ! defined HAVE_DECL_LOCALTIME_R
extern struct tm* localtime_r ();
#endif
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
@@ -141,7 +131,7 @@ extern char *tzname[];
add one for integer division truncation;
add one more for a minus sign if t is signed. */
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
#define TM_YEAR_BASE 1900
@@ -154,19 +144,20 @@ extern char *tzname[];
#ifdef _LIBC
# define gmtime_r __gmtime_r
# define localtime_r __localtime_r
# define my_strftime_gmtime_r __gmtime_r
# define my_strftime_localtime_r __localtime_r
# define tzname __tzname
# define tzset __tzset
#else
# if ! HAVE_LOCALTIME_R
# if ! HAVE_TM_GMTOFF
/* Approximate gmtime_r as best we can in its absence. */
# undef gmtime_r
# define gmtime_r my_gmtime_r
static struct tm *gmtime_r __P ((const time_t *, struct tm *));
/* If we're a strftime substitute in a GNU program, then prefer gmtime
to gmtime_r, since many gmtime_r implementations are buggy.
Similarly for localtime_r. */
# if ! HAVE_TM_GMTOFF
static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *));
static struct tm *
gmtime_r (t, tp)
my_strftime_gmtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
@@ -176,14 +167,11 @@ gmtime_r (t, tp)
*tp = *l;
return tp;
}
# endif /* ! HAVE_TM_GMTOFF */
# endif /* ! HAVE_TM_GMTOFF */
/* Approximate localtime_r as best we can in its absence. */
# undef localtime_r
# define localtime_r my_ftime_localtime_r
static struct tm *localtime_r __P ((const time_t *, struct tm *));
static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
static struct tm *
localtime_r (t, tp)
my_strftime_localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
@@ -193,7 +181,6 @@ localtime_r (t, tp)
*tp = *l;
return tp;
}
# endif /* ! HAVE_LOCALTIME_R */
#endif /* ! defined _LIBC */
@@ -381,34 +368,35 @@ static char const month_name[][10] =
#ifdef emacs
# define my_strftime emacs_strftime
/* Emacs 20.2 uses `-Dstrftime=emacs_strftime' when compiling,
because that's how strftime used to be configured.
Undo this, since it gets in the way of accessing the underlying strftime,
which is needed for things like %Ec in Solaris.
The following two lines can be removed once Emacs stops compiling with
`-Dstrftime=emacs_strftime'. */
# undef strftime
size_t strftime __P ((char *, size_t, const char *, const struct tm *));
# define my_strftime emacs_strftimeu
# define ut_argument , ut
# define ut_argument_spec int ut;
# define ut_argument_spec_iso , int ut
#else
# define my_strftime strftime
# define ut_argument
# define ut_argument_spec
# define ut_argument_spec_iso
/* We don't have this information in general. */
# define ut 0
#endif
#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
/* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
Work around this bug by copying *tp before it might be munged. */
size_t _strftime_copytm __P ((char *, size_t, const char *,
const struct tm *));
const struct tm * ut_argument_spec_iso));
size_t
my_strftime (s, maxsize, format, tp)
my_strftime (s, maxsize, format, tp ut_argument)
char *s;
size_t maxsize;
const char *format;
const struct tm *tp;
ut_argument_spec
{
struct tm tmcopy;
tmcopy = *tp;
return _strftime_copytm (s, maxsize, format, &tmcopy);
return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
}
# undef my_strftime
# define my_strftime(S, Maxsize, Format, Tp) \
@@ -423,41 +411,44 @@ size_t strftime __P ((char *, size_t, const char *, const struct tm *));
anywhere, so to determine how many characters would be
written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
size_t
my_strftime (s, maxsize, format, tp)
my_strftime (s, maxsize, format, tp ut_argument)
char *s;
size_t maxsize;
const char *format;
const struct tm *tp;
ut_argument_spec
{
int hour12 = tp->tm_hour;
#ifdef _NL_CURRENT
const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
const char *const ampm = _NL_CURRENT (LC_TIME,
hour12 > 11 ? PM_STR : AM_STR);
size_t aw_len = strlen (a_wkday);
size_t am_len = strlen (a_month);
size_t ap_len = strlen (ampm);
/* We cannot make the following values variables since we must delay
the evaluation of these values until really needed since some
expressions might not be valid in every situation. The `struct tm'
might be generated by a strptime() call that initialized
only a few elements. Dereference the pointers only if the format
requires this. Then it is ok to fail if the pointers are invalid. */
# define a_wkday _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday)
# define f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday)
# define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon)
# define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon)
# define ampm _NL_CURRENT (LC_TIME, tp->tm_hour > 11 ? PM_STR : AM_STR)
# define aw_len strlen (a_wkday)
# define am_len strlen (a_month)
# define ap_len strlen (ampm)
#else
# if !HAVE_STRFTIME
const char *const f_wkday = weekday_name[tp->tm_wday];
const char *const f_month = month_name[tp->tm_mon];
const char *const a_wkday = f_wkday;
const char *const a_month = f_month;
const char *const ampm = "AMPM" + 2 * (hour12 > 11);
# define f_wkday (weekday_name[tp->tm_wday])
# define f_month (month_name[tp->tm_mon])
# define a_wkday f_wkday
# define a_month f_month
# define ampm ("AMPM" + 2 * (tp->tm_hour > 11))
size_t aw_len = 3;
size_t am_len = 3;
size_t ap_len = 2;
# endif
#endif
#if defined _NL_CURRENT || !HAVE_STRFTIME
size_t wkday_len = strlen (f_wkday);
size_t month_len = strlen (f_month);
#endif
const char *zone;
size_t zonelen;
size_t i = 0;
char *p = s;
const char *f;
@@ -473,25 +464,27 @@ my_strftime (s, maxsize, format, tp)
zone = (const char *) tp->tm_zone;
#endif
#if HAVE_TZNAME
/* POSIX.1 8.1.1 requires that whenever strftime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
if (ut)
{
if (! (zone && *zone))
zone = "GMT";
}
else
{
/* POSIX.1 8.1.1 requires that whenever strftime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
# if HAVE_TZSET
tzset ();
tzset ();
# endif
if (!(zone && *zone) && tp->tm_isdst >= 0)
zone = tzname[tp->tm_isdst];
}
#endif
if (! zone)
zone = ""; /* POSIX.2 requires the empty string here. */
zonelen = strlen (zone);
if (hour12 > 12)
hour12 -= 12;
else
if (hour12 == 0) hour12 = 12;
if (hour12 == 0)
hour12 = 12;
for (f = format; *f != '\0'; ++f)
{
@@ -557,7 +550,13 @@ my_strftime (s, maxsize, format, tp)
if (bytes == 0)
break;
if (bytes == (size_t) -2 || bytes == (size_t) -1)
if (bytes == (size_t) -2)
{
len += strlen (f + len);
break;
}
if (bytes == (size_t) -1)
{
len++;
break;
@@ -568,6 +567,7 @@ my_strftime (s, maxsize, format, tp)
while (! mbsinit (&mbstate));
cpy (len, f);
f += len - 1;
continue;
}
}
@@ -677,7 +677,7 @@ my_strftime (s, maxsize, format, tp)
to_lowcase = 0;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (wkday_len, f_wkday);
cpy (strlen (f_wkday), f_wkday);
break;
#else
goto underlying_strftime;
@@ -703,7 +703,7 @@ my_strftime (s, maxsize, format, tp)
to_lowcase = 0;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (month_len, f_month);
cpy (strlen (f_month), f_month);
break;
#else
goto underlying_strftime;
@@ -727,9 +727,7 @@ my_strftime (s, maxsize, format, tp)
subformat:
{
char *old_start = p;
size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
if (len == 0 && *subfmt)
return 0;
size_t len = my_strftime (NULL, (size_t) -1, subfmt, tp);
add (len, my_strftime (p, maxsize - i, subfmt, tp));
if (to_uppcase)
@@ -755,7 +753,6 @@ my_strftime (s, maxsize, format, tp)
*u++ = modifier;
*u++ = format_char;
*u = '\0';
ubuf[0] = '\1';
len = strftime (ubuf, sizeof ubuf, ufmt, tp);
if (len == 0 && ubuf[0] != '\0')
return 0;
@@ -1155,7 +1152,16 @@ my_strftime (s, maxsize, format, tp)
to_uppcase = 0;
to_lowcase = 1;
}
cpy (zonelen, zone);
#if HAVE_TZNAME
/* The tzset() call might have changed the value. */
if (!(zone && *zone) && tp->tm_isdst >= 0)
zone = tzname[tp->tm_isdst];
#endif
if (! zone)
zone = ""; /* POSIX.2 requires the empty string here. */
cpy (strlen (zone), zone);
break;
case 'z': /* GNU extension. */
@@ -1167,34 +1173,39 @@ my_strftime (s, maxsize, format, tp)
#if HAVE_TM_GMTOFF
diff = tp->tm_gmtoff;
#else
struct tm gtm;
struct tm ltm;
time_t lt;
ltm = *tp;
lt = mktime (&ltm);
if (lt == (time_t) -1)
if (ut)
diff = 0;
else
{
/* mktime returns -1 for errors, but -1 is also a
valid time_t value. Check whether an error really
occurred. */
struct tm tm;
localtime_r (&lt, &tm);
struct tm gtm;
struct tm ltm;
time_t lt;
if ((ltm.tm_sec ^ tm.tm_sec)
| (ltm.tm_min ^ tm.tm_min)
| (ltm.tm_hour ^ tm.tm_hour)
| (ltm.tm_mday ^ tm.tm_mday)
| (ltm.tm_mon ^ tm.tm_mon)
| (ltm.tm_year ^ tm.tm_year))
ltm = *tp;
lt = mktime (&ltm);
if (lt == (time_t) -1)
{
/* mktime returns -1 for errors, but -1 is also a
valid time_t value. Check whether an error really
occurred. */
struct tm tm;
if (! my_strftime_localtime_r (&lt, &tm)
|| ((ltm.tm_sec ^ tm.tm_sec)
| (ltm.tm_min ^ tm.tm_min)
| (ltm.tm_hour ^ tm.tm_hour)
| (ltm.tm_mday ^ tm.tm_mday)
| (ltm.tm_mon ^ tm.tm_mon)
| (ltm.tm_year ^ tm.tm_year)))
break;
}
if (! my_strftime_gmtime_r (&lt, &gtm))
break;
diff = tm_diff (&ltm, &gtm);
}
if (! gmtime_r (&lt, &gtm))
break;
diff = tm_diff (&ltm, &gtm);
#endif
if (diff < 0)
@@ -1227,7 +1238,23 @@ my_strftime (s, maxsize, format, tp)
}
}
if (p)
if (p && i < maxsize)
*p = '\0';
return i;
}
#ifdef emacs
/* For Emacs we have a separate interface which corresponds to the normal
strftime function and does not have the extra information whether the
TP arguments comes from a `gmtime' call or not. */
size_t
emacs_strftime (s, maxsize, format, tp)
char *s;
size_t maxsize;
const char *format;
const struct tm *tp;
{
return my_strftime (s, maxsize, format, tp, 0);
}
#endif

View File

@@ -1,3 +1,7 @@
1998-10-18 Jim Meyering <meyering@ascend.com>
* check-decl.m4 (jm_CHECK_DECL_LOCALTIME_R): Remove macro.
1998-10-17 Jim Meyering <meyering@ascend.com>
* decl.m4 (jm_CHECK_DECLARATION): Don't hard-code which headers to

View File

@@ -1,4 +1,4 @@
#serial 3
#serial 4
dnl This is just a wrapper function to encapsulate this kludge.
dnl Putting it in a separate file like this helps share it between
@@ -35,42 +35,4 @@ AC_DEFUN(jm_CHECK_DECLS,
fi
jm_CHECK_DECLARATIONS($headers, free lseek malloc \
memchr realloc stpcpy strstr)
# Check for a declaration of localtime_r.
jm_CHECK_DECL_LOCALTIME_R
])
dnl localtime_r is a special case...
dnl Code that uses the result of this test must use the same cpp
dnl directives as are used below. Also include the following declaration
dnl after the inclusion of time.h.
dnl
dnl #if ! defined HAVE_DECL_LOCALTIME_R
dnl extern struct tm* localtime_r ();
dnl #endif
AC_DEFUN(jm_CHECK_DECL_LOCALTIME_R,
[
if test x = y; then
dnl This code is deliberately never run via ./configure.
dnl FIXME: this is a gross hack to make autoheader put entries
dnl for each of these symbols in the config.h.in.
dnl Otherwise, I'd have to update acconfig.h every time I change
dnl this list of functions.
AC_CHECK_FUNCS(DECL_LOCALTIME_R)
fi
headers='
/* Some systems need this in order to declare localtime_r properly. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <time.h>
'
jm_CHECK_DECLARATIONS($headers, localtime_r)
])

View File

@@ -1,3 +1,26 @@
1998-10-18 Jim Meyering <meyering@ascend.com>
* Version 4.0-b5.
* lib/mktime.c: Update from libc with this additional change from Paul.
* lib/strftime.c: Likewise.
1998-10-17 Paul Eggert <eggert@twinsun.com>
Don't invoke localtime_r or gmtime_r unless it's the GNU C
library's localtime_r and gmtime_r; there are too many buggy
implementations of localtime_r and gmtime_r out there, and
it's not worth keeping track of all the different bugs.
* mktime.c (__EXTENSIONS__, HAVE_LOCALTIME_R): Remove.
(my_mktime_localtime_r): Renamed from localtime_r; all uses changed.
Base it on localtime unless _LIBC.
* strftime.c (__EXTENSIONS__): Remove.
(my_strftime_gmtime_r): Renamed from gmtime_r; all uses changed.
(my_strftime_localtime_r): Renamed from localtime_r; all uses changed.
Base them on localtime/gmtime if not _LIBC.
1998-10-17 Jim Meyering <meyering@ascend.com>
* Version 4.0-b4.

View File

@@ -1,4 +1,6 @@
Changes in release 4.0:
[4.0-b5]
* still *more* mktime.c portability tweaks
[4.0-b4]
* mktime.c portability tweak for headers with GNU libc 5.4.44.
[4.0-b3]