> * Some which should obey TZ, just that they should ignore the values set by > Cygwin (instead of exhibiting garbage behaviour): > > ctime, _ctime*, _wctime* > https://msdn.microsoft.com/en-us/library/59w5xcdy.aspx > http://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html
This patch implements it. 2017-04-30 Bruno Haible <br...@clisp.org> ctime: New module. * lib/time.in.h (ctime): New declaration. * lib/ctime.c: New file. * m4/ctime.m4: New file. * m4/time_h.m4 (gl_HEADER_TIME_H_DEFAULTS): Initialize GNULIB_CTIME, REPLACE_CTIME. * modules/time (Makefile.am): Substitute GNULIB_CTIME, REPLACE_CTIME. * modules/ctime: New file. * doc/posix-functions/ctime.texi: Mention the new module. diff --git a/doc/posix-functions/ctime.texi b/doc/posix-functions/ctime.texi index e54a7b5..6abc4c4 100644 --- a/doc/posix-functions/ctime.texi +++ b/doc/posix-functions/ctime.texi @@ -4,18 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/ctime.html} -Gnulib module: --- +Gnulib module: ctime Portability problems fixed by Gnulib: @itemize +@item +On native Windows platforms (mingw, MSVC), this function works incorrectly +when the environment variable @code{TZ} has been set by Cygwin. @end itemize Portability problems not fixed by Gnulib: @itemize @item -On native Windows platforms (mingw, MSVC), this function works incorrectly -when the environment variable @code{TZ} has been set by Cygwin. -@item This function may overflow its internal buffer if an invalid year is passed. @item The @code{ctime} function need not be reentrant, and consequently is diff --git a/lib/ctime.c b/lib/ctime.c new file mode 100644 index 0000000..16416ab --- /dev/null +++ b/lib/ctime.c @@ -0,0 +1,40 @@ +/* Work around platform bugs in ctime. + Copyright (C) 2017 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <time.h> + +#include <stdlib.h> +#include <string.h> + +#undef ctime + +char * +rpl_ctime (const time_t *tp) +{ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* If the environment variable TZ has been set by Cygwin, neutralize it. + The Microsoft CRT interprets TZ differently than Cygwin and produces + incorrect results if TZ has the syntax used by Cygwin. */ + const char *tz = getenv ("TZ"); + if (tz != NULL && strchr (tz, '/') != NULL) + _putenv ("TZ="); +#endif + + return ctime (tp); +} diff --git a/lib/time.in.h b/lib/time.in.h index 86436c2..47087d8 100644 --- a/lib/time.in.h +++ b/lib/time.in.h @@ -233,6 +233,22 @@ _GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf, _GL_CXXALIASWARN (strptime); # endif +/* Convert *TP to a date and time string. See + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html>. */ +# if @GNULIB_CTIME@ +# if @REPLACE_CTIME@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define ctime rpl_ctime +# endif +_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp)); +# else +_GL_CXXALIAS_SYS (ctime, char *, (time_t const *__tp)); +# endif +_GL_CXXALIASWARN (ctime); +# endif + # if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@ typedef struct tm_zone *timezone_t; _GL_FUNCDECL_SYS (tzalloc, timezone_t, (char const *__name)); diff --git a/m4/ctime.m4 b/m4/ctime.m4 new file mode 100644 index 0000000..2d4b3f8 --- /dev/null +++ b/m4/ctime.m4 @@ -0,0 +1,15 @@ +# ctime.m4 serial 1 +dnl Copyright (C) 2017 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_CTIME], +[ + AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + mingw*) REPLACE_CTIME=1 ;; + *) REPLACE_CTIME=0 ;; + esac +]) diff --git a/m4/time_h.m4 b/m4/time_h.m4 index b925678..fdd819b 100644 --- a/m4/time_h.m4 +++ b/m4/time_h.m4 @@ -2,7 +2,7 @@ # Copyright (C) 2000-2001, 2003-2007, 2009-2017 Free Software Foundation, Inc. -# serial 9 +# serial 10 # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -104,6 +104,7 @@ AC_DEFUN([gl_TIME_MODULE_INDICATOR], AC_DEFUN([gl_HEADER_TIME_H_DEFAULTS], [ + GNULIB_CTIME=0; AC_SUBST([GNULIB_CTIME]) GNULIB_MKTIME=0; AC_SUBST([GNULIB_MKTIME]) GNULIB_NANOSLEEP=0; AC_SUBST([GNULIB_NANOSLEEP]) GNULIB_STRPTIME=0; AC_SUBST([GNULIB_STRPTIME]) @@ -118,6 +119,7 @@ AC_DEFUN([gl_HEADER_TIME_H_DEFAULTS], dnl If another module says to replace or to not replace, do that. dnl Otherwise, replace only if someone compiles with -DGNULIB_PORTCHECK; dnl this lets maintainers check for portability. + REPLACE_CTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_CTIME]) REPLACE_LOCALTIME_R=GNULIB_PORTCHECK; AC_SUBST([REPLACE_LOCALTIME_R]) REPLACE_MKTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_MKTIME]) REPLACE_NANOSLEEP=GNULIB_PORTCHECK; AC_SUBST([REPLACE_NANOSLEEP]) diff --git a/modules/ctime b/modules/ctime new file mode 100644 index 0000000..d700ca8 --- /dev/null +++ b/modules/ctime @@ -0,0 +1,27 @@ +Description: +ctime() function: convert time to string. + +Files: +lib/ctime.c +m4/ctime.m4 + +Depends-on: +time + +configure.ac: +gl_FUNC_CTIME +if test $REPLACE_CTIME = 1; then + AC_LIBOBJ([ctime]) +fi +gl_TIME_MODULE_INDICATOR([ctime]) + +Makefile.am: + +Include: +<time.h> + +License: +LGPLv2+ + +Maintainer: +all diff --git a/modules/time b/modules/time index d12add0..eff6132 100644 --- a/modules/time +++ b/modules/time @@ -30,6 +30,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \ + -e 's/@''GNULIB_CTIME''@/$(GNULIB_CTIME)/g' \ -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GNULIB_GETTIMEOFDAY)/g' \ -e 's/@''GNULIB_MKTIME''@/$(GNULIB_MKTIME)/g' \ -e 's/@''GNULIB_NANOSLEEP''@/$(GNULIB_NANOSLEEP)/g' \ @@ -42,6 +43,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $( -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \ -e 's|@''HAVE_TIMEGM''@|$(HAVE_TIMEGM)|g' \ -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \ + -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \ -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \ -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \ -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \