diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -229,6 +229,13 @@ libc.src.stdlib.exit libc.src.stdlib.getenv + # stdio.h entrypoints + libc.src.stdio.fclose + libc.src.stdio.fopen + libc.src.stdio.fread + libc.src.stdio.fseek + libc.src.stdio.fwrite + # signal.h entrypoints # TODO: Enable signal.h entrypoints after fixing signal.h # libc.src.signal.raise diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -481,13 +481,39 @@ ], [], // Enumerations [ + FunctionSpec< + "fclose", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "fopen", + RetValSpec, + [ArgSpec, + ArgSpec] + >, + FunctionSpec< + "fread", + RetValSpec, + [ArgSpec, + ArgSpec, + ArgSpec, + ArgSpec] + >, + FunctionSpec< + "fseek", + RetValSpec, + [ArgSpec, + ArgSpec, + ArgSpec] + >, FunctionSpec< "fwrite", RetValSpec, [ArgSpec, - ArgSpec, - ArgSpec, - ArgSpec] + ArgSpec, + ArgSpec, + ArgSpec] >, ] >; diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -1,3 +1,39 @@ +add_entrypoint_object( + fopen + SRCS + fopen.cpp + HDRS + fopen.h + DEPENDS + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + +add_entrypoint_object( + fclose + SRCS + fclose.cpp + HDRS + fclose.h + DEPENDS + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + +add_entrypoint_object( + fread + SRCS + fread.cpp + HDRS + fread.h + DEPENDS + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + add_entrypoint_object( fwrite SRCS @@ -5,6 +41,19 @@ HDRS fwrite.h DEPENDS - libc.src.threads.mtx_lock - libc.src.threads.mtx_unlock + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + +add_entrypoint_object( + fseek + SRCS + fseek.cpp + HDRS + fseek.h + DEPENDS + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file ) diff --git a/libc/src/stdio/FILE.h b/libc/src/stdio/fclose.h rename from libc/src/stdio/FILE.h rename to libc/src/stdio/fclose.h --- a/libc/src/stdio/FILE.h +++ b/libc/src/stdio/fclose.h @@ -1,4 +1,4 @@ -//===-- Internal definition of FILE -----------------------------*- C++ -*-===// +//===-- Implementation header of fclose -------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,22 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDIO_FILE_H -#define LLVM_LIBC_SRC_STDIO_FILE_H +#ifndef LLVM_LIBC_SRC_STDIO_FCLOSE_H +#define LLVM_LIBC_SRC_STDIO_FCLOSE_H -#include "include/threads.h" -#include +#include namespace __llvm_libc { -struct FILE { - mtx_t lock; - - using write_function_t = size_t(FILE *, const char *, size_t); - - write_function_t *write; -}; +int fclose(::FILE *stream); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDIO_FILE_H +#endif // LLVM_LIBC_SRC_STDIO_FCLOSE_H diff --git a/libc/src/stdio/fclose.cpp b/libc/src/stdio/fclose.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fclose.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of fclose ------------------------------------------===// +// +// 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/__support/File/file.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fclose, (::FILE * stream)) { + return reinterpret_cast<__llvm_libc::File *>(stream)->close(); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/FILE.h b/libc/src/stdio/fopen.h copy from libc/src/stdio/FILE.h copy to libc/src/stdio/fopen.h --- a/libc/src/stdio/FILE.h +++ b/libc/src/stdio/fopen.h @@ -1,4 +1,4 @@ -//===-- Internal definition of FILE -----------------------------*- C++ -*-===// +//===-- Implementation header of fopen --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,22 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDIO_FILE_H -#define LLVM_LIBC_SRC_STDIO_FILE_H +#ifndef LLVM_LIBC_SRC_STDIO_FOPEN_H +#define LLVM_LIBC_SRC_STDIO_FOPEN_H -#include "include/threads.h" -#include +#include namespace __llvm_libc { -struct FILE { - mtx_t lock; - - using write_function_t = size_t(FILE *, const char *, size_t); - - write_function_t *write; -}; +::FILE *fopen(const char *__restrict name, const char *__restrict mode); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDIO_FILE_H +#endif // LLVM_LIBC_SRC_STDIO_FOPEN_H diff --git a/libc/src/stdio/fopen.cpp b/libc/src/stdio/fopen.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fopen.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of fopen -------------------------------------------===// +// +// 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/fopen.h" +#include "src/__support/File/file.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(::FILE *, fopen, + (const char *__restrict name, const char *__restrict mode)) { + return reinterpret_cast<::FILE *>(__llvm_libc::openfile(name, mode)); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/FILE.h b/libc/src/stdio/fread.h copy from libc/src/stdio/FILE.h copy to libc/src/stdio/fread.h --- a/libc/src/stdio/FILE.h +++ b/libc/src/stdio/fread.h @@ -1,4 +1,4 @@ -//===-- Internal definition of FILE -----------------------------*- C++ -*-===// +//===-- Implementation header of fread --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,22 +6,16 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDIO_FILE_H -#define LLVM_LIBC_SRC_STDIO_FILE_H +#ifndef LLVM_LIBC_SRC_STDIO_FREAD_H +#define LLVM_LIBC_SRC_STDIO_FREAD_H -#include "include/threads.h" -#include +#include namespace __llvm_libc { -struct FILE { - mtx_t lock; - - using write_function_t = size_t(FILE *, const char *, size_t); - - write_function_t *write; -}; +size_t fread(void *__restrict buffer, size_t size, size_t nmemb, + ::FILE *stream); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDIO_FILE_H +#endif // LLVM_LIBC_SRC_STDIO_FREAD_H diff --git a/libc/src/stdio/fread.cpp b/libc/src/stdio/fread.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fread.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of fread -------------------------------------------===// +// +// 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/fread.h" +#include "src/__support/File/file.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(size_t, fread, + (void *__restrict buffer, size_t size, size_t nmemb, + ::FILE *stream)) { + return reinterpret_cast<__llvm_libc::File *>(stream)->read(buffer, + size * nmemb); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/FILE.h b/libc/src/stdio/fseek.h rename from libc/src/stdio/FILE.h rename to libc/src/stdio/fseek.h --- a/libc/src/stdio/FILE.h +++ b/libc/src/stdio/fseek.h @@ -1,4 +1,4 @@ -//===-- Internal definition of FILE -----------------------------*- C++ -*-===// +//===-- Implementation header of fseek --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,22 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDIO_FILE_H -#define LLVM_LIBC_SRC_STDIO_FILE_H +#ifndef LLVM_LIBC_SRC_STDIO_FSEEK_H +#define LLVM_LIBC_SRC_STDIO_FSEEK_H -#include "include/threads.h" -#include +#include namespace __llvm_libc { -struct FILE { - mtx_t lock; - - using write_function_t = size_t(FILE *, const char *, size_t); - - write_function_t *write; -}; +int fseek(::FILE *stream, long offset, int whence); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDIO_FILE_H +#endif // LLVM_LIBC_SRC_STDIO_FSEEK_H diff --git a/libc/src/stdio/fseek.cpp b/libc/src/stdio/fseek.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fseek.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of fseek -------------------------------------------===// +// +// 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/fseek.h" +#include "src/__support/File/file.h" + +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fseek, (::FILE * stream, long offset, int whence)) { + return reinterpret_cast<__llvm_libc::File *>(stream)->seek(offset, whence); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdio/fwrite.h b/libc/src/stdio/fwrite.h --- a/libc/src/stdio/fwrite.h +++ b/libc/src/stdio/fwrite.h @@ -9,13 +9,12 @@ #ifndef LLVM_LIBC_SRC_STDIO_FWRITE_H #define LLVM_LIBC_SRC_STDIO_FWRITE_H -#include "src/stdio/FILE.h" -#include +#include namespace __llvm_libc { -size_t fwrite(const void *__restrict ptr, size_t size, size_t nmeb, - __llvm_libc::FILE *__restrict stream); +size_t fwrite(const void *__restrict ptr, size_t size, size_t nmemb, + ::FILE *__restrict stream); } // namespace __llvm_libc diff --git a/libc/src/stdio/fwrite.cpp b/libc/src/stdio/fwrite.cpp --- a/libc/src/stdio/fwrite.cpp +++ b/libc/src/stdio/fwrite.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of fwrite and fwrite_unlocked ------------*- C++ -*-===// +//===-- Implementation of fwrite ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,24 +7,17 @@ //===----------------------------------------------------------------------===// #include "src/stdio/fwrite.h" -#include "src/stdio/FILE.h" -#include "src/threads/mtx_lock.h" -#include "src/threads/mtx_unlock.h" +#include "src/__support/File/file.h" -namespace __llvm_libc { +#include -size_t fwrite_unlocked(const void *__restrict ptr, size_t size, size_t nmeb, - __llvm_libc::FILE *__restrict stream) { - return stream->write(stream, reinterpret_cast(ptr), - size * nmeb); -} +namespace __llvm_libc { -size_t fwrite(const void *__restrict ptr, size_t size, size_t nmeb, - __llvm_libc::FILE *__restrict stream) { - __llvm_libc::mtx_lock(&stream->lock); - size_t written = fwrite_unlocked(ptr, size, nmeb, stream); - __llvm_libc::mtx_unlock(&stream->lock); - return written; +LLVM_LIBC_FUNCTION(size_t, fwrite, + (const void *__restrict buffer, size_t size, size_t nmemb, + ::FILE *stream)) { + return reinterpret_cast<__llvm_libc::File *>(stream)->write(buffer, + size * nmemb); } } // namespace __llvm_libc diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -1,11 +1,17 @@ add_libc_testsuite(libc_stdio_unittests) add_libc_unittest( - fwrite_test + fileop_test SUITE libc_stdio_unittests SRCS - fwrite_test.cpp + fileop_test.cpp DEPENDS + libc.src.stdio.fclose + libc.src.stdio.fopen + libc.src.stdio.fread + libc.src.stdio.fseek libc.src.stdio.fwrite ) + +add_subdirectory(testdata) diff --git a/libc/test/src/stdio/fileop_test.cpp b/libc/test/src/stdio/fileop_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdio/fileop_test.cpp @@ -0,0 +1,43 @@ +//===-- Unittests for file operations like fopen, flcose etc --------------===// +// +// 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/fopen.h" +#include "src/stdio/fread.h" +#include "src/stdio/fseek.h" +#include "src/stdio/fwrite.h" +#include "utils/UnitTest/Test.h" + +#include + +TEST(LlvmLibcStdio, SimpleOperations) { + constexpr char FILENAME[] = "testdata/simple_operations.test"; + ::FILE *file = __llvm_libc::fopen(FILENAME, "w"); + ASSERT_FALSE(file == nullptr); + constexpr char CONTENT[] = "1234567890987654321"; + ASSERT_EQ(sizeof(CONTENT) - 1, + __llvm_libc::fwrite(CONTENT, 1, sizeof(CONTENT) - 1, file)); + ASSERT_EQ(0, __llvm_libc::fclose(file)); + + file = __llvm_libc::fopen(FILENAME, "r"); + ASSERT_FALSE(file == nullptr); + + constexpr size_t READ_SIZE = 5; + char data[READ_SIZE]; + data[READ_SIZE - 1] = '\0'; + ASSERT_EQ(__llvm_libc::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1); + ASSERT_STREQ(data, "1234"); + ASSERT_EQ(__llvm_libc::fseek(file, 5, SEEK_CUR), 0); + ASSERT_EQ(__llvm_libc::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1); + ASSERT_STREQ(data, "0987"); + ASSERT_EQ(__llvm_libc::fseek(file, -5, SEEK_CUR), 0); + ASSERT_EQ(__llvm_libc::fread(data, 1, READ_SIZE - 1, file), READ_SIZE - 1); + ASSERT_STREQ(data, "9098"); + + ASSERT_EQ(__llvm_libc::fclose(file), 0); +} diff --git a/libc/test/src/stdio/fwrite_test.cpp b/libc/test/src/stdio/fwrite_test.cpp deleted file mode 100644 --- a/libc/test/src/stdio/fwrite_test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===-- Unittests for fwrite ----------------------------------------------===// -// -// 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/__support/CPP/Array.h" -#include "src/stdio/FILE.h" -#include "src/stdio/fwrite.h" -#include "utils/UnitTest/Test.h" - -TEST(LlvmLibcStdio, FWriteBasic) { - struct StrcpyFile : __llvm_libc::FILE { - char *buf; - } f; - char array[6]; - f.buf = array; - f.write = +[](__llvm_libc::FILE *file, const char *ptr, size_t size) { - StrcpyFile *strcpyFile = static_cast(file); - for (size_t i = 0; i < size; ++i) - strcpyFile->buf[i] = ptr[i]; - return size; - }; - EXPECT_EQ(fwrite("hello", 1, 6, &f), 6UL); - EXPECT_STREQ(array, "hello"); -} diff --git a/libc/test/src/stdio/testdata/CMakeLists.txt b/libc/test/src/stdio/testdata/CMakeLists.txt new file mode 100644