[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