Make mktime etc. compatible with __time64_t
Keep these functions compatible with Gnulib while adding __time64_t support. The basic idea is to move private API declarations from include/time.h to time/mktime-internal.h, since the former file cannot easily be shared with Gnulib whereas the latter can. Also, do some other minor cleanup while in the neighborhood. * include/time.h: Include stdbool.h, time/mktime-internal.h. (__mktime_internal): Move this prototype to time/mktime-internal.h, since Gnulib needs it. (__localtime64_r, __gmtime64_r) [__TIMESIZE == 64]: Move these macros to time/mktime-internal.h, since Gnulib needs them. (__mktime64, __timegm64) [__TIMESIZE != 64]: New prototypes. (in_time_t_range): New static function. * posix/bits/types.h (__time64_t) [__TIMESIZE == 64 && !defined __LIBC]: Do not define as a macro in this case, so that portable code is less tempted to use __time64_t. * time/mktime-internal.h: Rewrite so that it does both glibc and Gnulib work. Include time.h if not _LIBC. (mktime_offset_t) [!_LIBC]: Define for gnulib. (__time64_t, __gmtime64_r, __localtime64_r, __mktime64, __timegm64) [!_LIBC || __TIMESIZE == 64]: New macros, mostly moved here from include/time.h. (__gmtime_r, __localtime_r, __mktime_internal) [!_LIBC]: New macros, taken from GNulib. (__mktime_internal): New prototype, moved here from include/time.h. * time/mktime.c (mktime_min, mktime_max, convert_time) (ranged_convert, __mktime_internal, __mktime64): * time/timegm.c (__timegm64): Use __time64_t, not time_t. * time/mktime.c: Stop worrying about whether time_t is floating-point. (__mktime64) [! (_LIBC && __TIMESIZE != 64)]: Rename from mktime. (mktime) [_LIBC && __TIMESIZE != 64]: New function. * time/timegm.c [!_LIBC]: Include libc-config.h, not config.h, for libc_hidden_def. Include errno.h. (__timegm64) [! (_LIBC && __TIMESIZE != 64)]: Rename from timegm. (timegm) [_LIBC && __TIMESIZE != 64]: New function. First cut at publicizing __time64_t
This commit is contained in:
parent
87c266d758
commit
20aa581958
44
ChangeLog
44
ChangeLog
@ -1,3 +1,47 @@
|
||||
2019-04-30 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Make mktime etc. compatible with __time64_t
|
||||
Keep these functions compatible with Gnulib while adding
|
||||
__time64_t support. The basic idea is to move private API
|
||||
declarations from include/time.h to time/mktime-internal.h, since
|
||||
the former file cannot easily be shared with Gnulib whereas the
|
||||
latter can.
|
||||
Also, do some other minor cleanup while in the neighborhood.
|
||||
* include/time.h: Include stdbool.h, time/mktime-internal.h.
|
||||
(__mktime_internal): Move this prototype to time/mktime-internal.h,
|
||||
since Gnulib needs it.
|
||||
(__localtime64_r, __gmtime64_r) [__TIMESIZE == 64]:
|
||||
Move these macros to time/mktime-internal.h, since Gnulib needs them.
|
||||
(__mktime64, __timegm64) [__TIMESIZE != 64]: New prototypes.
|
||||
(in_time_t_range): New static function.
|
||||
* posix/bits/types.h (__time64_t): Move to time/mktime-internal.h,
|
||||
so that glibc users are not tempted to use __time64_t.
|
||||
* time/mktime-internal.h: Rewrite so that it does both glibc
|
||||
and Gnulib work. Include time.h if not _LIBC.
|
||||
(mktime_offset_t) [!_LIBC]: Define for gnulib.
|
||||
(__time64_t): New type or macro, moved here from
|
||||
posix/bits/types.h.
|
||||
(__gmtime64_r, __localtime64_r, __mktime64, __timegm64)
|
||||
[!_LIBC || __TIMESIZE == 64): New macros, mostly moved here
|
||||
from include/time.h.
|
||||
(__gmtime_r, __localtime_r, __mktime_internal) [!_LIBC]:
|
||||
New macros, taken from GNulib.
|
||||
(__mktime_internal): New prototype, moved here from include/time.h.
|
||||
* time/mktime.c (mktime_min, mktime_max, convert_time)
|
||||
(ranged_convert, __mktime_internal, __mktime64):
|
||||
* time/timegm.c (__timegm64):
|
||||
Use __time64_t, not time_t.
|
||||
* time/mktime.c: Stop worrying about whether time_t is floating-point.
|
||||
(__mktime64) [! (_LIBC && __TIMESIZE != 64)]:
|
||||
Rename from mktime.
|
||||
(mktime) [_LIBC && __TIMESIZE != 64]: New function.
|
||||
* time/timegm.c [!_LIBC]: Include libc-config.h, not config.h,
|
||||
for libc_hidden_def.
|
||||
Include errno.h.
|
||||
(__timegm64) [! (_LIBC && __TIMESIZE != 64)]:
|
||||
Rename from timegm.
|
||||
(timegm) [_LIBC && __TIMESIZE != 64]: New function.
|
||||
|
||||
2019-04-30 Maciej W. Rozycki <macro@wdc.com>
|
||||
|
||||
[BZ #19444]
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#ifndef _ISOMAC
|
||||
# include <bits/types/locale_t.h>
|
||||
# include <stdbool.h>
|
||||
# include <time/mktime-internal.h>
|
||||
|
||||
extern __typeof (strftime_l) __strftime_l;
|
||||
libc_hidden_proto (__strftime_l)
|
||||
@ -49,19 +51,11 @@ extern void __tzset_parse_tz (const char *tz) attribute_hidden;
|
||||
extern void __tz_compute (__time64_t timer, struct tm *tm, int use_localtime)
|
||||
__THROW attribute_hidden;
|
||||
|
||||
/* Subroutine of `mktime'. Return the `time_t' representation of TP and
|
||||
normalize TP, given that a `struct tm *' maps to a `time_t' as performed
|
||||
by FUNC. Record next guess for localtime-gmtime offset in *OFFSET. */
|
||||
extern time_t __mktime_internal (struct tm *__tp,
|
||||
struct tm *(*__func) (const time_t *,
|
||||
struct tm *),
|
||||
long int *__offset) attribute_hidden;
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
# define __ctime64 ctime
|
||||
#else
|
||||
extern char *__ctime64 (const __time64_t *__timer) __THROW;
|
||||
libc_hidden_proto (__ctime64);
|
||||
libc_hidden_proto (__ctime64)
|
||||
#endif
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
@ -69,7 +63,7 @@ libc_hidden_proto (__ctime64);
|
||||
#else
|
||||
extern char *__ctime64_r (const __time64_t *__restrict __timer,
|
||||
char *__restrict __buf) __THROW;
|
||||
libc_hidden_proto (__ctime64_r);
|
||||
libc_hidden_proto (__ctime64_r)
|
||||
#endif
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
@ -81,13 +75,13 @@ libc_hidden_proto (__localtime64)
|
||||
|
||||
extern struct tm *__localtime_r (const time_t *__timer,
|
||||
struct tm *__tp) attribute_hidden;
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
# define __localtime64_r __localtime_r
|
||||
#else
|
||||
#if __TIMESIZE != 64
|
||||
extern struct tm *__localtime64_r (const __time64_t *__timer,
|
||||
struct tm *__tp);
|
||||
libc_hidden_proto (__localtime64_r)
|
||||
|
||||
extern __time64_t __mktime64 (struct tm *__tp) __THROW;
|
||||
libc_hidden_proto (__mktime64)
|
||||
#endif
|
||||
|
||||
extern struct tm *__gmtime_r (const time_t *__restrict __timer,
|
||||
@ -99,14 +93,13 @@ libc_hidden_proto (__gmtime_r)
|
||||
#else
|
||||
extern struct tm *__gmtime64 (const __time64_t *__timer);
|
||||
libc_hidden_proto (__gmtime64)
|
||||
#endif
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
# define __gmtime64_r __gmtime_r
|
||||
#else
|
||||
extern struct tm *__gmtime64_r (const __time64_t *__restrict __timer,
|
||||
struct tm *__restrict __tp);
|
||||
libc_hidden_proto (__gmtime64_r);
|
||||
libc_hidden_proto (__gmtime64_r)
|
||||
|
||||
extern __time64_t __timegm64 (struct tm *__tp) __THROW;
|
||||
libc_hidden_proto (__timegm64)
|
||||
#endif
|
||||
|
||||
/* Compute the `struct tm' representation of T,
|
||||
@ -155,5 +148,13 @@ extern double __difftime (time_t time1, time_t time0);
|
||||
actual clock ID. */
|
||||
#define CLOCK_IDFIELD_SIZE 3
|
||||
|
||||
/* Check whether T fits in time_t. */
|
||||
static inline bool
|
||||
in_time_t_range (__time64_t t)
|
||||
{
|
||||
time_t s = t;
|
||||
return s == t;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -213,10 +213,13 @@ __STD_TYPE __U32_TYPE __socklen_t;
|
||||
It is not currently necessary for this to be machine-specific. */
|
||||
typedef int __sig_atomic_t;
|
||||
|
||||
#if __TIMESIZE == 64
|
||||
/* Seconds since the Epoch, visible to user code when time_t is too
|
||||
narrow only for consistency with the old way of widening too-narrow
|
||||
types. User code should never use __time64_t. */
|
||||
#if __TIMESIZE == 64 && defined __LIBC
|
||||
# define __time64_t __time_t
|
||||
#else
|
||||
__STD_TYPE __TIME64_T_TYPE __time64_t; /* Seconds since the Epoch. */
|
||||
#elif __TIMESIZE != 64
|
||||
__STD_TYPE __TIME64_T_TYPE __time64_t;
|
||||
#endif
|
||||
|
||||
#undef __STD_TYPE
|
||||
|
@ -1,2 +1,79 @@
|
||||
/* Gnulib mktime-internal.h, tailored for glibc. */
|
||||
/* Internals of mktime and related functions
|
||||
Copyright 2016-2019 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Paul Eggert <eggert@cs.ucla.edu>.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _LIBC
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
/* mktime_offset_t is a signed type wide enough to hold a UTC offset
|
||||
in seconds, and used as part of the type of the offset-guess
|
||||
argument to mktime_internal. In Glibc, it is always long int.
|
||||
When in Gnulib, use time_t on platforms where time_t
|
||||
is signed, to be compatible with platforms like BeOS that export
|
||||
this implementation detail of mktime. On platforms where time_t is
|
||||
unsigned, GNU and POSIX code can assume 'int' is at least 32 bits
|
||||
which is wide enough for a UTC offset. */
|
||||
#ifdef _LIBC
|
||||
typedef long int mktime_offset_t;
|
||||
#elif defined TIME_T_IS_SIGNED
|
||||
typedef time_t mktime_offset_t;
|
||||
#else
|
||||
typedef int mktime_offset_t;
|
||||
#endif
|
||||
|
||||
/* The source code uses identifiers like __time64_t for glibc
|
||||
timestamps that can contain 64-bit values even when time_t is only
|
||||
32 bits. These are just macros for the ordinary identifiers unless
|
||||
compiling within glibc when time_t is 32 bits. */
|
||||
#if ! (defined _LIBC && __TIMESIZE != 64)
|
||||
# undef __time64_t
|
||||
# define __time64_t time_t
|
||||
# define __gmtime64_r __gmtime_r
|
||||
# define __localtime64_r __localtime_r
|
||||
# define __mktime64 mktime
|
||||
# define __timegm64 timegm
|
||||
#endif
|
||||
|
||||
#ifndef _LIBC
|
||||
|
||||
/* Although glibc source code uses leading underscores, Gnulib wants
|
||||
ordinary names.
|
||||
|
||||
Portable standalone applications should supply a <time.h> that
|
||||
declares a POSIX-compliant localtime_r, for the benefit of older
|
||||
implementations that lack localtime_r or have a nonstandard one.
|
||||
Similarly for gmtime_r. See the gnulib time_r module for one way
|
||||
to implement this. */
|
||||
|
||||
# undef __gmtime_r
|
||||
# undef __localtime_r
|
||||
# define __gmtime_r gmtime_r
|
||||
# define __localtime_r localtime_r
|
||||
|
||||
# define __mktime_internal mktime_internal
|
||||
|
||||
#endif
|
||||
|
||||
/* Subroutine of mktime. Return the time_t representation of TP and
|
||||
normalize TP, given that a struct tm * maps to a time_t as performed
|
||||
by FUNC. Record next guess for localtime-gmtime offset in *OFFSET. */
|
||||
extern __time64_t __mktime_internal (struct tm *tp,
|
||||
struct tm *(*func) (__time64_t const *,
|
||||
struct tm *),
|
||||
mktime_offset_t *offset) attribute_hidden;
|
||||
|
@ -112,11 +112,11 @@ my_tzset (void)
|
||||
added to them, and then with another timestamp added, without
|
||||
worrying about overflow.
|
||||
|
||||
Much of the code uses long_int to represent time_t values, to
|
||||
lessen the hassle of dealing with platforms where time_t is
|
||||
Much of the code uses long_int to represent __time64_t values, to
|
||||
lessen the hassle of dealing with platforms where __time64_t is
|
||||
unsigned, and because long_int should suffice to represent all
|
||||
time_t values that mktime can generate even on platforms where
|
||||
time_t is excessively wide. */
|
||||
__time64_t values that mktime can generate even on platforms where
|
||||
__time64_t is wider than the int components of struct tm. */
|
||||
|
||||
#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
|
||||
typedef long int long_int;
|
||||
@ -144,16 +144,15 @@ shr (long_int a, int b)
|
||||
: a / (one << b) - (a % (one << b) < 0));
|
||||
}
|
||||
|
||||
/* Bounds for the intersection of time_t and long_int. */
|
||||
/* Bounds for the intersection of __time64_t and long_int. */
|
||||
|
||||
static long_int const mktime_min
|
||||
= ((TYPE_SIGNED (time_t) && TYPE_MINIMUM (time_t) < TYPE_MINIMUM (long_int))
|
||||
? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (time_t));
|
||||
= ((TYPE_SIGNED (__time64_t)
|
||||
&& TYPE_MINIMUM (__time64_t) < TYPE_MINIMUM (long_int))
|
||||
? TYPE_MINIMUM (long_int) : TYPE_MINIMUM (__time64_t));
|
||||
static long_int const mktime_max
|
||||
= (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (time_t)
|
||||
? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (time_t));
|
||||
|
||||
verify (TYPE_IS_INTEGER (time_t));
|
||||
= (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t)
|
||||
? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t));
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define TM_YEAR_BASE 1900
|
||||
@ -252,23 +251,23 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec,
|
||||
}
|
||||
|
||||
/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
|
||||
range for time_t. Return TM if successful, NULL (setting errno) on
|
||||
range for __time64_t. Return TM if successful, NULL (setting errno) on
|
||||
failure. */
|
||||
static struct tm *
|
||||
convert_time (struct tm *(*convert) (const time_t *, struct tm *),
|
||||
convert_time (struct tm *(*convert) (const __time64_t *, struct tm *),
|
||||
long_int t, struct tm *tm)
|
||||
{
|
||||
time_t x = t;
|
||||
__time64_t x = t;
|
||||
return convert (&x, tm);
|
||||
}
|
||||
|
||||
/* Use CONVERT to convert *T to a broken down time in *TP.
|
||||
If *T is out of range for conversion, adjust it so that
|
||||
it is the nearest in-range value and then convert that.
|
||||
A value is in range if it fits in both time_t and long_int.
|
||||
A value is in range if it fits in both __time64_t and long_int.
|
||||
Return TP on success, NULL (setting errno) on failure. */
|
||||
static struct tm *
|
||||
ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
|
||||
ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
|
||||
long_int *t, struct tm *tp)
|
||||
{
|
||||
long_int t1 = (*t < mktime_min ? mktime_min
|
||||
@ -310,7 +309,7 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
|
||||
}
|
||||
|
||||
|
||||
/* Convert *TP to a time_t value, inverting
|
||||
/* Convert *TP to a __time64_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
@ -318,9 +317,9 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
|
||||
If successful, set *TP to the canonicalized struct tm;
|
||||
otherwise leave *TP alone, return ((time_t) -1) and set errno.
|
||||
This function is external because it is used also by timegm.c. */
|
||||
time_t
|
||||
__time64_t
|
||||
__mktime_internal (struct tm *tp,
|
||||
struct tm *(*convert) (const time_t *, struct tm *),
|
||||
struct tm *(*convert) (const __time64_t *, struct tm *),
|
||||
mktime_offset_t *offset)
|
||||
{
|
||||
struct tm tm;
|
||||
@ -520,9 +519,9 @@ __mktime_internal (struct tm *tp,
|
||||
|
||||
#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS
|
||||
|
||||
/* Convert *TP to a time_t value. */
|
||||
time_t
|
||||
mktime (struct tm *tp)
|
||||
/* Convert *TP to a __time64_t value. */
|
||||
__time64_t
|
||||
__mktime64 (struct tm *tp)
|
||||
{
|
||||
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
|
||||
time zone names contained in the external variable 'tzname' shall
|
||||
@ -531,7 +530,7 @@ mktime (struct tm *tp)
|
||||
|
||||
# if defined _LIBC || NEED_MKTIME_WORKING
|
||||
static mktime_offset_t localtime_offset;
|
||||
return __mktime_internal (tp, __localtime_r, &localtime_offset);
|
||||
return __mktime_internal (tp, __localtime64_r, &localtime_offset);
|
||||
# else
|
||||
# undef mktime
|
||||
return mktime (tp);
|
||||
@ -539,11 +538,29 @@ mktime (struct tm *tp)
|
||||
}
|
||||
#endif /* _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS */
|
||||
|
||||
#ifdef weak_alias
|
||||
weak_alias (mktime, timelocal)
|
||||
#if defined _LIBC && __TIMESIZE != 64
|
||||
|
||||
libc_hidden_def (__mktime64)
|
||||
|
||||
time_t
|
||||
mktime (struct tm *tp)
|
||||
{
|
||||
struct tm tm = *tp;
|
||||
__time64_t t = __mktime64 (&tm);
|
||||
if (in_time_t_range (t))
|
||||
{
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
else
|
||||
{
|
||||
__set_errno (EOVERFLOW);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
weak_alias (mktime, timelocal)
|
||||
libc_hidden_def (mktime)
|
||||
libc_hidden_weak (timelocal)
|
||||
#endif
|
||||
|
@ -18,17 +18,41 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _LIBC
|
||||
# include <config.h>
|
||||
# include <libc-config.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mktime-internal.h"
|
||||
|
||||
__time64_t
|
||||
__timegm64 (struct tm *tmp)
|
||||
{
|
||||
static mktime_offset_t gmtime_offset;
|
||||
tmp->tm_isdst = 0;
|
||||
return __mktime_internal (tmp, __gmtime64_r, &gmtime_offset);
|
||||
}
|
||||
|
||||
#if defined _LIBC && __TIMESIZE != 64
|
||||
|
||||
libc_hidden_def (__timegm64)
|
||||
|
||||
time_t
|
||||
timegm (struct tm *tmp)
|
||||
{
|
||||
static mktime_offset_t gmtime_offset;
|
||||
tmp->tm_isdst = 0;
|
||||
return __mktime_internal (tmp, __gmtime_r, &gmtime_offset);
|
||||
struct tm tm = *tmp;
|
||||
__time64_t t = __timegm64 (&tm);
|
||||
if (in_time_t_range (t))
|
||||
{
|
||||
*tmp = tm;
|
||||
return t;
|
||||
}
|
||||
else
|
||||
{
|
||||
__set_errno (EOVERFLOW);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user