mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use std::string for string-formatted values (#1360)
* Use `std::string` for string-formatted values * Make `formatString` and `formatNumber` be `const`
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
enum FormatState {
|
||||
FORMAT_SIGN, // expects '+' or ' ' (optional)
|
||||
@@ -35,8 +36,9 @@ public:
|
||||
|
||||
void useCharacter(int c);
|
||||
void finishCharacters();
|
||||
void printString(char *buf, size_t bufLen, char const *value);
|
||||
void printNumber(char *buf, size_t bufLen, uint32_t value);
|
||||
|
||||
std::string formatString(std::string const &value) const;
|
||||
std::string formatNumber(uint32_t value) const;
|
||||
};
|
||||
|
||||
#endif // RGBDS_FORMAT_SPEC_H
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asm/fixpoint.hpp"
|
||||
#include "asm/lexer.hpp" // MAXSTRLEN
|
||||
#include "asm/warning.hpp"
|
||||
|
||||
void FormatSpec::useCharacter(int c) {
|
||||
@@ -104,10 +105,11 @@ void FormatSpec::finishCharacters() {
|
||||
state = FORMAT_INVALID;
|
||||
}
|
||||
|
||||
void FormatSpec::printString(char *buf, size_t bufLen, char const *value) {
|
||||
std::string FormatSpec::formatString(std::string const &value) const {
|
||||
int useType = type;
|
||||
if (isEmpty()) {
|
||||
// No format was specified
|
||||
type = 's';
|
||||
useType = 's';
|
||||
}
|
||||
|
||||
if (sign)
|
||||
@@ -118,52 +120,50 @@ void FormatSpec::printString(char *buf, size_t bufLen, char const *value) {
|
||||
error("Formatting string with padding flag '0'\n");
|
||||
if (hasFrac)
|
||||
error("Formatting string with fractional width\n");
|
||||
if (type != 's')
|
||||
error("Formatting string as type '%c'\n", type);
|
||||
if (useType != 's')
|
||||
error("Formatting string as type '%c'\n", useType);
|
||||
|
||||
size_t len = strlen(value);
|
||||
size_t totalLen = width > len ? width : len;
|
||||
|
||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||
error("Formatted string value too long\n");
|
||||
totalLen = bufLen - 1;
|
||||
if (len > totalLen)
|
||||
len = totalLen;
|
||||
}
|
||||
assert(len < bufLen && totalLen < bufLen && len <= totalLen);
|
||||
|
||||
size_t padLen = totalLen - len;
|
||||
size_t valueLen = value.length();
|
||||
size_t totalLen = width > valueLen ? width : valueLen;
|
||||
size_t padLen = totalLen - valueLen;
|
||||
|
||||
std::string str;
|
||||
str.reserve(totalLen);
|
||||
if (alignLeft) {
|
||||
memcpy(buf, value, len);
|
||||
for (size_t i = len; i < totalLen; i++)
|
||||
buf[i] = ' ';
|
||||
str.append(value);
|
||||
str.append(padLen, ' ');
|
||||
} else {
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[i] = ' ';
|
||||
memcpy(buf + padLen, value, len);
|
||||
str.append(padLen, ' ');
|
||||
str.append(value);
|
||||
}
|
||||
|
||||
buf[totalLen] = '\0';
|
||||
if (str.length() > MAXSTRLEN) {
|
||||
error("Formatted string value too long\n");
|
||||
str.resize(MAXSTRLEN);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
|
||||
std::string FormatSpec::formatNumber(uint32_t value) const {
|
||||
int useType = type;
|
||||
bool usePrefix = prefix;
|
||||
if (isEmpty()) {
|
||||
// No format was specified; default to uppercase $hex
|
||||
type = 'X';
|
||||
prefix = true;
|
||||
useType = 'X';
|
||||
usePrefix = true;
|
||||
}
|
||||
|
||||
if (type != 'X' && type != 'x' && type != 'b' && type != 'o' && prefix)
|
||||
error("Formatting type '%c' with prefix flag '#'\n", type);
|
||||
if (type != 'f' && hasFrac)
|
||||
error("Formatting type '%c' with fractional width\n", type);
|
||||
if (type == 's')
|
||||
if (useType != 'X' && useType != 'x' && useType != 'b' && useType != 'o' && usePrefix)
|
||||
error("Formatting type '%c' with prefix flag '#'\n", useType);
|
||||
if (useType != 'f' && hasFrac)
|
||||
error("Formatting type '%c' with fractional width\n", useType);
|
||||
if (useType == 's')
|
||||
error("Formatting number as type 's'\n");
|
||||
|
||||
char signChar = sign; // 0 or ' ' or '+'
|
||||
|
||||
if (type == 'd' || type == 'f') {
|
||||
if (useType == 'd' || useType == 'f') {
|
||||
int32_t v = value;
|
||||
|
||||
if (v < 0 && v != INT32_MIN) {
|
||||
@@ -172,16 +172,16 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
char prefixChar = !prefix ? 0
|
||||
: type == 'X' ? '$'
|
||||
: type == 'x' ? '$'
|
||||
: type == 'b' ? '%'
|
||||
: type == 'o' ? '&'
|
||||
: 0;
|
||||
char prefixChar = !usePrefix ? 0
|
||||
: useType == 'X' ? '$'
|
||||
: useType == 'x' ? '$'
|
||||
: useType == 'b' ? '%'
|
||||
: useType == 'o' ? '&'
|
||||
: 0;
|
||||
|
||||
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
|
||||
|
||||
if (type == 'b') {
|
||||
if (useType == 'b') {
|
||||
// Special case for binary
|
||||
char *ptr = valueBuf;
|
||||
|
||||
@@ -194,76 +194,68 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
|
||||
std::reverse(valueBuf, ptr);
|
||||
|
||||
*ptr = '\0';
|
||||
} else if (type == 'f') {
|
||||
} else if (useType == 'f') {
|
||||
// Special case for fixed-point
|
||||
|
||||
// Default fractional width (C++'s is 6 for "%f"; here 5 is enough for Q16.16)
|
||||
size_t cappedFracWidth = hasFrac ? fracWidth : 5;
|
||||
size_t useFracWidth = hasFrac ? fracWidth : 5;
|
||||
|
||||
if (cappedFracWidth > 255) {
|
||||
error("Fractional width %zu too long, limiting to 255\n", cappedFracWidth);
|
||||
cappedFracWidth = 255;
|
||||
if (useFracWidth > 255) {
|
||||
error("Fractional width %zu too long, limiting to 255\n", useFracWidth);
|
||||
useFracWidth = 255;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth, value / fix_PrecisionFactor()
|
||||
valueBuf, sizeof(valueBuf), "%.*f", (int)useFracWidth, value / fix_PrecisionFactor()
|
||||
);
|
||||
} else {
|
||||
char const *spec = type == 'd' ? "%" PRId32
|
||||
: type == 'u' ? "%" PRIu32
|
||||
: type == 'X' ? "%" PRIX32
|
||||
: type == 'x' ? "%" PRIx32
|
||||
: type == 'o' ? "%" PRIo32
|
||||
: "%" PRId32;
|
||||
char const *spec = useType == 'd' ? "%" PRId32
|
||||
: useType == 'u' ? "%" PRIu32
|
||||
: useType == 'X' ? "%" PRIX32
|
||||
: useType == 'x' ? "%" PRIx32
|
||||
: useType == 'o' ? "%" PRIo32
|
||||
: "%" PRId32;
|
||||
|
||||
snprintf(valueBuf, sizeof(valueBuf), spec, value);
|
||||
}
|
||||
|
||||
size_t len = strlen(valueBuf);
|
||||
size_t numLen = (signChar != 0) + (prefixChar != 0) + len;
|
||||
size_t valueLen = strlen(valueBuf);
|
||||
size_t numLen = (signChar != 0) + (prefixChar != 0) + valueLen;
|
||||
size_t totalLen = width > numLen ? width : numLen;
|
||||
|
||||
if (totalLen > bufLen - 1) { // bufLen includes terminator
|
||||
error("Formatted numeric value too long\n");
|
||||
totalLen = bufLen - 1;
|
||||
if (numLen > totalLen) {
|
||||
len -= numLen - totalLen;
|
||||
numLen = totalLen;
|
||||
}
|
||||
}
|
||||
assert(numLen < bufLen && totalLen < bufLen && numLen <= totalLen && len <= numLen);
|
||||
|
||||
size_t padLen = totalLen - numLen;
|
||||
size_t pos = 0;
|
||||
|
||||
std::string str;
|
||||
str.reserve(totalLen);
|
||||
if (alignLeft) {
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
str += signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
memcpy(buf + pos, valueBuf, len);
|
||||
for (size_t i = pos + len; i < totalLen; i++)
|
||||
buf[i] = ' ';
|
||||
str += prefixChar;
|
||||
str.append(valueBuf);
|
||||
str.append(padLen, ' ');
|
||||
} else {
|
||||
if (padZero) {
|
||||
// sign, then prefix, then zero padding
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
str += signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = '0';
|
||||
str += prefixChar;
|
||||
str.append(padLen, '0');
|
||||
} else {
|
||||
// space padding, then sign, then prefix
|
||||
for (size_t i = 0; i < padLen; i++)
|
||||
buf[pos++] = ' ';
|
||||
str.append(padLen, ' ');
|
||||
if (signChar)
|
||||
buf[pos++] = signChar;
|
||||
str += signChar;
|
||||
if (prefixChar)
|
||||
buf[pos++] = prefixChar;
|
||||
str += prefixChar;
|
||||
}
|
||||
memcpy(buf + pos, valueBuf, len);
|
||||
str.append(valueBuf);
|
||||
}
|
||||
|
||||
buf[totalLen] = '\0';
|
||||
if (str.length() > MAXSTRLEN) {
|
||||
error("Formatted numeric value too long\n");
|
||||
str.resize(MAXSTRLEN);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -1191,10 +1191,12 @@ static char const *readInterpolation(size_t depth) {
|
||||
if (!sym) {
|
||||
error("Interpolated symbol \"%s\" does not exist\n", fmtBuf.c_str());
|
||||
} else if (sym->type == SYM_EQUS) {
|
||||
fmt.printString(buf, sizeof(buf), sym->getEqus()->c_str());
|
||||
std::string str = fmt.formatString(*sym->getEqus());
|
||||
memcpy(buf, str.c_str(), str.length() + 1);
|
||||
return buf;
|
||||
} else if (sym->isNumeric()) {
|
||||
fmt.printNumber(buf, sizeof(buf), sym->getConstantValue());
|
||||
std::string str = fmt.formatNumber(sym->getConstantValue());
|
||||
memcpy(buf, str.c_str(), str.length() + 1);
|
||||
return buf;
|
||||
} else {
|
||||
error("Only numerical and string symbols can be interpolated\n");
|
||||
|
||||
@@ -2690,15 +2690,13 @@ static std::string strfmt(
|
||||
// Will warn after formatting is done.
|
||||
str += '%';
|
||||
} else {
|
||||
static char buf[MAXSTRLEN + 1];
|
||||
std::visit(
|
||||
str.append(std::visit(
|
||||
Visitor{
|
||||
[&](uint32_t n) { fmt.printNumber(buf, sizeof(buf), n); },
|
||||
[&](std::string const &s) { fmt.printString(buf, sizeof(buf), s.c_str()); },
|
||||
[&fmt](uint32_t n) { return fmt.formatNumber(n); },
|
||||
[&fmt](std::string const &s) { return fmt.formatString(s); },
|
||||
},
|
||||
args[argIndex]
|
||||
);
|
||||
str.append(buf);
|
||||
));
|
||||
}
|
||||
|
||||
argIndex++;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a
|
||||
$00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
$2a
|
||||
123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
hello
|
||||
000000000000000000000123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
hello
|
||||
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
|
||||
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
<$2a
|
||||
<123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
< hell
|
||||
<000000000000000000000123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
<
|
||||
<hello
|
||||
|
||||
Reference in New Issue
Block a user