[libc-commits] [libc] 000a3f0 - [libc][c11] implement ctime (#107285)
via libc-commits
libc-commits at lists.llvm.org
Mon Sep 16 11:27:15 PDT 2024
Author: Зишан Мирза
Date: 2024-09-16T11:27:11-07:00
New Revision: 000a3f0a54876f1519393e40085500e16ea12cf4
URL: https://github.com/llvm/llvm-project/commit/000a3f0a54876f1519393e40085500e16ea12cf4
DIFF: https://github.com/llvm/llvm-project/commit/000a3f0a54876f1519393e40085500e16ea12cf4.diff
LOG: [libc][c11] implement ctime (#107285)
This is an implementation of `ctime` and includes `ctime_r`.
According to documentation, `ctime` and `ctime_r` are defined as the
following:
```c
char *ctime(const time_t *timep);
char *ctime_r(const time_t *restrict timep, char buf[restrict 26]);
```
closes #86567
Added:
libc/src/time/ctime.cpp
libc/src/time/ctime.h
libc/src/time/ctime_r.cpp
libc/src/time/ctime_r.h
libc/test/src/time/ctime_r_test.cpp
libc/test/src/time/ctime_test.cpp
Modified:
libc/config/baremetal/arm/entrypoints.txt
libc/config/baremetal/riscv/entrypoints.txt
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/newhdrgen/yaml/time.yaml
libc/spec/stdc.td
libc/src/time/CMakeLists.txt
libc/src/time/time_utils.h
libc/test/src/time/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index af9a8bc9925441..68030f7f1775b5 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -203,6 +203,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
libc.src.time.
diff time
libc.src.time.gmtime
libc.src.time.gmtime_r
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 6ebe2e4a29025f..5894b591072ef0 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -199,6 +199,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
libc.src.time.
diff time
libc.src.time.gmtime
libc.src.time.gmtime_r
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 60aa7f5ccb319a..64fbe1a250c0ba 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -948,6 +948,8 @@ if(LLVM_LIBC_FULL_BUILD)
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.
diff time
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 9a2746dcb86f87..ff3d821c664c5b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -883,6 +883,8 @@ if(LLVM_LIBC_FULL_BUILD)
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.
diff time
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 3fd88fc0020e55..2a38db5bcdad8c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1003,6 +1003,8 @@ if(LLVM_LIBC_FULL_BUILD)
# time.h entrypoints
libc.src.time.asctime
libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.
diff time
diff --git a/libc/newhdrgen/yaml/time.yaml b/libc/newhdrgen/yaml/time.yaml
index d2344671831c7a..69b40bef3160dd 100644
--- a/libc/newhdrgen/yaml/time.yaml
+++ b/libc/newhdrgen/yaml/time.yaml
@@ -24,6 +24,19 @@ functions:
arguments:
- type: struct tm *
- type: char *
+ - name: ctime
+ standard:
+ - stdc
+ return_type: char *
+ arguments:
+ - type: const time_t *
+ - name: ctime_r
+ standard:
+ - stdc
+ return_type: char *
+ arguments:
+ - type: const time_t *
+ - type: char *
- name: clock
standard:
- stdc
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a4ae3e1ff7d9c6..c7b697d438a89e 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1600,6 +1600,19 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<CharPtr>,
]
>,
+ FunctionSpec<
+ "ctime",
+ RetValSpec<CharPtr>,
+ [ArgSpec<TimeTTypePtr>]
+ >,
+ FunctionSpec<
+ "ctime_r",
+ RetValSpec<CharPtr>,
+ [
+ ArgSpec<TimeTTypePtr>,
+ ArgSpec<CharPtr>,
+ ]
+ >,
FunctionSpec<
"clock",
RetValSpec<ClockT>,
diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 5680718715974e..b3318e7ca87fa5 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -36,6 +36,30 @@ add_entrypoint_object(
libc.include.time
)
+add_entrypoint_object(
+ ctime
+ SRCS
+ ctime.cpp
+ HDRS
+ ctime.h
+ DEPENDS
+ .time_utils
+ libc.hdr.types.time_t
+ libc.include.time
+)
+
+add_entrypoint_object(
+ ctime_r
+ SRCS
+ ctime_r.cpp
+ HDRS
+ ctime_r.h
+ DEPENDS
+ .time_utils
+ libc.hdr.types.time_t
+ libc.include.time
+)
+
add_entrypoint_object(
diff time
SRCS
diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
new file mode 100644
index 00000000000000..8adae9be73809a
--- /dev/null
+++ b/libc/src/time/ctime.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of ctime function ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ctime.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "time_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
+ if (t_ptr == nullptr || *t_ptr > cpp::numeric_limits<int32_t>::max()) {
+ return nullptr;
+ }
+ static char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+ return time_utils::asctime(time_utils::localtime(t_ptr), buffer,
+ TimeConstants::ASCTIME_MAX_BYTES);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
new file mode 100644
index 00000000000000..7760710776232f
--- /dev/null
+++ b/libc/src/time/ctime.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of ctime --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_CTIME_H
+#define LLVM_LIBC_SRC_TIME_CTIME_H
+
+#include "hdr/types/time_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *ctime(const time_t *t_ptr);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_CTIME_H
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
new file mode 100644
index 00000000000000..63d93c4085f38c
--- /dev/null
+++ b/libc/src/time/ctime_r.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of ctime_r function --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ctime_r.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "time_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
+ if (t_ptr == nullptr || buffer == nullptr ||
+ *t_ptr > cpp::numeric_limits<int32_t>::max()) {
+ return nullptr;
+ }
+
+ return time_utils::asctime(time_utils::localtime(t_ptr), buffer,
+ TimeConstants::ASCTIME_MAX_BYTES);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
new file mode 100644
index 00000000000000..d45bf7b64d3a65
--- /dev/null
+++ b/libc/src/time/ctime_r.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of ctime_r ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_CTIME_R_H
+#define LLVM_LIBC_SRC_TIME_CTIME_R_H
+
+#include "hdr/types/time_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *ctime_r(const time_t *t_ptr, char *buffer);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H
diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 47f55f7d389122..552ea925c1c7dc 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -156,6 +156,13 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
return result;
}
+// TODO: localtime is not yet implemented and a temporary solution is to
+// use gmtime, https://github.com/llvm/llvm-project/issues/107597
+LIBC_INLINE struct tm *localtime(const time_t *t_ptr) {
+ static struct tm result;
+ return time_utils::gmtime_internal(t_ptr, &result);
+}
+
} // namespace time_utils
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index 78cfe8f301615f..bba01f063fed27 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -30,6 +30,42 @@ add_libc_unittest(
libc.src.time.asctime_r
)
+add_libc_unittest(
+ ctime_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ ctime_test.cpp
+ HDRS
+ TmHelper.h
+ TmMatcher.h
+ CXX_STANDARD
+ 20
+ DEPENDS
+ libc.include.time
+ libc.hdr.types.time_t
+ libc.src.time.ctime
+ libc.src.time.time_utils
+)
+
+add_libc_unittest(
+ ctime_r_test
+ SUITE
+ libc_time_unittests
+ SRCS
+ ctime_r_test.cpp
+ HDRS
+ TmHelper.h
+ TmMatcher.h
+ CXX_STANDARD
+ 20
+ DEPENDS
+ libc.include.time
+ libc.hdr.types.time_t
+ libc.src.time.ctime_r
+ libc.src.time.time_utils
+)
+
add_libc_test(
clock_gettime_test
SUITE
diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
new file mode 100644
index 00000000000000..9ce6f75f754849
--- /dev/null
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -0,0 +1,58 @@
+//===-- Unittests for ctime_r ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/errno/libc_errno.h"
+#include "src/time/ctime_r.h"
+#include "src/time/time_utils.h"
+#include "test/UnitTest/Test.h"
+#include "test/src/time/TmHelper.h"
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+TEST(LlvmLibcCtimeR, Nullptr) {
+ char *result;
+ result = LIBC_NAMESPACE::ctime_r(nullptr, nullptr);
+ ASSERT_STREQ(nullptr, result);
+
+ char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+ result = LIBC_NAMESPACE::ctime_r(nullptr, buffer);
+ ASSERT_STREQ(nullptr, result);
+
+ time_t t;
+ result = LIBC_NAMESPACE::ctime_r(&t, nullptr);
+ ASSERT_STREQ(nullptr, result);
+}
+
+TEST(LlvmLibcCtimeR, ValidUnixTimestamp0) {
+ char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+ time_t t;
+ char *result;
+ // 1970-01-01 00:00:00. Test with a valid buffer size.
+ t = 0;
+ result = LIBC_NAMESPACE::ctime_r(&t, buffer);
+ ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", result);
+}
+
+TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
+ char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+ time_t t;
+ char *result;
+ // 2038-01-19 03:14:07. Test with a valid buffer size.
+ t = 2147483647;
+ result = LIBC_NAMESPACE::ctime_r(&t, buffer);
+ ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
+}
+
+TEST(LlvmLibcCtimeR, InvalidArgument) {
+ char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+ time_t t;
+ char *result;
+ t = 2147483648;
+ result = LIBC_NAMESPACE::ctime_r(&t, buffer);
+ ASSERT_STREQ(nullptr, result);
+}
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
new file mode 100644
index 00000000000000..7ec71bb1e4ed1e
--- /dev/null
+++ b/libc/test/src/time/ctime_test.cpp
@@ -0,0 +1,42 @@
+//===-- Unittests for ctime -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/errno/libc_errno.h"
+#include "src/time/ctime.h"
+#include "test/UnitTest/Test.h"
+#include "test/src/time/TmHelper.h"
+
+TEST(LlvmLibcCtime, NULL) {
+ char *result;
+ result = LIBC_NAMESPACE::ctime(NULL);
+ ASSERT_STREQ(NULL, result);
+}
+
+TEST(LlvmLibcCtime, ValidUnixTimestamp0) {
+ time_t t;
+ char *result;
+ t = 0;
+ result = LIBC_NAMESPACE::ctime(&t);
+ ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", result);
+}
+
+TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
+ time_t t;
+ char *result;
+ t = 2147483647;
+ result = LIBC_NAMESPACE::ctime(&t);
+ ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
+}
+
+TEST(LlvmLibcCtime, InvalidArgument) {
+ time_t t;
+ char *result;
+ t = 2147483648;
+ result = LIBC_NAMESPACE::ctime(&t);
+ ASSERT_STREQ(NULL, result);
+}
More information about the libc-commits
mailing list