mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-29 06:17:48 +00:00
Factor out a single parseNumber utility function (#1839)
This commit is contained in:
@@ -11,24 +11,21 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "util.hpp" // isDigit
|
||||
#include "util.hpp" // parseNumber
|
||||
|
||||
#include "asm/main.hpp" // options
|
||||
#include "asm/warning.hpp"
|
||||
|
||||
static size_t parseNumber(char const *spec, size_t &value) {
|
||||
size_t i = 0;
|
||||
|
||||
value = 0;
|
||||
for (; isDigit(spec[i]); ++i) {
|
||||
value = value * 10 + (spec[i] - '0');
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t FormatSpec::parseSpec(char const *spec) {
|
||||
size_t i = 0;
|
||||
|
||||
auto parseSpecNumber = [&spec, &i]() {
|
||||
char const *end = &spec[i];
|
||||
size_t number = parseNumber(end, BASE_10).value_or(0);
|
||||
i += end - &spec[i];
|
||||
return number;
|
||||
};
|
||||
|
||||
// <sign>
|
||||
if (char c = spec[i]; c == ' ' || c == '+') {
|
||||
++i;
|
||||
@@ -51,19 +48,19 @@ size_t FormatSpec::parseSpec(char const *spec) {
|
||||
}
|
||||
// <width>
|
||||
if (isDigit(spec[i])) {
|
||||
i += parseNumber(&spec[i], width);
|
||||
width = parseSpecNumber();
|
||||
}
|
||||
// <frac>
|
||||
if (spec[i] == '.') {
|
||||
++i;
|
||||
hasFrac = true;
|
||||
i += parseNumber(&spec[i], fracWidth);
|
||||
fracWidth = parseSpecNumber();
|
||||
}
|
||||
// <prec>
|
||||
if (spec[i] == 'q') {
|
||||
++i;
|
||||
hasPrec = true;
|
||||
i += parseNumber(&spec[i], precision);
|
||||
precision = parseSpecNumber();
|
||||
}
|
||||
// <type>
|
||||
switch (char c = spec[i]; c) {
|
||||
|
||||
@@ -1009,8 +1009,8 @@ static bool isValidDigit(char c) {
|
||||
return isAlphanumeric(c) || c == '.' || c == '#' || c == '@';
|
||||
}
|
||||
|
||||
static bool isBinDigit(int c) {
|
||||
return c == '0' || c == '1' || c == options.binDigits[0] || c == options.binDigits[1];
|
||||
static bool isCustomBinDigit(int c) {
|
||||
return isBinDigit(c) || c == options.binDigits[0] || c == options.binDigits[1];
|
||||
}
|
||||
|
||||
static bool checkDigitErrors(char const *digits, size_t n, char const *type) {
|
||||
@@ -1078,7 +1078,7 @@ static uint32_t readBinaryNumber(char const *prefix) {
|
||||
if (value > (UINT32_MAX - bit) / 2) {
|
||||
warning(WARNING_LARGE_CONSTANT, "Integer constant is too large");
|
||||
// Discard any additional digits
|
||||
skipChars([](int d) { return isBinDigit(d) || d == '_'; });
|
||||
skipChars([](int d) { return isCustomBinDigit(d) || d == '_'; });
|
||||
return 0;
|
||||
}
|
||||
value = value * 2 + bit;
|
||||
@@ -1836,7 +1836,7 @@ static Token yylex_NORMAL() {
|
||||
|
||||
case '%': // Either %=, MOD, or a binary constant
|
||||
c = peek();
|
||||
if (isBinDigit(c) || c == '_') {
|
||||
if (isCustomBinDigit(c) || c == '_') {
|
||||
return Token(T_(NUMBER), readBinaryNumber("'%'"));
|
||||
}
|
||||
return oneOrTwo('=', T_(POP_MODEQ), T_(OP_MOD));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -299,6 +300,8 @@ int main(int argc, char *argv[]) {
|
||||
// https://reproducible-builds.org/docs/source-date-epoch/
|
||||
time_t now = time(nullptr);
|
||||
if (char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH"); sourceDateEpoch) {
|
||||
// Use `strtoul`, not `parseWholeNumber`, because SOURCE_DATE_EPOCH does
|
||||
// not conventionally support our custom base prefixes
|
||||
now = static_cast<time_t>(strtoul(sourceDateEpoch, nullptr, 0));
|
||||
}
|
||||
sym_Init(now);
|
||||
@@ -378,51 +381,41 @@ int main(int argc, char *argv[]) {
|
||||
fstk_AddPreIncludeFile(musl_optarg);
|
||||
break;
|
||||
|
||||
case 'p': {
|
||||
char *endptr;
|
||||
unsigned long padByte = strtoul(musl_optarg, &endptr, 0);
|
||||
|
||||
if (musl_optarg[0] == '\0' || *endptr != '\0') {
|
||||
case 'p':
|
||||
if (std::optional<uint64_t> padByte = parseWholeNumber(musl_optarg); !padByte) {
|
||||
fatal("Invalid argument for option '-p'");
|
||||
}
|
||||
|
||||
if (padByte > 0xFF) {
|
||||
} else if (*padByte > 0xFF) {
|
||||
fatal("Argument for option '-p' must be between 0 and 0xFF");
|
||||
} else {
|
||||
opt_P(*padByte);
|
||||
}
|
||||
|
||||
opt_P(padByte);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Q': {
|
||||
char const *precisionArg = musl_optarg;
|
||||
if (precisionArg[0] == '.') {
|
||||
++precisionArg;
|
||||
}
|
||||
char *endptr;
|
||||
unsigned long precision = strtoul(precisionArg, &endptr, 0);
|
||||
|
||||
if (precisionArg[0] == '\0' || *endptr != '\0') {
|
||||
if (std::optional<uint64_t> precision = parseWholeNumber(precisionArg); !precision) {
|
||||
fatal("Invalid argument for option '-Q'");
|
||||
}
|
||||
|
||||
if (precision < 1 || precision > 31) {
|
||||
} else if (*precision < 1 || *precision > 31) {
|
||||
fatal("Argument for option '-Q' must be between 1 and 31");
|
||||
} else {
|
||||
opt_Q(*precision);
|
||||
}
|
||||
|
||||
opt_Q(precision);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'r': {
|
||||
char *endptr;
|
||||
options.maxRecursionDepth = strtoul(musl_optarg, &endptr, 0);
|
||||
|
||||
if (musl_optarg[0] == '\0' || *endptr != '\0') {
|
||||
case 'r':
|
||||
if (std::optional<uint64_t> maxDepth = parseWholeNumber(musl_optarg); !maxDepth) {
|
||||
fatal("Invalid argument for option '-r'");
|
||||
} else if (errno == ERANGE) {
|
||||
fatal("Argument for option '-r' is out of range");
|
||||
} else {
|
||||
options.maxRecursionDepth = *maxDepth;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
// Split "<features>:<name>" so `musl_optarg` is "<features>" and `name` is "<name>"
|
||||
@@ -459,21 +452,15 @@ int main(int argc, char *argv[]) {
|
||||
warnings.state.warningsEnabled = false;
|
||||
break;
|
||||
|
||||
case 'X': {
|
||||
char *endptr;
|
||||
uint64_t maxErrors = strtoul(musl_optarg, &endptr, 0);
|
||||
|
||||
if (musl_optarg[0] == '\0' || *endptr != '\0') {
|
||||
case 'X':
|
||||
if (std::optional<uint64_t> maxErrors = parseWholeNumber(musl_optarg); !maxErrors) {
|
||||
fatal("Invalid argument for option '-X'");
|
||||
}
|
||||
|
||||
if (maxErrors > UINT64_MAX) {
|
||||
} else if (*maxErrors > UINT64_MAX) {
|
||||
fatal("Argument for option '-X' must be between 0 and %" PRIu64, UINT64_MAX);
|
||||
} else {
|
||||
options.maxErrors = *maxErrors;
|
||||
}
|
||||
|
||||
options.maxErrors = maxErrors;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0: // Long-only options
|
||||
switch (longOpt) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <iterator> // std::size
|
||||
#include <optional>
|
||||
#include <stack>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -9,8 +10,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "diagnostics.hpp"
|
||||
#include "helpers.hpp" // assume
|
||||
#include "util.hpp" // isBlankSpace
|
||||
#include "util.hpp"
|
||||
|
||||
#include "asm/fstack.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
@@ -81,50 +81,38 @@ void opt_Parse(char const *s) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p': {
|
||||
char *endptr;
|
||||
unsigned long padByte = strtoul(s, &endptr, 0);
|
||||
|
||||
if (s[0] == '\0' || *endptr != '\0') {
|
||||
case 'p':
|
||||
if (std::optional<uint64_t> padByte = parseWholeNumber(s); !padByte) {
|
||||
error("Invalid argument for option 'p'");
|
||||
} else if (padByte > 0xFF) {
|
||||
} else if (*padByte > 0xFF) {
|
||||
error("Argument for option 'p' must be between 0 and 0xFF");
|
||||
} else {
|
||||
opt_P(padByte);
|
||||
opt_P(*padByte);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Q': {
|
||||
case 'Q':
|
||||
if (s[0] == '.') {
|
||||
++s; // Skip leading '.'
|
||||
}
|
||||
char *endptr;
|
||||
unsigned long precision = strtoul(s, &endptr, 0);
|
||||
|
||||
if (s[0] == '\0' || *endptr != '\0') {
|
||||
if (std::optional<uint64_t> precision = parseWholeNumber(s); !precision) {
|
||||
error("Invalid argument for option 'Q'");
|
||||
} else if (precision < 1 || precision > 31) {
|
||||
} else if (*precision < 1 || *precision > 31) {
|
||||
error("Argument for option 'Q' must be between 1 and 31");
|
||||
} else {
|
||||
opt_Q(precision);
|
||||
opt_Q(*precision);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'r': {
|
||||
char *endptr;
|
||||
unsigned long maxRecursionDepth = strtoul(s, &endptr, 0);
|
||||
|
||||
if (s[0] == '\0' || *endptr != '\0') {
|
||||
case 'r':
|
||||
if (std::optional<uint64_t> maxRecursionDepth = parseWholeNumber(s); !maxRecursionDepth) {
|
||||
error("Invalid argument for option 'r'");
|
||||
} else if (errno == ERANGE) {
|
||||
error("Argument for option 'r' is out of range");
|
||||
} else {
|
||||
opt_R(maxRecursionDepth);
|
||||
opt_R(*maxRecursionDepth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'W':
|
||||
if (strlen(s) > 0) {
|
||||
|
||||
Reference in New Issue
Block a user