-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[libc] Allow using sscanf() and vsscanf() on baremetal targets. #130527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,13 +11,17 @@ | |
|
||
#include "hdr/types/FILE.h" | ||
|
||
#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE | ||
#if !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) && \ | ||
!defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
#include "src/__support/File/file.h" | ||
#endif | ||
|
||
#if defined(LIBC_TARGET_ARCH_IS_GPU) | ||
#include "src/stdio/getc.h" | ||
#include "src/stdio/ungetc.h" | ||
#elif defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
#include "hdr/stdio_macros.h" // for EOF. | ||
#include "src/stdio/getchar.h" | ||
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We try to avoid having libc functions depend on each other where possible. The GPU build is a special case (that I'd like to clean up at some point) but for baremetal I think just calling |
||
#endif | ||
|
||
#include "src/__support/macros/attributes.h" // For LIBC_INLINE | ||
|
@@ -47,6 +51,28 @@ LIBC_INLINE void ungetc(int c, void *f) { | |
LIBC_NAMESPACE::ungetc(c, reinterpret_cast<::FILE *>(f)); | ||
} | ||
|
||
#elif defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
// The baremetal build does not currently support file operations, but it does | ||
// declare pointers to the stanard FILE streams. The user just needs to declare | ||
// "FILE *stdin;" somwhere. That is not much to ask since a user already has to | ||
// define cookie structures for stdio. | ||
extern "C" FILE *stdin; | ||
|
||
LIBC_INLINE int getc(void *f) { | ||
if (f == stdin) { | ||
int c = getchar(); | ||
if (EOF == c) | ||
c = '\0'; | ||
|
||
return c; | ||
} | ||
|
||
return '\0'; | ||
} | ||
Comment on lines
+61
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally this code would go in |
||
|
||
// Baremetal does not currently provide an ungetc(), so the Reader will need to | ||
// handle that for now. | ||
|
||
#elif !defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE) | ||
|
||
LIBC_INLINE int getc(void *f) { | ||
|
@@ -89,6 +115,10 @@ class Reader { | |
ReadBuffer *rb; | ||
void *input_stream = nullptr; | ||
size_t cur_chars_read = 0; | ||
#if defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
// Baremetal does not provide an ungetc(), so track that ourselves for now. | ||
int unget_char = EOF; | ||
#endif | ||
Comment on lines
+118
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the char from ungetc can be ignored since we never modify it, so you can skip most of the extra handling there. |
||
|
||
public: | ||
// TODO: Set buff_len with a proper constant | ||
|
@@ -107,6 +137,13 @@ class Reader { | |
++(rb->buff_cur); | ||
return output; | ||
} | ||
#if defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
if (EOF != unget_char) { | ||
char output = (char)unget_char; | ||
unget_char = EOF; | ||
return output; | ||
} | ||
#endif | ||
// This should reset the buffer if applicable. | ||
return static_cast<char>(reader_internal::getc(input_stream)); | ||
} | ||
|
@@ -123,7 +160,11 @@ class Reader { | |
--(rb->buff_cur); | ||
return; | ||
} | ||
#if defined(LIBC_TARGET_OS_IS_BAREMETAL) | ||
unget_char = c; | ||
#else | ||
reader_internal::ungetc(static_cast<int>(c), input_stream); | ||
#endif | ||
} | ||
|
||
LIBC_INLINE size_t chars_read() { return cur_chars_read; } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When possible we prefer to have compile options based on capabilities instead of targets. In this specific case we'd probably want something similar to
LIBC_COPT_STDIO_USE_SYSTEM_FILE
, which is an existing flag that changes printf/scanf behavior to use another libc's FILE* functions. It's also defined closer to where it's used, in the stdio CMake file, which I think would also be good here.