mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[util] Move remaining *printf impementations to util::format
I added util::format as a replacement for other printf implementations last year, but it sat there only being used by the kernel all this time. Now I've templated it so that it can be used by the bootloader, and removed printf from panic.serial as well.
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <uefi/protos/simple_text_output.h>
|
#include <uefi/protos/simple_text_output.h>
|
||||||
#include <uefi/types.h>
|
#include <uefi/types.h>
|
||||||
|
#include <util/format.h>
|
||||||
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@@ -58,130 +59,13 @@ console::announce()
|
|||||||
m_out->output_string(L" booting...\r\n");
|
m_out->output_string(L" booting...\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
|
||||||
console::print_hex(uint32_t n) const
|
|
||||||
{
|
|
||||||
wchar_t buffer[9];
|
|
||||||
wchar_t *p = buffer;
|
|
||||||
for (int i = 7; i >= 0; --i) {
|
|
||||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
|
||||||
*p++ = digits[nibble];
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
m_out->output_string(buffer);
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
console::print_long_hex(uint64_t n) const
|
|
||||||
{
|
|
||||||
wchar_t buffer[17];
|
|
||||||
wchar_t *p = buffer;
|
|
||||||
for (int i = 15; i >= 0; --i) {
|
|
||||||
uint8_t nibble = (n >> (i*4)) & 0xf;
|
|
||||||
*p++ = digits[nibble];
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
m_out->output_string(buffer);
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
console::print_dec(uint32_t n) const
|
|
||||||
{
|
|
||||||
wchar_t buffer[11];
|
|
||||||
wchar_t *p = buffer + 10;
|
|
||||||
*p-- = 0;
|
|
||||||
do {
|
|
||||||
*p-- = digits[n % 10];
|
|
||||||
n /= 10;
|
|
||||||
} while (n != 0);
|
|
||||||
|
|
||||||
m_out->output_string(++p);
|
|
||||||
return 10 - (p - buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
console::print_long_dec(uint64_t n) const
|
|
||||||
{
|
|
||||||
wchar_t buffer[21];
|
|
||||||
wchar_t *p = buffer + 20;
|
|
||||||
*p-- = 0;
|
|
||||||
do {
|
|
||||||
*p-- = digits[n % 10];
|
|
||||||
n /= 10;
|
|
||||||
} while (n != 0);
|
|
||||||
|
|
||||||
m_out->output_string(++p);
|
|
||||||
return 20 - (p - buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
console::vprintf(const wchar_t *fmt, va_list args) const
|
console::vprintf(const wchar_t *fmt, va_list args) const
|
||||||
{
|
{
|
||||||
wchar_t buffer[256];
|
wchar_t buffer[256];
|
||||||
const wchar_t *r = fmt;
|
util::counted<wchar_t> output {buffer, sizeof(buffer)/sizeof(wchar_t)};
|
||||||
wchar_t *w = buffer;
|
size_t count = util::vformat(output, fmt, args);
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
while (r && *r) {
|
|
||||||
if (*r != L'%') {
|
|
||||||
count++;
|
|
||||||
*w++ = *r++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*w = 0;
|
|
||||||
m_out->output_string(buffer);
|
|
||||||
w = buffer;
|
|
||||||
|
|
||||||
r++; // chomp the %
|
|
||||||
|
|
||||||
switch (*r++) {
|
|
||||||
case L'%':
|
|
||||||
m_out->output_string(const_cast<wchar_t*>(L"%"));
|
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L'x':
|
|
||||||
count += print_hex(va_arg(args, uint32_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L'd':
|
|
||||||
case L'u':
|
|
||||||
count += print_dec(va_arg(args, uint32_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L's':
|
|
||||||
{
|
|
||||||
wchar_t *s = va_arg(args, wchar_t*);
|
|
||||||
count += wstrlen(s);
|
|
||||||
m_out->output_string(s);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L'l':
|
|
||||||
switch (*r++) {
|
|
||||||
case L'x':
|
|
||||||
count += print_long_hex(va_arg(args, uint64_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case L'd':
|
|
||||||
case L'u':
|
|
||||||
count += print_long_dec(va_arg(args, uint64_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*w = 0;
|
|
||||||
m_out->output_string(buffer);
|
m_out->output_string(buffer);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ public:
|
|||||||
|
|
||||||
void announce();
|
void announce();
|
||||||
|
|
||||||
size_t print_hex(uint32_t n) const;
|
|
||||||
size_t print_dec(uint32_t n) const;
|
|
||||||
size_t print_long_hex(uint64_t n) const;
|
|
||||||
size_t print_long_dec(uint64_t n) const;
|
|
||||||
size_t printf(const wchar_t *fmt, ...) const;
|
size_t printf(const wchar_t *fmt, ...) const;
|
||||||
|
|
||||||
static console & get() { return *s_console; }
|
static console & get() { return *s_console; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "printf/printf.h"
|
#include <util/format.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
@@ -29,7 +29,7 @@ print_header(
|
|||||||
out.write(":");
|
out.write(":");
|
||||||
|
|
||||||
char linestr[6];
|
char linestr[6];
|
||||||
snprintf(linestr, sizeof(linestr), "%ld", line);
|
util::format({linestr, sizeof(linestr)}, "%ld", line);
|
||||||
out.write(linestr);
|
out.write(linestr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ print_cpu(serial_port &out, cpu_data &cpu)
|
|||||||
{
|
{
|
||||||
out.write("\n \e[0;31m==[ CPU: ");
|
out.write("\n \e[0;31m==[ CPU: ");
|
||||||
char cpuid[7];
|
char cpuid[7];
|
||||||
snprintf(cpuid, sizeof(cpuid), "%4x", cpu.id);
|
util::format({cpuid, sizeof(cpuid)}, "%4x", cpu.id);
|
||||||
out.write(cpuid);
|
out.write(cpuid);
|
||||||
out.write(" ]====================================================================\n");
|
out.write(" ]====================================================================\n");
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ print_callstack(serial_port &out, symbol_table &syms, frame const *fp)
|
|||||||
if (!name)
|
if (!name)
|
||||||
name = "<unknown>";
|
name = "<unknown>";
|
||||||
|
|
||||||
snprintf(message, sizeof(message),
|
util::format({message, sizeof(message)},
|
||||||
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
|
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
|
||||||
count++, fp->return_addr, name);
|
count++, fp->return_addr, name);
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ print_reg(serial_port &out, const char *name, uint64_t val, const char *color)
|
|||||||
{
|
{
|
||||||
char message[512];
|
char message[512];
|
||||||
|
|
||||||
snprintf(message, sizeof(message), " \e[0;%sm%-3s %016lx\e[0m", color, name, val);
|
util::format({message, sizeof(message)}, " \e[0;%sm%3s %016lx\e[0m", color, name, val);
|
||||||
out.write(message);
|
out.write(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,11 +124,11 @@ print_rip(serial_port &out, uintptr_t addr)
|
|||||||
|
|
||||||
out.write("\n");
|
out.write("\n");
|
||||||
for (unsigned i = 0; i < per_line*3; i += per_line) {
|
for (unsigned i = 0; i < per_line*3; i += per_line) {
|
||||||
snprintf(bit, sizeof(bit), "\e[0;33m%20lx: \e[0m", addr + i);
|
util::format({bit, sizeof(bit)}, "\e[0;33m%20lx: \e[0m", addr + i);
|
||||||
out.write(bit);
|
out.write(bit);
|
||||||
|
|
||||||
for (unsigned j = 0; j < per_line; ++j) {
|
for (unsigned j = 0; j < per_line; ++j) {
|
||||||
snprintf(bit, sizeof(bit), "%02x ", data[i+j]);
|
util::format({bit, sizeof(bit)}, "%02x ", data[i+j]);
|
||||||
out.write(bit);
|
out.write(bit);
|
||||||
}
|
}
|
||||||
out.write("\n");
|
out.write("\n");
|
||||||
@@ -155,6 +155,3 @@ print_user_state(serial_port &out, const cpu_state ®s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace panicking
|
} // namespace panicking
|
||||||
|
|
||||||
// For printf.c
|
|
||||||
extern "C" void putchar_(char c) {}
|
|
||||||
|
|||||||
@@ -13,5 +13,4 @@ panic = module("panic.serial",
|
|||||||
"main.cpp",
|
"main.cpp",
|
||||||
"serial.cpp",
|
"serial.cpp",
|
||||||
"symbol_table.cpp",
|
"symbol_table.cpp",
|
||||||
"../printf/printf.c",
|
|
||||||
])
|
])
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,151 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
|
|
||||||
* 2021, Haifa, Palestine/Israel
|
|
||||||
* @author (c) Marco Paland (info@paland.com)
|
|
||||||
* 2014-2019, PALANDesign Hannover, Germany
|
|
||||||
*
|
|
||||||
* @note Others have made smaller contributions to this file: see the
|
|
||||||
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
|
|
||||||
* or ask one of the authors.
|
|
||||||
*
|
|
||||||
* @brief Small stand-alone implementation of the printf family of functions
|
|
||||||
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
|
|
||||||
* a very limited resources.
|
|
||||||
*
|
|
||||||
* @note the implementations are thread-safe; re-entrant; use no functions from
|
|
||||||
* the standard library; and do not dynamically allocate any memory.
|
|
||||||
*
|
|
||||||
* @license The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PRINTF_H_
|
|
||||||
#define PRINTF_H_
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
# define ATTR_PRINTF(one_based_format_index, first_arg) \
|
|
||||||
__attribute__((format(__printf__, (one_based_format_index), (first_arg))))
|
|
||||||
# define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF(one_based_format_index, 0)
|
|
||||||
#else
|
|
||||||
# define ATTR_PRINTF(one_based_format_index, first_arg)
|
|
||||||
# define ATTR_VPRINTF(one_based_format_index)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
|
||||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
|
||||||
# define printf_ printf
|
|
||||||
# define sprintf_ sprintf
|
|
||||||
# define vsprintf_ vsprintf
|
|
||||||
# define snprintf_ snprintf
|
|
||||||
# define vsnprintf_ vsnprintf
|
|
||||||
# define vprintf_ vprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output a character to a custom device like UART, used by the printf() function
|
|
||||||
* This function is declared here only. You have to write your custom implementation somewhere
|
|
||||||
* @param character Character to output
|
|
||||||
*/
|
|
||||||
void putchar_(char character);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tiny printf implementation
|
|
||||||
* You have to implement putchar_ if you use printf()
|
|
||||||
* To avoid conflicts with the regular printf() API it is overridden by macro defines
|
|
||||||
* and internal underscore-appended functions like printf_() are used
|
|
||||||
* @param format A string that specifies the format of the output
|
|
||||||
* @return The number of characters that are written into the array, not counting the terminating null character
|
|
||||||
*/
|
|
||||||
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tiny sprintf/vsprintf implementation
|
|
||||||
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
|
|
||||||
* @param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
|
|
||||||
* @param format A string that specifies the format of the output
|
|
||||||
* @param va A value identifying a variable arguments list
|
|
||||||
* @return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
|
||||||
*/
|
|
||||||
int sprintf_(char* buffer, const char* format, ...) ATTR_PRINTF(2, 3);
|
|
||||||
int vsprintf_(char* buffer, const char* format, va_list va) ATTR_VPRINTF(2);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tiny snprintf/vsnprintf implementation
|
|
||||||
* @param buffer A pointer to the buffer where to store the formatted string
|
|
||||||
* @param count The maximum number of characters to store in the buffer, including a terminating null character
|
|
||||||
* @param format A string that specifies the format of the output
|
|
||||||
* @param va A value identifying a variable arguments list
|
|
||||||
* @return The number of characters that COULD have been written into the buffer, not counting the terminating
|
|
||||||
* null character. A value equal or larger than count indicates truncation. Only when the returned value
|
|
||||||
* is non-negative and less than count, the string has been completely written.
|
|
||||||
*/
|
|
||||||
int snprintf_(char* buffer, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
|
|
||||||
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) ATTR_VPRINTF(3);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tiny vprintf implementation
|
|
||||||
* @param format A string that specifies the format of the output
|
|
||||||
* @param va A value identifying a variable arguments list
|
|
||||||
* @return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
|
|
||||||
*/
|
|
||||||
int vprintf_(const char* format, va_list va) ATTR_VPRINTF(1);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* printf/vprintf with output function
|
|
||||||
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
|
|
||||||
* @param out An output function which takes one character and an argument pointer
|
|
||||||
* @param arg An argument pointer for user data passed to output function
|
|
||||||
* @param format A string that specifies the format of the output
|
|
||||||
* @param va A value identifying a variable arguments list
|
|
||||||
* @return The number of characters that are sent to the output function, not counting the terminating null character
|
|
||||||
*/
|
|
||||||
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) ATTR_PRINTF(3, 4);
|
|
||||||
int vfctprintf(void (*out)(char character, void* arg), void* arg, const char* format, va_list va) ATTR_VPRINTF(3);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
|
||||||
# undef printf_
|
|
||||||
# undef sprintf_
|
|
||||||
# undef vsprintf_
|
|
||||||
# undef snprintf_
|
|
||||||
# undef vsnprintf_
|
|
||||||
# undef vprintf_
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // PRINTF_H_
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// \file printf_config.h
|
|
||||||
// Configuration for eyalroz/printf
|
|
||||||
|
|
||||||
#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 0
|
|
||||||
#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 0
|
|
||||||
#define PRINTF_SUPPORT_WRITEBACK_SPECIFIER 0
|
|
||||||
#define PRINTF_SUPPORT_LONG_LONG 1
|
|
||||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 1
|
|
||||||
@@ -5,22 +5,60 @@ namespace util {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char digits[] = "0123456789abcdef";
|
template <typename char_t> struct char_traits;
|
||||||
|
|
||||||
template <typename I, unsigned N> void
|
template <>
|
||||||
append_int(char *&out, size_t &count, size_t max, I value, unsigned min_width, char pad)
|
struct char_traits<char>
|
||||||
{
|
{
|
||||||
static constexpr size_t bufsize = sizeof(I)*3;
|
static constexpr const char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
static constexpr char d0 = '0';
|
||||||
|
static constexpr char d9 = '9';
|
||||||
|
|
||||||
|
static constexpr char per = '%';
|
||||||
|
static constexpr char space = ' ';
|
||||||
|
|
||||||
|
static constexpr char d = 'd';
|
||||||
|
static constexpr char l = 'l';
|
||||||
|
static constexpr char s = 's';
|
||||||
|
static constexpr char u = 'u';
|
||||||
|
static constexpr char x = 'x';
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct char_traits<wchar_t>
|
||||||
|
{
|
||||||
|
static constexpr const wchar_t digits[] = L"0123456789abcdef";
|
||||||
|
|
||||||
|
static constexpr wchar_t d0 = L'0';
|
||||||
|
static constexpr wchar_t d9 = L'9';
|
||||||
|
|
||||||
|
static constexpr wchar_t per = L'%';
|
||||||
|
static constexpr wchar_t space = L' ';
|
||||||
|
|
||||||
|
static constexpr wchar_t d = L'd';
|
||||||
|
static constexpr wchar_t l = L'l';
|
||||||
|
static constexpr wchar_t s = L's';
|
||||||
|
static constexpr wchar_t u = L'u';
|
||||||
|
static constexpr wchar_t x = L'x';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename char_t, typename I, unsigned N> void
|
||||||
|
append_int(char_t *&out, size_t &count, size_t max, I value, unsigned min_width, char_t pad)
|
||||||
|
{
|
||||||
|
using chars = char_traits<char_t>;
|
||||||
|
static constexpr size_t bufsize = sizeof(I)*4;
|
||||||
|
|
||||||
unsigned num_digits = 0;
|
unsigned num_digits = 0;
|
||||||
char buffer[bufsize];
|
char_t buffer[bufsize];
|
||||||
char *p = buffer + (bufsize - 1);
|
char_t *p = buffer + (bufsize - 1);
|
||||||
do {
|
do {
|
||||||
if (value) {
|
if (value) {
|
||||||
*p-- = digits[value % N];
|
*p-- = chars::digits[value % N];
|
||||||
value /= N;
|
value /= N;
|
||||||
} else {
|
} else {
|
||||||
*p-- = num_digits ? pad : '0';
|
*p-- = num_digits ? pad : chars::d0;
|
||||||
}
|
}
|
||||||
num_digits++;
|
num_digits++;
|
||||||
} while (value || num_digits < min_width);
|
} while (value || num_digits < min_width);
|
||||||
@@ -33,81 +71,91 @@ append_int(char *&out, size_t &count, size_t max, I value, unsigned min_width, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
template <typename char_t> void
|
||||||
append_string(char *&out, size_t &count, size_t max, char const *value)
|
append_string(char_t *&out, size_t &count, size_t max, unsigned width, char_t const *value)
|
||||||
{
|
{
|
||||||
|
using chars = char_traits<char_t>;
|
||||||
|
|
||||||
while (value && *value && count < max) {
|
while (value && *value && count < max) {
|
||||||
count++;
|
++count;
|
||||||
|
if (width) --width;
|
||||||
*out++ = *value++;
|
*out++ = *value++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (width-- && count < max) {
|
||||||
|
++count;
|
||||||
|
*out++ = chars::space;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
size_t
|
template <typename char_t> size_t
|
||||||
vformat(stringbuf output, char const *format, va_list va)
|
vformat(counted<char_t> output, char_t const *format, va_list va)
|
||||||
{
|
{
|
||||||
char * out = output.pointer;
|
using chars = char_traits<char_t>;
|
||||||
|
|
||||||
|
char_t * out = output.pointer;
|
||||||
const size_t max = output.count - 1;
|
const size_t max = output.count - 1;
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
while (format && *format && count < max) {
|
while (format && *format && count < max) {
|
||||||
if (*format != '%') {
|
if (*format != chars::per) {
|
||||||
count++;
|
count++;
|
||||||
*out++ = *format++;
|
*out++ = *format++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
format++; // chomp the % character
|
format++; // chomp the % character
|
||||||
char spec = *format++;
|
char_t spec = *format++;
|
||||||
|
|
||||||
bool long_type = false;
|
bool long_type = false;
|
||||||
if (spec == '%') {
|
if (spec == chars::per) {
|
||||||
count++;
|
count++;
|
||||||
*out++ = '%';
|
*out++ = chars::per;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
char pad = ' ';
|
char_t pad = chars::space;
|
||||||
|
|
||||||
while (spec) {
|
while (spec) {
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
if (spec >= '0' && spec <= '9') {
|
if (spec >= chars::d0 && spec <= chars::d9) {
|
||||||
if (spec == '0' && width == 0)
|
if (spec == chars::d0 && width == 0)
|
||||||
pad = '0';
|
pad = chars::d0;
|
||||||
else
|
else
|
||||||
width = width * 10 + (spec - '0');
|
width = width * 10 + (spec - chars::d0);
|
||||||
|
|
||||||
spec = *format++;
|
spec = *format++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (spec) {
|
switch (spec) {
|
||||||
case 'l':
|
case chars::l:
|
||||||
long_type = true;
|
long_type = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
case chars::x:
|
||||||
if (long_type)
|
if (long_type)
|
||||||
append_int<uint64_t, 16>(out, count, max, va_arg(va, uint64_t), width, pad);
|
append_int<char_t, uint64_t, 16>(out, count, max, va_arg(va, uint64_t), width, pad);
|
||||||
else
|
else
|
||||||
append_int<uint32_t, 16>(out, count, max, va_arg(va, uint32_t), width, pad);
|
append_int<char_t, uint32_t, 16>(out, count, max, va_arg(va, uint32_t), width, pad);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case chars::d:
|
||||||
case 'u':
|
case chars::u:
|
||||||
if (long_type)
|
if (long_type)
|
||||||
append_int<uint64_t, 10>(out, count, max, va_arg(va, uint64_t), width, pad);
|
append_int<char_t, uint64_t, 10>(out, count, max, va_arg(va, uint64_t), width, pad);
|
||||||
else
|
else
|
||||||
append_int<uint32_t, 10>(out, count, max, va_arg(va, uint32_t), width, pad);
|
append_int<char_t, uint32_t, 10>(out, count, max, va_arg(va, uint32_t), width, pad);
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case chars::s:
|
||||||
append_string(out, count, max, va_arg(va, const char *));
|
append_string(out, count, max, width, va_arg(va, const char_t *));
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -117,17 +165,24 @@ vformat(stringbuf output, char const *format, va_list va)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*out = 0;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
template <typename char_t> size_t
|
||||||
format(stringbuf output, const char *format, ...)
|
format(counted<char_t> output, const char_t *format, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
size_t result = vformat(output, format, va);
|
size_t result = vformat<char_t>(output, format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template size_t format<char>(counted<char> output, const char *format, ...);
|
||||||
|
template size_t vformat<char>(counted<char> output, const char *format, va_list va);
|
||||||
|
|
||||||
|
template size_t format<wchar_t>(counted<wchar_t> output, const wchar_t *format, ...);
|
||||||
|
template size_t vformat<wchar_t>(counted<wchar_t> output, const wchar_t *format, va_list va);
|
||||||
|
|
||||||
} //namespace util
|
} //namespace util
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
using stringbuf = counted<char>;
|
template <typename char_t>
|
||||||
|
size_t format(counted<char_t> output, const char_t *format, ...);
|
||||||
|
|
||||||
size_t format(stringbuf output, const char *format, ...);
|
template <typename char_t>
|
||||||
size_t vformat(stringbuf output, const char *format, va_list va);
|
size_t vformat(counted<char_t> output, const char_t *format, va_list va);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user