diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-03-18 14:14:15 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-04-30 09:02:17 -0700 |
commit | 20aa5819586ac7ad11f711bab64feda307965191 (patch) | |
tree | 81a1ab6c9d471bf99609784cbd3a446c67ef2471 /time/mktime.c | |
parent | 87c266d758d29e52bfb717f90025ef1fe2663d38 (diff) | |
download | glibc-20aa5819586ac7ad11f711bab64feda307965191.zip glibc-20aa5819586ac7ad11f711bab64feda307965191.tar.gz glibc-20aa5819586ac7ad11f711bab64feda307965191.tar.bz2 |
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
Diffstat (limited to 'time/mktime.c')
-rw-r--r-- | time/mktime.c | 71 |
1 files changed, 44 insertions, 27 deletions
diff --git a/time/mktime.c b/time/mktime.c index 57efee9..8fe2f96 100644 --- a/time/mktime.c +++ b/time/mktime.c @@ -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 |