Update printf

This commit is contained in:
Baptiste Wicht 2014-03-11 22:00:40 +01:00
parent 1cb20b40d0
commit d1e190a0f4
11 changed files with 272 additions and 402 deletions

4
cpp.mk
View File

@ -4,7 +4,7 @@ OC=x86_64-elf-objcopy
AR=x86_64-elf-ar AR=x86_64-elf-ar
WARNING_FLAGS=-Wall -Wextra -pedantic -Wold-style-cast WARNING_FLAGS=-Wall -Wextra -pedantic -Wold-style-cast
COMMON_CPP_FLAGS=-masm=intel -I../../tstl/include/ -I../tstl/include/ -I../tlib/include/ -Iinclude/ -nostdlib -g -Os -std=c++11 -fno-stack-protector -fno-exceptions -funsigned-char -fno-rtti -ffreestanding -fomit-frame-pointer -mno-red-zone -mno-3dnow -mno-mmx -fno-asynchronous-unwind-tables COMMON_CPP_FLAGS=-masm=intel -I../../tstl/include/ -I../printf/include/ -I../tstl/include/ -I../tlib/include/ -Iinclude/ -nostdlib -g -Os -std=c++11 -fno-stack-protector -fno-exceptions -funsigned-char -fno-rtti -ffreestanding -fomit-frame-pointer -mno-red-zone -mno-3dnow -mno-mmx -fno-asynchronous-unwind-tables
DISABLE_SSE_FLAGS=-mno-sse -mno-sse2 -mno-sse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2 DISABLE_SSE_FLAGS=-mno-sse -mno-sse2 -mno-sse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2
ENABLE_SSE_FLAGS=-msse -msse2 -msse3 -msse4 -msse4.1 -msse4.2 ENABLE_SSE_FLAGS=-msse -msse2 -msse3 -msse4 -msse4.1 -msse4.2
@ -25,5 +25,5 @@ KERNEL_LINK_FLAGS=$(COMMON_LINK_FLAGS) -T linker.ld
LIB_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -mcmodel=small -fPIC -ffunction-sections -fdata-sections LIB_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -mcmodel=small -fPIC -ffunction-sections -fdata-sections
LIB_LINK_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -mcmodel=small -fPIC -Wl,-gc-sections LIB_LINK_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -mcmodel=small -fPIC -Wl,-gc-sections
PROGRAM_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -I../../tlib/include/ -static -L../../tlib/ -ltlib -mcmodel=small -fPIC PROGRAM_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) -I../../tlib/include/ -I../../printf/include/ -static -L../../tlib/ -ltlib -mcmodel=small -fPIC
PROGRAM_LINK_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) $(COMMON_LINK_FLAGS) -static -L../../tlib/ -ltlib -mcmodel=small -fPIC -z max-page-size=0x1000 -T ../linker.ld -Wl,-gc-sections PROGRAM_LINK_FLAGS=$(CPP_FLAGS_64) $(WARNING_FLAGS) $(COMMON_LINK_FLAGS) -static -L../../tlib/ -ltlib -mcmodel=small -fPIC -z max-page-size=0x1000 -T ../linker.ld -Wl,-gc-sections

View File

@ -8,6 +8,8 @@
#ifndef CONSOLE_H #ifndef CONSOLE_H
#define CONSOLE_H #define CONSOLE_H
#include <stdarg.h>
#include <types.hpp> #include <types.hpp>
#include <enable_if.hpp> #include <enable_if.hpp>
#include <string.hpp> #include <string.hpp>
@ -40,8 +42,6 @@ void k_print(int16_t number);
void k_print(int32_t number); void k_print(int32_t number);
void k_print(int64_t number); void k_print(int64_t number);
void k_printf(const char* fmt, ...);
template<typename... Arguments> template<typename... Arguments>
typename std::enable_if_t<(sizeof...(Arguments) == 0)> k_print_line(const Arguments&... args){ typename std::enable_if_t<(sizeof...(Arguments) == 0)> k_print_line(const Arguments&... args){
k_print('\n'); k_print('\n');
@ -53,4 +53,6 @@ typename std::enable_if_t<(sizeof...(Arguments) > 0)> k_print_line(const Argumen
k_print('\n'); k_print('\n');
} }
#include "printf_dec.hpp"
#endif #endif

View File

@ -214,177 +214,8 @@ void wipeout(){
current_column = 0; current_column = 0;
} }
void k_printf(const char* fmt, ...){ #include "printf_def.hpp"
va_list va;
va_start(va, fmt);
char ch; void __printf(const std::string& str){
k_print(str);
while ((ch=*(fmt++))) {
if(ch != '%'){
k_print(ch);
} else {
ch = *(fmt++);
size_t min_width = 0;
while(ch >= '0' && ch <= '9'){
min_width = 10 * min_width + (ch - '0');
ch = *(fmt++);
}
size_t min_digits = 0;
if(ch == '.'){
ch = *(fmt++);
while(ch >= '0' && ch <= '9'){
min_digits = 10 * min_digits + (ch - '0');
ch = *(fmt++);
}
}
auto prev = current_column;
//Signed decimal
if(ch == 'd'){
auto arg = va_arg(va, int64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
if(arg < 0){
arg *= -1;
k_print('-');
}
while(min_digits > 0){
while(min_digits > 0){
k_print('0');
--min_digits;
}
}
}
}
k_print(arg);
}
//Unsigned Decimal
else if(ch == 'u'){
auto arg = va_arg(va, uint64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
while(min_digits > 0){
while(min_digits > 0){
k_print('0');
--min_digits;
}
}
}
}
k_print(arg);
}
//Hexadecimal
else if(ch == 'h'){
k_print("0x");
uint8_t buffer[20];
auto arg = va_arg(va, uint64_t);
size_t i = 0;
while(arg / 16 != 0){
buffer[i++] = arg % 16;
arg /= 16;
}
buffer[i] = arg;
if(min_digits > 0 && min_digits > i){
min_digits -= i + 1;
while(min_digits > 0){
k_print('0');
--min_digits;
}
}
while(true){
uint8_t digit = buffer[i];
if(digit < 10){
k_print(static_cast<char>('0' + digit));
} else {
switch(digit){
case 10:
k_print('A');
break;
case 11:
k_print('B');
break;
case 12:
k_print('C');
break;
case 13:
k_print('D');
break;
case 14:
k_print('E');
break;
case 15:
k_print('F');
break;
}
}
if(i == 0){
break;
}
--i;
}
}
//Memory
else if(ch == 'm'){
auto memory= va_arg(va, uint64_t);
if(memory >= 1024 * 1024 * 1024){
k_print(memory / (1024 * 1024 * 1024));
k_print("GiB");
} else if(memory >= 1024 * 1024){
k_print(memory / (1024 * 1024));
k_print("MiB");
} else if(memory >= 1024){
k_print(memory / 1024);
k_print("KiB");
} else {
k_print(memory);
k_print("B");
}
}
//String
else if(ch == 's'){
auto arg = va_arg(va, const char*);
k_print(arg);
}
if(min_width > 0){
size_t width = current_column - prev;
if(min_width > width){
min_width -= width;
while(min_width > 0){
k_print(' ');
--min_width;
}
}
}
}
}
va_end(va);
} }

View File

@ -224,16 +224,16 @@ const char* exceptions_title[32] {
extern "C" { extern "C" {
void _fault_handler(interrupt::fault_regs regs){ void _fault_handler(interrupt::fault_regs regs){
k_printf("Exception %u (%s) occured\n", regs.error_no, exceptions_title[regs.error_no]); printf("Exception %u (%s) occured\n", regs.error_no, exceptions_title[regs.error_no]);
k_printf("error_code=%u\n", regs.error_code); printf("error_code=%u\n", regs.error_code);
k_printf("rip=%h\n", regs.rip); printf("rip=%h\n", regs.rip);
k_printf("rflags=%h\n", regs.rflags); printf("rflags=%h\n", regs.rflags);
k_printf("cs=%h\n", regs.cs); printf("cs=%h\n", regs.cs);
k_printf("rsp=%h\n", regs.rsp); printf("rsp=%h\n", regs.rsp);
k_printf("ss=%h\n", regs.ss); printf("ss=%h\n", regs.ss);
k_printf("pid=%u\n", scheduler::get_pid()); printf("pid=%u\n", scheduler::get_pid());
k_printf("cr2=%h\n", get_cr2()); printf("cr2=%h\n", get_cr2());
k_printf("cr3=%h\n", get_cr3()); printf("cr3=%h\n", get_cr3());
//TODO Improve that with kind of blue screen //TODO Improve that with kind of blue screen

View File

@ -151,21 +151,21 @@ void debug_malloc(const char* point = nullptr){
k_print(" next: "); k_print(" next: ");
do { do {
k_printf("%u%h -> ", static_cast<size_t>(it->is_free()), reinterpret_cast<uint64_t>(it)); printf("%u%h -> ", static_cast<size_t>(it->is_free()), reinterpret_cast<uint64_t>(it));
it = it->next(); it = it->next();
} while(it != malloc_head); } while(it != malloc_head);
k_printf("%h\n", malloc_head); printf("%h\n", malloc_head);
it = malloc_head; it = malloc_head;
k_print("prev: "); k_print("prev: ");
do { do {
k_printf("%h <- ", reinterpret_cast<uint64_t>(it)); printf("%h <- ", reinterpret_cast<uint64_t>(it));
it = it->prev(); it = it->prev();
} while(it != malloc_head); } while(it != malloc_head);
k_printf("%h\n", malloc_head); printf("%h\n", malloc_head);
} }
} }
@ -414,7 +414,7 @@ void* kalloc::k_malloc(uint64_t bytes){
auto block_start = reinterpret_cast<uintptr_t>(current) + sizeof(malloc_header_chunk); auto block_start = reinterpret_cast<uintptr_t>(current) + sizeof(malloc_header_chunk);
if(TRACE_MALLOC){ if(TRACE_MALLOC){
k_printf("m %u(%u) %h ", bytes, current->size(), block_start); printf("m %u(%u) %h ", bytes, current->size(), block_start);
} }
return reinterpret_cast<void*>(block_start); return reinterpret_cast<void*>(block_start);
@ -429,7 +429,7 @@ void kalloc::k_free(void* block){
} }
if(TRACE_MALLOC){ if(TRACE_MALLOC){
k_printf("f %u %h ", free_header->size(), reinterpret_cast<uint64_t>(block)); printf("f %u %h ", free_header->size(), reinterpret_cast<uint64_t>(block));
} }
//Less memory is used //Less memory is used
@ -472,7 +472,7 @@ void kalloc::debug(){
auto it = malloc_head; auto it = malloc_head;
k_printf("malloc overhead: %u\n", META_SIZE); printf("malloc overhead: %u\n", META_SIZE);
k_print("Free blocks:"); k_print("Free blocks:");
do { do {
if(!it->is_free()){ if(!it->is_free()){
@ -484,14 +484,14 @@ void kalloc::debug(){
++inconsistent; ++inconsistent;
} }
k_printf("b(%u) ", it->size()); printf("b(%u) ", it->size());
memory_free += it->size(); memory_free += it->size();
it = it->next(); it = it->next();
} while(it != malloc_head); } while(it != malloc_head);
k_print_line(); k_print_line();
k_printf("memory free in malloc chain: %m (%u)\n", memory_free, memory_free); printf("memory free in malloc chain: %m (%u)\n", memory_free, memory_free);
k_printf("There are %u non free blocks in the free list\n", non_free_blocks); printf("There are %u non free blocks in the free list\n", non_free_blocks);
k_printf("There are %u inconsistent sized blocks in the free list\n", inconsistent); printf("There are %u inconsistent sized blocks in the free list\n", inconsistent);
} }

View File

@ -41,5 +41,5 @@ void out_word(uint16_t _port, uint16_t _data){
} }
void print_stack(const char* s, size_t check){ void print_stack(const char* s, size_t check){
k_printf("%s stack: %u (16B-a:%u) \n", s, check, static_cast<size_t>(check % 16)); printf("%s stack: %u (16B-a:%u) \n", s, check, static_cast<size_t>(check % 16));
} }

View File

@ -93,7 +93,7 @@ void gc_task(){
auto& desc = process.process; auto& desc = process.process;
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Clean process %u\n", desc.pid); printf("Clean process %u\n", desc.pid);
} }
//1. Release physical memory of PML4T //1. Release physical memory of PML4T
@ -266,7 +266,7 @@ void switch_to_process(size_t pid){
current_pid = pid; current_pid = pid;
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Switch to %u\n", current_pid); printf("Switch to %u\n", current_pid);
} }
auto& process = pcb[current_pid]; auto& process = pcb[current_pid];
@ -363,7 +363,7 @@ bool allocate_user_memory(scheduler::process_t& process, size_t address, size_t
(physical_memory / paging::PAGE_SIZE + 1) * paging::PAGE_SIZE; (physical_memory / paging::PAGE_SIZE + 1) * paging::PAGE_SIZE;
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Map(p%u) virtual:%h into phys: %h\n", process.pid, first_page, aligned_physical_memory); printf("Map(p%u) virtual:%h into phys: %h\n", process.pid, first_page, aligned_physical_memory);
} }
@ -396,7 +396,7 @@ bool create_paging(char* buffer, scheduler::process_t& process){
process.paging_size = paging::PAGE_SIZE; process.paging_size = paging::PAGE_SIZE;
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Process %u cr3:%h\n", process.pid, process.physical_cr3); printf("Process %u cr3:%h\n", process.pid, process.physical_cr3);
} }
clear_physical_memory(process.physical_cr3, 1); clear_physical_memory(process.physical_cr3, 1);
@ -442,7 +442,7 @@ bool create_paging(char* buffer, scheduler::process_t& process){
physical_pointer phys_ptr(segment.physical, pages); physical_pointer phys_ptr(segment.physical, pages);
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Copy to physical:%h\n", segment.physical); printf("Copy to physical:%h\n", segment.physical);
} }
auto memory_start = phys_ptr.get() + left_padding; auto memory_start = phys_ptr.get() + left_padding;
@ -672,7 +672,7 @@ void scheduler::sbrk(size_t inc){
auto virtual_start = process.brk_start; auto virtual_start = process.brk_start;
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Map(p%u) virtual:%h into phys: %h\n", process.pid, virtual_start, physical); printf("Map(p%u) virtual:%h into phys: %h\n", process.pid, virtual_start, physical);
} }
//Map the memory inside the process memory space //Map the memory inside the process memory space
@ -710,7 +710,7 @@ void scheduler::await_termination(pid_t pid){
void scheduler::kill_current_process(){ void scheduler::kill_current_process(){
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Kill %u\n", current_pid); printf("Kill %u\n", current_pid);
} }
//Notify parent if waiting //Notify parent if waiting
@ -801,7 +801,7 @@ void scheduler::block_process(pid_t pid){
thor_assert(pcb[pid].state == process_state::RUNNING, "Can only block RUNNING processes"); thor_assert(pcb[pid].state == process_state::RUNNING, "Can only block RUNNING processes");
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Block process %u\n", pid); printf("Block process %u\n", pid);
} }
pcb[pid].state = process_state::BLOCKED; pcb[pid].state = process_state::BLOCKED;
@ -814,7 +814,7 @@ void scheduler::unblock_process(pid_t pid){
thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::WAITING, "Can only unblock BLOCKED/WAITING processes"); thor_assert(pcb[pid].state == process_state::BLOCKED || pcb[pid].state == process_state::WAITING, "Can only unblock BLOCKED/WAITING processes");
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Unblock process %u\n", pid); printf("Unblock process %u\n", pid);
} }
pcb[pid].state = process_state::READY; pcb[pid].state = process_state::READY;
@ -825,7 +825,7 @@ void scheduler::sleep_ms(pid_t pid, size_t time){
thor_assert(pcb[pid].state == process_state::RUNNING, "Only RUNNING processes can sleep"); thor_assert(pcb[pid].state == process_state::RUNNING, "Only RUNNING processes can sleep");
if(DEBUG_SCHEDULER){ if(DEBUG_SCHEDULER){
k_printf("Put %u to sleep\n", pid); printf("Put %u to sleep\n", pid);
} }
pcb[pid].state = process_state::SLEEPING; pcb[pid].state = process_state::SLEEPING;

View File

@ -0,0 +1,20 @@
//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
//Is made to be included as is in a header file
//
//Implement is provided in printf_def.hpp which must be included in
//source file
std::string sprintf(const std::string& format, ...);
std::string vsprintf(const std::string& format, va_list va);
void printf(const std::string& format, ...);
void vprintf(const std::string& format, va_list va);
//Definition of this function must be provided
void __printf(const std::string& formatted);

View File

@ -0,0 +1,205 @@
//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
std::string vsprintf(const std::string& format, va_list va){
std::string s(format.size());
char ch;
int fi = 0;
while ((ch = format[fi++])) {
if(ch != '%'){
s += ch;
} else {
ch = format[fi++];
size_t min_width = 0;
while(ch >= '0' && ch <= '9'){
min_width = 10 * min_width + (ch - '0');
ch = format[fi++];
}
size_t min_digits = 0;
if(ch == '.'){
ch = format[fi++];
while(ch >= '0' && ch <= '9'){
min_digits = 10 * min_digits + (ch - '0');
ch = format[fi++];
}
}
auto prev = s.size();
//Signed decimal
if(ch == 'd'){
auto arg = va_arg(va, int64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
if(arg < 0){
arg *= -1;
s += '-';
}
while(min_digits > 0){
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
}
}
s += std::to_string(arg);
}
//Unsigned Decimal
else if(ch == 'u'){
auto arg = va_arg(va, uint64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
while(min_digits > 0){
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
}
}
s += std::to_string(arg);
}
//Hexadecimal
else if(ch == 'h'){
s += "0x";
uint8_t buffer[20];
auto arg = va_arg(va, uint64_t);
size_t i = 0;
while(arg / 16 != 0){
buffer[i++] = arg % 16;
arg /= 16;
}
buffer[i] = arg;
if(min_digits > 0 && min_digits > i){
min_digits -= i + 1;
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
while(true){
uint8_t digit = buffer[i];
if(digit < 10){
s += static_cast<char>('0' + digit);
} else {
switch(digit){
case 10:
s += 'A';
break;
case 11:
s += 'B';
break;
case 12:
s += 'C';
break;
case 13:
s += 'D';
break;
case 14:
s += 'E';
break;
case 15:
s += 'F';
break;
}
}
if(i == 0){
break;
}
--i;
}
}
//Memory
else if(ch == 'm'){
auto memory= va_arg(va, uint64_t);
if(memory >= 1024 * 1024 * 1024){
s += std::to_string(memory / (1024 * 1024 * 1024));
s += "GiB";
} else if(memory >= 1024 * 1024){
s += std::to_string(memory / (1024 * 1024));
s += "MiB";
} else if(memory >= 1024){
s += std::to_string(memory / 1024);
s += "KiB";
} else {
s += std::to_string(memory);
s += "B";
}
}
//String
else if(ch == 's'){
auto arg = va_arg(va, const char*);
s += arg;
}
if(min_width > 0){
size_t width = s.size() - prev;
if(min_width > width){
min_width -= width;
while(min_width > 0){
s += ' ';
--min_width;
}
}
}
}
}
return std::move(s);
}
std::string sprintf(const std::string& format, ...){
va_list va;
va_start(va, format);
auto s = vsprintf(format, va);
va_end(va);
return std::move(s);
}
void printf(const std::string& format, va_list va){
__printf(vsprintf(format, va));
}
void printf(const std::string& format, ...){
va_list va;
va_start(va, format);
printf(format, va);
va_end(va);
}

View File

@ -10,6 +10,8 @@
//TODO Rename in console //TODO Rename in console
#include <stdarg.h>
#include <types.hpp> #include <types.hpp>
#include <string.hpp> #include <string.hpp>
@ -39,7 +41,6 @@ void clear();
size_t get_columns(); size_t get_columns();
size_t get_rows(); size_t get_rows();
std::string sprintf(const std::string& format, ...); #include "printf_dec.hpp"
void printf(const std::string& format, ...);
#endif #endif

View File

@ -112,197 +112,8 @@ void print_line(const std::string& s){
print_line(); print_line();
} }
std::string vsprintf(const std::string& format, va_list va){ #include "printf_def.hpp"
std::string s(format.size());
char ch; void __printf(const std::string& formatted){
int fi = 0; print(formatted);
while ((ch = format[fi++])) {
if(ch != '%'){
s += ch;
} else {
ch = format[fi++];
size_t min_width = 0;
while(ch >= '0' && ch <= '9'){
min_width = 10 * min_width + (ch - '0');
ch = format[fi++];
}
size_t min_digits = 0;
if(ch == '.'){
ch = format[fi++];
while(ch >= '0' && ch <= '9'){
min_digits = 10 * min_digits + (ch - '0');
ch = format[fi++];
}
}
auto prev = s.size();
//Signed decimal
if(ch == 'd'){
auto arg = va_arg(va, int64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
if(arg < 0){
arg *= -1;
s += '-';
}
while(min_digits > 0){
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
}
}
s += std::to_string(arg);
}
//Unsigned Decimal
else if(ch == 'u'){
auto arg = va_arg(va, uint64_t);
if(min_digits > 0){
size_t d = std::digits(arg);
if(min_digits > d){
min_digits -= d;
while(min_digits > 0){
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
}
}
s += std::to_string(arg);
}
//Hexadecimal
else if(ch == 'h'){
s += "0x";
uint8_t buffer[20];
auto arg = va_arg(va, uint64_t);
size_t i = 0;
while(arg / 16 != 0){
buffer[i++] = arg % 16;
arg /= 16;
}
buffer[i] = arg;
if(min_digits > 0 && min_digits > i){
min_digits -= i + 1;
while(min_digits > 0){
arg += '0';
--min_digits;
}
}
while(true){
uint8_t digit = buffer[i];
if(digit < 10){
s += static_cast<char>('0' + digit);
} else {
switch(digit){
case 10:
s += 'A';
break;
case 11:
s += 'B';
break;
case 12:
s += 'C';
break;
case 13:
s += 'D';
break;
case 14:
s += 'E';
break;
case 15:
s += 'F';
break;
}
}
if(i == 0){
break;
}
--i;
}
}
//Memory
else if(ch == 'm'){
auto memory= va_arg(va, uint64_t);
if(memory >= 1024 * 1024 * 1024){
s += std::to_string(memory / (1024 * 1024 * 1024));
s += "GiB";
} else if(memory >= 1024 * 1024){
s += std::to_string(memory / (1024 * 1024));
s += "MiB";
} else if(memory >= 1024){
s += std::to_string(memory / 1024);
s += "KiB";
} else {
s += std::to_string(memory);
s += "B";
}
}
//String
else if(ch == 's'){
auto arg = va_arg(va, const char*);
s += arg;
}
if(min_width > 0){
size_t width = s.size() - prev;
if(min_width > width){
min_width -= width;
while(min_width > 0){
s += ' ';
--min_width;
}
}
}
}
}
return std::move(s);
}
std::string sprintf(const std::string& format, ...){
va_list va;
va_start(va, format);
auto s = vsprintf(format, va);
va_end(va);
return std::move(s);
}
void printf(const std::string& format, ...){
va_list va;
va_start(va, format);
print(vsprintf(format, va));
va_end(va);
} }