Skip to content

Commit e9b681a

Browse files
committed
[libc] Allow using sscanf() and vsscanf() on baremetal targets.
In addition to the normal "cookie" definitions a baremetal user needs to provide to use printf(), a user also needs to add "FILE *stdin;" somehere in their source. I have not updated the default baremetal entrypoints, so a user will currently need to supply their own to add sscanf() and vsscanf(). This might also work for regular sscanf(), but I have not yet tried it. This updates LLVMCCompileOptionRules.cmake to add a macro the libc build can use to determine if it is doing a baremetal build. This also updates the baremetal getchar() function because it looked like it would return an uninitialized value if __llvm_libc_stdio_read() returned 0. The baremetal build does not provide ungetc(), so the baremetal Reader class tracks the would-be ungot character itself. From what I could see in the code, tracking only one character is sufficient.
1 parent 437d587 commit e9b681a

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

libc/cmake/modules/LLVMLibCCompileOptionRules.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ function(_get_common_compile_options output_var flags)
119119
list(APPEND compile_options "-fpie")
120120

121121
if(LLVM_LIBC_FULL_BUILD)
122+
if(LIBC_TARGET_OS_IS_BAREMETAL)
123+
list(APPEND compile_options "-DLIBC_TARGET_OS_IS_BAREMETAL")
124+
endif()
122125
# Only add -ffreestanding flag in non-GPU full build mode.
123126
if(NOT LIBC_TARGET_OS_IS_GPU)
124127
list(APPEND compile_options "-ffreestanding")

libc/src/stdio/baremetal/getchar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
1717
LLVM_LIBC_FUNCTION(int, getchar, ()) {
1818
char buf[1];
1919
auto result = read_from_stdin(buf, sizeof(buf));
20-
if (result < 0)
20+
if (result <= 0)
2121
return EOF;
2222
return buf[0];
2323
}

libc/src/stdio/scanf_core/CMakeLists.txt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ if(LIBC_TARGET_OS_IS_GPU)
1616
libc.src.stdio.ungetc
1717
libc.src.stdio.ferror
1818
)
19+
elseif(LIBC_TARGET_OS_IS_BAREMETAL)
20+
list(APPEND file_deps
21+
libc.src.stdio.getchar
22+
)
1923
elseif(LLVM_LIBC_FULL_BUILD)
2024
list(APPEND file_deps
2125
libc.src.__support.File.file
@@ -54,13 +58,6 @@ add_header_library(
5458
libc.src.__support.CPP.string_view
5559
)
5660

57-
if(NOT(TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD AND
58-
(NOT LIBC_TARGET_OS_IS_GPU))
59-
# Not all platforms have a file implementation. If file is unvailable, and a
60-
# full build is requested, then we must skip all file based scanf sections.
61-
return()
62-
endif()
63-
6461
add_object_library(
6562
scanf_main
6663
SRCS
@@ -117,6 +114,13 @@ add_object_library(
117114
${use_system_file}
118115
)
119116

117+
if(NOT(TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD AND
118+
(NOT LIBC_TARGET_OS_IS_GPU))
119+
# Not all platforms have a file implementation. If file is unvailable, and a
120+
# full build is requested, then we must skip all file based scanf sections.
121+
return()
122+
endif()
123+
120124
#TODO: condense the file-related code as possible.
121125
add_header_library(
122126
vfscanf_internal

libc/src/stdio/scanf_core/reader.h

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111

1212
#include "hdr/types/FILE.h"
1313

14-
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
14+
#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && !defined(LIBC_TARGET_OS_IS_BAREMETAL)
1515
#include "src/__support/File/file.h"
1616
#endif
1717

1818
#if defined(LIBC_TARGET_ARCH_IS_GPU)
1919
#include "src/stdio/getc.h"
2020
#include "src/stdio/ungetc.h"
21+
#elif defined(LIBC_TARGET_OS_IS_BAREMETAL)
22+
#include "src/stdio/getchar.h"
23+
#include "hdr/stdio_macros.h" // for EOF.
2124
#endif
2225

2326
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
@@ -47,6 +50,28 @@ LIBC_INLINE void ungetc(int c, void *f) {
4750
LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f));
4851
}
4952

53+
#elif defined(LIBC_TARGET_OS_IS_BAREMETAL)
54+
// The baremetal build does not currently support file operations, but it does
55+
// declare pointers to the stanard FILE streams. The user just needs to declare
56+
// "FILE *stdin;" somwhere. That is not much to ask since a user already has to
57+
// define cookie structures for stdio.
58+
extern "C" FILE *stdin;
59+
60+
LIBC_INLINE int getc(void *f) {
61+
if (f == stdin) {
62+
int c = getchar();
63+
if (EOF == c)
64+
c = '\0';
65+
66+
return c;
67+
}
68+
69+
return '\0';
70+
}
71+
72+
// Baremetal does not currently provide an ungetc(), so the Reader will need to
73+
// handle that for now.
74+
5075
#elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
5176

5277
LIBC_INLINE int getc(void *f) {
@@ -89,6 +114,10 @@ class Reader {
89114
ReadBuffer *rb;
90115
void *input_stream = nullptr;
91116
size_t cur_chars_read = 0;
117+
#if defined(LIBC_TARGET_OS_IS_BAREMETAL)
118+
// Baremetal does not provide an ungetc(), so track that ourselves for now.
119+
int unget_char = EOF;
120+
#endif
92121

93122
public:
94123
// TODO: Set buff_len with a proper constant
@@ -107,6 +136,13 @@ class Reader {
107136
++(rb->buff_cur);
108137
return output;
109138
}
139+
#if defined(LIBC_TARGET_OS_IS_BAREMETAL)
140+
if (EOF != unget_char) {
141+
char output = (char)unget_char;
142+
unget_char = EOF;
143+
return output;
144+
}
145+
#endif
110146
// This should reset the buffer if applicable.
111147
return static_cast<char>(reader_internal::getc(input_stream));
112148
}
@@ -123,7 +159,11 @@ class Reader {
123159
--(rb->buff_cur);
124160
return;
125161
}
162+
#if defined(LIBC_TARGET_OS_IS_BAREMETAL)
163+
unget_char = c;
164+
#else
126165
reader_internal::ungetc(static_cast<int>(c), input_stream);
166+
#endif
127167
}
128168

129169
LIBC_INLINE size_t chars_read() { return cur_chars_read; }

0 commit comments

Comments
 (0)