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