[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
This commit is contained in:
Michael Jones 2022-09-20 16:58:05 -07:00
parent f40266603e
commit a9e0dbefdd
13 changed files with 214 additions and 4 deletions

View File

@ -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"];
}

View File

@ -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

View File

@ -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

View File

@ -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>,

View File

@ -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;

View File

@ -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

30
libc/src/stdio/fputs.cpp Normal file
View File

@ -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

20
libc/src/stdio/fputs.h Normal file
View File

@ -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

32
libc/src/stdio/puts.cpp Normal file
View File

@ -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

20
libc/src/stdio/puts.h Normal file
View File

@ -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

View File

@ -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(

View File

@ -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,10 +67,39 @@ 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);
}
TEST(LlvmLibcFILETest, FFlush) {

View File

@ -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);
}