changeset 24312:88b7e8906bff

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.
author Paul Eggert <eggert@cs.ucla.edu>
date Sat, 06 Sep 2003 21:34:07 +0000
parents 068b62985ab0
children eaed0e7d5702
files ChangeLog MODULES.html.sh lib/ChangeLog lib/mktime.c lib/strftime.c lib/time_r.c lib/time_r.h lib/timegm.c lib/timegm.h m4/ChangeLog m4/mktime.m4 m4/time_r.m4 m4/timegm.m4 modules/mktime modules/strftime modules/time_r modules/timegm
diffstat 17 files changed, 299 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Sep 03 19:57:54 2003 +0000
+++ b/ChangeLog	Sat Sep 06 21:34:07 2003 +0000
@@ -1,3 +1,10 @@
+2003-09-06  Paul Eggert  <eggert@twinsun.com>
+
+	* 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  <jas@extundo.com>
 
 	* modules/timegm: New file.
--- a/MODULES.html.sh	Wed Sep 03 19:57:54 2003 +0000
+++ b/MODULES.html.sh	Sat Sep 06 21:34:07 2003 +0000
@@ -1689,6 +1689,7 @@
   func_module readlink
   func_module stat
   func_module lstat
+  func_module time_r
   func_module timespec
   func_module nanosleep
   func_module regex
--- a/lib/ChangeLog	Wed Sep 03 19:57:54 2003 +0000
+++ b/lib/ChangeLog	Sat Sep 06 21:34:07 2003 +0000
@@ -1,3 +1,28 @@
+2003-09-06  Paul Eggert  <eggert@twinsun.com>
+
+	* 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 <time_r.h>.
+	(__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 <time_r.h>.
+
+	* timegm.c: Switch to glibc implementation, with the following changes:
+	[defined HAVE_CONFIG_H]: Include <config.h>.
+	[!defined _LIBC]: Include "timegm.h" rather than <time.h>.
+	(__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 <time.h>" out of #ifdef.
+	(timegm): Declare only if HAVE_DECL_TIMEGM.
+
 2003-09-03  Paul Eggert  <eggert@twinsun.com>
 
 	* human.c (human_readable): Fix bug that rounded 10501 to 10k.
--- a/lib/mktime.c	Wed Sep 03 19:57:54 2003 +0000
+++ b/lib/mktime.c	Sat Sep 06 21:34:07 2003 +0000
@@ -106,22 +106,15 @@
   };
 
 
-#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 @@
    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 @@
   __tzset ();
 #endif
 
-  return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
+  return __mktime_internal (tp, __localtime_r, &localtime_offset);
 }
 
 #ifdef weak_alias
--- a/lib/strftime.c	Wed Sep 03 19:57:54 2003 +0000
+++ b/lib/strftime.c	Sat Sep 06 21:34:07 2003 +0000
@@ -167,44 +167,21 @@
 
 
 #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.  */
+#endif
 
-# 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;
-}
-
-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 @@
 		       occurred.  */
 		    struct tm tm;
 
-		    if (! my_strftime_localtime_r (&lt, &tm)
+		    if (! __localtime_r (&lt, &tm)
 			|| ((ltm.tm_sec ^ tm.tm_sec)
 			    | (ltm.tm_min ^ tm.tm_min)
 			    | (ltm.tm_hour ^ tm.tm_hour)
@@ -1410,7 +1387,7 @@
 		      break;
 		  }
 
-		if (! my_strftime_gmtime_r (&lt, &gtm))
+		if (! __gmtime_r (&lt, &gtm))
 		  break;
 
 		diff = tm_diff (&ltm, &gtm);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/time_r.c	Sat Sep 06 21:34:07 2003 +0000
@@ -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 <config.h>
+#endif
+
+#include "time_r.h"
+
+#include <string.h>
+
+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));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/time_r.h	Sat Sep 06 21:34:07 2003 +0000
@@ -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 <time.h> first, since it may declare these functions with
+   signatures that disagree with POSIX, and we don't want to rename
+   those declarations.  */
+#include <time.h>
+
+#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
--- a/lib/timegm.c	Wed Sep 03 19:57:54 2003 +0000
+++ b/lib/timegm.c	Sat Sep 06 21:34:07 2003 +0000
@@ -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 <config.h>
 #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 <beeman@cisco.com>, with the help of
-   Mark Baushke <mdb@cisco.com> 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 <time.h>
+#else
+# include "timegm.h"
+# include <time_r.h>
+# 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);
 }
--- a/lib/timegm.h	Wed Sep 03 19:57:54 2003 +0000
+++ b/lib/timegm.h	Sat Sep 06 21:34:07 2003 +0000
@@ -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 <time.h>
 
-#else
-
-/* Get time_t and struct tm.  */
-#include <time.h>
-
-/* 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
--- a/m4/ChangeLog	Wed Sep 03 19:57:54 2003 +0000
+++ b/m4/ChangeLog	Sat Sep 06 21:34:07 2003 +0000
@@ -1,3 +1,14 @@
+2003-09-06  Paul Eggert  <eggert@twinsun.com>
+
+	* 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  <jas@extundo.com>
 
 	* timegm.m4: New file.
--- a/m4/mktime.m4	Wed Sep 03 19:57:54 2003 +0000
+++ b/m4/mktime.m4	Sat Sep 06 21:34:07 2003 +0000
@@ -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 @@
 # Prerequisites of lib/mktime.c.
 AC_DEFUN([gl_PREREQ_MKTIME], [
   AC_REQUIRE([AC_HEADER_STDC])
-  AC_CHECK_HEADERS_ONCE(limits.h)
 ])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/time_r.m4	Sat Sep 06 21:34:07 2003 +0000
@@ -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 <time.h>],
+       [/* 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], [
+  :
+])
--- a/m4/timegm.m4	Wed Sep 03 19:57:54 2003 +0000
+++ b/m4/timegm.m4	Sat Sep 06 21:34:07 2003 +0000
@@ -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 @@
 
 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 <time.h>])
 ])
 
 # Prerequisites of lib/timegm.c.
 AC_DEFUN([gl_PREREQ_TIMEGM], [
-  AC_CHECK_DECLS(gmtime_r,,,[
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
+  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
 ])
-  AC_CHECK_FUNCS(gmtime_r)
-])
--- a/modules/mktime	Wed Sep 03 19:57:54 2003 +0000
+++ b/modules/mktime	Sat Sep 06 21:34:07 2003 +0000
@@ -6,6 +6,7 @@
 m4/mktime.m4
 
 Depends-on:
+time_r
 
 configure.ac:
 gl_FUNC_MKTIME
--- a/modules/strftime	Wed Sep 03 19:57:54 2003 +0000
+++ b/modules/strftime	Sat Sep 06 21:34:07 2003 +0000
@@ -8,6 +8,7 @@
 m4/strftime.m4
 
 Depends-on:
+time_r
 tzset
 
 configure.ac:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/time_r	Sat Sep 06 21:34:07 2003 +0000
@@ -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:
+<time_r.h>
+
+Maintainer:
+Paul Eggert
+
--- a/modules/timegm	Wed Sep 03 19:57:54 2003 +0000
+++ b/modules/timegm	Sat Sep 06 21:34:07 2003 +0000
@@ -7,6 +7,8 @@
 m4/timegm.m4
 
 Depends-on:
+mktime
+time_r
 
 configure.ac:
 gl_FUNC_TIMEGM
@@ -18,4 +20,4 @@
 "timegm.h"
 
 Maintainer:
-Simon Josefsson
+all, glibc