1
0
Fork 0

Codechange: make parsing of IniItems overridable functions of SettingDesc

pull/9302/head
rubidium42 2021-05-22 20:57:41 +02:00 committed by rubidium42
parent 1f8ff0e4f9
commit f6723b53da
2 changed files with 104 additions and 100 deletions

View File

@ -374,75 +374,70 @@ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32
} }
/** /**
* Convert a string representation (external) of a setting to the internal rep. * Convert a string representation (external) of an integer-like setting to an integer.
* @param desc SettingDesc struct that holds all information about the variable * @param str Input string that will be parsed based on the type of desc.
* @param orig_str input string that will be parsed based on the type of desc * @return The value from the parse string, or the default value of the setting.
* @return return the parsed value of the setting
*/ */
static const void *StringToVal(const SettingDesc *desc, const char *orig_str) size_t IntSettingDesc::ParseValue(const char *str) const
{ {
const char *str = orig_str == nullptr ? "" : orig_str; switch (this->cmd) {
switch (desc->cmd) {
case SDT_NUMX: { case SDT_NUMX: {
char *end; char *end;
size_t val = strtoul(str, &end, 0); size_t val = strtoul(str, &end, 0);
if (end == str) { if (end == str) {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str); msg.SetDParamStr(0, str);
msg.SetDParamStr(1, desc->name); msg.SetDParamStr(1, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
return desc->def; break;
} }
if (*end != '\0') { if (*end != '\0') {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS);
msg.SetDParamStr(0, desc->name); msg.SetDParamStr(0, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
} }
return (void*)val; return val;
} }
case SDT_ONEOFMANY: { case SDT_ONEOFMANY: {
size_t r = LookupOneOfMany(desc->many, str); size_t r = LookupOneOfMany(this->many, str);
/* if the first attempt of conversion from string to the appropriate value fails, /* if the first attempt of conversion from string to the appropriate value fails,
* look if we have defined a converter from old value to new value. */ * look if we have defined a converter from old value to new value. */
if (r == (size_t)-1 && desc->proc_cnvt != nullptr) r = desc->proc_cnvt(str); if (r == (size_t)-1 && this->proc_cnvt != nullptr) r = this->proc_cnvt(str);
if (r != (size_t)-1) return (void*)r; // and here goes converted value if (r != (size_t)-1) return r; // and here goes converted value
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str); msg.SetDParamStr(0, str);
msg.SetDParamStr(1, desc->name); msg.SetDParamStr(1, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
return desc->def; break;
} }
case SDT_MANYOFMANY: { case SDT_MANYOFMANY: {
size_t r = LookupManyOfMany(desc->many, str); size_t r = LookupManyOfMany(this->many, str);
if (r != (size_t)-1) return (void*)r; if (r != (size_t)-1) return r;
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str); msg.SetDParamStr(0, str);
msg.SetDParamStr(1, desc->name); msg.SetDParamStr(1, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
return desc->def; break;
} }
case SDT_BOOLX: { case SDT_BOOLX: {
if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return (void*)true; if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true;
if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false; if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false;
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str); msg.SetDParamStr(0, str);
msg.SetDParamStr(1, desc->name); msg.SetDParamStr(1, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
return desc->def; break;
} }
case SDT_STDSTRING: return orig_str; default: NOT_REACHED();
case SDT_INTLIST: return str;
default: break;
} }
return nullptr; return (size_t)this->def;
} }
/** /**
@ -590,36 +585,33 @@ static void IniLoadSettings(IniFile *ini, const SettingTable &settings_table, co
if (sc != std::string::npos) item = ini->GetGroup(s.substr(0, sc))->GetItem(s.substr(sc + 1), false); if (sc != std::string::npos) item = ini->GetGroup(s.substr(0, sc))->GetItem(s.substr(sc + 1), false);
} }
const void *p = (item == nullptr) ? sdb->def : StringToVal(sdb, item->value.has_value() ? item->value->c_str() : nullptr); sdb->ParseValue(item, object);
void *ptr = GetVariableAddress(object, sld); }
}
switch (sdb->cmd) { void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
case SDT_BOOLX: // All four are various types of (integer) numbers {
case SDT_NUMX: size_t val = (item == nullptr) ? (size_t)this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
case SDT_ONEOFMANY: this->Write_ValidateSetting(object, (int32)val);
case SDT_MANYOFMANY: }
sd->AsIntSetting()->Write_ValidateSetting(object, (int32)(size_t)p);
break;
case SDT_STDSTRING: void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
sd->AsStringSetting()->Write_ValidateSetting(object, (const char *)p); {
break; const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr;
this->Write_ValidateSetting(object, str);
}
case SDT_INTLIST: { void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { {
const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr;
void *ptr = GetVariableAddress(object, &this->save);
if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
msg.SetDParamStr(0, sdb->name); msg.SetDParamStr(0, this->name);
_settings_error_list.push_back(msg); _settings_error_list.push_back(msg);
/* Use default */ /* Use default */
LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); LoadIntList((const char*)this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
} else if (sd->proc_cnvt != nullptr) {
sd->proc_cnvt((const char*)p);
}
break;
}
default: NOT_REACHED();
}
} }
} }
@ -640,7 +632,6 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co
IniGroup *group_def = nullptr, *group; IniGroup *group_def = nullptr, *group;
IniItem *item; IniItem *item;
char buf[512]; char buf[512];
void *ptr;
for (auto &sd : settings_table) { for (auto &sd : settings_table) {
const SettingDesc *sdb = sd.get(); const SettingDesc *sdb = sd.get();
@ -664,52 +655,14 @@ static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, co
item = group->GetItem(s, true); item = group->GetItem(s, true);
if (item->value.has_value()) { if (!item->value.has_value() || !sdb->IsSameValue(item, object)) {
/* check if the value is the same as the old value */
const void *p = StringToVal(sdb, item->value->c_str());
ptr = GetVariableAddress(object, sld);
/* The main type of a variable/setting is in bytes 8-15
* The subtype (what kind of numbers do we have there) is in 0-7 */
switch (sdb->cmd) {
case SDT_BOOLX:
case SDT_NUMX:
case SDT_ONEOFMANY:
case SDT_MANYOFMANY:
switch (GetVarMemType(sld->conv)) {
case SLE_VAR_BL:
if (*(bool*)ptr == (p != nullptr)) continue;
break;
case SLE_VAR_I8:
case SLE_VAR_U8:
if (*(byte*)ptr == (byte)(size_t)p) continue;
break;
case SLE_VAR_I16:
case SLE_VAR_U16:
if (*(uint16*)ptr == (uint16)(size_t)p) continue;
break;
case SLE_VAR_I32:
case SLE_VAR_U32:
if (*(uint32*)ptr == (uint32)(size_t)p) continue;
break;
default: NOT_REACHED();
}
break;
default: break; // Assume the other types are always changed
}
}
/* Value has changed, get the new value and put it into a buffer */ /* Value has changed, get the new value and put it into a buffer */
sdb->FormatValue(buf, lastof(buf), object); sdb->FormatValue(buf, lastof(buf), object);
/* The value is different, that means we have to write it to the ini */ /* The value is different, that means we have to write it to the ini */
item->value.emplace(buf); item->value.emplace(buf);
} }
}
} }
void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object) const void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object) const
@ -724,10 +677,17 @@ void IntSettingDesc::FormatValue(char *buf, const char *last, const void *object
} }
} }
bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
{
int64 item_value = this->ParseValue(item->value->c_str());
int64 object_value = ReadValue(GetVariableAddress(object, &this->save), this->save.conv);
return item_value == object_value;
}
void StringSettingDesc::FormatValue(char *buf, const char *last, const void *object) const void StringSettingDesc::FormatValue(char *buf, const char *last, const void *object) const
{ {
const std::string &str = this->Read(object); const std::string &str = this->Read(object);
switch (GetVarMemType(this->save. conv)) { switch (GetVarMemType(this->save.conv)) {
case SLE_VAR_STR: strecpy(buf, str.c_str(), last); break; case SLE_VAR_STR: strecpy(buf, str.c_str(), last); break;
case SLE_VAR_STRQ: case SLE_VAR_STRQ:
@ -742,6 +702,22 @@ void StringSettingDesc::FormatValue(char *buf, const char *last, const void *obj
} }
} }
bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
{
/* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
* so those values are always different in the parsed ini item than they should be. */
if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
const std::string &str = this->Read(object);
return item->value->compare(str) == 0;
}
bool ListSettingDesc::IsSameValue(const IniItem *item, void *object) const
{
/* Checking for equality is way more expensive than just writing the value. */
return false;
}
/** /**
* Loads all items from a 'grpname' section into a list * Loads all items from a 'grpname' section into a list
* The list parameter can be a nullptr pointer, in this case nothing will be * The list parameter can be a nullptr pointer, in this case nothing will be

View File

@ -79,6 +79,7 @@ enum SettingType {
ST_ALL, ///< Used in setting filter to match all types. ST_ALL, ///< Used in setting filter to match all types.
}; };
struct IniItem;
typedef bool OnChange(int32 var); ///< callback prototype on data modification typedef bool OnChange(int32 var); ///< callback prototype on data modification
typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error
@ -122,6 +123,24 @@ struct SettingDesc {
* @param object The object the setting is in. * @param object The object the setting is in.
*/ */
virtual void FormatValue(char *buf, const char *last, const void *object) const = 0; virtual void FormatValue(char *buf, const char *last, const void *object) const = 0;
/**
* Parse/read the value from the Ini item into the setting associated with this object.
* @param item The Ini item with the content of this setting.
* @param object The object the setting is in.
*/
virtual void ParseValue(const IniItem *item, void *object) const = 0;
/**
* Check whether the value in the Ini item is the same as is saved in this setting in the object.
* It might be that determining whether the value is the same is way more expensive than just
* writing the value. In those cases this function may unconditionally return false even though
* the value might be the same as in the Ini item.
* @param item The Ini item with the content of this setting.
* @param object The object the setting is in.
* @return True if the value is definitely the same (might be false when the same).
*/
virtual bool IsSameValue(const IniItem *item, void *object) const = 0;
}; };
/** Integer type, including boolean, settings. Only these are shown in the settings UI. */ /** Integer type, including boolean, settings. Only these are shown in the settings UI. */
@ -136,7 +155,10 @@ struct IntSettingDesc : SettingDesc {
void ChangeValue(const void *object, int32 newvalue) const; void ChangeValue(const void *object, int32 newvalue) const;
void Write_ValidateSetting(const void *object, int32 value) const; void Write_ValidateSetting(const void *object, int32 value) const;
size_t ParseValue(const char *str) const;
void FormatValue(char *buf, const char *last, const void *object) const override; void FormatValue(char *buf, const char *last, const void *object) const override;
void ParseValue(const IniItem *item, void *object) const override;
bool IsSameValue(const IniItem *item, void *object) const override;
}; };
/** String settings. */ /** String settings. */
@ -150,6 +172,8 @@ struct StringSettingDesc : SettingDesc {
void Write_ValidateSetting(const void *object, const char *str) const; void Write_ValidateSetting(const void *object, const char *str) const;
void FormatValue(char *buf, const char *last, const void *object) const override; void FormatValue(char *buf, const char *last, const void *object) const override;
void ParseValue(const IniItem *item, void *object) const override;
bool IsSameValue(const IniItem *item, void *object) const override;
const std::string &Read(const void *object) const; const std::string &Read(const void *object) const;
}; };
@ -160,6 +184,8 @@ struct ListSettingDesc : SettingDesc {
virtual ~ListSettingDesc() {} virtual ~ListSettingDesc() {}
void FormatValue(char *buf, const char *last, const void *object) const override; void FormatValue(char *buf, const char *last, const void *object) const override;
void ParseValue(const IniItem *item, void *object) const override;
bool IsSameValue(const IniItem *item, void *object) const override;
}; };
/** Placeholder for settings that have been removed, but might still linger in the savegame. */ /** Placeholder for settings that have been removed, but might still linger in the savegame. */
@ -169,6 +195,8 @@ struct NullSettingDesc : SettingDesc {
virtual ~NullSettingDesc() {} virtual ~NullSettingDesc() {}
void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); } void FormatValue(char *buf, const char *last, const void *object) const override { NOT_REACHED(); }
void ParseValue(const IniItem *item, void *object) const override { NOT_REACHED(); }
bool IsSameValue(const IniItem *item, void *object) const override { NOT_REACHED(); }
}; };
typedef std::initializer_list<std::unique_ptr<const SettingDesc>> SettingTable; typedef std::initializer_list<std::unique_ptr<const SettingDesc>> SettingTable;