Skip to content

Commit a9e0dbe

Browse files
[libc] add fputs and puts
add fputs, puts, and the EOF macro that they use. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D134328
1 parent f402666 commit a9e0dbe

File tree

13 files changed

+214
-4
lines changed

13 files changed

+214
-4
lines changed

libc/config/linux/api.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def StdIOAPI : PublicAPI<"stdio.h"> {
153153
SimpleMacroDef<"_IOFBF", "0">,
154154
SimpleMacroDef<"_IOLBF", "1">,
155155
SimpleMacroDef<"_IONBF", "2">,
156+
SimpleMacroDef<"EOF", "-1">,
156157
];
157158
let Types = ["size_t", "FILE", "cookie_io_functions_t"];
158159
}

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ if(LLVM_LIBC_FULL_BUILD)
324324
libc.src.stdio.ferror_unlocked
325325
libc.src.stdio.fflush
326326
libc.src.stdio.fopen
327+
libc.src.stdio.fputs
327328
libc.src.stdio.fopencookie
328329
libc.src.stdio.fread
329330
libc.src.stdio.fread_unlocked
@@ -333,6 +334,7 @@ if(LLVM_LIBC_FULL_BUILD)
333334
libc.src.stdio.fwrite_unlocked
334335
libc.src.stdio.fprintf
335336
libc.src.stdio.printf
337+
libc.src.stdio.puts
336338
libc.src.stdio.stderr
337339
libc.src.stdio.stdout
338340

libc/docs/stdio.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ These functions operate on files on the host's system, without using the
7272
============= =========
7373
Function_Name Available
7474
============= =========
75-
remove
75+
remove YES
7676
rename
7777
tmpnam
7878
============= =========
@@ -91,7 +91,7 @@ fgets
9191
getchar
9292
fread YES
9393
(f)putc
94-
(f)puts
94+
(f)puts YES
9595
putchar
9696
fwrite YES
9797
ungetc

libc/spec/stdc.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ def StdC : StandardSpec<"stdc"> {
496496
Macro<"_IOFBF">,
497497
Macro<"_IOLBF">,
498498
Macro<"_IONBF">,
499+
Macro<"EOF">,
499500
], // Macros
500501
[ // Types
501502
SizeTType,
@@ -534,6 +535,17 @@ def StdC : StandardSpec<"stdc"> {
534535
[ArgSpec<ConstCharPtr>,
535536
ArgSpec<ConstCharPtr>]
536537
>,
538+
FunctionSpec<
539+
"fputs",
540+
RetValSpec<IntType>,
541+
[ArgSpec<ConstCharRestrictedPtr>,
542+
ArgSpec<FILERestrictedPtr>]
543+
>,
544+
FunctionSpec<
545+
"puts",
546+
RetValSpec<IntType>,
547+
[ArgSpec<ConstCharRestrictedPtr>]
548+
>,
537549
FunctionSpec<
538550
"fread",
539551
RetValSpec<SizeTType>,

libc/src/__support/File/file.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ size_t File::write_unlocked_fbf(const uint8_t *data, size_t len) {
131131
size_t File::write_unlocked_lbf(const uint8_t *data, size_t len) {
132132
constexpr uint8_t NEWLINE_CHAR = '\n';
133133
size_t last_newline = len;
134-
for (size_t i = len; i > 1; --i) {
134+
for (size_t i = len; i >= 1; --i) {
135135
if (data[i - 1] == NEWLINE_CHAR) {
136136
last_newline = i - 1;
137137
break;

libc/src/stdio/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,31 @@ add_entrypoint_object(
184184
libc.src.__support.File.platform_file
185185
)
186186

187+
add_entrypoint_object(
188+
fputs
189+
SRCS
190+
fputs.cpp
191+
HDRS
192+
fputs.h
193+
DEPENDS
194+
libc.include.stdio
195+
libc.src.__support.File.file
196+
libc.src.__support.File.platform_file
197+
)
198+
199+
200+
add_entrypoint_object(
201+
puts
202+
SRCS
203+
puts.cpp
204+
HDRS
205+
puts.h
206+
DEPENDS
207+
libc.include.stdio
208+
libc.src.__support.File.file
209+
libc.src.__support.File.platform_file
210+
)
211+
187212
add_entrypoint_object(
188213
fseek
189214
SRCS

libc/src/stdio/fputs.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===-- Implementation of fputs -------------------------------------------===//
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/stdio/fputs.h"
10+
#include "src/__support/CPP/string_view.h"
11+
#include "src/__support/File/file.h"
12+
13+
#include <stdio.h>
14+
15+
namespace __llvm_libc {
16+
17+
LLVM_LIBC_FUNCTION(int, fputs,
18+
(const char *__restrict str, ::FILE *__restrict stream)) {
19+
cpp::string_view str_view(str);
20+
21+
size_t written = reinterpret_cast<__llvm_libc::File *>(stream)->write(
22+
str, str_view.size());
23+
if (str_view.size() != written) {
24+
// The stream should be in an error state in this case.
25+
return EOF;
26+
}
27+
return 0;
28+
}
29+
30+
} // namespace __llvm_libc

libc/src/stdio/fputs.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header of fputs --------------------------*- 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_STDIO_FPUTS_H
10+
#define LLVM_LIBC_SRC_STDIO_FPUTS_H
11+
12+
#include <stdio.h>
13+
14+
namespace __llvm_libc {
15+
16+
int fputs(const char *__restrict str, ::FILE *__restrict stream);
17+
18+
} // namespace __llvm_libc
19+
20+
#endif // LLVM_LIBC_SRC_STDIO_FPUTS_H

libc/src/stdio/puts.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===-- Implementation of puts --------------------------------------------===//
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/stdio/puts.h"
10+
#include "src/__support/CPP/string_view.h"
11+
#include "src/__support/File/file.h"
12+
13+
#include <stdio.h>
14+
15+
namespace __llvm_libc {
16+
17+
LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) {
18+
cpp::string_view str_view(str);
19+
size_t written = __llvm_libc::stdout->write(str, str_view.size());
20+
if (str_view.size() != written) {
21+
// The stream should be in an error state in this case.
22+
return EOF;
23+
}
24+
written = __llvm_libc::stdout->write("\n", 1);
25+
if (1 != written) {
26+
// The stream should be in an error state in this case.
27+
return EOF;
28+
}
29+
return 0;
30+
}
31+
32+
} // namespace __llvm_libc

libc/src/stdio/puts.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header of puts ---------------------------*- 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_STDIO_PUTS_H
10+
#define LLVM_LIBC_SRC_STDIO_PUTS_H
11+
12+
#include <stdio.h>
13+
14+
namespace __llvm_libc {
15+
16+
int puts(const char *__restrict str);
17+
18+
} // namespace __llvm_libc
19+
20+
#endif // LLVM_LIBC_SRC_STDIO_PUTS_H

libc/test/src/stdio/CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_libc_unittest(
1515
libc.src.stdio.ferror
1616
libc.src.stdio.fflush
1717
libc.src.stdio.fopen
18+
libc.src.stdio.fputs
1819
libc.src.stdio.fread
1920
libc.src.stdio.fseek
2021
libc.src.stdio.fwrite
@@ -108,7 +109,16 @@ add_libc_unittest(
108109
printf_test.cpp
109110
DEPENDS
110111
libc.src.stdio.printf
111-
libc.src.fenv.fesetround
112+
)
113+
114+
add_libc_unittest(
115+
puts_test
116+
SUITE
117+
libc_stdio_unittests
118+
SRCS
119+
puts_test.cpp
120+
DEPENDS
121+
libc.src.stdio.puts
112122
)
113123

114124
add_libc_unittest(

libc/test/src/stdio/fileop_test.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "src/stdio/ferror.h"
1313
#include "src/stdio/fflush.h"
1414
#include "src/stdio/fopen.h"
15+
#include "src/stdio/fputs.h"
1516
#include "src/stdio/fread.h"
1617
#include "src/stdio/fseek.h"
1718
#include "src/stdio/fwrite.h"
@@ -66,9 +67,38 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) {
6667
ASSERT_NE(errno, 0);
6768
errno = 0;
6869

70+
__llvm_libc::clearerr(file);
71+
72+
// Should be an error to puts.
73+
ASSERT_EQ(EOF, __llvm_libc::fputs(CONTENT, file));
74+
ASSERT_NE(__llvm_libc::ferror(file), 0);
75+
ASSERT_NE(errno, 0);
76+
errno = 0;
77+
78+
__llvm_libc::clearerr(file);
79+
ASSERT_EQ(__llvm_libc::ferror(file), 0);
80+
81+
ASSERT_EQ(__llvm_libc::fclose(file), 0);
82+
83+
// Now try puts.
84+
file = __llvm_libc::fopen(FILENAME, "w");
85+
ASSERT_FALSE(file == nullptr);
86+
// fputs returns a negative value on error (EOF) or any non-negative value on
87+
// success. This assert checks that the return value is non-negative.
88+
ASSERT_GE(__llvm_libc::fputs(CONTENT, file), 0);
89+
6990
__llvm_libc::clearerr(file);
7091
ASSERT_EQ(__llvm_libc::ferror(file), 0);
7192

93+
ASSERT_EQ(0, __llvm_libc::fclose(file));
94+
95+
file = __llvm_libc::fopen(FILENAME, "r");
96+
ASSERT_FALSE(file == nullptr);
97+
98+
ASSERT_EQ(__llvm_libc::fread(read_data, 1, sizeof(CONTENT) - 1, file),
99+
sizeof(CONTENT) - 1);
100+
read_data[sizeof(CONTENT) - 1] = '\0';
101+
ASSERT_STREQ(read_data, CONTENT);
72102
ASSERT_EQ(__llvm_libc::fclose(file), 0);
73103
}
74104

libc/test/src/stdio/puts_test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- Unittests for puts ---------------------------------------------===//
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/stdio/puts.h"
10+
11+
#include "utils/UnitTest/Test.h"
12+
13+
TEST(LlvmLibcPutsTest, PrintOut) {
14+
int result;
15+
16+
constexpr char simple[] = "A simple string";
17+
result = __llvm_libc::puts(simple);
18+
EXPECT_GE(result, 0);
19+
20+
// check that it appends a second newline at the end.
21+
constexpr char numbers[] = "1234567890\n";
22+
result = __llvm_libc::puts(numbers);
23+
EXPECT_GE(result, 0);
24+
25+
constexpr char more[] = "1234 and more\n6789 and rhyme";
26+
result = __llvm_libc::puts(more);
27+
EXPECT_GE(result, 0);
28+
}

0 commit comments

Comments
 (0)