[libc-commits] [libc] dd63127 - [libc] Support opaque FILE* on baremetal (#168931)
via libc-commits
libc-commits at lists.llvm.org
Wed Dec 17 10:56:49 PST 2025
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
More information about the libc-commits
mailing list