[libc] Add implementation of getc, getc_unlocked and fgetc_unlocked.
Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D137507
This commit is contained in:
parent
4fa00ce15c
commit
6a6101958a
|
@ -376,6 +376,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||||
libc.src.stdio.ferror
|
libc.src.stdio.ferror
|
||||||
libc.src.stdio.ferror_unlocked
|
libc.src.stdio.ferror_unlocked
|
||||||
libc.src.stdio.fgetc
|
libc.src.stdio.fgetc
|
||||||
|
libc.src.stdio.fgetc_unlocked
|
||||||
libc.src.stdio.fgets
|
libc.src.stdio.fgets
|
||||||
libc.src.stdio.fflush
|
libc.src.stdio.fflush
|
||||||
libc.src.stdio.fopen
|
libc.src.stdio.fopen
|
||||||
|
@ -390,6 +391,8 @@ if(LLVM_LIBC_FULL_BUILD)
|
||||||
libc.src.stdio.fwrite
|
libc.src.stdio.fwrite
|
||||||
libc.src.stdio.fwrite_unlocked
|
libc.src.stdio.fwrite_unlocked
|
||||||
libc.src.stdio.fprintf
|
libc.src.stdio.fprintf
|
||||||
|
libc.src.stdio.getc
|
||||||
|
libc.src.stdio.getc_unlocked
|
||||||
libc.src.stdio.printf
|
libc.src.stdio.printf
|
||||||
libc.src.stdio.putc
|
libc.src.stdio.putc
|
||||||
libc.src.stdio.putchar
|
libc.src.stdio.putchar
|
||||||
|
|
|
@ -137,6 +137,11 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> {
|
||||||
ArgSpec<SizeTType>,
|
ArgSpec<SizeTType>,
|
||||||
ArgSpec<FILERestrictedPtr>]
|
ArgSpec<FILERestrictedPtr>]
|
||||||
>,
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"fgetc_unlocked",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<FILEPtr>]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -1011,6 +1011,11 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
RetValSpec<VoidType>,
|
RetValSpec<VoidType>,
|
||||||
[ArgSpec<FILEPtr>]
|
[ArgSpec<FILEPtr>]
|
||||||
>,
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"getc_unlocked",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<FILEPtr>]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -568,6 +568,11 @@ def StdC : StandardSpec<"stdc"> {
|
||||||
RetValSpec<LongType>,
|
RetValSpec<LongType>,
|
||||||
[ArgSpec<FILEPtr>]
|
[ArgSpec<FILEPtr>]
|
||||||
>,
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"getc",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[ArgSpec<FILEPtr>]
|
||||||
|
>,
|
||||||
FunctionSpec<
|
FunctionSpec<
|
||||||
"putc",
|
"putc",
|
||||||
RetValSpec<IntType>,
|
RetValSpec<IntType>,
|
||||||
|
|
|
@ -113,6 +113,42 @@ add_entrypoint_object(
|
||||||
libc.src.__support.File.platform_file
|
libc.src.__support.File.platform_file
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
fgetc_unlocked
|
||||||
|
SRCS
|
||||||
|
fgetc_unlocked.cpp
|
||||||
|
HDRS
|
||||||
|
fgetc_unlocked.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.stdio
|
||||||
|
libc.src.__support.File.file
|
||||||
|
libc.src.__support.File.platform_file
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
getc
|
||||||
|
SRCS
|
||||||
|
getc.cpp
|
||||||
|
HDRS
|
||||||
|
getc.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.stdio
|
||||||
|
libc.src.__support.File.file
|
||||||
|
libc.src.__support.File.platform_file
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
getc_unlocked
|
||||||
|
SRCS
|
||||||
|
getc_unlocked.cpp
|
||||||
|
HDRS
|
||||||
|
getc_unlocked.h
|
||||||
|
DEPENDS
|
||||||
|
libc.include.stdio
|
||||||
|
libc.src.__support.File.file
|
||||||
|
libc.src.__support.File.platform_file
|
||||||
|
)
|
||||||
|
|
||||||
add_entrypoint_object(
|
add_entrypoint_object(
|
||||||
fgets
|
fgets
|
||||||
SRCS
|
SRCS
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
//===-- Implementation of fgetc_unlocked ----------------------------------===//
|
||||||
|
//
|
||||||
|
// 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/fgetc_unlocked.h"
|
||||||
|
#include "src/__support/File/file.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(int, fgetc_unlocked, (::FILE * stream)) {
|
||||||
|
unsigned char c;
|
||||||
|
size_t r =
|
||||||
|
reinterpret_cast<__llvm_libc::File *>(stream)->read_unlocked(&c, 1);
|
||||||
|
if (r != 1)
|
||||||
|
return EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header of fgetc_unlocked -----------------*- 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_FGETC_UNLOCKED_H
|
||||||
|
#define LLVM_LIBC_SRC_STDIO_FGETC_UNLOCKED_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int fgetc_unlocked(::FILE *f);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_STDIO_FGETC_UNLOCKED_H
|
|
@ -0,0 +1,24 @@
|
||||||
|
//===-- Implementation of getc --------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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/getc.h"
|
||||||
|
#include "src/__support/File/file.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(int, getc, (::FILE * stream)) {
|
||||||
|
unsigned char c;
|
||||||
|
size_t r = reinterpret_cast<__llvm_libc::File *>(stream)->read(&c, 1);
|
||||||
|
if (r != 1)
|
||||||
|
return EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header of getc ---------------------------*- 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_GETC_H
|
||||||
|
#define LLVM_LIBC_SRC_STDIO_GETC_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int getc(::FILE *f);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_STDIO_GETC_H
|
|
@ -0,0 +1,25 @@
|
||||||
|
//===-- Implementation of getc_unlocked ----------------------------------===//
|
||||||
|
//
|
||||||
|
// 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/getc_unlocked.h"
|
||||||
|
#include "src/__support/File/file.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(int, getc_unlocked, (::FILE * stream)) {
|
||||||
|
unsigned char c;
|
||||||
|
size_t r =
|
||||||
|
reinterpret_cast<__llvm_libc::File *>(stream)->read_unlocked(&c, 1);
|
||||||
|
if (r != 1)
|
||||||
|
return EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
||||||
|
//===-- Implementation header of getc_unlocked ------------------*- 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_GETC_UNLOCKED_H
|
||||||
|
#define LLVM_LIBC_SRC_STDIO_GETC_UNLOCKED_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
int getc_unlocked(::FILE *f);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_STDIO_GETC_UNLOCKED_H
|
|
@ -216,6 +216,29 @@ add_libc_unittest(
|
||||||
libc.src.stdio.fgetc
|
libc.src.stdio.fgetc
|
||||||
libc.src.stdio.fopen
|
libc.src.stdio.fopen
|
||||||
libc.src.stdio.fwrite
|
libc.src.stdio.fwrite
|
||||||
|
libc.src.stdio.getc
|
||||||
|
)
|
||||||
|
|
||||||
|
add_libc_unittest(
|
||||||
|
fgetc_unlocked_test
|
||||||
|
SUITE
|
||||||
|
libc_stdio_unittests
|
||||||
|
SRCS
|
||||||
|
fgetc_unlocked_test.cpp
|
||||||
|
DEPENDS
|
||||||
|
libc.include.errno
|
||||||
|
libc.include.stdio
|
||||||
|
libc.src.stdio.fclose
|
||||||
|
libc.src.stdio.ferror
|
||||||
|
libc.src.stdio.ferror_unlocked
|
||||||
|
libc.src.stdio.feof
|
||||||
|
libc.src.stdio.feof_unlocked
|
||||||
|
libc.src.stdio.fgetc_unlocked
|
||||||
|
libc.src.stdio.flockfile
|
||||||
|
libc.src.stdio.fopen
|
||||||
|
libc.src.stdio.funlockfile
|
||||||
|
libc.src.stdio.fwrite
|
||||||
|
libc.src.stdio.getc_unlocked
|
||||||
)
|
)
|
||||||
|
|
||||||
add_libc_unittest(
|
add_libc_unittest(
|
||||||
|
|
|
@ -13,38 +13,50 @@
|
||||||
#include "src/stdio/fgetc.h"
|
#include "src/stdio/fgetc.h"
|
||||||
#include "src/stdio/fopen.h"
|
#include "src/stdio/fopen.h"
|
||||||
#include "src/stdio/fwrite.h"
|
#include "src/stdio/fwrite.h"
|
||||||
|
#include "src/stdio/getc.h"
|
||||||
#include "utils/UnitTest/Test.h"
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
TEST(LlvmLibcFGetCTest, WriteAndReadCharacters) {
|
class LlvmLibcGetcTest : public __llvm_libc::testing::Test {
|
||||||
constexpr char FILENAME[] = "testdata/fgetc.test";
|
public:
|
||||||
::FILE *file = __llvm_libc::fopen(FILENAME, "w");
|
using GetcFunc = int(FILE *);
|
||||||
ASSERT_FALSE(file == nullptr);
|
void test_with_func(GetcFunc *func, const char *filename) {
|
||||||
constexpr char CONTENT[] = "123456789";
|
::FILE *file = __llvm_libc::fopen(filename, "w");
|
||||||
constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
|
ASSERT_FALSE(file == nullptr);
|
||||||
ASSERT_EQ(WRITE_SIZE, __llvm_libc::fwrite(CONTENT, 1, WRITE_SIZE, file));
|
constexpr char CONTENT[] = "123456789";
|
||||||
// This is a write-only file so reads should fail.
|
constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
|
||||||
ASSERT_EQ(__llvm_libc::fgetc(file), EOF);
|
ASSERT_EQ(WRITE_SIZE, __llvm_libc::fwrite(CONTENT, 1, WRITE_SIZE, file));
|
||||||
// This is an error and not a real EOF.
|
// This is a write-only file so reads should fail.
|
||||||
ASSERT_EQ(__llvm_libc::feof(file), 0);
|
ASSERT_EQ(func(file), EOF);
|
||||||
ASSERT_NE(__llvm_libc::ferror(file), 0);
|
// This is an error and not a real EOF.
|
||||||
errno = 0;
|
ASSERT_EQ(__llvm_libc::feof(file), 0);
|
||||||
|
ASSERT_NE(__llvm_libc::ferror(file), 0);
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
||||||
|
|
||||||
file = __llvm_libc::fopen(FILENAME, "r");
|
file = __llvm_libc::fopen(filename, "r");
|
||||||
ASSERT_FALSE(file == nullptr);
|
ASSERT_FALSE(file == nullptr);
|
||||||
|
|
||||||
for (size_t i = 0; i < WRITE_SIZE; ++i) {
|
for (size_t i = 0; i < WRITE_SIZE; ++i) {
|
||||||
int c = __llvm_libc::fgetc(file);
|
int c = func(file);
|
||||||
ASSERT_EQ(c, int('1' + i));
|
ASSERT_EQ(c, int('1' + i));
|
||||||
|
}
|
||||||
|
// Reading more should return EOF but not set error.
|
||||||
|
ASSERT_EQ(func(file), EOF);
|
||||||
|
ASSERT_NE(__llvm_libc::feof(file), 0);
|
||||||
|
ASSERT_EQ(__llvm_libc::ferror(file), 0);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
||||||
}
|
}
|
||||||
// Reading more should return EOF but not set error.
|
};
|
||||||
ASSERT_EQ(__llvm_libc::fgetc(file), EOF);
|
|
||||||
ASSERT_NE(__llvm_libc::feof(file), 0);
|
|
||||||
ASSERT_EQ(__llvm_libc::ferror(file), 0);
|
|
||||||
|
|
||||||
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
TEST_F(LlvmLibcGetcTest, WriteAndReadCharactersWithFgetc) {
|
||||||
|
test_with_func(&__llvm_libc::fgetc, "testdata/fgetc.test");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcGetcTest, WriteAndReadCharactersWithGetc) {
|
||||||
|
test_with_func(&__llvm_libc::getc, "testdata/getc.test");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
//===-- Unittests for fgetc -----------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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/fclose.h"
|
||||||
|
#include "src/stdio/feof.h"
|
||||||
|
#include "src/stdio/feof_unlocked.h"
|
||||||
|
#include "src/stdio/ferror.h"
|
||||||
|
#include "src/stdio/ferror_unlocked.h"
|
||||||
|
#include "src/stdio/fgetc_unlocked.h"
|
||||||
|
#include "src/stdio/flockfile.h"
|
||||||
|
#include "src/stdio/fopen.h"
|
||||||
|
#include "src/stdio/funlockfile.h"
|
||||||
|
#include "src/stdio/fwrite.h"
|
||||||
|
#include "src/stdio/getc_unlocked.h"
|
||||||
|
#include "utils/UnitTest/Test.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
class LlvmLibcGetcTest : public __llvm_libc::testing::Test {
|
||||||
|
public:
|
||||||
|
using GetcFunc = int(FILE *);
|
||||||
|
void test_with_func(GetcFunc *func, const char *filename) {
|
||||||
|
::FILE *file = __llvm_libc::fopen(filename, "w");
|
||||||
|
ASSERT_FALSE(file == nullptr);
|
||||||
|
constexpr char CONTENT[] = "123456789";
|
||||||
|
constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
|
||||||
|
ASSERT_EQ(WRITE_SIZE, __llvm_libc::fwrite(CONTENT, 1, WRITE_SIZE, file));
|
||||||
|
// This is a write-only file so reads should fail.
|
||||||
|
ASSERT_EQ(func(file), EOF);
|
||||||
|
// This is an error and not a real EOF.
|
||||||
|
ASSERT_EQ(__llvm_libc::feof(file), 0);
|
||||||
|
ASSERT_NE(__llvm_libc::ferror(file), 0);
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
||||||
|
|
||||||
|
file = __llvm_libc::fopen(filename, "r");
|
||||||
|
ASSERT_FALSE(file == nullptr);
|
||||||
|
|
||||||
|
__llvm_libc::flockfile(file);
|
||||||
|
for (size_t i = 0; i < WRITE_SIZE; ++i) {
|
||||||
|
int c = func(file);
|
||||||
|
ASSERT_EQ(c, int('1' + i));
|
||||||
|
}
|
||||||
|
// Reading more should return EOF but not set error.
|
||||||
|
ASSERT_EQ(func(file), EOF);
|
||||||
|
ASSERT_NE(__llvm_libc::feof_unlocked(file), 0);
|
||||||
|
ASSERT_EQ(__llvm_libc::ferror_unlocked(file), 0);
|
||||||
|
|
||||||
|
__llvm_libc::funlockfile(file);
|
||||||
|
ASSERT_EQ(0, __llvm_libc::fclose(file));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcGetcTest, WriteAndReadCharactersWithFgetcUnlocked) {
|
||||||
|
test_with_func(&__llvm_libc::fgetc_unlocked, "testdata/fgetc_unlocked.test");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcGetcTest, WriteAndReadCharactersWithGetcUnlocked) {
|
||||||
|
test_with_func(&__llvm_libc::getc_unlocked, "testdata/getc_unlocked.test");
|
||||||
|
}
|
Loading…
Reference in New Issue