Author: Petr Hosek Date: 2025-12-17T10:56:45-08:00 New Revision: dd63127b567820531f0b52ec5d9c6228c995a67e
URL: https://github.com/llvm/llvm-project/commit/dd63127b567820531f0b52ec5d9c6228c995a67e DIFF: https://github.com/llvm/llvm-project/commit/dd63127b567820531f0b52ec5d9c6228c995a67e.diff LOG: [libc] Support opaque FILE* on baremetal (#168931) This change expands the stdio support on baremetal to support opaque FILE*. This builds on top of the existing baremetal embedding API; we treat the standard FILE* streams as pointers that point to the cookie symbols which are a part of the embedding API. This also allows users to define their own FILE* streams, but we don't (yet) support the API that return FILE* such as fopen or fopencookie. Added: libc/src/stdio/baremetal/feof.cpp libc/src/stdio/baremetal/ferror.cpp libc/src/stdio/baremetal/fgetc.cpp libc/src/stdio/baremetal/fgets.cpp libc/src/stdio/baremetal/file_internal.h libc/src/stdio/baremetal/fprintf.cpp libc/src/stdio/baremetal/fputc.cpp libc/src/stdio/baremetal/fputs.cpp libc/src/stdio/baremetal/fread.cpp libc/src/stdio/baremetal/fscanf.cpp libc/src/stdio/baremetal/fwrite.cpp libc/src/stdio/baremetal/getc.cpp libc/src/stdio/baremetal/putc.cpp libc/src/stdio/baremetal/vfprintf.cpp libc/src/stdio/baremetal/vfprintf_internal.h libc/src/stdio/baremetal/vfscanf.cpp libc/src/stdio/baremetal/vfscanf_internal.h Modified: clang/cmake/caches/Fuchsia-stage2.cmake libc/config/baremetal/aarch64/entrypoints.txt libc/config/baremetal/arm/entrypoints.txt libc/config/baremetal/riscv/entrypoints.txt libc/src/__support/OSUtil/baremetal/io.cpp libc/src/__support/OSUtil/baremetal/io.h libc/src/stdio/baremetal/CMakeLists.txt libc/src/stdio/baremetal/getchar.cpp libc/src/stdio/baremetal/printf.cpp libc/src/stdio/baremetal/putchar.cpp libc/src/stdio/baremetal/puts.cpp libc/src/stdio/baremetal/scanf.cpp libc/src/stdio/baremetal/vprintf.cpp libc/src/stdio/baremetal/vscanf.cpp Removed: libc/src/stdio/baremetal/scanf_internal.h ################################################################################ diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 9df14d444eed6..be41a6db7dff3 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -341,7 +341,7 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv7em-none-eabi;armv8m.main-n foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dfputs(string, stream)=puts(string)\" -D_LIBCPP_PRINT=1") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment") if(NOT ${target} STREQUAL "aarch64-none-elf") set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mthumb") endif() @@ -372,6 +372,7 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv7em-none-eabi;armv8m.main-n set(RUNTIMES_${target}_LIBCXX_ENABLE_RTTI OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_THREADS OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "") + set(RUNTIMES_${target}_LIBCXX_HAS_TERMINAL_AVAILABLE OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${target}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "") set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "") @@ -406,7 +407,7 @@ foreach(target riscv32-unknown-elf) foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dfputs(string, stream)=puts(string)\" -D_LIBCPP_PRINT=1" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment" CACHE STRING "") endforeach() foreach(type SHARED;MODULE;EXE) set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") @@ -427,6 +428,7 @@ foreach(target riscv32-unknown-elf) set(RUNTIMES_${target}_LIBCXX_ENABLE_RTTI OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_THREADS OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "") + set(RUNTIMES_${target}_LIBCXX_HAS_TERMINAL_AVAILABLE OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${target}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "") set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "") diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt index c69ab3d0bb37c..742d96761c415 100644 --- a/libc/config/baremetal/aarch64/entrypoints.txt +++ b/libc/config/baremetal/aarch64/entrypoints.txt @@ -124,8 +124,19 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.asprintf + libc.src.stdio.feof + libc.src.stdio.ferror + libc.src.stdio.fgetc + libc.src.stdio.fgets + libc.src.stdio.fprintf + libc.src.stdio.fputc + libc.src.stdio.fputs + libc.src.stdio.fread + libc.src.stdio.fscanf + libc.src.stdio.fwrite libc.src.stdio.getchar libc.src.stdio.printf + libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts libc.src.stdio.remove @@ -134,6 +145,8 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdio.sprintf libc.src.stdio.sscanf libc.src.stdio.vasprintf + libc.src.stdio.vfprintf + libc.src.stdio.vfscanf libc.src.stdio.vprintf libc.src.stdio.vscanf libc.src.stdio.vsnprintf diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index c566f8ad08c8e..95cb0dea8e49e 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -124,8 +124,19 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.asprintf + libc.src.stdio.feof + libc.src.stdio.ferror + libc.src.stdio.fgetc + libc.src.stdio.fgets + libc.src.stdio.fprintf + libc.src.stdio.fputc + libc.src.stdio.fputs + libc.src.stdio.fread + libc.src.stdio.fscanf + libc.src.stdio.fwrite libc.src.stdio.getchar libc.src.stdio.printf + libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts libc.src.stdio.remove @@ -134,6 +145,8 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdio.sprintf libc.src.stdio.sscanf libc.src.stdio.vasprintf + libc.src.stdio.vfprintf + libc.src.stdio.vfscanf libc.src.stdio.vprintf libc.src.stdio.vscanf libc.src.stdio.vsnprintf diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index a6aef96e91698..3fc71280f5163 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -124,8 +124,19 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.asprintf + libc.src.stdio.feof + libc.src.stdio.ferror + libc.src.stdio.fgetc + libc.src.stdio.fgets + libc.src.stdio.fprintf + libc.src.stdio.fputc + libc.src.stdio.fputs + libc.src.stdio.fread + libc.src.stdio.fscanf + libc.src.stdio.fwrite libc.src.stdio.getchar libc.src.stdio.printf + libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts libc.src.stdio.remove @@ -134,6 +145,8 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdio.sprintf libc.src.stdio.sscanf libc.src.stdio.vasprintf + libc.src.stdio.vfprintf + libc.src.stdio.vfscanf libc.src.stdio.vprintf libc.src.stdio.vscanf libc.src.stdio.vsnprintf diff --git a/libc/src/__support/OSUtil/baremetal/io.cpp b/libc/src/__support/OSUtil/baremetal/io.cpp index 2a9ef6bfa6579..2978d701017a5 100644 --- a/libc/src/__support/OSUtil/baremetal/io.cpp +++ b/libc/src/__support/OSUtil/baremetal/io.cpp @@ -8,49 +8,15 @@ #include "io.h" +#include "hdr/types/FILE.h" #include "src/__support/CPP/string_view.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { -// These are intended to be provided by the vendor. -// -// The signature of these types and functions intentionally match `fopencookie` -// which allows the following: -// -// ``` -// struct __llvm_libc_stdio_cookie { ... }; -// ... -// struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie; -// cookie_io_functions_t stdin_func = { .read = __llvm_libc_stdio_read }; -// FILE *stdin = fopencookie(&__llvm_libc_stdin_cookie, "r", stdin_func); -// ... -// struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie; -// cookie_io_functions_t stdout_func = { .write = __llvm_libc_stdio_write }; -// FILE *stdout = fopencookie(&__llvm_libc_stdout_cookie, "w", stdout_func); -// ... -// struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie; -// cookie_io_functions_t stderr_func = { .write = __llvm_libc_stdio_write }; -// FILE *stderr = fopencookie(&__llvm_libc_stderr_cookie, "w", stderr_func); -// ``` -// -// At the same time, implementation of functions like `printf` and `scanf` can -// use `__llvm_libc_stdio_read` and `__llvm_libc_stdio_write` directly to avoid -// the extra indirection. -// -// All three symbols `__llvm_libc_stdin_cookie`, `__llvm_libc_stdout_cookie`, -// and `__llvm_libc_stderr_cookie` must be provided, even if they don't point -// at anything. - -struct __llvm_libc_stdio_cookie; - -extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie; -extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie; -extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie; - -extern "C" ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size); -extern "C" ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf, - size_t size); +extern "C" FILE *stdin = reinterpret_cast<FILE *>(&__llvm_libc_stdin_cookie); +extern "C" FILE *stdout = reinterpret_cast<FILE *>(&__llvm_libc_stdout_cookie); +extern "C" FILE *stderr = reinterpret_cast<FILE *>(&__llvm_libc_stderr_cookie); ssize_t read_from_stdin(char *buf, size_t size) { return __llvm_libc_stdio_read(static_cast<void *>(&__llvm_libc_stdin_cookie), diff --git a/libc/src/__support/OSUtil/baremetal/io.h b/libc/src/__support/OSUtil/baremetal/io.h index aed34ec7e62e3..2605fd45776b9 100644 --- a/libc/src/__support/OSUtil/baremetal/io.h +++ b/libc/src/__support/OSUtil/baremetal/io.h @@ -16,6 +16,45 @@ namespace LIBC_NAMESPACE_DECL { +// These are intended to be provided by the vendor. +// +// The signature of these types and functions intentionally match `fopencookie` +// which allows the following: +// +// ``` +// struct __llvm_libc_stdio_cookie { ... }; +// ... +// struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie; +// cookie_io_functions_t stdin_func = { .read = __llvm_libc_stdio_read }; +// FILE *stdin = fopencookie(&__llvm_libc_stdin_cookie, "r", stdin_func); +// ... +// struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie; +// cookie_io_functions_t stdout_func = { .write = __llvm_libc_stdio_write }; +// FILE *stdout = fopencookie(&__llvm_libc_stdout_cookie, "w", stdout_func); +// ... +// struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie; +// cookie_io_functions_t stderr_func = { .write = __llvm_libc_stdio_write }; +// FILE *stderr = fopencookie(&__llvm_libc_stderr_cookie, "w", stderr_func); +// ``` +// +// At the same time, implementation of functions like `printf` and `scanf` can +// use `__llvm_libc_stdio_read` and `__llvm_libc_stdio_write` directly to avoid +// the extra indirection. +// +// All three symbols `__llvm_libc_stdin_cookie`, `__llvm_libc_stdout_cookie`, +// and `__llvm_libc_stderr_cookie` must be provided, even if they don't point +// at anything. + +struct __llvm_libc_stdio_cookie; + +extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie; +extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie; +extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie; + +extern "C" ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size); +extern "C" ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf, + size_t size); + ssize_t read_from_stdin(char *buf, size_t size); void write_to_stderr(cpp::string_view msg); void write_to_stdout(cpp::string_view msg); diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt index bfeff0e2b5880..a706accecf152 100644 --- a/libc/src/stdio/baremetal/CMakeLists.txt +++ b/libc/src/stdio/baremetal/CMakeLists.txt @@ -1,3 +1,169 @@ +add_header_library( + file_internal + HDRS + file_internal.h + DEPENDS + libc.hdr.types.FILE + libc.src.__support.CPP.string_view + libc.src.__support.OSUtil.osutil +) + +add_header_library( + vfprintf_internal + HDRS + vfprintf_internal.h + DEPENDS + libc.hdr.types.FILE + libc.hdr.stdio_macros + libc.src.__support.arg_list + libc.src.__support.CPP.limits + libc.src.__support.CPP.string_view + libc.src.__support.libc_errno + libc.src.__support.OSUtil.osutil + libc.src.stdio.printf_core.printf_main + libc.src.stdio.printf_core.writer + libc.src.stdio.printf_core.error_mapper + libc.src.stdio.printf_core.core_structs +) + +add_header_library( + vfscanf_internal + HDRS + vfscanf_internal.h + DEPENDS + libc.hdr.types.FILE + libc.hdr.stdio_macros + libc.src.__support.arg_list + libc.src.__support.OSUtil.osutil + libc.src.__support.CPP.limits + libc.src.__support.CPP.string_view + libc.src.__support.libc_errno + libc.src.__support.OSUtil.osutil + libc.src.stdio.scanf_core.reader + libc.src.stdio.scanf_core.scanf_main +) + +add_entrypoint_object( + feof + SRCS + feof.cpp + HDRS + ../feof.h + DEPENDS + libc.hdr.types.FILE +) + +add_entrypoint_object( + ferror + SRCS + ferror.cpp + HDRS + ../ferror.h + DEPENDS + libc.hdr.types.FILE +) + +add_entrypoint_object( + fgetc + SRCS + fgetc.cpp + HDRS + ../fgetc.h + DEPENDS + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno +) + +add_entrypoint_object( + fgets + SRCS + fgets.cpp + HDRS + ../fgets.h + DEPENDS + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno +) + +add_entrypoint_object( + fprintf + SRCS + fprintf.cpp + HDRS + ../fprintf.h + DEPENDS + .vfprintf_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.__support.arg_list +) + +add_entrypoint_object( + fputc + SRCS + fputc.cpp + HDRS + ../fputc.h + DEPENDS + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno +) + +add_entrypoint_object( + fputs + SRCS + fputs.cpp + HDRS + ../fputc.h + DEPENDS + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno +) + +add_entrypoint_object( + fread + SRCS + fread.cpp + HDRS + ../fread.h + DEPENDS + .file_internal + libc.hdr.types.FILE + libc.src.errno.errno +) + +add_entrypoint_object( + fscanf + SRCS + fscanf.cpp + HDRS + ../fscanf.h + DEPENDS + .vfscanf_internal + libc.src.__support.arg_list +) + +add_entrypoint_object( + fwrite + SRCS + fwrite.cpp + HDRS + ../fwrite.h + DEPENDS + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno +) + add_entrypoint_object( getchar SRCS @@ -5,9 +171,9 @@ add_entrypoint_object( HDRS ../getchar.h DEPENDS - libc.hdr.stdio_macros - libc.src.__support.OSUtil.osutil - libc.src.__support.CPP.string_view + .file_internal + libc.hdr.types.FILE + libc.src.errno.errno ) add_entrypoint_object( @@ -27,14 +193,9 @@ add_entrypoint_object( HDRS ../printf.h DEPENDS - libc.src.stdio.printf_core.printf_main - libc.src.stdio.printf_core.writer - libc.src.stdio.printf_core.error_mapper - libc.src.stdio.printf_core.core_structs + .vfprintf_internal + libc.hdr.stdio_macros libc.src.__support.arg_list - libc.src.__support.OSUtil.osutil - libc.src.__support.libc_errno - libc.src.__support.CPP.limits ) add_entrypoint_object( @@ -44,28 +205,34 @@ add_entrypoint_object( HDRS ../putchar.h DEPENDS - libc.src.__support.OSUtil.osutil - libc.src.__support.CPP.string_view + .file_internal + libc.hdr.stdio_macros + libc.src.errno.errno ) add_entrypoint_object( - puts + putc SRCS - puts.cpp + putc.cpp HDRS - ../puts.h + ../putc.h DEPENDS - libc.src.__support.OSUtil.osutil - libc.src.__support.CPP.string_view + .file_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.errno.errno ) -add_header_library( - scanf_internal +add_entrypoint_object( + puts + SRCS + puts.cpp HDRS - scanf_internal.h + ../puts.h DEPENDS - libc.src.stdio.scanf_core.reader - libc.src.__support.OSUtil.osutil + .file_internal + libc.hdr.stdio_macros + libc.src.errno.errno ) add_entrypoint_object( @@ -75,11 +242,36 @@ add_entrypoint_object( HDRS ../scanf.h DEPENDS - .scanf_internal - libc.include.inttypes - libc.src.stdio.scanf_core.scanf_main + .vfscanf_internal + libc.hdr.types.FILE + libc.hdr.stdio_macros + libc.src.__support.arg_list +) + +add_entrypoint_object( + vfprintf + SRCS + vfprintf.cpp + HDRS + ../vfprintf.h + DEPENDS + .vfprintf_internal + libc.hdr.stdio_macros + libc.hdr.types.FILE + libc.src.__support.arg_list +) + +add_entrypoint_object( + vfscanf + SRCS + vfscanf.cpp + HDRS + ../vfscanf.h + DEPENDS + .vfscanf_internal + libc.hdr.types.FILE + libc.hdr.stdio_macros libc.src.__support.arg_list - libc.src.__support.OSUtil.osutil ) add_entrypoint_object( @@ -89,14 +281,9 @@ add_entrypoint_object( HDRS ../vprintf.h DEPENDS - libc.src.stdio.printf_core.printf_main - libc.src.stdio.printf_core.writer - libc.src.stdio.printf_core.error_mapper - libc.src.stdio.printf_core.core_structs + .vfprintf_internal + libc.hdr.stdio_macros libc.src.__support.arg_list - libc.src.__support.OSUtil.osutil - libc.src.__support.libc_errno - libc.src.__support.CPP.limits ) add_entrypoint_object( @@ -106,8 +293,7 @@ add_entrypoint_object( HDRS ../vscanf.h DEPENDS - .scanf_internal - libc.src.stdio.scanf_core.scanf_main + .vfscanf_internal + libc.hdr.stdio_macros libc.src.__support.arg_list - libc.src.__support.OSUtil.osutil ) diff --git a/libc/src/stdio/baremetal/feof.cpp b/libc/src/stdio/baremetal/feof.cpp new file mode 100644 index 0000000000000..42862f244d204 --- /dev/null +++ b/libc/src/stdio/baremetal/feof.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of feof for baremetal --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/feof.h" + +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, feof, (::FILE * stream)) { + (void)stream; + // TODO: Shall we have an embeddeding API for feof? + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/ferror.cpp b/libc/src/stdio/baremetal/ferror.cpp new file mode 100644 index 0000000000000..5af5a1efdcd9a --- /dev/null +++ b/libc/src/stdio/baremetal/ferror.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of ferror for baremetal ------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/ferror.h" + +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, ferror, (::FILE * stream)) { + (void)stream; + // TODO: Shall we have an embeddeding API for ferror? + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fgetc.cpp b/libc/src/stdio/baremetal/fgetc.cpp new file mode 100644 index 0000000000000..4f9cd71628a99 --- /dev/null +++ b/libc/src/stdio/baremetal/fgetc.cpp @@ -0,0 +1,31 @@ +//===-- Implementation of fgetc for baremetal -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fgetc.h" + +#include "hdr/stdio_macros.h" // for EOF. +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, fgetc, (::FILE * stream)) { + unsigned char c; + auto result = read_internal(reinterpret_cast<char *>(&c), 1, stream); + if (result.has_error()) + libc_errno = result.error; + + if (result.value != 1) + return EOF; + return c; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fgets.cpp b/libc/src/stdio/baremetal/fgets.cpp new file mode 100644 index 0000000000000..76e80449aed11 --- /dev/null +++ b/libc/src/stdio/baremetal/fgets.cpp @@ -0,0 +1,49 @@ +//===-- Implementation of fgets for baremetal -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fgets.h" + +#include "hdr/stdio_macros.h" // for EOF. +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(char *, fgets, + (char *__restrict str, int count, + ::FILE *__restrict stream)) { + if (count < 1) + return nullptr; + + char c = '\0'; + // i is an int because it's frequently compared to count, which is also int. + int i = 0; + + for (; i < (count - 1) && c != '\n'; ++i) { + auto result = read_internal(&c, 1, stream); + if (result.has_error()) + libc_errno = result.error; + + if (result.value != 1) + break; + str[i] = c; + } + + // If the requested read size makes no sense, an error occured, or no bytes + // were read due to an EOF, then return nullptr and don't write the null byte. + if (i == 0) + return nullptr; + + str[i] = '\0'; + return str; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/file_internal.h b/libc/src/stdio/baremetal/file_internal.h new file mode 100644 index 0000000000000..292a1e22c954b --- /dev/null +++ b/libc/src/stdio/baremetal/file_internal.h @@ -0,0 +1,52 @@ +//===--- Helper functions for file I/O on baremetal -----------------------===// +// +// 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_BAREMETAL_FILE_INTERNAL_H +#define LLVM_LIBC_SRC_STDIO_BAREMETAL_FILE_INTERNAL_H + +#include "hdr/types/FILE.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/OSUtil/io.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +// TODO: Deduplicate this with __support/File/file.h. +struct FileIOResult { + size_t value; + int error; + + constexpr FileIOResult(size_t val) : value(val), error(0) {} + constexpr FileIOResult(size_t val, int error) : value(val), error(error) {} + + constexpr bool has_error() { return error != 0; } + + constexpr operator size_t() { return value; } +}; + +LIBC_INLINE FileIOResult read_internal(char *buf, size_t size, ::FILE *stream) { + ssize_t ret = __llvm_libc_stdio_read(stream, buf, size); + if (ret < 0) + return {0, static_cast<int>(-ret)}; + return ret; +} + +LIBC_INLINE FileIOResult write_internal(const char *buf, size_t size, + ::FILE *stream) { + ssize_t ret = __llvm_libc_stdio_write(stream, buf, size); + if (ret < 0) + return {0, static_cast<int>(-ret)}; + return ret; +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_BAREMETAL_FILE_INTERNAL_H diff --git a/libc/src/stdio/baremetal/fprintf.cpp b/libc/src/stdio/baremetal/fprintf.cpp new file mode 100644 index 0000000000000..fc96c56ec77ed --- /dev/null +++ b/libc/src/stdio/baremetal/fprintf.cpp @@ -0,0 +1,34 @@ +//===-- Implementation of fprintf for baremetal -----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fprintf.h" + +#include "hdr/types/FILE.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfprintf_internal.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, fprintf, + (::FILE *__restrict stream, const char *__restrict format, + ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + + return vfprintf_internal(stream, format, args); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fputc.cpp b/libc/src/stdio/baremetal/fputc.cpp new file mode 100644 index 0000000000000..e179fbd722b68 --- /dev/null +++ b/libc/src/stdio/baremetal/fputc.cpp @@ -0,0 +1,33 @@ +//===-- Implementation of fputc for baremetal -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fputc.h" + +#include "hdr/stdio_macros.h" // for EOF +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, fputc, (int c, ::FILE *stream)) { + unsigned char uc = static_cast<unsigned char>(c); + auto result = write_internal(reinterpret_cast<char *>(&uc), 1, stream); + if (result.has_error()) + libc_errno = result.error; + size_t written = result.value; + if (written != 1) { + // The stream should be in an error state in this case. + return EOF; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fputs.cpp b/libc/src/stdio/baremetal/fputs.cpp new file mode 100644 index 0000000000000..196f11dc96238 --- /dev/null +++ b/libc/src/stdio/baremetal/fputs.cpp @@ -0,0 +1,35 @@ +//===-- Implementation of fputs for baremetal -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fputs.h" + +#include "hdr/stdio_macros.h" // for EOF +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, fputs, + (const char *__restrict str, ::FILE *__restrict stream)) { + cpp::string_view str_view(str); + + auto result = write_internal(str_view.data(), str_view.size(), stream); + if (result.has_error()) + libc_errno = result.error; + size_t written = result.value; + if (written != str_view.size()) { + // The stream should be in an error state in this case. + return EOF; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fread.cpp b/libc/src/stdio/baremetal/fread.cpp new file mode 100644 index 0000000000000..17962e882b764 --- /dev/null +++ b/libc/src/stdio/baremetal/fread.cpp @@ -0,0 +1,35 @@ +//===-- Implementation of fread for baremetal -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fread.h" + +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, fread, + (void *__restrict buffer, size_t size, size_t nmemb, + ::FILE *stream)) { + if (size == 0 || nmemb == 0) + return 0; + auto result = + read_internal(reinterpret_cast<char *>(buffer), size * nmemb, stream); + if (result.has_error()) + libc_errno = result.error; + LIBC_ASSERT(result.value % size == 0 && "result not multiple of size"); + return result.value / size; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fscanf.cpp b/libc/src/stdio/baremetal/fscanf.cpp new file mode 100644 index 0000000000000..eb8b2326ad6b7 --- /dev/null +++ b/libc/src/stdio/baremetal/fscanf.cpp @@ -0,0 +1,38 @@ +//===-- Implementation of fscanf for baremetal ------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fscanf.h" + +#include "hdr/stdio_macros.h" // for EOF. +#include "hdr/types/FILE.h" +#include "src/__support/arg_list.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfscanf_internal.h" + +#include "hdr/types/FILE.h" +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, fscanf, + (::FILE *__restrict stream, const char *__restrict format, + ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + + int ret_val = vfscanf_internal(stream, format, args); + // This is done to avoid including stdio.h in the internals. On most systems + // EOF is -1, so this will be transformed into just "return ret_val". + return (ret_val == -1) ? EOF : ret_val; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/fwrite.cpp b/libc/src/stdio/baremetal/fwrite.cpp new file mode 100644 index 0000000000000..017429405bf17 --- /dev/null +++ b/libc/src/stdio/baremetal/fwrite.cpp @@ -0,0 +1,35 @@ +//===-- Implementation of fwrite for baremetal ------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fwrite.h" + +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(size_t, fwrite, + (const void *__restrict buffer, size_t size, size_t nmemb, + ::FILE *stream)) { + if (size == 0 || nmemb == 0) + return 0; + auto result = write_internal(reinterpret_cast<const char *>(buffer), + size * nmemb, stream); + if (result.has_error()) + libc_errno = result.error; + LIBC_ASSERT(result.value % size == 0 && "result not multiple of size"); + return result.value / size; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/getc.cpp b/libc/src/stdio/baremetal/getc.cpp new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/libc/src/stdio/baremetal/getchar.cpp b/libc/src/stdio/baremetal/getchar.cpp index 8fb7bc32537e7..6e599c9337e9c 100644 --- a/libc/src/stdio/baremetal/getchar.cpp +++ b/libc/src/stdio/baremetal/getchar.cpp @@ -1,4 +1,4 @@ -//===-- Baremetal implementation of getchar -------------------------------===// +//===-- Implementation of getchar for baremetal -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,19 +7,24 @@ //===----------------------------------------------------------------------===// #include "src/stdio/getchar.h" -#include "src/__support/OSUtil/io.h" -#include "src/__support/macros/config.h" #include "hdr/stdio_macros.h" // for EOF. +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, getchar, ()) { - char buf[1]; - auto result = read_from_stdin(buf, sizeof(buf)); - if (result <= 0) + unsigned char c; + auto result = read_internal(reinterpret_cast<char *>(&c), 1, stdin); + if (result.has_error()) + libc_errno = result.error; + + if (result.value != 1) return EOF; - return buf[0]; + return c; } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 2fa9cf7c9f3cd..5010810906e24 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -7,30 +7,17 @@ //===----------------------------------------------------------------------===// #include "src/stdio/printf.h" -#include "src/__support/CPP/limits.h" -#include "src/__support/OSUtil/io.h" + +#include "hdr/stdio_macros.h" #include "src/__support/arg_list.h" -#include "src/__support/libc_errno.h" +#include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/stdio/printf_core/core_structs.h" -#include "src/stdio/printf_core/error_mapper.h" -#include "src/stdio/printf_core/printf_main.h" -#include "src/stdio/printf_core/writer.h" +#include "src/stdio/baremetal/vfprintf_internal.h" #include <stdarg.h> -#include <stddef.h> namespace LIBC_NAMESPACE_DECL { -namespace { - -LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { - write_to_stdout(new_str); - return printf_core::WRITE_OK; -} - -} // namespace - LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { va_list vlist; va_start(vlist, format); @@ -38,32 +25,8 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); - static constexpr size_t BUFF_SIZE = 1024; - char buffer[BUFF_SIZE]; - - printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &stdout_write_hook, - nullptr); - printf_core::Writer writer(wb); - - auto retval = printf_core::printf_main(&writer, format, args); - if (!retval.has_value()) { - libc_errno = printf_core::internal_error_to_errno(retval.error()); - return -1; - } - - int flushval = wb.flush_to_stream(); - if (flushval != printf_core::WRITE_OK) { - libc_errno = printf_core::internal_error_to_errno(-flushval); - return -1; - } - - if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { - libc_errno = - printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); - return -1; - } - return static_cast<int>(retval.value()); + return vfprintf_internal(stdout, format, args); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/putc.cpp b/libc/src/stdio/baremetal/putc.cpp new file mode 100644 index 0000000000000..7b05b7fe60cea --- /dev/null +++ b/libc/src/stdio/baremetal/putc.cpp @@ -0,0 +1,33 @@ +//===-- Implementation of putc for baremetal --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/putc.h" + +#include "hdr/stdio_macros.h" // for EOF +#include "hdr/types/FILE.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, putc, (int c, ::FILE *stream)) { + unsigned char uc = static_cast<unsigned char>(c); + auto result = write_internal(reinterpret_cast<char *>(&uc), 1, stream); + if (result.has_error()) + libc_errno = result.error; + size_t written = result.value; + if (written != 1) { + // The stream should be in an error state in this case. + return EOF; + } + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/putchar.cpp b/libc/src/stdio/baremetal/putchar.cpp index ac21e6e783b01..45737954d139e 100644 --- a/libc/src/stdio/baremetal/putchar.cpp +++ b/libc/src/stdio/baremetal/putchar.cpp @@ -1,4 +1,4 @@ -//===-- Baremetal Implementation of putchar -------------------------------===// +//===-- Implementation of putchar for baremetal -----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,17 +7,25 @@ //===----------------------------------------------------------------------===// #include "src/stdio/putchar.h" -#include "src/__support/CPP/string_view.h" -#include "src/__support/OSUtil/io.h" + +#include "hdr/stdio_macros.h" // for EOF +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, putchar, (int c)) { - char uc = static_cast<char>(c); - - write_to_stdout(cpp::string_view(&uc, 1)); - + unsigned char uc = static_cast<unsigned char>(c); + auto result = write_internal(reinterpret_cast<char *>(&uc), 1, stdout); + if (result.has_error()) + libc_errno = result.error; + size_t written = result.value; + if (written != 1) { + // The stream should be in an error state in this case. + return EOF; + } return 0; } diff --git a/libc/src/stdio/baremetal/puts.cpp b/libc/src/stdio/baremetal/puts.cpp index fcd3aa086b2bf..d6b58e1d47a9a 100644 --- a/libc/src/stdio/baremetal/puts.cpp +++ b/libc/src/stdio/baremetal/puts.cpp @@ -7,19 +7,33 @@ //===----------------------------------------------------------------------===// #include "src/stdio/puts.h" -#include "src/__support/CPP/string_view.h" -#include "src/__support/OSUtil/io.h" + +#include "hdr/stdio_macros.h" // for EOF +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" +#include "src/stdio/baremetal/file_internal.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, puts, (const char *__restrict str)) { cpp::string_view str_view(str); - - // TODO: Can we combine these to avoid needing two writes? - write_to_stdout(str_view); - write_to_stdout("\n"); - + auto result = write_internal(str_view.data(), str_view.size(), stdout); + if (result.has_error()) + libc_errno = result.error; + size_t written = result.value; + if (written != str_view.size()) { + // The stream should be in an error state in this case. + return EOF; + } + result = write_internal("\n", 1, stdout); + if (result.has_error()) + libc_errno = result.error; + written = result.value; + if (written != 1) { + // The stream should be in an error state in this case. + return EOF; + } return 0; } diff --git a/libc/src/stdio/baremetal/scanf.cpp b/libc/src/stdio/baremetal/scanf.cpp index 8d07aa1da76aa..7f939ed0fcaa2 100644 --- a/libc/src/stdio/baremetal/scanf.cpp +++ b/libc/src/stdio/baremetal/scanf.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of scanf ---------------------------------*- C++ -*-===// +//===-- Implementation of scanf for baremetal -------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,11 +9,9 @@ #include "src/stdio/scanf.h" #include "hdr/stdio_macros.h" -#include "src/__support/OSUtil/io.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" -#include "src/stdio/baremetal/scanf_internal.h" -#include "src/stdio/scanf_core/scanf_main.h" +#include "src/stdio/baremetal/vfscanf_internal.h" #include <stdarg.h> @@ -27,11 +25,10 @@ LLVM_LIBC_FUNCTION(int, scanf, (const char *__restrict format, ...)) { // destruction automatically. va_end(vlist); - scanf_core::StdinReader reader; - int retval = scanf_core::scanf_main(&reader, format, args); + int ret_val = vfscanf_internal(stdin, format, args); // This is done to avoid including stdio.h in the internals. On most systems // EOF is -1, so this will be transformed into just "return retval". - return (retval == -1) ? EOF : retval; + return (ret_val == -1) ? EOF : ret_val; } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/scanf_internal.h b/libc/src/stdio/baremetal/scanf_internal.h deleted file mode 100644 index 57d4b8c8d1a61..0000000000000 --- a/libc/src/stdio/baremetal/scanf_internal.h +++ /dev/null @@ -1,30 +0,0 @@ -//===-- Internal implementation header of scanf -----------------*- 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 -// -//===----------------------------------------------------------------------===// - -#include "src/__support/OSUtil/io.h" -#include "src/__support/macros/config.h" -#include "src/stdio/scanf_core/reader.h" - -namespace LIBC_NAMESPACE_DECL { - -namespace scanf_core { - -struct StdinReader : public Reader<StdinReader> { - LIBC_INLINE char getc() { - char buf[1]; - auto result = read_from_stdin(buf, sizeof(buf)); - if (result <= 0) - return EOF; - return buf[0]; - } - LIBC_INLINE void ungetc(int) {} -}; - -} // namespace scanf_core - -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vfprintf.cpp b/libc/src/stdio/baremetal/vfprintf.cpp new file mode 100644 index 0000000000000..2393ca4bcdb3e --- /dev/null +++ b/libc/src/stdio/baremetal/vfprintf.cpp @@ -0,0 +1,31 @@ +//===-- Implementation of vfprintf for baremetal ----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/vfprintf.h" + +#include "hdr/types/FILE.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfprintf_internal.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, vfprintf, + (::FILE *__restrict stream, const char *__restrict format, + va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + + return vfprintf_internal(stream, format, args); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vfprintf_internal.h b/libc/src/stdio/baremetal/vfprintf_internal.h new file mode 100644 index 0000000000000..59a95ea23c89e --- /dev/null +++ b/libc/src/stdio/baremetal/vfprintf_internal.h @@ -0,0 +1,74 @@ +//===-- Implementation header of vfprintf for baremetal ---------*- 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_BAREMETAL_VFPRINTF_INTERNAL_H +#define LLVM_LIBC_SRC_STDIO_BAREMETAL_VFPRINTF_INTERNAL_H + +#include "hdr/types/FILE.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/OSUtil/io.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/printf_main.h" +#include "src/stdio/printf_core/writer.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace internal { + +LIBC_INLINE int write_hook(cpp::string_view str_view, void *cookie) { + auto result = + __llvm_libc_stdio_write(cookie, str_view.data(), str_view.size()); + if (result <= 0) + return result; + if (static_cast<size_t>(result) != str_view.size()) + return printf_core::FILE_WRITE_ERROR; + return printf_core::WRITE_OK; +} + +} // namespace internal + +LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, + const char *__restrict format, + internal::ArgList &args) { + static constexpr size_t BUFF_SIZE = 1024; + char buffer[BUFF_SIZE]; + + printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &internal::write_hook, + stream); + printf_core::Writer writer(wb); + + auto retval = printf_core::printf_main(&writer, format, args); + if (!retval.has_value()) { + libc_errno = printf_core::internal_error_to_errno(retval.error()); + return -1; + } + + int flushval = wb.flush_to_stream(); + if (flushval != printf_core::WRITE_OK) { + libc_errno = printf_core::internal_error_to_errno(-flushval); + return -1; + } + + if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + + return static_cast<int>(retval.value()); +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_BAREMETAL_VFPRINTF_INTERNAL_H diff --git a/libc/src/stdio/baremetal/vfscanf.cpp b/libc/src/stdio/baremetal/vfscanf.cpp new file mode 100644 index 0000000000000..a98d3dbfa14f3 --- /dev/null +++ b/libc/src/stdio/baremetal/vfscanf.cpp @@ -0,0 +1,35 @@ +//===-- Implementation of vfscanf for baremetal -----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/vfscanf.h" + +#include "hdr/stdio_macros.h" // for EOF. +#include "hdr/types/FILE.h" +#include "src/__support/arg_list.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfscanf_internal.h" + +#include "hdr/types/FILE.h" +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, vfscanf, + (::FILE *__restrict stream, const char *__restrict format, + va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + + int ret_val = vfscanf_internal(stream, format, args); + // This is done to avoid including stdio.h in the internals. On most systems + // EOF is -1, so this will be transformed into just "return ret_val". + return (ret_val == -1) ? EOF : ret_val; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vfscanf_internal.h b/libc/src/stdio/baremetal/vfscanf_internal.h new file mode 100644 index 0000000000000..fc90dc3bc044f --- /dev/null +++ b/libc/src/stdio/baremetal/vfscanf_internal.h @@ -0,0 +1,58 @@ +//===-- Implementation header of vfscanf ------------------------*- 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_BAREMETAL_VFPRINTF_INTERNAL_H +#define LLVM_LIBC_SRC_STDIO_BAREMETAL_VFPRINTF_INTERNAL_H + +#include "hdr/stdio_macros.h" // for EOF. +#include "hdr/types/FILE.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/OSUtil/io.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/scanf_core/reader.h" +#include "src/stdio/scanf_core/scanf_main.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace internal { + +class StreamReader : public scanf_core::Reader<StreamReader> { + ::FILE *stream; + +public: + LIBC_INLINE StreamReader(::FILE *stream) : stream(stream) {} + + LIBC_INLINE char getc() { + char c; + auto result = __llvm_libc_stdio_read(stream, &c, 1); + if (result != 1) + return '\0'; + return c; + } + LIBC_INLINE void ungetc(int) {} +}; + +} // namespace internal + +LIBC_INLINE int vfscanf_internal(::FILE *__restrict stream, + const char *__restrict format, + internal::ArgList &args) { + internal::StreamReader reader(stream); + // This is done to avoid including stdio.h in the internals. On most systems + // EOF is -1, so this will be transformed into just "return retval". + int retval = scanf_core::scanf_main(&reader, format, args); + return (retval == 0) ? EOF : retval; +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDIO_BAREMETAL_VFPRINTF_INTERNAL_H diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index d89f26cd72b0a..38f12ab09fa25 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -7,61 +7,24 @@ //===----------------------------------------------------------------------===// #include "src/stdio/vprintf.h" -#include "src/__support/CPP/limits.h" -#include "src/__support/OSUtil/io.h" + +#include "hdr/stdio_macros.h" #include "src/__support/arg_list.h" -#include "src/__support/libc_errno.h" +#include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/stdio/printf_core/core_structs.h" -#include "src/stdio/printf_core/error_mapper.h" -#include "src/stdio/printf_core/printf_main.h" -#include "src/stdio/printf_core/writer.h" +#include "src/stdio/baremetal/vfprintf_internal.h" #include <stdarg.h> -#include <stddef.h> namespace LIBC_NAMESPACE_DECL { -namespace { - -LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) { - write_to_stdout(new_str); - return printf_core::WRITE_OK; -} - -} // namespace - LLVM_LIBC_FUNCTION(int, vprintf, (const char *__restrict format, va_list vlist)) { internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - static constexpr size_t BUFF_SIZE = 1024; - char buffer[BUFF_SIZE]; - - printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &stdout_write_hook, - nullptr); - printf_core::Writer writer(wb); - - auto retval = printf_core::printf_main(&writer, format, args); - if (!retval.has_value()) { - libc_errno = printf_core::internal_error_to_errno(retval.error()); - return -1; - } - - int flushval = wb.flush_to_stream(); - if (flushval != printf_core::WRITE_OK) { - libc_errno = printf_core::internal_error_to_errno(-flushval); - return -1; - } - - if (retval.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { - libc_errno = - printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); - return -1; - } - return static_cast<int>(retval.value()); + return vfprintf_internal(stdout, format, args); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vscanf.cpp b/libc/src/stdio/baremetal/vscanf.cpp index 249f8fd5dbe3c..3d41e2a9f4bd8 100644 --- a/libc/src/stdio/baremetal/vscanf.cpp +++ b/libc/src/stdio/baremetal/vscanf.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of vscanf --------------------------------*- C++ -*-===// +//===-- Implementation of vscanf for baremetal ------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,11 +9,9 @@ #include "src/stdio/vscanf.h" #include "hdr/stdio_macros.h" -#include "src/__support/OSUtil/io.h" #include "src/__support/arg_list.h" #include "src/__support/macros/config.h" -#include "src/stdio/baremetal/scanf_internal.h" -#include "src/stdio/scanf_core/scanf_main.h" +#include "src/stdio/baremetal/vfscanf_internal.h" #include <stdarg.h> @@ -24,13 +22,8 @@ LLVM_LIBC_FUNCTION(int, vscanf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. - va_end(vlist); - scanf_core::StdinReader reader; - int retval = scanf_core::scanf_main(&reader, format, args); - // This is done to avoid including stdio.h in the internals. On most systems - // EOF is -1, so this will be transformed into just "return retval". - return (retval == -1) ? EOF : retval; + return vfscanf_internal(stdin, format, args); } } // namespace LIBC_NAMESPACE_DECL _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
