From 3ad39e9878310e5317ee73c9b353c1e2c1c5c4ee Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Sat, 11 Jul 2026 22:48:30 +0800 Subject: lib: establish Zircon libc++ and KTL foundation --- lib/libc/LICENSE | 21 +++ lib/libc/README.lume | 10 ++ lib/libc/include-after/ctype.h | 33 +++++ lib/libc/include-after/limits.h | 7 + lib/libc/include/assert.h | 20 +++ lib/libc/include/inttypes.h | 117 +++++++++++++++++ lib/libc/include/multi-file.h | 50 ++++++++ lib/libc/include/stdint.h | 278 ++++++++++++++++++++++++++++++++++++++++ lib/libc/include/stdio.h | 102 +++++++++++++++ lib/libc/include/stdlib.h | 36 ++++++ lib/libc/include/string-file.h | 79 ++++++++++++ lib/libc/include/string.h | 97 ++++++++++++++ 12 files changed, 850 insertions(+) create mode 100644 lib/libc/LICENSE create mode 100644 lib/libc/README.lume create mode 100644 lib/libc/include-after/ctype.h create mode 100644 lib/libc/include-after/limits.h create mode 100644 lib/libc/include/assert.h create mode 100644 lib/libc/include/inttypes.h create mode 100644 lib/libc/include/multi-file.h create mode 100644 lib/libc/include/stdint.h create mode 100644 lib/libc/include/stdio.h create mode 100644 lib/libc/include/stdlib.h create mode 100644 lib/libc/include/string-file.h create mode 100644 lib/libc/include/string.h (limited to 'lib/libc') diff --git a/lib/libc/LICENSE b/lib/libc/LICENSE new file mode 100644 index 0000000..8580f02 --- /dev/null +++ b/lib/libc/LICENSE @@ -0,0 +1,21 @@ +Copyright 2016 The Fuchsia Authors +Copyright (c) 2008-2015 Travis Geiselbrecht + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/libc/README.lume b/lib/libc/README.lume new file mode 100644 index 0000000..8d50752 --- /dev/null +++ b/lib/libc/README.lume @@ -0,0 +1,10 @@ +Zircon kernel libc header layer + +Source: zircon/kernel/lib/libc/include and include-after +Fuchsia revision: f8d670ab4bbb71bfb4d569893ba12fbb8a83bacd + +This first import contains the complete public header layer. The libc +implementation sources are intentionally not imported yet because abort, +panic, heap, console output, and C++ ABI providers belong to later foundation +batches. Existing LumeOS C implementations continue to provide the symbols +used by the current kernel. diff --git a/lib/libc/include-after/ctype.h b/lib/libc/include-after/ctype.h new file mode 100644 index 0000000..ff2fcfe --- /dev/null +++ b/lib/libc/include-after/ctype.h @@ -0,0 +1,33 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// 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_CTYPE_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_CTYPE_H_ + +#include + +__BEGIN_CDECLS + +int isalnum(int c); +int isalpha(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); + +int tolower(int c); +int toupper(int c); + +__END_CDECLS + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_CTYPE_H_ diff --git a/lib/libc/include-after/limits.h b/lib/libc/include-after/limits.h new file mode 100644 index 0000000..f946def --- /dev/null +++ b/lib/libc/include-after/limits.h @@ -0,0 +1,7 @@ +// 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 + +// Empty file for toolchain's #include_next to find. diff --git a/lib/libc/include/assert.h b/lib/libc/include/assert.h new file mode 100644 index 0000000..8b6252e --- /dev/null +++ b/lib/libc/include/assert.h @@ -0,0 +1,20 @@ +// 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 + +#pragma once + +#include + +#ifdef NDEBUG +#define assert(expr) ((void)0) +#else +#define assert(expr) ZX_ASSERT(expr) +#endif + +// make sure static_assert() is defined, even in C +#if !defined(__cplusplus) && !defined(static_assert) +#define static_assert(e, msg) _Static_assert(e, msg) +#endif diff --git a/lib/libc/include/inttypes.h b/lib/libc/include/inttypes.h new file mode 100644 index 0000000..b19e0f5 --- /dev/null +++ b/lib/libc/include/inttypes.h @@ -0,0 +1,117 @@ +// Copyright 2016 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_INTTYPES_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_INTTYPES_H_ + +// This (or the compiler) defines all the ___FMT__ macros. +#include + +#define PRId8 __INT8_FMTd__ +#define PRId16 __INT16_FMTd__ +#define PRId32 __INT32_FMTd__ +#define PRId64 __INT64_FMTd__ + +#define PRIdLEAST8 __INT_LEAST8_FMTd__ +#define PRIdLEAST16 __INT_LEAST16_FMTd__ +#define PRIdLEAST32 __INT_LEAST32_FMTd__ +#define PRIdLEAST64 __INT_LEAST64_FMTd__ + +#define PRIdFAST8 __INT_FAST8_FMTd__ +#define PRIdFAST16 __INT_FAST16_FMTd__ +#define PRIdFAST32 __INT_FAST32_FMTd__ +#define PRIdFAST64 __INT_FAST64_FMTd__ + +#define PRIi8 __INT8_FMTi__ +#define PRIi16 __INT16_FMTi__ +#define PRIi32 __INT32_FMTi__ +#define PRIi64 __INT64_FMTi__ + +#define PRIiLEAST8 __INT_LEAST8_FMTi__ +#define PRIiLEAST16 __INT_LEAST16_FMTi__ +#define PRIiLEAST32 __INT_LEAST32_FMTi__ +#define PRIiLEAST64 __INT_LEAST64_FMTi__ + +#define PRIiFAST8 __INT_FAST8_FMTi__ +#define PRIiFAST16 __INT_FAST16_FMTi__ +#define PRIiFAST32 __INT_FAST32_FMTi__ +#define PRIiFAST64 __INT_FAST64_FMTi__ + +#define PRIo8 __UINT8_FMTo__ +#define PRIo16 __UINT16_FMTo__ +#define PRIo32 __UINT32_FMTo__ +#define PRIo64 __UINT64_FMTo__ + +#define PRIoLEAST8 __UINT_LEAST8_FMTo__ +#define PRIoLEAST16 __UINT_LEAST16_FMTo__ +#define PRIoLEAST32 __UINT_LEAST32_FMTo__ +#define PRIoLEAST64 __UINT_LEAST64_FMTo__ + +#define PRIoFAST8 __UINT_FAST8_FMTo__ +#define PRIoFAST16 __UINT_FAST16_FMTo__ +#define PRIoFAST32 __UINT_FAST32_FMTo__ +#define PRIoFAST64 __UINT_FAST64_FMTo__ + +#define PRIu8 __UINT8_FMTu__ +#define PRIu16 __UINT16_FMTu__ +#define PRIu32 __UINT32_FMTu__ +#define PRIu64 __UINT64_FMTu__ + +#define PRIuLEAST8 __UINT_LEAST8_FMTu__ +#define PRIuLEAST16 __UINT_LEAST16_FMTu__ +#define PRIuLEAST32 __UINT_LEAST32_FMTu__ +#define PRIuLEAST64 __UINT_LEAST64_FMTu__ + +#define PRIuFAST8 __UINT_FAST8_FMTu__ +#define PRIuFAST16 __UINT_FAST16_FMTu__ +#define PRIuFAST32 __UINT_FAST32_FMTu__ +#define PRIuFAST64 __UINT_FAST64_FMTu__ + +#define PRIx8 __UINT8_FMTx__ +#define PRIx16 __UINT16_FMTx__ +#define PRIx32 __UINT32_FMTx__ +#define PRIx64 __UINT64_FMTx__ + +#define PRIxLEAST8 __UINT_LEAST8_FMTx__ +#define PRIxLEAST16 __UINT_LEAST16_FMTx__ +#define PRIxLEAST32 __UINT_LEAST32_FMTx__ +#define PRIxLEAST64 __UINT_LEAST64_FMTx__ + +#define PRIxFAST8 __UINT_FAST8_FMTx__ +#define PRIxFAST16 __UINT_FAST16_FMTx__ +#define PRIxFAST32 __UINT_FAST32_FMTx__ +#define PRIxFAST64 __UINT_FAST64_FMTx__ + +#define PRIX8 __UINT8_FMTX__ +#define PRIX16 __UINT16_FMTX__ +#define PRIX32 __UINT32_FMTX__ +#define PRIX64 __UINT64_FMTX__ + +#define PRIXLEAST8 __UINT_LEAST8_FMTX__ +#define PRIXLEAST16 __UINT_LEAST16_FMTX__ +#define PRIXLEAST32 __UINT_LEAST32_FMTX__ +#define PRIXLEAST64 __UINT_LEAST64_FMTX__ + +#define PRIXFAST8 __UINT_FAST8_FMTX__ +#define PRIXFAST16 __UINT_FAST16_FMTX__ +#define PRIXFAST32 __UINT_FAST32_FMTX__ +#define PRIXFAST64 __UINT_FAST64_FMTX__ + +#define PRIdMAX __INTMAX_FMTd__ +#define PRIiMAX __INTMAX_FMTi__ +#define PRIoMAX __UINTMAX_FMTo__ +#define PRIuMAX __UINTMAX_FMTu__ +#define PRIxMAX __UINTMAX_FMTx__ +#define PRIXMAX __UINTMAX_FMTX__ + +#define PRIdPTR __INTPTR_FMTd__ +#define PRIiPTR __INTPTR_FMTi__ +#define PRIoPTR __UINTPTR_FMTo__ +#define PRIuPTR __UINTPTR_FMTu__ +#define PRIxPTR __UINTPTR_FMTx__ +#define PRIXPTR __UINTPTR_FMTX__ + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_INTTYPES_H_ diff --git a/lib/libc/include/multi-file.h b/lib/libc/include/multi-file.h new file mode 100644 index 0000000..a04a031 --- /dev/null +++ b/lib/libc/include/multi-file.h @@ -0,0 +1,50 @@ +// Copyright 2022 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_MULTI_FILE_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_MULTI_FILE_H_ + +#include + +#include +#include +#include +#include + +// MultiFile broadcasts Write calls across multiple FILE* pointers. Each +// pointer is ignored if it's null. MultiFile::Write always returns success, +// ignoring any failures or short writes from the underlying FILE objects. +template +class MultiFile : public FILE { + public: + using FileArray = ktl::array; + + constexpr MultiFile() : FILE{this} {} + + constexpr explicit MultiFile(const FileArray& files) : FILE{this}, files_(files) {} + + constexpr MultiFile(const MultiFile& other) : MultiFile(other.files_) {} + + FileArray& files() { return files_; } + const FileArray& files() const { return files_; } + + int Write(ktl::string_view str) { + for (FILE* file : files_) { + if (file) { + file->Write(str); + } + } + return static_cast(str.size()); + } + + private: + FileArray files_ = {}; +}; + +template +MultiFile(const ktl::array&) -> MultiFile; + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_MULTI_FILE_H_ diff --git a/lib/libc/include/stdint.h b/lib/libc/include/stdint.h new file mode 100644 index 0000000..3cbdfeb --- /dev/null +++ b/lib/libc/include/stdint.h @@ -0,0 +1,278 @@ +// Copyright 2016 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_STDINT_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDINT_H_ + +// The compiler predefines macros ___TYPE__, ___MAX__, +// and ___C for the various types. All we have to do here is +// define the public names based on those macros. + +// Clang predefines macros ___FMT__ for each type, +// with being i and for signed types, and o, u, x, and X +// for unsigned types. That lets do its work without +// any special knowledge of what the underlying types are. +// Unfortunately, GCC does not define these macros. To keep all +// knowledge of the compiler's choices isolated to this file, define +// them here for GCC so that can use them unconditionally. +#ifndef __INTMAX_FMTd__ + +#define __INT8_FMT_MODIFIER__ "hh" +#define __INT16_FMT_MODIFIER__ "h" +#ifdef _LP64 +#define __INT32_FMT_MODIFIER__ "" +#else +#define __INT32_FMT_MODIFIER__ "l" +#endif + +#define __INT_LEAST8_FMT_MODIFIER__ __INT8_FMT_MODIFIER__ +#define __INT_LEAST16_FMT_MODIFIER__ __INT16_FMT_MODIFIER__ +#define __INT_LEAST32_FMT_MODIFIER__ __INT32_FMT_MODIFIER__ +#define __INT_LEAST64_FMT_MODIFIER__ __INT64_FMT_MODIFIER__ + +// The *-elf and arm-eabi GCC targets use 'int' for the fast{8,16,32} +// types. On LP64 systems, 'long' is used for the fast64 type, and +// 'long long' on non-LP64 systems. +#define __INT_FAST8_FMT_MODIFIER__ "" +#define __INT_FAST16_FMT_MODIFIER__ "" +#define __INT_FAST32_FMT_MODIFIER__ "" +#if _LP64 +#define __INT_FAST64_FMT_MODIFIER__ "l" +#else +#define __INT_FAST64_FMT_MODIFIER__ "ll" +#endif + +// On machines where 'long' types are 64 bits, the compiler defines +// __INT64_TYPE__ et al using 'long', not 'long long', though both are +// 64-bit types. +#ifdef _LP64 +#define __INT64_FMT_MODIFIER__ "l" +#define __INTPTR_FMT_MODIFIER__ "l" +#else +#define __INT64_FMT_MODIFIER__ "ll" +#define __INTPTR_FMT_MODIFIER__ "" +#endif + +#define __INTMAX_FMT_MODIFIER__ __INT64_FMT_MODIFIER__ + +#define __INTMAX_FMTd__ __INTMAX_FMT_MODIFIER__ "d" +#define __INTMAX_FMTi__ __INTMAX_FMT_MODIFIER__ "i" +#define __UINTMAX_FMTo__ __INTMAX_FMT_MODIFIER__ "o" +#define __UINTMAX_FMTu__ __INTMAX_FMT_MODIFIER__ "u" +#define __UINTMAX_FMTx__ __INTMAX_FMT_MODIFIER__ "x" +#define __UINTMAX_FMTX__ __INTMAX_FMT_MODIFIER__ "X" +#define __INTPTR_FMTd__ __INTPTR_FMT_MODIFIER__ "d" +#define __INTPTR_FMTi__ __INTPTR_FMT_MODIFIER__ "i" +#define __UINTPTR_FMTo__ __INTPTR_FMT_MODIFIER__ "o" +#define __UINTPTR_FMTu__ __INTPTR_FMT_MODIFIER__ "u" +#define __UINTPTR_FMTx__ __INTPTR_FMT_MODIFIER__ "x" +#define __UINTPTR_FMTX__ __INTPTR_FMT_MODIFIER__ "X" +#define __INT8_FMTd__ __INT8_FMT_MODIFIER__ "d" +#define __INT8_FMTi__ __INT8_FMT_MODIFIER__ "i" +#define __INT16_FMTd__ __INT16_FMT_MODIFIER__ "d" +#define __INT16_FMTi__ __INT16_FMT_MODIFIER__ "i" +#define __INT32_FMTd__ __INT32_FMT_MODIFIER__ "d" +#define __INT32_FMTi__ __INT32_FMT_MODIFIER__ "i" +#define __INT64_FMTd__ __INT64_FMT_MODIFIER__ "d" +#define __INT64_FMTi__ __INT64_FMT_MODIFIER__ "i" +#define __UINT8_FMTo__ __INT8_FMT_MODIFIER__ "o" +#define __UINT8_FMTu__ __INT8_FMT_MODIFIER__ "u" +#define __UINT8_FMTx__ __INT8_FMT_MODIFIER__ "x" +#define __UINT8_FMTX__ __INT8_FMT_MODIFIER__ "X" +#define __UINT16_FMTo__ __INT16_FMT_MODIFIER__ "o" +#define __UINT16_FMTu__ __INT16_FMT_MODIFIER__ "u" +#define __UINT16_FMTx__ __INT16_FMT_MODIFIER__ "x" +#define __UINT16_FMTX__ __INT16_FMT_MODIFIER__ "X" +#define __UINT32_FMTo__ __INT32_FMT_MODIFIER__ "o" +#define __UINT32_FMTu__ __INT32_FMT_MODIFIER__ "u" +#define __UINT32_FMTx__ __INT32_FMT_MODIFIER__ "x" +#define __UINT32_FMTX__ __INT32_FMT_MODIFIER__ "X" +#define __UINT64_FMTo__ __INT64_FMT_MODIFIER__ "o" +#define __UINT64_FMTu__ __INT64_FMT_MODIFIER__ "u" +#define __UINT64_FMTx__ __INT64_FMT_MODIFIER__ "x" +#define __UINT64_FMTX__ __INT64_FMT_MODIFIER__ "X" +#define __INT_LEAST8_FMTd__ __INT_LEAST8_FMT_MODIFIER__ "d" +#define __INT_LEAST8_FMTi__ __INT_LEAST8_FMT_MODIFIER__ "i" +#define __UINT_LEAST8_FMTo__ __INT_LEAST8_FMT_MODIFIER__ "o" +#define __UINT_LEAST8_FMTu__ __INT_LEAST8_FMT_MODIFIER__ "u" +#define __UINT_LEAST8_FMTx__ __INT_LEAST8_FMT_MODIFIER__ "x" +#define __UINT_LEAST8_FMTX__ __INT_LEAST8_FMT_MODIFIER__ "X" +#define __INT_LEAST16_FMTd__ __INT_LEAST16_FMT_MODIFIER__ "d" +#define __INT_LEAST16_FMTi__ __INT_LEAST16_FMT_MODIFIER__ "i" +#define __UINT_LEAST16_FMTo__ __INT_LEAST16_FMT_MODIFIER__ "o" +#define __UINT_LEAST16_FMTu__ __INT_LEAST16_FMT_MODIFIER__ "u" +#define __UINT_LEAST16_FMTx__ __INT_LEAST16_FMT_MODIFIER__ "x" +#define __UINT_LEAST16_FMTX__ __INT_LEAST16_FMT_MODIFIER__ "X" +#define __INT_LEAST32_FMTd__ __INT_LEAST32_FMT_MODIFIER__ "d" +#define __INT_LEAST32_FMTi__ __INT_LEAST32_FMT_MODIFIER__ "i" +#define __UINT_LEAST32_FMTo__ __INT_LEAST32_FMT_MODIFIER__ "o" +#define __UINT_LEAST32_FMTu__ __INT_LEAST32_FMT_MODIFIER__ "u" +#define __UINT_LEAST32_FMTx__ __INT_LEAST32_FMT_MODIFIER__ "x" +#define __UINT_LEAST32_FMTX__ __INT_LEAST32_FMT_MODIFIER__ "X" +#define __INT_LEAST64_FMTd__ __INT_LEAST64_FMT_MODIFIER__ "d" +#define __INT_LEAST64_FMTi__ __INT_LEAST64_FMT_MODIFIER__ "i" +#define __UINT_LEAST64_FMTo__ __INT_LEAST64_FMT_MODIFIER__ "o" +#define __UINT_LEAST64_FMTu__ __INT_LEAST64_FMT_MODIFIER__ "u" +#define __UINT_LEAST64_FMTx__ __INT_LEAST64_FMT_MODIFIER__ "x" +#define __UINT_LEAST64_FMTX__ __INT_LEAST64_FMT_MODIFIER__ "X" +#define __INT_FAST8_FMTd__ __INT_FAST8_FMT_MODIFIER__ "d" +#define __INT_FAST8_FMTi__ __INT_FAST8_FMT_MODIFIER__ "i" +#define __UINT_FAST8_FMTo__ __INT_FAST8_FMT_MODIFIER__ "o" +#define __UINT_FAST8_FMTu__ __INT_FAST8_FMT_MODIFIER__ "u" +#define __UINT_FAST8_FMTx__ __INT_FAST8_FMT_MODIFIER__ "x" +#define __UINT_FAST8_FMTX__ __INT_FAST8_FMT_MODIFIER__ "X" +#define __INT_FAST16_FMTd__ __INT_FAST16_FMT_MODIFIER__ "d" +#define __INT_FAST16_FMTi__ __INT_FAST16_FMT_MODIFIER__ "i" +#define __UINT_FAST16_FMTo__ __INT_FAST16_FMT_MODIFIER__ "o" +#define __UINT_FAST16_FMTu__ __INT_FAST16_FMT_MODIFIER__ "u" +#define __UINT_FAST16_FMTx__ __INT_FAST16_FMT_MODIFIER__ "x" +#define __UINT_FAST16_FMTX__ __INT_FAST16_FMT_MODIFIER__ "X" +#define __INT_FAST32_FMTd__ __INT_FAST32_FMT_MODIFIER__ "d" +#define __INT_FAST32_FMTi__ __INT_FAST32_FMT_MODIFIER__ "i" +#define __UINT_FAST32_FMTo__ __INT_FAST32_FMT_MODIFIER__ "o" +#define __UINT_FAST32_FMTu__ __INT_FAST32_FMT_MODIFIER__ "u" +#define __UINT_FAST32_FMTx__ __INT_FAST32_FMT_MODIFIER__ "x" +#define __UINT_FAST32_FMTX__ __INT_FAST32_FMT_MODIFIER__ "X" +#define __INT_FAST64_FMTd__ __INT_FAST64_FMT_MODIFIER__ "d" +#define __INT_FAST64_FMTi__ __INT_FAST64_FMT_MODIFIER__ "i" +#define __UINT_FAST64_FMTo__ __INT_FAST64_FMT_MODIFIER__ "o" +#define __UINT_FAST64_FMTu__ __INT_FAST64_FMT_MODIFIER__ "u" +#define __UINT_FAST64_FMTx__ __INT_FAST64_FMT_MODIFIER__ "x" +#define __UINT_FAST64_FMTX__ __INT_FAST64_FMT_MODIFIER__ "X" + +#endif + +typedef __UINT8_TYPE__ uint8_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __UINT32_TYPE__ uint32_t; +typedef __UINT64_TYPE__ uint64_t; +typedef __INT8_TYPE__ int8_t; +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; +typedef __INT64_TYPE__ int64_t; + +#define UINT8_MAX __UINT8_MAX__ +#define UINT16_MAX __UINT16_MAX__ +#define UINT32_MAX __UINT32_MAX__ +#define UINT64_MAX __UINT64_MAX__ + +#define INT8_MAX __INT8_MAX__ +#define INT16_MAX __INT16_MAX__ +#define INT32_MAX __INT32_MAX__ +#define INT64_MAX __INT64_MAX__ + +#define INT8_MIN (-INT8_MAX - 1) +#define INT16_MIN (-INT16_MAX - 1) +#define INT32_MIN (-INT32_MAX - 1) +#define INT64_MIN (-INT64_MAX - 1) + +typedef __UINT_LEAST8_TYPE__ uint_least8_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST64_TYPE__ uint_least64_t; +typedef __INT_LEAST8_TYPE__ int_least8_t; +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST64_TYPE__ int_least64_t; + +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ + +#define INT_LEAST8_MAX __INT_LEAST8_MAX__ +#define INT_LEAST16_MAX __INT_LEAST16_MAX__ +#define INT_LEAST32_MAX __INT_LEAST32_MAX__ +#define INT_LEAST64_MAX __INT_LEAST64_MAX__ + +#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1) +#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1) +#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1) +#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1) + +typedef __UINT_FAST8_TYPE__ uint_fast8_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST64_TYPE__ uint_fast64_t; +typedef __INT_FAST8_TYPE__ int_fast8_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST64_TYPE__ int_fast64_t; + +#define UINT_FAST8_MAX __UINT_FAST8_MAX__ +#define UINT_FAST16_MAX __UINT_FAST16_MAX__ +#define UINT_FAST32_MAX __UINT_FAST32_MAX__ +#define UINT_FAST64_MAX __UINT_FAST64_MAX__ + +#define INT_FAST8_MAX __INT_FAST8_MAX__ +#define INT_FAST16_MAX __INT_FAST16_MAX__ +#define INT_FAST32_MAX __INT_FAST32_MAX__ +#define INT_FAST64_MAX __INT_FAST64_MAX__ + +#define INT_FAST8_MIN (-INT_FAST8_MAX - 1) +#define INT_FAST16_MIN (-INT_FAST16_MAX - 1) +#define INT_FAST32_MIN (-INT_FAST32_MAX - 1) +#define INT_FAST64_MIN (-INT_FAST64_MAX - 1) + +typedef __INTPTR_TYPE__ intptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; + +#define INTPTR_MAX __INTPTR_MAX__ +#define INTPTR_MIN (-INTPTR_MAX - 1) +#define UINTPTR_MAX __UINTPTR_MAX__ + +typedef __INTMAX_TYPE__ intmax_t; +typedef __UINTMAX_TYPE__ uintmax_t; + +#define INTMAX_MAX __INTMAX_MAX__ +#define INTMAX_MIN (-INTMAX_MAX - 1) +#define UINTMAX_MAX __UINTMAX_MAX__ + +#define SIZE_MAX __SIZE_MAX__ + +// GCC defines __INT_C macros which append the correct suffix +// to an (un)signed integer literal, with being one of 8, 16, 32, 64 +// and MAX, and type being U for unsigned types. The standard stdint.h macros +// with the same names without the leading __ could be implemented in terms of +// these macros. +// +// Clang predefines macros __INT_C_SUFFIX__ which expand to the +// suffix itself. We define the standard stdint.h macros in terms of the GCC +// variants and for Clang we define their equivalents. +#ifndef __INTMAX_C + +#define __int_c_join(a, b) a##b +#define __int_c(v, suffix) __int_c_join(v, suffix) + +#define __INT8_C(c) __int_c(c, __INT8_C_SUFFIX__) +#define __INT16_C(c) __int_c(c, __INT16_C_SUFFIX__) +#define __INT32_C(c) __int_c(c, __INT32_C_SUFFIX__) +#define __INT64_C(c) __int_c(c, __INT64_C_SUFFIX__) + +#define __UINT8_C(c) __int_c(c, __UINT8_C_SUFFIX__) +#define __UINT16_C(c) __int_c(c, __UINT16_C_SUFFIX__) +#define __UINT32_C(c) __int_c(c, __UINT32_C_SUFFIX__) +#define __UINT64_C(c) __int_c(c, __UINT64_C_SUFFIX__) + +#define __INTMAX_C(c) __int_c(c, __INTMAX_C_SUFFIX__) +#define __UINTMAX_C(c) __int_c(c, __UINTMAX_C_SUFFIX__) + +#endif + +#define INT8_C(c) __INT8_C(c) +#define INT16_C(c) __INT16_C(c) +#define INT32_C(c) __INT32_C(c) +#define INT64_C(c) __INT64_C(c) + +#define UINT8_C(c) __UINT8_C(c) +#define UINT16_C(c) __UINT16_C(c) +#define UINT32_C(c) __UINT32_C(c) +#define UINT64_C(c) __UINT64_C(c) + +#define INTMAX_C(c) __INTMAX_C(c) +#define UINTMAX_C(c) __UINTMAX_C(c) + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDINT_H_ 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 +#include +#include + +// All anybody really wants from stdio is printf. + +#ifdef __cplusplus +#include + +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 + explicit FILE(T* writer) + : write_([](void* ptr, ktl::string_view s) { return static_cast(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(c); + return f->Write({reinterpret_cast(&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(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_ diff --git a/lib/libc/include/stdlib.h b/lib/libc/include/stdlib.h new file mode 100644 index 0000000..45c5a21 --- /dev/null +++ b/lib/libc/include/stdlib.h @@ -0,0 +1,36 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008-2014 Travis Geiselbrecht +// +// 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_STDLIB_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDLIB_H_ + +#include +#include +#include + +#ifdef _KERNEL +#include // lib/heap provides malloc/free definitions. +#endif + +__BEGIN_CDECLS + +long strtol(const char *nptr, char **endptr, int base); +unsigned long int strtoul(const char *nptr, char **endptr, int base); + +void abort(void) __attribute__((noreturn)); + +#define RAND_MAX (0x7fffffff) + +int rand(void); +void srand(unsigned int seed); + +// Note: POSIX.1 specifies unsigned int, but we use uintptr_t instead. +int rand_r(uintptr_t *seed); + +__END_CDECLS + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STDLIB_H_ diff --git a/lib/libc/include/string-file.h b/lib/libc/include/string-file.h new file mode 100644 index 0000000..1632933 --- /dev/null +++ b/lib/libc/include/string-file.h @@ -0,0 +1,79 @@ +// Copyright 2021 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// 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_STRING_FILE_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_FILE_H_ + +#ifdef __cplusplus +#include + +#include +#include +#include + +// FILE* wrapper over a string. +class StringFile : public FILE { + public: + StringFile() = delete; + StringFile(const StringFile &) = delete; + StringFile operator=(const StringFile &) = delete; + + explicit StringFile(ktl::span s) : FILE(this), buffer_(s) {} + + ~StringFile() = default; + + // Adds a null character at the end of the current buffer and returns a view + // into the written section. + ktl::span take() &&; + + // Returns |str.size()| and writes as much of |str| as it would fit in the + // buffer [offest_, size - 1) while reserving the last byte for null + // character. + int Write(ktl::string_view str); + + // Returns a region representing the currently used portion of the buffer. + ktl::span used_region() const { + return (offset_ > 0) ? ktl::span{buffer_.data(), offset_} : ktl::span{}; + } + + // Returns a region representing the remaining unused space in the buffer, + // _not_ including the space reserved for the final null character. + ktl::span available_region() const { + const size_t available = ktl::max(buffer_.size() - offset_, 1) - 1; + return (available > 0) ? ktl::span{buffer_.data() + offset_, available} + : ktl::span{}; + } + + // Skip up to |amt| bytes in the buffer, advancing the write pointer as if we + // had written data, but without actually changing the buffer. + void Skip(size_t amt) { + amt = ktl::min(amt, available_region().size()); + offset_ += amt; + } + + // Provide two ways for users to convert the currently used buffer into a + // string_view. Given a string file |S|, users may say either: + // + // 1) S.as_string_view(); // or + // 2) static_cast(S); + // + // to perform the conversion. + // + ktl::string_view as_string_view() const { + return (offset_ > 0) ? ktl::string_view{buffer_.data(), offset_} : ktl::string_view{}; + } + + explicit operator ktl::string_view() const { return this->as_string_view(); } + + private: + ktl::span buffer_; + size_t offset_ = 0; +}; + +#endif // __cplusplus + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_FILE_H_ diff --git a/lib/libc/include/string.h b/lib/libc/include/string.h new file mode 100644 index 0000000..3b55ccb --- /dev/null +++ b/lib/libc/include/string.h @@ -0,0 +1,97 @@ +// Copyright 2016 The Fuchsia Authors +// Copyright (c) 2008 Travis Geiselbrecht +// +// 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_STRING_H_ +#define ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_H_ + +// Other libc++ headers use but libc++'s complains if it +// thinks is not its own wrapper, which we do not need. We always +// get the kernel's before the libc++ with the way the include paths +// are set up, which is necessary because of other headers where preempting +// libc++'s header is unavoidable for the kernel environment. So just we +// define the macro that checks for to keep it happy. +#define _LIBCPP_STRING_H + +#include +#include + +__BEGIN_CDECLS + +int memcmp(const void*, const void*, size_t) __PURE; +void* memcpy(void*, const void*, size_t); +void* memmove(void*, const void*, size_t); +void* memset(void*, int, size_t); + +char* strcat(char*, const char*); +int strcmp(const char*, const char*) __PURE; +char* strcpy(char*, const char*); +size_t strlen(const char*) __PURE; +char* strncat(char*, const char*, size_t); +int strncmp(const char*, const char*, size_t) __PURE; +char* strncpy(char*, const char*, size_t); +size_t strspn(const char*, const char*) __PURE; +size_t strcspn(const char* s, const char*) __PURE; +char* strtok(char*, const char*); +int strcoll(const char* s1, const char* s2) __PURE; +size_t strxfrm(char* dest, const char* src, size_t n) __PURE; + +// Not actually defined in the kernel, but expects the declaration. +char* strerror(int); + +// Nonstandard. +size_t strlcat(char*, const char*, size_t); +size_t strlcpy(char*, const char*, size_t); +int strncasecmp(const char*, const char*, size_t) __PURE; +int strnicmp(const char*, const char*, size_t) __PURE; +size_t strnlen(const char* s, size_t count) __PURE; + +// Used by address sanitizer. +__typeof(memcpy) __unsanitized_memcpy; +__typeof(memmove) __unsanitized_memmove; +__typeof(memset) __unsanitized_memset; + +__END_CDECLS + +// C++ wants overloads for const and non-const versions of some functions. +#ifdef __cplusplus + +const char* strchr(const char*, int) __asm__("strchr") __PURE; +inline char* strchr(char* s, int c) { + return const_cast(strchr(const_cast(s), c)); +} + +const char* strpbrk(const char*, const char*) __asm__("strpbrk") __PURE; +inline char* strpbrk(char* s1, const char* s2) { + return const_cast(strpbrk(const_cast(s1), s2)); +} + +const char* strrchr(const char*, int) __asm__("strrchr") __PURE; +inline char* strrchr(char* s, int c) { + return const_cast(strrchr(const_cast(s), c)); +} + +const void* memchr(const void*, int, size_t) __asm__("memchr") __PURE; +inline void* memchr(void* s, int c, size_t n) { + return const_cast(memchr(const_cast(s), c, n)); +} + +const char* strstr(const char*, const char*) __asm__("strstr") __PURE; +inline char* strstr(char* s1, const char* s2) { + return const_cast(strstr(const_cast(s1), s2)); +} + +#else + +void* memchr(const void*, int, size_t); +char* strchr(const char*, int) __PURE; +char* strpbrk(const char*, const char*) __PURE; +char* strrchr(const char*, int) __PURE; +char* strstr(const char*, const char*) __PURE; + +#endif // __cplusplus + +#endif // ZIRCON_KERNEL_LIB_LIBC_INCLUDE_STRING_H_ -- cgit v1.2.3