From 7b224479dcac36108cbf435aff9b45767143ed25 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 6 Sep 2003 21:34:07 +0000 Subject: [PATCH] Add time_r module. Change timegm, mktime, and strftime to use localtime_r and gmtime_r, now supplied by the time_r module. This fixes some timegm bugs and cleans up mktime and strftime a bit. --- ChangeLog | 7 +++++ MODULES.html.sh | 1 + lib/ChangeLog | 25 +++++++++++++++ lib/mktime.c | 30 ++++++------------ lib/strftime.c | 51 +++++++++--------------------- lib/time_r.c | 69 +++++++++++++++++++++++++++++++++++++++++ lib/time_r.h | 46 +++++++++++++++++++++++++++ lib/timegm.c | 94 ++++++++++++-------------------------------------------- lib/timegm.h | 16 +++------- m4/ChangeLog | 11 +++++++ m4/mktime.m4 | 3 +- m4/time_r.m4 | 41 ++++++++++++++++++++++++ m4/timegm.m4 | 30 +++++++++++++----- modules/mktime | 1 + modules/strftime | 1 + modules/time_r | 23 ++++++++++++++ modules/timegm | 4 ++- 17 files changed, 299 insertions(+), 154 deletions(-) create mode 100644 lib/time_r.c create mode 100644 lib/time_r.h create mode 100644 m4/time_r.m4 create mode 100644 modules/time_r diff --git a/ChangeLog b/ChangeLog index 714da6711..08fc4da27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-09-06 Paul Eggert + + * MODULES.html.sh (func_all_modules): Add time_r. + * modules/time_r: New file. + * modules/mktime, modules/strftime, modules/timegm: Depend on time_r. + * modules/timegm: Depend on mktime. Change maintainer to "all, glibc". + 2003-08-31 Simon Josefsson * modules/timegm: New file. diff --git a/MODULES.html.sh b/MODULES.html.sh index 5b552b74a..7d586af62 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1689,6 +1689,7 @@ func_all_modules () func_module readlink func_module stat func_module lstat + func_module time_r func_module timespec func_module nanosleep func_module regex diff --git a/lib/ChangeLog b/lib/ChangeLog index 795d1ab3e..25364daa4 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,28 @@ +2003-09-06 Paul Eggert + + * time_r.c, time_r.h: New files. + + * mktime.c (my_mktime_localtime_r): Remove; all uses changed to + __localtime_r. + (__localtime_r) [!defined _LIBC]: New macro. Include . + (__mktime_internal) [!defined _LIBC]: Now extern, not static. + + * strftime.c (my_strftime_gmtime_r): Remove; all uses changed to + __gmtime_r. + (my_strftime_localtime_r): Remove; all uses changed to __localtime_r. + (__gtime_r, __localtime_r) [!HAVE_TM_GMTOFF]: New macros. + Include . + + * timegm.c: Switch to glibc implementation, with the following changes: + [defined HAVE_CONFIG_H]: Include . + [!defined _LIBC]: Include "timegm.h" rather than . + (__mktime_internal) [!defined _LIBC]: New decl. + (__gmtime_r) [!defined _LIBC]: New macro and function. + (timegm): Use a prototype, since gnulib assumes C89. + Do not bother declaring tmp to be const, as it's not really usefu. + * timegm.h: Hoist "#include " out of #ifdef. + (timegm): Declare only if HAVE_DECL_TIMEGM. + 2003-09-03 Paul Eggert * human.c (human_readable): Fix bug that rounded 10501 to 10k. diff --git a/lib/mktime.c b/lib/mktime.c index 02acc5206..5a17eecc6 100644 --- a/lib/mktime.c +++ b/lib/mktime.c @@ -106,22 +106,15 @@ const unsigned short int __mon_yday[2][13] = }; -#ifdef _LIBC -# define my_mktime_localtime_r __localtime_r -#else -/* 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 (const time_t *t, struct tm *tp) -{ - struct tm *l = localtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} -#endif /* ! _LIBC */ +#ifndef _LIBC +/* Portable standalone applications should supply a "time_r.h" that + declares a POSIX-compliant localtime_r, for the benefit of older + implementations that lack localtime_r or have a nonstandard one. + See the gnulib time_r module for one way to implement this. */ +# include "time_r.h" +# undef __localtime_r +# define __localtime_r localtime_r +#endif /* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) - (YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks @@ -244,9 +237,6 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), 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. If *OFFSET's guess is correct, only one CONVERT call is needed. */ -#ifndef _LIBC -static -#endif time_t __mktime_internal (struct tm *tp, struct tm *(*convert) (const time_t *, struct tm *), @@ -486,7 +476,7 @@ mktime (struct tm *tp) __tzset (); #endif - return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset); + return __mktime_internal (tp, __localtime_r, &localtime_offset); } #ifdef weak_alias diff --git a/lib/strftime.c b/lib/strftime.c index 490b099b7..1e026649d 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -167,44 +167,21 @@ extern char *tzname[]; #ifdef _LIBC -# define my_strftime_gmtime_r __gmtime_r -# define my_strftime_localtime_r __localtime_r # define tzname __tzname # define tzset __tzset -#else - -/* 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 * -my_strftime_gmtime_r (t, tp) - const time_t *t; - struct tm *tp; -{ - struct tm *l = gmtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} +#endif -static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *)); -static struct tm * -my_strftime_localtime_r (t, tp) - const time_t *t; - struct tm *tp; -{ - struct tm *l = localtime (t); - if (! l) - return 0; - *tp = *l; - return tp; -} -# endif /* ! HAVE_TM_GMTOFF */ -#endif /* ! defined _LIBC */ +#if !HAVE_TM_GMTOFF +/* Portable standalone applications should supply a "time_r.h" that + declares a POSIX-compliant localtime_r, for the benefit of older + implementations that lack localtime_r or have a nonstandard one. + See the gnulib time_r module for one way to implement this. */ +# include "time_r.h" +# undef __gmtime_r +# undef __localtime_r +# define __gmtime_r gmtime_r +# define __localtime_r localtime_r +#endif #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC @@ -1400,7 +1377,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) occurred. */ struct tm tm; - if (! my_strftime_localtime_r (<, &tm) + if (! __localtime_r (<, &tm) || ((ltm.tm_sec ^ tm.tm_sec) | (ltm.tm_min ^ tm.tm_min) | (ltm.tm_hour ^ tm.tm_hour) @@ -1410,7 +1387,7 @@ my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM) break; } - if (! my_strftime_gmtime_r (<, >m)) + if (! __gmtime_r (<, >m)) break; diff = tm_diff (<m, >m); diff --git a/lib/time_r.c b/lib/time_r.c new file mode 100644 index 000000000..7368f3bdf --- /dev/null +++ b/lib/time_r.c @@ -0,0 +1,69 @@ +/* Reentrant time functions like localtime_r. + + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Eggert. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include "time_r.h" + +#include + +static char * +copy_string_result (char *dest, char const *src) +{ + if (! src) + return 0; + return strcpy (dest, src); +} + +static struct tm * +copy_tm_result (struct tm *dest, struct tm const *src) +{ + if (! src) + return 0; + *dest = *src; + return dest; +} + + +char * +asctime_r (struct tm const * restrict tm, char * restrict buf) +{ + return copy_string_result (buf, asctime (tm)); +} + +char * +ctime_r (time_t const *t, char *buf) +{ + return copy_string_result (buf, ctime (t)); +} + +struct tm * +gmtime_r (time_t const * restrict t, struct tm * restrict tp) +{ + return copy_tm_result (gmtime (t)); +} + +struct tm * +localtime_r (time_t const * restrict t, struct tm * restrict tp) +{ + return copy_tm_result (localtime (t)); +} diff --git a/lib/time_r.h b/lib/time_r.h new file mode 100644 index 000000000..fbd3375e9 --- /dev/null +++ b/lib/time_r.h @@ -0,0 +1,46 @@ +/* Reentrant time functions like localtime_r. + + Copyright (C) 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Eggert. */ + +#ifndef _TIME_R_H +#define _TIME_R_H + +/* Include first, since it may declare these functions with + signatures that disagree with POSIX, and we don't want to rename + those declarations. */ +#include + +#if !HAVE_TIME_R_POSIX +# undef asctime_r +# undef ctime_r +# undef gmtime_r +# undef localtime_r + +# define asctime_r rpl_asctime_r +# define ctime_r rpl_ctime_r +# define gmtime_r rpl_gmtime_r +# define localtime_r rpl_localtime_r + +char *asctime_r (struct tm const * restrict, char * restrict); +char *ctime_r (time_t const *, char *); +struct tm *gmtime_r (time_t const * restrict, struct tm * restrict); +struct tm *localtime_r (time_t const * restrict, struct tm * restrict); +#endif + +#endif diff --git a/lib/timegm.c b/lib/timegm.c index a7b953da5..8072cb467 100644 --- a/lib/timegm.c +++ b/lib/timegm.c @@ -1,6 +1,7 @@ -/* Convert calendar time to simple time, inverse of mktime. - Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003 - Free Software Foundation, Inc. +/* Convert UTC calendar time to simple time. Like mktime but assumes UTC. + + Copyright (C) 1994, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,81 +17,26 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H # include #endif -/* Specification. Get mktime and gmtime declarations. */ -#include "timegm.h" - -/* Converts struct tm to time_t, assuming the data in tm is UTC rather - than local timezone. - - mktime is similar but assumes struct tm, also known as the - "broken-down" form of time, is in local time zone. mktime_from_utc - uses mktime to make the conversion understanding that an offset - will be introduced by the local time assumption. - - mktime_from_utc then measures the introduced offset by applying - gmtime to the initial result and applying mktime to the resulting - "broken-down" form. The difference between the two mktime results - is the measured offset which is then subtracted from the initial - mktime result to yield a calendar time which is the value returned. - - tm_isdst in struct tm is set to 0 to force mktime to introduce a - consistent offset (the non DST offset) since tm and tm+o might be - on opposite sides of a DST change. - - Some implementations of mktime return -1 for the nonexistent - localtime hour at the beginning of DST. In this event, use - mktime(tm - 1hr) + 3600. - - Schematically - mktime(tm) --> t+o - gmtime(t+o) --> tm+o - mktime(tm+o) --> t+2o - t+o - (t+2o - t+o) = t - - Note that glibc contains a function of the same purpose named - `timegm' (reverse of gmtime). But obviously, it is not universally - available, and unfortunately it is not straightforwardly - extractable for use here. Perhaps configure should detect timegm - and use it where available. - - Contributed by Roger Beeman , with the help of - Mark Baushke and the rest of the Gurus at CISCO. - Further improved by Roger with assistance from Edward J. Sabol - based on input by Jamie Zawinski. */ +#ifdef _LIBC +# include +#else +# include "timegm.h" +# include +# undef __gmtime_r +# define __gmtime_r gmtime_r +time_t __mktime_internal (struct tm *, + struct tm * (*) (time_t const *, struct tm *), + time_t *); +#endif time_t -timegm (struct tm *tm) +timegm (struct tm *tmp) { - time_t tl, tb; - struct tm *tg; - - tl = mktime (tm); - if (tl == (time_t) -1) - { - tm->tm_hour--; - tl = mktime (tm); - if (tl == (time_t) -1) - return (time_t) -1; - tl += 3600; - } -#if HAVE_GMTIME_R && HAVE_DECL_GMTIME_R - tg = gmtime_r (&tl, tg); -#else - tg = gmtime (&tl); -#endif - tg->tm_isdst = 0; - tb = mktime (tg); - if (tb == (time_t) -1) - { - tg->tm_hour--; - tb = mktime (tg); - if (tb == (time_t) -1) - return (time_t) -1; - tb += 3600; - } - return (tl - (tb - tl)); + static time_t gmtime_offset; + tmp->tm_isdst = 0; + return __mktime_internal (tmp, __gmtime_r, &gmtime_offset); } diff --git a/lib/timegm.h b/lib/timegm.h index 18df9813e..4d30b211f 100644 --- a/lib/timegm.h +++ b/lib/timegm.h @@ -1,4 +1,5 @@ -/* Convert calendar time to simple time, inverse of mktime. +/* Convert UTC calendar time to simple time. Like mktime but assumes UTC. + Copyright (C) 2003 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify @@ -15,17 +16,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifdef HAVE_TIMEGM - -/* Get timegm declaration. */ -#include - -#else - -/* Get time_t and struct tm. */ #include -/* Convert calendar time to simple time, inverse of mktime. */ -extern time_t timegm (struct tm *tm); - +#ifndef HAVE_DECL_TIMEGM +time_t timegm (struct tm *tm); #endif diff --git a/m4/ChangeLog b/m4/ChangeLog index 1e3ac030d..66f077223 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,14 @@ +2003-09-06 Paul Eggert + + * time_4.m4: New file. + * mktime.m4 (gl_PREREQ_MKTIME): Remove check for limits.h. + * timegm.m4 (gl_FUNC_TIMEGM): Assume that timegm is buggy if mktime is. + Check for timegm declaration. + (gl_PREREQ_TIMEGM): Require gl_FUNC_MKTIME. + Do not check for gmtime_r. + Replace mktime if __mktime_internal does not exist and if mktime + hasn't been replaced already. + 2003-08-31 Simon Josefsson * timegm.m4: New file. diff --git a/m4/mktime.m4 b/m4/mktime.m4 index 2131cff4f..739757b6a 100644 --- a/m4/mktime.m4 +++ b/m4/mktime.m4 @@ -1,4 +1,4 @@ -# mktime.m4 serial 2 +# mktime.m4 serial 3 dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General @@ -201,5 +201,4 @@ AC_DEFUN([gl_FUNC_MKTIME], # Prerequisites of lib/mktime.c. AC_DEFUN([gl_PREREQ_MKTIME], [ AC_REQUIRE([AC_HEADER_STDC]) - AC_CHECK_HEADERS_ONCE(limits.h) ]) diff --git a/m4/time_r.m4 b/m4/time_r.m4 new file mode 100644 index 000000000..5f5369871 --- /dev/null +++ b/m4/time_r.m4 @@ -0,0 +1,41 @@ +dnl Reentrant time functions like localtime_r. + +dnl Copyright (C) 2003 Free Software Foundation, Inc. + +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl Written by Paul Eggert. + +AC_DEFUN([gl_TIME_R], +[ + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([gl_C_RESTRICT]) + + AC_CACHE_CHECK([whether localtime_r is compatible with its POSIX signature], + [gl_cv_time_r_posix], + [AC_TRY_COMPILE( + [#include ], + [/* We don't need to append 'restrict's to the argument types, + even though the POSIX signature has the 'restrict's, + since C99 says they can't affect type compatibility. */ + struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;], + [gl_cv_time_r_posix=yes], + [gl_cv_time_r_posix=no])]) + if test $gl_cv_time_r_posix = yes; then + AC_DEFINE([HAVE_TIME_R_POSIX], 1, + [Define to 1 if localtime_r, etc. have the type signatures that + POSIX requires.]) + else + AC_LIBOBJ([time_r]) + gl_PREREQ_TIME_R + fi +]) + +# Prerequisites of lib/time_r.c. +AC_DEFUN([gl_PREREQ_TIME_R], [ + : +]) diff --git a/m4/timegm.m4 b/m4/timegm.m4 index a0ba0e3a8..94305aefa 100644 --- a/m4/timegm.m4 +++ b/m4/timegm.m4 @@ -1,4 +1,4 @@ -# timegm.m4 serial 1 +# timegm.m4 serial 2 dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General @@ -8,18 +8,32 @@ dnl the same distribution terms as the rest of that program. AC_DEFUN([gl_FUNC_TIMEGM], [ - AC_REPLACE_FUNCS(timegm) + AC_REQUIRE([gl_FUNC_MKTIME]) + if test $ac_cv_func_working_mktime = no; then + # Assume that timegm is buggy if mktime is. + AC_LIBOBJ([timegm]) + ac_cv_func_timegm=no + else + AC_REPLACE_FUNCS(timegm) + fi if test $ac_cv_func_timegm = no; then gl_PREREQ_TIMEGM fi + + AC_CHECK_DECLS([timegm], , , [#include ]) ]) # Prerequisites of lib/timegm.c. AC_DEFUN([gl_PREREQ_TIMEGM], [ - AC_CHECK_DECLS(gmtime_r,,,[ -#ifdef HAVE_TIME_H -#include -#endif -]) - AC_CHECK_FUNCS(gmtime_r) + AC_REQUIRE([gl_TIME_R]) + AC_REQUIRE([gl_FUNC_MKTIME]) + if test $ac_cv_func_working_mktime = yes; then + AC_CHECK_FUNC(__mktime_internal, , + [# mktime works but it doesn't export __mktime_internal, + # so we need to substitute our own mktime implementation. + AC_LIBOBJ([mktime]) + AC_DEFINE([mktime], [rpl_mktime], + [Define to rpl_mktime if the replacement function should be used.]) + gl_PREREQ_MKTIME]) + fi ]) diff --git a/modules/mktime b/modules/mktime index 4e8b77344..13973fc83 100644 --- a/modules/mktime +++ b/modules/mktime @@ -6,6 +6,7 @@ lib/mktime.c m4/mktime.m4 Depends-on: +time_r configure.ac: gl_FUNC_MKTIME diff --git a/modules/strftime b/modules/strftime index 4d2d9f952..fe1b391d5 100644 --- a/modules/strftime +++ b/modules/strftime @@ -8,6 +8,7 @@ m4/tm_gmtoff.m4 m4/strftime.m4 Depends-on: +time_r tzset configure.ac: diff --git a/modules/time_r b/modules/time_r new file mode 100644 index 000000000..958f1ca8b --- /dev/null +++ b/modules/time_r @@ -0,0 +1,23 @@ +Description: +Reentrant time functions like localtime_r. + +Files: +lib/time_r.c +lib/time_r.h +m4/time_r.m4 + +Depends-on: +extensions + +configure.ac: +gl_TIME_R + +Makefile.am: +lib_SOURCES += time_r.h + +Include: + + +Maintainer: +Paul Eggert + diff --git a/modules/timegm b/modules/timegm index 34002c4cf..e841a5512 100644 --- a/modules/timegm +++ b/modules/timegm @@ -7,6 +7,8 @@ lib/timegm.c m4/timegm.m4 Depends-on: +mktime +time_r configure.ac: gl_FUNC_TIMEGM @@ -18,4 +20,4 @@ Include: "timegm.h" Maintainer: -Simon Josefsson +all, glibc -- 2.11.0