From 75e322aa32e4d9d37e3a42aec4c55b2b722cb1a5 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Thu, 13 Jun 2024 14:40:01 +0800 Subject: [PATCH] libc: common: implement ctime() & ctime_r() Add implementation & test for `ctime()` & `ctime_r()`. Since this function is equivalent to `asctime(localtime(clock))`, it inherits the limitation of `localtime()` as well, which only supports UTC results currently. Signed-off-by: Yong Cong Sin --- .../portability/posix/option_groups/index.rst | 2 +- lib/libc/common/CMakeLists.txt | 1 + lib/libc/common/Kconfig | 13 ++++++++++ lib/libc/common/source/time/ctime.c | 26 +++++++++++++++++++ lib/libc/minimal/Kconfig | 1 + lib/libc/minimal/include/time.h | 5 ++++ lib/posix/options/Kconfig.pthread | 1 + tests/lib/c_lib/common/src/main.c | 19 +++++++++++++- tests/lib/c_lib/common/testcase.yaml | 1 + 9 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 lib/libc/common/source/time/ctime.c diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 20150fd359d99ec..317a01856881cb6 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -900,7 +900,7 @@ _POSIX_THREAD_SAFE_FUNCTIONS :widths: 50,10 asctime_r(), yes - ctime_r(), + ctime_r(), yes (UTC timezone only) flockfile(), ftrylockfile(), funlockfile(), diff --git a/lib/libc/common/CMakeLists.txt b/lib/libc/common/CMakeLists.txt index b9bda222dca5434..779e5735a8bca5c 100644 --- a/lib/libc/common/CMakeLists.txt +++ b/lib/libc/common/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ASCTIME source/time/asctime.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_GMTIME_R source/time/gmtime_r.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_LOCALTIME_R_UTC source/time/localtime_r_utc.c) +zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_CTIME source/time/ctime.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c) zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c) diff --git a/lib/libc/common/Kconfig b/lib/libc/common/Kconfig index bb1ee57dcf7ec22..8d510af57c0cebc 100644 --- a/lib/libc/common/Kconfig +++ b/lib/libc/common/Kconfig @@ -18,6 +18,19 @@ config COMMON_LIBC_ASCTIME_R help common implementation of asctime_r(). +config COMMON_LIBC_CTIME + bool + select COMMON_LIBC_LOCALTIME_R_UTC + help + common implementation of ctime(). + +config COMMON_LIBC_CTIME_R + bool "Thread-safe version of ctime()" + default y if POSIX_THREAD_SAFE_FUNCTIONS + select COMMON_LIBC_CTIME + help + common implementation of ctime_r(). + config COMMON_LIBC_GMTIME_R bool help diff --git a/lib/libc/common/source/time/ctime.c b/lib/libc/common/source/time/ctime.c new file mode 100644 index 000000000000000..454feb363c5af7c --- /dev/null +++ b/lib/libc/common/source/time/ctime.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/** + * `ctime()` is equivalent to `asctime(localtime(clock))` + * See: https://pubs.opengroup.org/onlinepubs/009695399/functions/ctime.html + */ + +char *ctime(const time_t *clock) +{ + return asctime(localtime(clock)); +} + +#if defined(CONFIG_COMMON_LIBC_CTIME_R) +char *ctime_r(const time_t *clock, char *buf) +{ + struct tm tmp; + + return asctime_r(localtime_r(clock, &tmp), buf); +} +#endif /* CONFIG_COMMON_LIBC_CTIME_R */ diff --git a/lib/libc/minimal/Kconfig b/lib/libc/minimal/Kconfig index 17a56d702de8861..0b99994963de1c9 100644 --- a/lib/libc/minimal/Kconfig +++ b/lib/libc/minimal/Kconfig @@ -41,6 +41,7 @@ config MINIMAL_LIBC_TIME select COMMON_LIBC_GMTIME_R select COMMON_LIBC_ASCTIME select COMMON_LIBC_LOCALTIME_R_UTC + select COMMON_LIBC_CTIME default y help Enable time() and gmtime_r() for the minimal libc. diff --git a/lib/libc/minimal/include/time.h b/lib/libc/minimal/include/time.h index df2d77014180400..7994c139916ba9b 100644 --- a/lib/libc/minimal/include/time.h +++ b/lib/libc/minimal/include/time.h @@ -54,11 +54,16 @@ struct tm *gmtime_r(const time_t *ZRESTRICT timep, char *asctime(const struct tm *timeptr); struct tm *localtime(const time_t *timer); struct tm *localtime_r(const time_t *ZRESTRICT timer, struct tm *ZRESTRICT result); +char *ctime(const time_t *clock); #if defined(CONFIG_COMMON_LIBC_ASCTIME_R) || defined(__DOXYGEN__) char *asctime_r(const struct tm *ZRESTRICT tp, char *ZRESTRICT buf); #endif /* CONFIG_COMMON_LIBC_ASCTIME_R */ +#if defined(CONFIG_COMMON_LIBC_CTIME_R) || defined(__DOXYGEN__) +char *ctime_r(const time_t *clock, char *buf); +#endif /* CONFIG_COMMON_LIBC_CTIME_R */ + time_t time(time_t *tloc); #ifdef __cplusplus diff --git a/lib/posix/options/Kconfig.pthread b/lib/posix/options/Kconfig.pthread index f3d22b6cb4b5341..ffa272e33626e5c 100644 --- a/lib/posix/options/Kconfig.pthread +++ b/lib/posix/options/Kconfig.pthread @@ -159,6 +159,7 @@ config POSIX_THREAD_SAFE_FUNCTIONS select COMMON_LIBC_ASCTIME_R select COMMON_LIBC_GMTIME_R select COMMON_LIBC_LOCALTIME_R_UTC + select COMMON_LIBC_CTIME_R help Select 'y' here to enable POSIX thread-safe functions including asctime_r(), ctime_r(), flockfile(), ftrylockfile(), funlockfile(), getc_unlocked(), getchar_unlocked(), diff --git a/tests/lib/c_lib/common/src/main.c b/tests/lib/c_lib/common/src/main.c index 3b1bb4b85f73a44..1d74f0b1120724a 100644 --- a/tests/lib/c_lib/common/src/main.c +++ b/tests/lib/c_lib/common/src/main.c @@ -1135,7 +1135,7 @@ ZTEST(libc_common, test_time_asctime) } /** - * @brief Test time function + * @brief Test time function * * @see localtime(), localtime_r(). */ @@ -1156,6 +1156,23 @@ ZTEST(libc_common, test_time_localtime) zassert_not_null(localtime_r(&tests4, &tp), "localtime_r failed"); } +/** + * @brief Test time function + * + * @see ctime(), ctime_r(). + */ +ZTEST(libc_common, test_time_ctime) +{ + char buf[26] = {0}; + time_t time = 1718260000; + + zassert_not_null(ctime_r(&time, buf)); + zassert_equal(strncmp("Thu Jun 13 06:26:40 2024\n", buf, sizeof(buf)), 0); + + zassert_not_null(ctime(&time)); + zassert_equal(strncmp("Thu Jun 13 06:26:40 2024\n", ctime(&time), sizeof(buf)), 0); +} + /** * * @brief Test rand function diff --git a/tests/lib/c_lib/common/testcase.yaml b/tests/lib/c_lib/common/testcase.yaml index 9ee91fcd2452806..40a33afe0cf981f 100644 --- a/tests/lib/c_lib/common/testcase.yaml +++ b/tests/lib/c_lib/common/testcase.yaml @@ -14,6 +14,7 @@ tests: - CONFIG_MINIMAL_LIBC_NON_REENTRANT_FUNCTIONS=y - CONFIG_MINIMAL_LIBC_RAND=y - CONFIG_COMMON_LIBC_ASCTIME_R=y + - CONFIG_COMMON_LIBC_CTIME_R=y libraries.libc.common.newlib: filter: CONFIG_NEWLIB_LIBC_SUPPORTED min_ram: 32