Changeset - r25536:93e072c5a8dc
[Not reviewed]
master
0 2 0
rubidium42 - 3 years ago 2021-05-22 18:57:41
rubidium@openttd.org
Codechange: make parsing of IniItems overridable functions of SettingDesc
2 files changed with 105 insertions and 101 deletions:
0 comments (0 inline, 0 general)
src/settings.cpp
Show inline comments
 
@@ -374,75 +374,70 @@ static void MakeManyOfMany(char *buf, co
 
}
 

	
 
/**
 
 * Convert a string representation (external) of a setting to the internal rep.
 
 * @param desc SettingDesc struct that holds all information about the variable
 
 * @param orig_str input string that will be parsed based on the type of desc
 
 * @return return the parsed value of the setting
 
 * Convert a string representation (external) of an integer-like setting to an integer.
 
 * @param 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.
 
 */
 
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 (desc->cmd) {
 
	switch (this->cmd) {
 
		case SDT_NUMX: {
 
			char *end;
 
			size_t val = strtoul(str, &end, 0);
 
			if (end == str) {
 
				ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
 
				msg.SetDParamStr(0, str);
 
				msg.SetDParamStr(1, desc->name);
 
				msg.SetDParamStr(1, this->name);
 
				_settings_error_list.push_back(msg);
 
				return desc->def;
 
				break;
 
			}
 
			if (*end != '\0') {
 
				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);
 
			}
 
			return (void*)val;
 
			return val;
 
		}
 

	
 
		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,
 
			 * 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) return (void*)r; // and here goes converted value
 
			if (r == (size_t)-1 && this->proc_cnvt != nullptr) r = this->proc_cnvt(str);
 
			if (r != (size_t)-1) return r; // and here goes converted value
 

	
 
			ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
 
			msg.SetDParamStr(0, str);
 
			msg.SetDParamStr(1, desc->name);
 
			msg.SetDParamStr(1, this->name);
 
			_settings_error_list.push_back(msg);
 
			return desc->def;
 
			break;
 
		}
 

	
 
		case SDT_MANYOFMANY: {
 
			size_t r = LookupManyOfMany(desc->many, str);
 
			if (r != (size_t)-1) return (void*)r;
 
			size_t r = LookupManyOfMany(this->many, str);
 
			if (r != (size_t)-1) return r;
 
			ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
 
			msg.SetDParamStr(0, str);
 
			msg.SetDParamStr(1, desc->name);
 
			msg.SetDParamStr(1, this->name);
 
			_settings_error_list.push_back(msg);
 
			return desc->def;
 
			break;
 
		}
 

	
 
		case SDT_BOOLX: {
 
			if (strcmp(str, "true")  == 0 || strcmp(str, "on")  == 0 || strcmp(str, "1") == 0) return (void*)true;
 
			if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false;
 
			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 false;
 

	
 
			ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
 
			msg.SetDParamStr(0, str);
 
			msg.SetDParamStr(1, desc->name);
 
			msg.SetDParamStr(1, this->name);
 
			_settings_error_list.push_back(msg);
 
			return desc->def;
 
			break;
 
		}
 

	
 
		case SDT_STDSTRING: return orig_str;
 
		case SDT_INTLIST: return str;
 
		default: break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	return nullptr;
 
	return (size_t)this->def;
 
}
 

	
 
/**
 
@@ -590,36 +585,33 @@ static void IniLoadSettings(IniFile *ini
 
			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);
 
		void *ptr = GetVariableAddress(object, sld);
 
		sdb->ParseValue(item, object);
 
	}
 
}
 

	
 
		switch (sdb->cmd) {
 
			case SDT_BOOLX: // All four are various types of (integer) numbers
 
			case SDT_NUMX:
 
			case SDT_ONEOFMANY:
 
			case SDT_MANYOFMANY:
 
				sd->AsIntSetting()->Write_ValidateSetting(object, (int32)(size_t)p);
 
				break;
 

	
 
			case SDT_STDSTRING:
 
				sd->AsStringSetting()->Write_ValidateSetting(object, (const char *)p);
 
				break;
 
void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
 
{
 
	size_t val = (item == nullptr) ? (size_t)this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
 
	this->Write_ValidateSetting(object, (int32)val);
 
}
 

	
 
			case SDT_INTLIST: {
 
				if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) {
 
					ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
 
					msg.SetDParamStr(0, sdb->name);
 
					_settings_error_list.push_back(msg);
 
void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
 
{
 
	const char *str = (item == nullptr) ? (const char *)this->def : item->value.has_value() ? item->value->c_str() : nullptr;
 
	this->Write_ValidateSetting(object, str);
 
}
 

	
 
					/* Use default */
 
					LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv));
 
				} else if (sd->proc_cnvt != nullptr) {
 
					sd->proc_cnvt((const char*)p);
 
				}
 
				break;
 
			}
 
			default: NOT_REACHED();
 
		}
 
void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
 
{
 
	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);
 
		msg.SetDParamStr(0, this->name);
 
		_settings_error_list.push_back(msg);
 

	
 
		/* Use default */
 
		LoadIntList((const char*)this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
 
	}
 
}
 

	
 
@@ -640,7 +632,6 @@ static void IniSaveSettings(IniFile *ini
 
	IniGroup *group_def = nullptr, *group;
 
	IniItem *item;
 
	char buf[512];
 
	void *ptr;
 

	
 
	for (auto &sd : settings_table) {
 
		const SettingDesc *sdb = sd.get();
 
@@ -664,51 +655,13 @@ static void IniSaveSettings(IniFile *ini
 

	
 
		item = group->GetItem(s, true);
 

	
 
		if (item->value.has_value()) {
 
			/* 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;
 
		if (!item->value.has_value() || !sdb->IsSameValue(item, object)) {
 
			/* Value has changed, get the new value and put it into a buffer */
 
			sdb->FormatValue(buf, lastof(buf), object);
 

	
 
						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
 
			}
 
			/* The value is different, that means we have to write it to the ini */
 
			item->value.emplace(buf);
 
		}
 

	
 
		/* Value has changed, get the new value and put it into a buffer */
 
		sdb->FormatValue(buf, lastof(buf), object);
 

	
 
		/* The value is different, that means we have to write it to the ini */
 
		item->value.emplace(buf);
 
	}
 
}
 

	
 
@@ -724,10 +677,17 @@ void IntSettingDesc::FormatValue(char *b
 
	}
 
}
 

	
 
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
 
{
 
	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_STRQ:
 
@@ -742,6 +702,22 @@ void StringSettingDesc::FormatValue(char
 
	}
 
}
 

	
 
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
 
 * The list parameter can be a nullptr pointer, in this case nothing will be
src/settings_internal.h
Show inline comments
 
@@ -79,6 +79,7 @@ enum SettingType {
 
	ST_ALL,       ///< Used in setting filter to match all types.
 
};
 

	
 
struct IniItem;
 
typedef bool OnChange(int32 var);           ///< callback prototype on data modification
 
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.
 
	 */
 
	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. */
 
@@ -136,7 +155,10 @@ struct IntSettingDesc : SettingDesc {
 
	void ChangeValue(const void *object, int32 newvalue) 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 ParseValue(const IniItem *item, void *object) const override;
 
	bool IsSameValue(const IniItem *item, void *object) const override;
 
};
 

	
 
/** String settings. */
 
@@ -150,6 +172,8 @@ struct StringSettingDesc : SettingDesc {
 
	void Write_ValidateSetting(const void *object, const char *str) const;
 

	
 
	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;
 
};
 

	
 
@@ -160,6 +184,8 @@ struct ListSettingDesc : SettingDesc {
 
	virtual ~ListSettingDesc() {}
 

	
 
	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. */
 
@@ -169,6 +195,8 @@ struct NullSettingDesc : SettingDesc {
 
	virtual ~NullSettingDesc() {}
 

	
 
	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;
0 comments (0 inline, 0 general)