Skip to content

Commit 000a3f0

Browse files
authored
[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
1 parent 0ea0e3a commit 000a3f0

File tree

16 files changed

+302
-0
lines changed

16 files changed

+302
-0
lines changed

libc/config/baremetal/arm/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ set(TARGET_LIBC_ENTRYPOINTS
203203
# time.h entrypoints
204204
libc.src.time.asctime
205205
libc.src.time.asctime_r
206+
libc.src.time.ctime
207+
libc.src.time.ctime_r
206208
libc.src.time.difftime
207209
libc.src.time.gmtime
208210
libc.src.time.gmtime_r

libc/config/baremetal/riscv/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ set(TARGET_LIBC_ENTRYPOINTS
199199
# time.h entrypoints
200200
libc.src.time.asctime
201201
libc.src.time.asctime_r
202+
libc.src.time.ctime
203+
libc.src.time.ctime_r
202204
libc.src.time.difftime
203205
libc.src.time.gmtime
204206
libc.src.time.gmtime_r

libc/config/linux/aarch64/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,8 @@ if(LLVM_LIBC_FULL_BUILD)
948948
# time.h entrypoints
949949
libc.src.time.asctime
950950
libc.src.time.asctime_r
951+
libc.src.time.ctime
952+
libc.src.time.ctime_r
951953
libc.src.time.clock
952954
libc.src.time.clock_gettime
953955
libc.src.time.difftime

libc/config/linux/riscv/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,8 @@ if(LLVM_LIBC_FULL_BUILD)
883883
# time.h entrypoints
884884
libc.src.time.asctime
885885
libc.src.time.asctime_r
886+
libc.src.time.ctime
887+
libc.src.time.ctime_r
886888
libc.src.time.clock
887889
libc.src.time.clock_gettime
888890
libc.src.time.difftime

libc/config/linux/x86_64/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,8 @@ if(LLVM_LIBC_FULL_BUILD)
10031003
# time.h entrypoints
10041004
libc.src.time.asctime
10051005
libc.src.time.asctime_r
1006+
libc.src.time.ctime
1007+
libc.src.time.ctime_r
10061008
libc.src.time.clock
10071009
libc.src.time.clock_gettime
10081010
libc.src.time.difftime

libc/newhdrgen/yaml/time.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ functions:
2424
arguments:
2525
- type: struct tm *
2626
- type: char *
27+
- name: ctime
28+
standard:
29+
- stdc
30+
return_type: char *
31+
arguments:
32+
- type: const time_t *
33+
- name: ctime_r
34+
standard:
35+
- stdc
36+
return_type: char *
37+
arguments:
38+
- type: const time_t *
39+
- type: char *
2740
- name: clock
2841
standard:
2942
- stdc

libc/spec/stdc.td

+13
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,19 @@ def StdC : StandardSpec<"stdc"> {
16001600
ArgSpec<CharPtr>,
16011601
]
16021602
>,
1603+
FunctionSpec<
1604+
"ctime",
1605+
RetValSpec<CharPtr>,
1606+
[ArgSpec<TimeTTypePtr>]
1607+
>,
1608+
FunctionSpec<
1609+
"ctime_r",
1610+
RetValSpec<CharPtr>,
1611+
[
1612+
ArgSpec<TimeTTypePtr>,
1613+
ArgSpec<CharPtr>,
1614+
]
1615+
>,
16031616
FunctionSpec<
16041617
"clock",
16051618
RetValSpec<ClockT>,

libc/src/time/CMakeLists.txt

+24
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@ add_entrypoint_object(
3636
libc.include.time
3737
)
3838

39+
add_entrypoint_object(
40+
ctime
41+
SRCS
42+
ctime.cpp
43+
HDRS
44+
ctime.h
45+
DEPENDS
46+
.time_utils
47+
libc.hdr.types.time_t
48+
libc.include.time
49+
)
50+
51+
add_entrypoint_object(
52+
ctime_r
53+
SRCS
54+
ctime_r.cpp
55+
HDRS
56+
ctime_r.h
57+
DEPENDS
58+
.time_utils
59+
libc.hdr.types.time_t
60+
libc.include.time
61+
)
62+
3963
add_entrypoint_object(
4064
difftime
4165
SRCS

libc/src/time/ctime.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- Implementation of ctime function ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "ctime.h"
10+
#include "src/__support/CPP/limits.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
#include "time_utils.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
using LIBC_NAMESPACE::time_utils::TimeConstants;
18+
19+
LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
20+
if (t_ptr == nullptr || *t_ptr > cpp::numeric_limits<int32_t>::max()) {
21+
return nullptr;
22+
}
23+
static char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
24+
return time_utils::asctime(time_utils::localtime(t_ptr), buffer,
25+
TimeConstants::ASCTIME_MAX_BYTES);
26+
}
27+
28+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/ctime.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header of ctime --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_TIME_CTIME_H
10+
#define LLVM_LIBC_SRC_TIME_CTIME_H
11+
12+
#include "hdr/types/time_t.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
char *ctime(const time_t *t_ptr);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_TIME_CTIME_H

libc/src/time/ctime_r.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- Implementation of ctime_r function --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "ctime_r.h"
10+
#include "src/__support/CPP/limits.h"
11+
#include "src/__support/common.h"
12+
#include "src/__support/macros/config.h"
13+
#include "time_utils.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
using LIBC_NAMESPACE::time_utils::TimeConstants;
18+
19+
LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
20+
if (t_ptr == nullptr || buffer == nullptr ||
21+
*t_ptr > cpp::numeric_limits<int32_t>::max()) {
22+
return nullptr;
23+
}
24+
25+
return time_utils::asctime(time_utils::localtime(t_ptr), buffer,
26+
TimeConstants::ASCTIME_MAX_BYTES);
27+
}
28+
29+
} // namespace LIBC_NAMESPACE_DECL

libc/src/time/ctime_r.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header of ctime_r ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_TIME_CTIME_R_H
10+
#define LLVM_LIBC_SRC_TIME_CTIME_R_H
11+
12+
#include "hdr/types/time_t.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
char *ctime_r(const time_t *t_ptr, char *buffer);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H

libc/src/time/time_utils.h

+7
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
156156
return result;
157157
}
158158

159+
// TODO: localtime is not yet implemented and a temporary solution is to
160+
// use gmtime, https://github.com/llvm/llvm-project/issues/107597
161+
LIBC_INLINE struct tm *localtime(const time_t *t_ptr) {
162+
static struct tm result;
163+
return time_utils::gmtime_internal(t_ptr, &result);
164+
}
165+
159166
} // namespace time_utils
160167
} // namespace LIBC_NAMESPACE_DECL
161168

libc/test/src/time/CMakeLists.txt

+36
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,42 @@ add_libc_unittest(
3030
libc.src.time.asctime_r
3131
)
3232

33+
add_libc_unittest(
34+
ctime_test
35+
SUITE
36+
libc_time_unittests
37+
SRCS
38+
ctime_test.cpp
39+
HDRS
40+
TmHelper.h
41+
TmMatcher.h
42+
CXX_STANDARD
43+
20
44+
DEPENDS
45+
libc.include.time
46+
libc.hdr.types.time_t
47+
libc.src.time.ctime
48+
libc.src.time.time_utils
49+
)
50+
51+
add_libc_unittest(
52+
ctime_r_test
53+
SUITE
54+
libc_time_unittests
55+
SRCS
56+
ctime_r_test.cpp
57+
HDRS
58+
TmHelper.h
59+
TmMatcher.h
60+
CXX_STANDARD
61+
20
62+
DEPENDS
63+
libc.include.time
64+
libc.hdr.types.time_t
65+
libc.src.time.ctime_r
66+
libc.src.time.time_utils
67+
)
68+
3369
add_libc_test(
3470
clock_gettime_test
3571
SUITE

libc/test/src/time/ctime_r_test.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===-- Unittests for ctime_r ---------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/errno/libc_errno.h"
10+
#include "src/time/ctime_r.h"
11+
#include "src/time/time_utils.h"
12+
#include "test/UnitTest/Test.h"
13+
#include "test/src/time/TmHelper.h"
14+
15+
using LIBC_NAMESPACE::time_utils::TimeConstants;
16+
17+
TEST(LlvmLibcCtimeR, Nullptr) {
18+
char *result;
19+
result = LIBC_NAMESPACE::ctime_r(nullptr, nullptr);
20+
ASSERT_STREQ(nullptr, result);
21+
22+
char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
23+
result = LIBC_NAMESPACE::ctime_r(nullptr, buffer);
24+
ASSERT_STREQ(nullptr, result);
25+
26+
time_t t;
27+
result = LIBC_NAMESPACE::ctime_r(&t, nullptr);
28+
ASSERT_STREQ(nullptr, result);
29+
}
30+
31+
TEST(LlvmLibcCtimeR, ValidUnixTimestamp0) {
32+
char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
33+
time_t t;
34+
char *result;
35+
// 1970-01-01 00:00:00. Test with a valid buffer size.
36+
t = 0;
37+
result = LIBC_NAMESPACE::ctime_r(&t, buffer);
38+
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", result);
39+
}
40+
41+
TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
42+
char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
43+
time_t t;
44+
char *result;
45+
// 2038-01-19 03:14:07. Test with a valid buffer size.
46+
t = 2147483647;
47+
result = LIBC_NAMESPACE::ctime_r(&t, buffer);
48+
ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
49+
}
50+
51+
TEST(LlvmLibcCtimeR, InvalidArgument) {
52+
char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
53+
time_t t;
54+
char *result;
55+
t = 2147483648;
56+
result = LIBC_NAMESPACE::ctime_r(&t, buffer);
57+
ASSERT_STREQ(nullptr, result);
58+
}

libc/test/src/time/ctime_test.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- Unittests for ctime -----------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/errno/libc_errno.h"
10+
#include "src/time/ctime.h"
11+
#include "test/UnitTest/Test.h"
12+
#include "test/src/time/TmHelper.h"
13+
14+
TEST(LlvmLibcCtime, NULL) {
15+
char *result;
16+
result = LIBC_NAMESPACE::ctime(NULL);
17+
ASSERT_STREQ(NULL, result);
18+
}
19+
20+
TEST(LlvmLibcCtime, ValidUnixTimestamp0) {
21+
time_t t;
22+
char *result;
23+
t = 0;
24+
result = LIBC_NAMESPACE::ctime(&t);
25+
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", result);
26+
}
27+
28+
TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
29+
time_t t;
30+
char *result;
31+
t = 2147483647;
32+
result = LIBC_NAMESPACE::ctime(&t);
33+
ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
34+
}
35+
36+
TEST(LlvmLibcCtime, InvalidArgument) {
37+
time_t t;
38+
char *result;
39+
t = 2147483648;
40+
result = LIBC_NAMESPACE::ctime(&t);
41+
ASSERT_STREQ(NULL, result);
42+
}

0 commit comments

Comments
 (0)