Codechange: use C++ containers for parsing the settings int lists

This commit is contained in:
Rubidium 2024-04-06 17:44:11 +02:00 committed by rubidium42
parent 434c49a1f8
commit 1691b41b54
2 changed files with 30 additions and 54 deletions

View File

@ -239,24 +239,20 @@ static size_t LookupManyOfMany(const std::vector<std::string> &many, const char
} }
/** /**
* Parse an integerlist string and set each found value * Parse a string into a vector of uint32s.
* @param p the string to be parsed. Each element in the list is separated by a * @param p the string to be parsed. Each element in the list is separated by a comma or a space character
* comma or a space character * @return std::optional with a vector of parsed integers. The optional is empty upon an error.
* @param items pointer to the integerlist-array that will be filled with values
* @param maxitems the maximum number of elements the integerlist-array has
* @return returns the number of items found, or -1 on an error
*/ */
template<typename T> static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
static int ParseIntList(const char *p, T *items, size_t maxitems)
{ {
size_t n = 0; // number of items read so far
bool comma = false; // do we accept comma? bool comma = false; // do we accept comma?
std::vector<uint32_t> result;
while (*p != '\0') { while (*p != '\0') {
switch (*p) { switch (*p) {
case ',': case ',':
/* Do not accept multiple commas between numbers */ /* Do not accept multiple commas between numbers */
if (!comma) return -1; if (!comma) return std::nullopt;
comma = false; comma = false;
[[fallthrough]]; [[fallthrough]];
@ -265,12 +261,11 @@ static int ParseIntList(const char *p, T *items, size_t maxitems)
break; break;
default: { default: {
if (n == maxitems) return -1; // we don't accept that many numbers
char *end; char *end;
unsigned long v = std::strtoul(p, &end, 0); unsigned long v = std::strtoul(p, &end, 0);
if (p == end) return -1; // invalid character (not a number) if (p == end) return std::nullopt; // invalid character (not a number)
if (sizeof(T) < sizeof(v)) v = Clamp<unsigned long>(v, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
items[n++] = v; result.push_back(ClampTo<uint32_t>(v));
p = end; // first non-number p = end; // first non-number
comma = true; // we accept comma now comma = true; // we accept comma now
break; break;
@ -280,52 +275,35 @@ static int ParseIntList(const char *p, T *items, size_t maxitems)
/* If we have read comma but no number after it, fail. /* If we have read comma but no number after it, fail.
* We have read comma when (n != 0) and comma is not allowed */ * We have read comma when (n != 0) and comma is not allowed */
if (n != 0 && !comma) return -1; if (!result.empty() && !comma) return std::nullopt;
return ClampTo<int>(n); return result;
} }
/** /**
* Load parsed string-values into an integer-array (intlist) * Load parsed string-values into an integer-array (intlist)
* @param str the string that contains the values (and will be parsed) * @param str the string that contains the values (and will be parsed)
* @param array pointer to the integer-arrays that will be filled * @param array pointer to the integer-arrays that will be filled
* @param nelems the number of elements the array holds. Maximum is 64 elements * @param nelems the number of elements the array holds.
* @param type the type of elements the array holds (eg INT8, UINT16, etc.) * @param type the type of elements the array holds (eg INT8, UINT16, etc.)
* @return return true on success and false on error * @return return true on success and false on error
*/ */
static bool LoadIntList(const char *str, void *array, int nelems, VarType type) static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
{ {
unsigned long items[64]; size_t elem_size = SlVarSize(type);
int i, nitems;
if (str == nullptr) { if (str == nullptr) {
memset(items, 0, sizeof(items)); memset(array, 0, nelems * elem_size);
nitems = nelems; return true;
} else {
nitems = ParseIntList(str, items, lengthof(items));
if (nitems != nelems) return false;
} }
switch (type) { auto opt_items = ParseIntList(str);
case SLE_VAR_BL: if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
case SLE_VAR_I8:
case SLE_VAR_U8:
for (i = 0; i != nitems; i++) ((uint8_t*)array)[i] = items[i];
break;
case SLE_VAR_I16: char *p = static_cast<char *>(array);
case SLE_VAR_U16: for (auto item : *opt_items) {
for (i = 0; i != nitems; i++) ((uint16_t*)array)[i] = items[i]; WriteValue(p, type, item);
break; p += elem_size;
case SLE_VAR_I32:
case SLE_VAR_U32:
for (i = 0; i != nitems; i++) ((uint32_t*)array)[i] = items[i];
break;
default: NOT_REACHED();
} }
return true; return true;
} }
@ -1030,15 +1008,13 @@ static void GraphicsSetLoadConfig(IniFile &ini)
if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) BaseGraphics::ini_data.extra_version = std::strtoul(item->value->c_str(), nullptr, 10); if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) BaseGraphics::ini_data.extra_version = std::strtoul(item->value->c_str(), nullptr, 10);
if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) { if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
auto &extra_params = BaseGraphics::ini_data.extra_params; auto params = ParseIntList(item->value->c_str());
extra_params.resize(0x80); // TODO: make ParseIntList work nicely with C++ containers if (params.has_value()) {
int count = ParseIntList(item->value->c_str(), &extra_params.front(), extra_params.size()); BaseGraphics::ini_data.extra_params = params.value();
if (count < 0) { } else {
SetDParamStr(0, BaseGraphics::ini_data.name); SetDParamStr(0, BaseGraphics::ini_data.name);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
count = 0;
} }
extra_params.resize(count);
} }
} }
} }
@ -1099,13 +1075,13 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
/* Parse parameters */ /* Parse parameters */
if (item.value.has_value() && !item.value->empty()) { if (item.value.has_value() && !item.value->empty()) {
int count = ParseIntList(item.value->c_str(), c->param.data(), c->param.size()); auto params = ParseIntList(item.value->c_str());
if (count < 0) { if (params.has_value()) {
c->SetParams(params.value());
} else {
SetDParamStr(0, filename); SetDParamStr(0, filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
count = 0;
} }
c->num_params = count;
} }
/* Check if item is valid */ /* Check if item is valid */

View File

@ -148,7 +148,7 @@ cat = SC_BASIC
; workaround for implicit lengthof() in SDTG_LIST ; workaround for implicit lengthof() in SDTG_LIST
[SDTG_LIST] [SDTG_LIST]
name = ""resolution"" name = ""resolution""
type = SLE_INT type = SLE_UINT
length = 2 length = 2
var = _cur_resolution var = _cur_resolution
def = ""0,0"" def = ""0,0""