209 lines
4.3 KiB
C++
209 lines
4.3 KiB
C++
|
|
#include <stdio.h>
|
|
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <stdarg.h>
|
|
#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<char>('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<char>('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<char>('0' + digit);
|
|
}
|
|
else
|
|
{
|
|
*pos = static_cast<char>('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<uint64_t>(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<int>(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<char>(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<char>(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"
|
|
|