#include #include #include #include #include "os/tty.hpp" extern "C" { namespace { int printInt(int value) { if (value == 0) { putchar('0'); return 1; } if (value < 0) { putchar('-'); return printInt(-value) + 1; } char digits[10]; // 2147483647 has 10 digits char* pos = &digits[0]; while (value > 0) { *pos = static_cast('0' + (value % 10)); value /= 10; ++pos; } for (char* chr = pos - 1; chr >= digits; --chr) { putchar(*chr); } return pos - digits; } int printUInt(uint64_t value) { if (value == 0) { putchar('0'); return 1; } char digits[20]; // 18,446,744,073,709,551,615 has 20 digits char* pos = &digits[0]; while (value > 0) { *pos = static_cast('0' + (value % 10)); value /= 10; ++pos; } for (char* chr = pos - 1; chr >= digits; --chr) { putchar(*chr); } return pos - digits; } int printHexInt(uint64_t value) { if (value == 0) { putchar('0'); return 1; } char digits[16]; // FFFFFFFFFFFFFFFF has 16 digits char* pos = &digits[0]; while (value > 0) { const uint64_t digit = (value % 16); if (digit < 10) { *pos = static_cast('0' + digit); } else { *pos = static_cast('A' + digit - 10); } value /= 16; ++pos; } for (char* chr = pos - 1; chr >= digits; --chr) { putchar(*chr); } return pos - digits; } int printPointer(void* ptr) { return printHexInt(reinterpret_cast(ptr)); } int printString(const char* str) { const size_t len = std::strlen(str); for (size_t idx = 0; idx < len; ++idx) { putchar(str[idx]); } return static_cast(len); } int printByteSize(size_t bytes) { const char* suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB" }; int suffixIdx = 0; for (; suffixIdx < sizeof(suffixes) / sizeof(suffixes[0]); ++suffixIdx) { if (bytes < 1024) { break; } bytes /= 1024; } return printUInt(bytes) + printString(suffixes[suffixIdx]); } } int putchar(int chr) noexcept { tty::putChar(static_cast(chr)); return 0; } int puts(const char* str) noexcept { tty::write(str); tty::putChar('\n'); return 0; } int printf(const char* format, ...) noexcept { va_list parameters; va_start(parameters, format); const int result = vprintf(format, parameters); va_end(parameters); return result; } int vprintf(const char* format, std::va_list vlist) BA_CXX_NOEXCEPT { int result = 0; const char* pos = format; while (*pos != '\0') { if (*pos == '%') { ++pos; switch (*pos) { case '%': putchar('%'); ++result; break; case '\0': // TODO: invalid format string, do something assert(!"Invalid format string, ends with %."); return -1; case 'b': result += printByteSize(va_arg(vlist, size_t)); break; case 'c': { const char chr = static_cast(va_arg(vlist, int)); putchar(chr); ++result; break; } case 's': result += printString(va_arg(vlist, const char*)); break; case 'd': result += printInt(va_arg(vlist, int)); break; case 'p': result += printPointer(va_arg(vlist, void*)); break; case 'X': result += printHexInt(va_arg(vlist, unsigned)); break; default: assert(!"Invalid format string, unknown format identifier."); return -1; } } else { putchar(*pos); } ++pos; } ++result; return result; } } // extern "C"