[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