diff options
Diffstat (limited to 'lib/libc/include/stdio.h')
| -rw-r--r-- | lib/libc/include/stdio.h | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/libc/include/stdio.h b/lib/libc/include/stdio.h new file mode 100644 index 0000000..ae5a84b --- /dev/null +++ b/lib/libc/include/stdio.h @@ -0,0 +1,102 @@ +// Copyright 2020 The Fuchsia Authors +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT + +#ifndef ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDIO_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDIO_H_ + +#include <stdarg.h> +#include <stddef.h> +#include <zircon/compiler.h> + +// All anybody really wants from stdio is printf. + +#ifdef __cplusplus +#include <ktl/string_view.h> + +class FILE { + public: + // This is basically equivalent to having a virtual Write function with + // subclasses providing their own data members in lieu of ptr. But it's + // simpler and avoids a vtable that might need address fixup at load time + // (and the double indirection for a single-entry vtable--at the cost of + // double indirection for the ptr data in a callback that uses it). + + using Callback = int(void*, ktl::string_view); + + FILE() = default; + + constexpr FILE(Callback* write, void* ptr) : write_(write), ptr_(ptr) {} + + template <typename T> + explicit FILE(T* writer) + : write_([](void* ptr, ktl::string_view s) { return static_cast<T*>(ptr)->Write(s); }), + ptr_(writer) {} + + // This is what fprintf calls to do output. + int Write(ktl::string_view s) { return write_(ptr_, s); } + + constexpr explicit operator bool() const { return write_; } + + constexpr bool operator==(const FILE& other) const { + return write_ == other.write_ && ptr_ == other.ptr_; + } + + constexpr bool operator!=(const FILE& other) const { return !(*this == other); } + + // This is not defined by libc itself. The kernel defines it to point at + // the default console output mechanism. + static FILE stdout_; + + private: + Callback* write_ = nullptr; + void* ptr_ = nullptr; +}; + +#define stdout (&FILE::stdout_) + +inline int fputc(int c, FILE* f) { + const unsigned char uc = static_cast<unsigned char>(c); + return f->Write({reinterpret_cast<const char*>(&uc), 1}) == 1 ? uc : -1; +} + +inline int putc(int c, FILE* f) { return fputc(c, f); } + +inline int putchar(int c) { return fputc(c, stdout); } + +inline int fputs(const char* s, FILE* f) { + ktl::string_view str(s); + return f->Write(str) == static_cast<int>(str.size()) ? 0 : -1; +} + +inline int puts(const char* s) { return fputs(s, stdout) == 0 ? putchar('\n') : -1; } + +#else // !__cplusplus + +// C users just need the function declarations. +typedef struct _FILE_is_opaque FILE; + +#endif // __cplusplus + +__BEGIN_CDECLS + +int printf(const char*, ...) __PRINTFLIKE(1, 2); +int fprintf(FILE*, const char*, ...) __PRINTFLIKE(2, 3); +int snprintf(char* buf, size_t len, const char*, ...) __PRINTFLIKE(3, 4); + +int vprintf(const char*, va_list); +int vfprintf(FILE*, const char*, va_list); +int vsnprintf(char* buf, size_t len, const char*, va_list); + +__END_CDECLS + +#if DISABLE_DEBUG_OUTPUT +// The declarations stand so these can be used without parens to get +// the real functions (e.g. &printf or (printf)(...)). +#define printf(...) +#define vprintf(fmt, args) +#endif + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDIO_H_ |
