1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
#pragma once
namespace nall {
//nall::format is a vector<string> of parameters that can be applied to a string
//each {#} token will be replaced with its appropriate format parameter
auto string::format(const nall::string_format& params) -> type& {
auto size = (int)this->size();
auto data = (char*)memory::allocate(size);
memory::copy(data, this->data(), size);
int x = 0;
while(x < size - 2) { //2 = minimum tag length
if(data[x] != '{') { x++; continue; }
int y = x + 1;
while(y < size - 1) { //-1 avoids going out of bounds on test after this loop
if(data[y] != '}') { y++; continue; }
break;
}
if(data[y++] != '}') { x++; continue; }
static auto isNumeric = [](char* s, char* e) -> bool {
if(s == e) return false; //ignore empty tags: {}
while(s < e) {
if(*s >= '0' && *s <= '9') { s++; continue; }
return false;
}
return true;
};
if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; }
uint index = toNatural(&data[x + 1]);
if(index >= params.size()) { x++; continue; }
uint sourceSize = y - x;
uint targetSize = params[index].size();
uint remaining = size - x;
if(sourceSize > targetSize) {
uint difference = sourceSize - targetSize;
memory::move(&data[x], &data[x + difference], remaining);
size -= difference;
} else if(targetSize > sourceSize) {
uint difference = targetSize - sourceSize;
data = (char*)realloc(data, size + difference);
size += difference;
memory::move(&data[x + difference], &data[x], remaining);
}
memory::copy(&data[x], params[index].data(), targetSize);
x += targetSize;
}
resize(size);
memory::copy(get(), data, size);
memory::free(data);
return *this;
}
template<typename T, typename... P> auto string_format::append(const T& value, P&&... p) -> string_format& {
vector<string>::append(value);
return append(forward<P>(p)...);
}
auto string_format::append() -> string_format& {
return *this;
}
template<typename... P> auto print(P&&... p) -> void {
string s{forward<P>(p)...};
fwrite(s.data(), 1, s.size(), stdout);
}
template<typename... P> auto print(FILE* fp, P&&... p) -> void {
string s{forward<P>(p)...};
fwrite(s.data(), 1, s.size(), fp);
}
template<typename T> auto pad(const T& value, long precision, char padchar) -> string {
string buffer{value};
if(precision) buffer.size(precision, padchar);
return buffer;
}
auto hex(uintmax value, long precision, char padchar) -> string {
string buffer;
buffer.resize(sizeof(uintmax) * 2);
char* p = buffer.get();
uint size = 0;
do {
uint n = value & 15;
p[size++] = n < 10 ? '0' + n : 'a' + n - 10;
value >>= 4;
} while(value);
buffer.resize(size);
buffer.reverse();
if(precision) buffer.size(precision, padchar);
return buffer;
}
auto octal(uintmax value, long precision, char padchar) -> string {
string buffer;
buffer.resize(sizeof(uintmax) * 3);
char* p = buffer.get();
uint size = 0;
do {
p[size++] = '0' + (value & 7);
value >>= 3;
} while(value);
buffer.resize(size);
buffer.reverse();
if(precision) buffer.size(precision, padchar);
return buffer;
}
auto binary(uintmax value, long precision, char padchar) -> string {
string buffer;
buffer.resize(sizeof(uintmax) * 8);
char* p = buffer.get();
uint size = 0;
do {
p[size++] = '0' + (value & 1);
value >>= 1;
} while(value);
buffer.resize(size);
buffer.reverse();
if(precision) buffer.size(precision, padchar);
return buffer;
}
auto pointer(uintptr value, long precision) -> string {
if(value == 0) return "(nullptr)";
return {"0x", hex(value, precision)};
}
template<typename T> auto pointer(const T* value, long precision) -> string {
if(value == nullptr) return "(nullptr)";
return {"0x", hex((uintptr)value, precision)};
}
}
|