localtime: detect thread-safe alternatives and use them

- add local API `toolx_localtime()` to wrap the banned function
  `localtime()`. Used from libcurl, libtests and test servers.
- auto-detect and use `localtime_r()` where available (e.g. Linux).
  Also to support multi-threading.
- use `localtime_s()` on Windows. It requires MSVC or mingw-w64 v4+.
  Also to support multi-threading.
  Use local workaround to also support mingw-w64 v3.
- add `src/toolx` to keep internal APIs used by the curl tool and tests,
  but not by libcurl. `toolx_localtime()` is the first API in it.
- replace `localtime()` calls with `toolx_localtime()`.
  Except in examples.
- note Windows XP's default `msvcrt.dll` doesn't offer secure CRT APIs.
  XP likely needs a newer version of this DLL, or may not run.
- note that `localtime()` mirrors `gmtime()`, with the difference that
  `gmtime()`'s internal wrapper lives in curlx.

Also:
- drop redundant `int` casts.

Refs:
https://learn.microsoft.com/cpp/c-runtime-library/reference/localtime-localtime32-localtime64
https://learn.microsoft.com/cpp/c-runtime-library/reference/localtime-s-localtime32-s-localtime64-s
https://pubs.opengroup.org/onlinepubs/9799919799/functions/localtime.html
https://linux.die.net/man/3/localtime_r

Ref: #19955 (for `gmtime_r()`)
Follow-up to 54d9f060b4b0a8fb5fa006813e4db1ca5c1a07e8
Closes #19957
This commit is contained in:
Viktor Szakats 2025-12-13 04:27:41 +01:00
parent c6988f9131
commit 32454b954a
No known key found for this signature in database
GPG Key ID: B5ABD165E2AEF201
23 changed files with 285 additions and 29 deletions

View File

@ -169,6 +169,7 @@ else()
set(HAVE_LINUX_TCP_H 0)
endif()
set(HAVE_LOCALE_H 1)
set(HAVE_LOCALTIME_R 1)
set(HAVE_LONGLONG 1)
if(APPLE)
set(HAVE_MACH_ABSOLUTE_TIME 1)

View File

@ -123,6 +123,7 @@ set(HAVE_IOCTL_SIOCGIFADDR 0)
set(HAVE_IO_H 1)
set(HAVE_LINUX_TCP_H 0)
set(HAVE_LOCALE_H 1)
set(HAVE_LOCALTIME_R 0)
set(HAVE_MEMRCHR 0)
set(HAVE_MSG_NOSIGNAL 0)
set(HAVE_NETDB_H 0)

View File

@ -1570,6 +1570,7 @@ check_function_exists("getpwuid_r" HAVE_GETPWUID_R)
check_function_exists("geteuid" HAVE_GETEUID)
check_function_exists("utime" HAVE_UTIME)
check_symbol_exists("gmtime_r" "stdlib.h;time.h" HAVE_GMTIME_R)
check_symbol_exists("localtime_r" "stdlib.h;time.h" HAVE_LOCALTIME_R)
check_symbol_exists("gethostbyname_r" "netdb.h" HAVE_GETHOSTBYNAME_R)
check_symbol_exists("gethostname" "${CURL_INCLUDES}" HAVE_GETHOSTNAME) # winsock2.h unistd.h proto/bsdsocket.h

View File

@ -4203,6 +4203,7 @@ CURL_CHECK_FUNC_GMTIME_R
CURL_CHECK_FUNC_IOCTL
CURL_CHECK_FUNC_IOCTLSOCKET
CURL_CHECK_FUNC_IOCTLSOCKET_CAMEL
CURL_CHECK_FUNC_LOCALTIME_R
CURL_CHECK_FUNC_MEMRCHR
CURL_CHECK_FUNC_SIGACTION
CURL_CHECK_FUNC_SIGINTERRUPT

View File

@ -108,6 +108,9 @@
/* Define if you have the GNU gssapi libraries */
#undef HAVE_GSSGNU
/* Define if you have the `localtime_r' function. */
#define HAVE_LOCALTIME_R
/* Define if you have the <netdb.h> header file. */
#define HAVE_NETDB_H

View File

@ -86,6 +86,7 @@
#define HAVE_LIBGEN_H 1
#define HAVE_LIBZ 1
#define HAVE_LOCALE_H 1
#define HAVE_LOCALTIME_R 1
#define HAVE_LONGLONG 1
#define HAVE_NETDB_H 1
#define HAVE_NETINET_IN_H 1

View File

@ -391,6 +391,9 @@
/* Define to 1 if you have the <locale.h> header file. */
#cmakedefine HAVE_LOCALE_H 1
/* Define to 1 if you have a working localtime_r function. */
#cmakedefine HAVE_LOCALTIME_R 1
/* Define to 1 if the compiler supports the 'long long' data type. */
#cmakedefine HAVE_LONGLONG 1

View File

@ -94,8 +94,7 @@
#define _CRT_NONSTDC_NO_DEPRECATE /* for close(), fileno(), unlink(), etc. */
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS /* for getenv(), strcpy(),
in tests: localtime(), sscanf() */
#define _CRT_SECURE_NO_WARNINGS /* for getenv(), strcpy(), tests: sscanf() */
#endif
#endif /* _MSC_VER */

View File

@ -2204,6 +2204,126 @@ AC_DEFUN([CURL_CHECK_FUNC_GMTIME_R], [
])
dnl CURL_CHECK_FUNC_LOCALTIME_R
dnl -------------------------------------------------
dnl Verify if localtime_r is available, prototyped, can
dnl be compiled and seems to work. If all of these are
dnl true, and usage has not been previously disallowed
dnl with shell variable curl_disallow_localtime_r, then
dnl HAVE_LOCALTIME_R will be defined.
AC_DEFUN([CURL_CHECK_FUNC_LOCALTIME_R], [
AC_REQUIRE([CURL_INCLUDES_STDLIB])dnl
AC_REQUIRE([CURL_INCLUDES_TIME])dnl
#
tst_links_localtime_r="unknown"
tst_proto_localtime_r="unknown"
tst_compi_localtime_r="unknown"
tst_works_localtime_r="unknown"
tst_allow_localtime_r="unknown"
#
AC_MSG_CHECKING([if localtime_r can be linked])
AC_LINK_IFELSE([
AC_LANG_FUNC_LINK_TRY([localtime_r])
],[
AC_MSG_RESULT([yes])
tst_links_localtime_r="yes"
],[
AC_MSG_RESULT([no])
tst_links_localtime_r="no"
])
#
if test "$tst_links_localtime_r" = "yes"; then
AC_MSG_CHECKING([if localtime_r is prototyped])
AC_EGREP_CPP([localtime_r],[
$curl_includes_time
],[
AC_MSG_RESULT([yes])
tst_proto_localtime_r="yes"
],[
AC_MSG_RESULT([no])
tst_proto_localtime_r="no"
])
fi
#
if test "$tst_proto_localtime_r" = "yes"; then
AC_MSG_CHECKING([if localtime_r is compilable])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
$curl_includes_time
]],[[
time_t clock = 1170352587;
struct tm result;
if(localtime_r(&clock, &result) != 0)
return 1;
(void)result;
]])
],[
AC_MSG_RESULT([yes])
tst_compi_localtime_r="yes"
],[
AC_MSG_RESULT([no])
tst_compi_localtime_r="no"
])
fi
#
dnl only do runtime verification when not cross-compiling
if test "$cross_compiling" != "yes" &&
test "$tst_compi_localtime_r" = "yes"; then
AC_MSG_CHECKING([if localtime_r seems to work])
CURL_RUN_IFELSE([
AC_LANG_PROGRAM([[
$curl_includes_stdlib
$curl_includes_time
]],[[
time_t clock = 1170352587;
struct tm *tmp = 0;
struct tm result;
tmp = localtime_r(&clock, &result);
(void)result;
if(tmp)
return 0;
else
return 1;
]])
],[
AC_MSG_RESULT([yes])
tst_works_localtime_r="yes"
],[
AC_MSG_RESULT([no])
tst_works_localtime_r="no"
])
fi
#
if test "$tst_compi_localtime_r" = "yes" &&
test "$tst_works_localtime_r" != "no"; then
AC_MSG_CHECKING([if localtime_r usage allowed])
if test "x$curl_disallow_localtime_r" != "xyes"; then
AC_MSG_RESULT([yes])
tst_allow_localtime_r="yes"
else
AC_MSG_RESULT([no])
tst_allow_localtime_r="no"
fi
fi
#
AC_MSG_CHECKING([if localtime_r might be used])
if test "$tst_links_localtime_r" = "yes" &&
test "$tst_proto_localtime_r" = "yes" &&
test "$tst_compi_localtime_r" = "yes" &&
test "$tst_allow_localtime_r" = "yes" &&
test "$tst_works_localtime_r" != "no"; then
AC_MSG_RESULT([yes])
AC_DEFINE_UNQUOTED(HAVE_LOCALTIME_R, 1,
[Define to 1 if you have a working localtime_r function.])
curl_cv_func_localtime_r="yes"
else
AC_MSG_RESULT([no])
curl_cv_func_localtime_r="no"
fi
])
dnl CURL_CHECK_FUNC_INET_NTOP
dnl -------------------------------------------------
dnl Verify if inet_ntop is available, prototyped, can

View File

@ -2296,10 +2296,12 @@
</ItemDefinitionGroup>
<ItemGroup>
CURL_LIB_CURLX_C_FILES
CURL_SRC_TOOLX_C_FILES
CURL_SRC_C_FILES
</ItemGroup>
<ItemGroup>
CURL_LIB_CURLX_H_FILES
CURL_SRC_TOOLX_H_FILES
CURL_SRC_X_H_FILES
CURL_SRC_H_FILES
</ItemGroup>

View File

@ -226,6 +226,10 @@ rem
for /f "delims=" %%c in ('dir /b ..\lib\vtls\*.c') do call :element lib\vtls "%%c" %3
) else if "!var!" == "CURL_LIB_VTLS_H_FILES" (
for /f "delims=" %%h in ('dir /b ..\lib\vtls\*.h') do call :element lib\vtls "%%h" %3
) else if "!var!" == "CURL_SRC_TOOLX_C_FILES" (
for /f "delims=" %%c in ('dir /b ..\src\toolx\*.c') do call :element src\toolx "%%c" %3
) else if "!var!" == "CURL_SRC_TOOLX_H_FILES" (
for /f "delims=" %%h in ('dir /b ..\src\toolx\*.h') do call :element src\toolx "%%h" %3
) else (
echo.!var!>> %3
)

View File

@ -64,6 +64,12 @@ CURLX_HFILES = \
../lib/curlx/warnless.h \
../lib/curlx/winapi.h
TOOLX_CFILES = \
toolx/tool_time.c
TOOLX_HFILES = \
toolx/tool_time.h
CURL_CFILES = \
config2setopts.c \
slist_wc.c \
@ -107,7 +113,8 @@ CURL_CFILES = \
tool_writeout.c \
tool_writeout_json.c \
tool_xattr.c \
var.c
var.c \
$(TOOLX_CFILES)
CURL_HFILES = \
config2setopts.h \
@ -154,6 +161,7 @@ CURL_HFILES = \
tool_writeout.h \
tool_writeout_json.h \
tool_xattr.h \
var.h
var.h \
$(TOOLX_HFILES)
CURL_RCFILES = curl.rc

View File

@ -27,6 +27,7 @@
#include "tool_msgs.h"
#include "tool_cb_dbg.h"
#include "tool_util.h"
#include "toolx/tool_time.h"
static void dump(const char *timebuf, const char *idsbuf, const char *text,
FILE *stream, const unsigned char *ptr, size_t size,
@ -34,7 +35,6 @@ static void dump(const char *timebuf, const char *idsbuf, const char *text,
/*
* Return the formatted HH:MM:SS for the tv_sec given.
* NOT thread safe.
*/
static const char *hms_for_sec(time_t tv_sec)
{
@ -42,10 +42,12 @@ static const char *hms_for_sec(time_t tv_sec)
static char hms_buf[12];
if(tv_sec != cached_tv_sec) {
/* !checksrc! disable BANNEDFUNC 1 */
struct tm *now = localtime(&tv_sec); /* not thread safe either */
struct tm now;
CURLcode result = toolx_localtime(tv_sec, &now);
if(result)
memset(&now, 0, sizeof(now));
curl_msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
now->tm_hour, now->tm_min, now->tm_sec);
now.tm_hour, now.tm_min, now.tm_sec);
cached_tv_sec = tv_sec;
}
return hms_buf;

61
src/toolx/tool_time.c Normal file
View File

@ -0,0 +1,61 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "tool_time.h"
#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 3)
#include <sec_api/time_s.h> /* for _localtime32_s(), _localtime64_s() */
#ifdef _USE_32BIT_TIME_T
#define localtime_s _localtime32_s
#else
#define localtime_s _localtime64_s
#endif
#endif
/*
* toolx_localtime() is a localtime() replacement for portability. Do not use
* the localtime_s(), localtime_r() or localtime() functions anywhere else but
* here.
*/
CURLcode toolx_localtime(time_t intime, struct tm *store)
{
#ifdef _WIN32
if(localtime_s(store, &intime)) /* thread-safe */
return CURLE_BAD_FUNCTION_ARGUMENT;
#elif defined(HAVE_LOCALTIME_R)
const struct tm *tm;
tm = localtime_r(&intime, store); /* thread-safe */
if(!tm)
return CURLE_BAD_FUNCTION_ARGUMENT;
#else
const struct tm *tm;
/* !checksrc! disable BANNEDFUNC 1 */
tm = localtime(&intime); /* not thread-safe */
if(tm)
*store = *tm; /* copy the pointed struct to the local copy */
else
return CURLE_BAD_FUNCTION_ARGUMENT;
#endif
return CURLE_OK;
}

30
src/toolx/tool_time.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef HEADER_TOOLX_TOOL_TIME_H
#define HEADER_TOOLX_TOOL_TIME_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
CURLcode toolx_localtime(time_t intime, struct tm *store);
#endif /* HEADER_TOOLX_TOOL_TIME_H */

View File

@ -22,7 +22,7 @@
#
###########################################################################
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
@ -41,10 +41,10 @@ list(APPEND TESTS_C "lib1521.c")
add_custom_command(OUTPUT "${BUNDLE}.c"
COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl"
--include ${UTILS_C} ${CURLX_C} --test ${TESTS_C} > "${BUNDLE}.c"
--include ${UTILS_C} ${CURLX_C} ${TOOLX_C} --test ${TESTS_C} > "${BUNDLE}.c"
DEPENDS
"${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl" "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.inc"
${FIRST_C} ${UTILS_C} ${CURLX_C} ${TESTS_C}
${FIRST_C} ${UTILS_C} ${CURLX_C} ${TOOLX_C} ${TESTS_C}
VERBATIM)
add_executable(${BUNDLE} EXCLUDE_FROM_ALL "${BUNDLE}.c")
@ -53,6 +53,7 @@ target_link_libraries(${BUNDLE} ${LIB_SELECTED} ${CURL_LIBS})
target_include_directories(${BUNDLE} PRIVATE
"${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
"${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h", curlx
"${PROJECT_SOURCE_DIR}/src" # for toolx
"${CMAKE_CURRENT_SOURCE_DIR}" # for the generated bundle source to find included test sources
)
target_compile_definitions(${BUNDLE} PRIVATE ${CURL_DEBUG_MACROS})

View File

@ -31,14 +31,16 @@ AUTOMAKE_OPTIONS = foreign nostdinc
# $(top_srcdir)/include is for libcurl's external include files
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
# $(top_srcdir)/src for toolx header files
# $(srcdir) for the generated bundle source to find included test sources
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_builddir)/lib \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src \
-I$(srcdir)
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
include Makefile.inc
EXTRA_DIST = CMakeLists.txt $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C) \
@ -65,8 +67,8 @@ else
# These are part of the libcurl static lib. Add them here when linking shared.
curlx_c_lib = $(CURLX_C)
endif
$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(curlx_c_lib) $(TESTS_C) lib1521.c
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(curlx_c_lib) --test $(TESTS_C) lib1521.c > $(BUNDLE).c
$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) $(TESTS_C) lib1521.c
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) --test $(TESTS_C) lib1521.c > $(BUNDLE).c
noinst_PROGRAMS = $(BUNDLE)
LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@

View File

@ -46,6 +46,9 @@ CURLX_C = \
../../lib/curlx/warnless.c \
../../lib/curlx/winapi.c
TOOLX_C = \
../../src/toolx/tool_time.c
# All libtest programs
TESTS_C = \
cli_ftp_upload.c \

View File

@ -23,6 +23,8 @@
***************************************************************************/
#include "testtrace.h"
#include <toolx/tool_time.h>
struct libtest_trace_cfg debug_config;
static time_t epoch_offset; /* for test time tracing */
@ -93,7 +95,8 @@ int libtest_debug_cb(CURL *curl, curl_infotype type,
timestr = &timebuf[0];
if(trace_cfg->tracetime) {
struct tm *now;
CURLcode result;
struct tm now;
struct curltime tv;
time_t secs;
tv = curlx_now();
@ -102,10 +105,11 @@ int libtest_debug_cb(CURL *curl, curl_infotype type,
known_offset = 1;
}
secs = epoch_offset + tv.tv_sec;
/* !checksrc! disable BANNEDFUNC 1 */
now = localtime(&secs); /* not thread safe but we do not care */
result = toolx_localtime(secs, &now);
if(result)
memset(&now, 0, sizeof(now));
curl_msnprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
now.tm_hour, now.tm_min, now.tm_sec, (long)tv.tv_usec);
}
switch(type) {

View File

@ -22,16 +22,16 @@
#
###########################################################################
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
add_custom_command(OUTPUT "${BUNDLE}.c"
COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl"
--include ${UTILS_C} ${CURLX_C} --test ${TESTS_C} > "${BUNDLE}.c"
--include ${UTILS_C} ${CURLX_C} ${TOOLX_C} --test ${TESTS_C} > "${BUNDLE}.c"
DEPENDS
"${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl" "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.inc"
${FIRST_C} ${UTILS_C} ${CURLX_C} ${TESTS_C}
${FIRST_C} ${UTILS_C} ${CURLX_C} ${TOOLX_C} ${TESTS_C}
VERBATIM)
add_executable(${BUNDLE} EXCLUDE_FROM_ALL "${BUNDLE}.c")
@ -40,6 +40,7 @@ target_link_libraries(${BUNDLE} ${CURL_NETWORK_AND_TIME_LIBS})
target_include_directories(${BUNDLE} PRIVATE
"${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
"${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h", curlx
"${PROJECT_SOURCE_DIR}/src" # for toolx
"${CMAKE_CURRENT_SOURCE_DIR}" # for the generated bundle source to find included test sources
)
set_target_properties(${BUNDLE} PROPERTIES OUTPUT_NAME "${BUNDLE}" PROJECT_LABEL "Test ${BUNDLE}" UNITY_BUILD OFF C_CLANG_TIDY "")

View File

@ -31,14 +31,16 @@ AUTOMAKE_OPTIONS = foreign nostdinc
# $(top_srcdir)/include is for libcurl's external include files
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
# $(top_srcdir)/src for toolx header files
# $(srcdir) for the generated bundle source to find included test sources
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_builddir)/lib \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src \
-I$(srcdir)
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TESTS_C variables
# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
include Makefile.inc
EXTRA_DIST = CMakeLists.txt .checksrc $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C)
@ -48,8 +50,8 @@ CFLAGS += @CURL_CFLAG_EXTRAS@
# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(CURLX_C) $(TESTS_C)
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(CURLX_C) --test $(TESTS_C) > $(BUNDLE).c
$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(CURLX_C) $(TOOLX_C) $(TESTS_C)
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(CURLX_C) $(TOOLX_C) --test $(TESTS_C) > $(BUNDLE).c
noinst_PROGRAMS = $(BUNDLE)
LDADD = @CURL_NETWORK_AND_TIME_LIBS@

View File

@ -49,6 +49,9 @@ CURLX_C = \
../../lib/curlx/warnless.c \
../../lib/curlx/winapi.c
TOOLX_C = \
../../src/toolx/tool_time.c
# All test servers
TESTS_C = \
dnsd.c \

View File

@ -23,6 +23,8 @@
***************************************************************************/
#include "first.h"
#include <toolx/tool_time.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@ -83,8 +85,9 @@ void logmsg(const char *msg, ...)
char buffer[2048 + 1];
FILE *logfp;
struct curltime tv;
CURLcode result;
time_t sec;
struct tm *now;
struct tm now;
char timebuf[50];
static time_t epoch_offset;
static int known_offset;
@ -100,12 +103,12 @@ void logmsg(const char *msg, ...)
known_offset = 1;
}
sec = epoch_offset + tv.tv_sec;
/* !checksrc! disable BANNEDFUNC 1 */
now = localtime(&sec); /* not thread safe but we do not care */
result = toolx_localtime(sec, &now);
if(result)
memset(&now, 0, sizeof(now));
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld",
(int)now->tm_hour, (int)now->tm_min, (int)now->tm_sec,
(long)tv.tv_usec);
now.tm_hour, now.tm_min, now.tm_sec, (long)tv.tv_usec);
va_start(ap, msg);
#ifdef __clang__