[libc-commits] [libc] a9e0dbe - [libc] add fputs and puts
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Wed Sep 21 11:10:28 PDT 2022
Author: Michael Jones
Date: 2022-09-21T11:10:20-07:00
New Revision: a9e0dbefdd1ae5d46ae4a462d71d6352d2f1c105
URL: https://github.com/llvm/llvm-project/commit/a9e0dbefdd1ae5d46ae4a462d71d6352d2f1c105
DIFF: https://github.com/llvm/llvm-project/commit/a9e0dbefdd1ae5d46ae4a462d71d6352d2f1c105.diff
LOG: [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
Added:
libc/src/stdio/fputs.cpp
libc/src/stdio/fputs.h
libc/src/stdio/puts.cpp
libc/src/stdio/puts.h
libc/test/src/stdio/puts_test.cpp
Modified:
libc/config/linux/api.td
libc/config/linux/x86_64/entrypoints.txt
libc/docs/stdio.rst
libc/spec/stdc.td
libc/src/__support/File/file.cpp
libc/src/stdio/CMakeLists.txt
libc/test/src/stdio/CMakeLists.txt
libc/test/src/stdio/fileop_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 463f40fe220e9..97eed64c9f3a6 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -153,6 +153,7 @@ def StdIOAPI : PublicAPI<"stdio.h"> {
SimpleMacroDef<"_IOFBF", "0">,
SimpleMacroDef<"_IOLBF", "1">,
SimpleMacroDef<"_IONBF", "2">,
+ SimpleMacroDef<"EOF", "-1">,
];
let Types = ["size_t", "FILE", "cookie_io_functions_t"];
}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index fe39ad8a9872a..187165a2b8a5e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -324,6 +324,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdio.ferror_unlocked
libc.src.stdio.fflush
libc.src.stdio.fopen
+ libc.src.stdio.fputs
libc.src.stdio.fopencookie
libc.src.stdio.fread
libc.src.stdio.fread_unlocked
@@ -333,6 +334,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.stdio.fwrite_unlocked
libc.src.stdio.fprintf
libc.src.stdio.printf
+ libc.src.stdio.puts
libc.src.stdio.stderr
libc.src.stdio.stdout
diff --git a/libc/docs/stdio.rst b/libc/docs/stdio.rst
index 5467aac5060cb..14067eb40958b 100644
--- a/libc/docs/stdio.rst
+++ b/libc/docs/stdio.rst
@@ -72,7 +72,7 @@ These functions operate on files on the host's system, without using the
============= =========
Function_Name Available
============= =========
-remove
+remove YES
rename
tmpnam
============= =========
@@ -91,7 +91,7 @@ fgets
getchar
fread YES
(f)putc
-(f)puts
+(f)puts YES
putchar
fwrite YES
ungetc
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index fbd3cfa8a589c..11d21ad831a30 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -496,6 +496,7 @@ def StdC : StandardSpec<"stdc"> {
Macro<"_IOFBF">,
Macro<"_IOLBF">,
Macro<"_IONBF">,
+ Macro<"EOF">,
], // Macros
[ // Types
SizeTType,
@@ -534,6 +535,17 @@ def StdC : StandardSpec<"stdc"> {
[ArgSpec<ConstCharPtr>,
ArgSpec<ConstCharPtr>]
>,
+ FunctionSpec<
+ "fputs",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharRestrictedPtr>,
+ ArgSpec<FILERestrictedPtr>]
+ >,
+ FunctionSpec<
+ "puts",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharRestrictedPtr>]
+ >,
FunctionSpec<
"fread",
RetValSpec<SizeTType>,
diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index e9766dbeb68fb..b5d00b7a876da 100644
--- a/libc/src/__support/File/file.cpp
+++ b/libc/src/__support/File/file.cpp
@@ -131,7 +131,7 @@ size_t File::write_unlocked_fbf(const uint8_t *data, size_t len) {
size_t File::write_unlocked_lbf(const uint8_t *data, size_t len) {
constexpr uint8_t NEWLINE_CHAR = '\n';
size_t last_newline = len;
- for (size_t i = len; i > 1; --i) {
+ for (size_t i = len; i >= 1; --i) {
if (data[i - 1] == NEWLINE_CHAR) {
last_newline = i - 1;
break;
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 3aa096cf1c1c8..e928847409d3e 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -184,6 +184,31 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)
+add_entrypoint_object(
+ fputs
+ SRCS
+ fputs.cpp
+ HDRS
+ fputs.h
+ DEPENDS
+ libc.include.stdio
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+)
+
+
+add_entrypoint_object(
+ puts
+ SRCS
+ puts.cpp
+ HDRS
+ puts.h
+ DEPENDS
+ libc.include.stdio
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+)
+
add_entrypoint_object(
fseek
SRCS
diff --git a/libc/src/stdio/fputs.cpp b/libc/src/stdio/fputs.cpp
new file mode 100644
index 0000000000000..aee15c1a2ac14
--- /dev/null
+++ b/libc/src/stdio/fputs.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of fputs -------------------------------------------===//
+//
+// 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/stdio/fputs.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, fputs,
+ (const char *__restrict str, ::FILE *__restrict stream)) {
+ cpp::string_view str_view(str);
+
+ size_t written = reinterpret_cast<__llvm_libc::File *>(stream)->write(
+ str, str_view.size());
+ if (str_view.size() != written) {
+ // The stream should be in an error state in this case.
+ return EOF;
+ }
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/fputs.h b/libc/src/stdio/fputs.h
new file mode 100644
index 0000000000000..2419fe8eeac70
--- /dev/null
+++ b/libc/src/stdio/fputs.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of fputs --------------------------*- 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_STDIO_FPUTS_H
+#define LLVM_LIBC_SRC_STDIO_FPUTS_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int fputs(const char *__restrict str, ::FILE *__restrict stream);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FPUTS_H
diff --git a/libc/src/stdio/puts.cpp b/libc/src/stdio/puts.cpp
new file mode 100644
index 0000000000000..93132da8bed32
--- /dev/null
+++ b/libc/src/stdio/puts.cpp
@@ -0,0 +1,32 @@
+//===-- Implementation of puts --------------------------------------------===//
+//
+// 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/stdio/puts.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) {
+ cpp::string_view str_view(str);
+ size_t written = __llvm_libc::stdout->write(str, str_view.size());
+ if (str_view.size() != written) {
+ // The stream should be in an error state in this case.
+ return EOF;
+ }
+ written = __llvm_libc::stdout->write("\n", 1);
+ if (1 != written) {
+ // The stream should be in an error state in this case.
+ return EOF;
+ }
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/puts.h b/libc/src/stdio/puts.h
new file mode 100644
index 0000000000000..fa5d6f77356aa
--- /dev/null
+++ b/libc/src/stdio/puts.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of puts ---------------------------*- 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_STDIO_PUTS_H
+#define LLVM_LIBC_SRC_STDIO_PUTS_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int puts(const char *__restrict str);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_PUTS_H
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 961077d2a94c6..962fa270204e9 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -15,6 +15,7 @@ add_libc_unittest(
libc.src.stdio.ferror
libc.src.stdio.fflush
libc.src.stdio.fopen
+ libc.src.stdio.fputs
libc.src.stdio.fread
libc.src.stdio.fseek
libc.src.stdio.fwrite
@@ -108,7 +109,16 @@ add_libc_unittest(
printf_test.cpp
DEPENDS
libc.src.stdio.printf
- libc.src.fenv.fesetround
+)
+
+add_libc_unittest(
+ puts_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ puts_test.cpp
+ DEPENDS
+ libc.src.stdio.puts
)
add_libc_unittest(
diff --git a/libc/test/src/stdio/fileop_test.cpp b/libc/test/src/stdio/fileop_test.cpp
index ab98fa5eefc16..399cc799a9382 100644
--- a/libc/test/src/stdio/fileop_test.cpp
+++ b/libc/test/src/stdio/fileop_test.cpp
@@ -12,6 +12,7 @@
#include "src/stdio/ferror.h"
#include "src/stdio/fflush.h"
#include "src/stdio/fopen.h"
+#include "src/stdio/fputs.h"
#include "src/stdio/fread.h"
#include "src/stdio/fseek.h"
#include "src/stdio/fwrite.h"
@@ -66,9 +67,38 @@ TEST(LlvmLibcFILETest, SimpleFileOperations) {
ASSERT_NE(errno, 0);
errno = 0;
+ __llvm_libc::clearerr(file);
+
+ // Should be an error to puts.
+ ASSERT_EQ(EOF, __llvm_libc::fputs(CONTENT, file));
+ ASSERT_NE(__llvm_libc::ferror(file), 0);
+ ASSERT_NE(errno, 0);
+ errno = 0;
+
+ __llvm_libc::clearerr(file);
+ ASSERT_EQ(__llvm_libc::ferror(file), 0);
+
+ ASSERT_EQ(__llvm_libc::fclose(file), 0);
+
+ // Now try puts.
+ file = __llvm_libc::fopen(FILENAME, "w");
+ ASSERT_FALSE(file == nullptr);
+ // fputs returns a negative value on error (EOF) or any non-negative value on
+ // success. This assert checks that the return value is non-negative.
+ ASSERT_GE(__llvm_libc::fputs(CONTENT, file), 0);
+
__llvm_libc::clearerr(file);
ASSERT_EQ(__llvm_libc::ferror(file), 0);
+ ASSERT_EQ(0, __llvm_libc::fclose(file));
+
+ file = __llvm_libc::fopen(FILENAME, "r");
+ ASSERT_FALSE(file == nullptr);
+
+ ASSERT_EQ(__llvm_libc::fread(read_data, 1, sizeof(CONTENT) - 1, file),
+ sizeof(CONTENT) - 1);
+ read_data[sizeof(CONTENT) - 1] = '\0';
+ ASSERT_STREQ(read_data, CONTENT);
ASSERT_EQ(__llvm_libc::fclose(file), 0);
}
diff --git a/libc/test/src/stdio/puts_test.cpp b/libc/test/src/stdio/puts_test.cpp
new file mode 100644
index 0000000000000..c32fdff3bcda6
--- /dev/null
+++ b/libc/test/src/stdio/puts_test.cpp
@@ -0,0 +1,28 @@
+//===-- Unittests for puts ---------------------------------------------===//
+//
+// 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/stdio/puts.h"
+
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcPutsTest, PrintOut) {
+ int result;
+
+ constexpr char simple[] = "A simple string";
+ result = __llvm_libc::puts(simple);
+ EXPECT_GE(result, 0);
+
+ // check that it appends a second newline at the end.
+ constexpr char numbers[] = "1234567890\n";
+ result = __llvm_libc::puts(numbers);
+ EXPECT_GE(result, 0);
+
+ constexpr char more[] = "1234 and more\n6789 and rhyme";
+ result = __llvm_libc::puts(more);
+ EXPECT_GE(result, 0);
+}
More information about the libc-commits
mailing list