Repository :
https://github.com/FarGroup/FarManager
On branch : master
Link :
https://github.com/FarGroup/FarManager/commit/7253c000a13f21d4d4f7490293e52a0dacbb5690
>---------------------------------------------------------------
commit 7253c000a13f21d4d4f7490293e52a0dacbb5690
Author: Yegor Mialyk <
16239726+y...@users.noreply.github.com>
Date: Tue Mar 10 23:07:13 2026 -0700
Read XML attributes via GetAttribute during import
>---------------------------------------------------------------
7253c000a13f21d4d4f7490293e52a0dacbb5690
far/changelog | 5 +++
far/configdb.cpp | 132 ++++++++++++++++++++++++++++---------------------------
far/configdb.hpp | 2 +-
far/vbuild.m4 | 2 +-
4 files changed, 75 insertions(+), 66 deletions(-)
diff --git a/far/changelog b/far/changelog
index bd56b590d..3bbec3fb9 100644
--- a/far/changelog
+++ b/far/changelog
@@ -1,3 +1,8 @@
+--------------------------------------------------------------------------------
+Yegor 2026-03-10 23:07:00-07:00 - build 6657
+
+1. Read XML attributes via GetAttribute during import
+
--------------------------------------------------------------------------------
drkns 2026-03-09 22:24:56+00:00 - build 6656
diff --git a/far/configdb.cpp b/far/configdb.cpp
index 3324943f6..cd9d7f8e4 100644
--- a/far/configdb.cpp
+++ b/far/configdb.cpp
@@ -233,33 +233,33 @@ void serialise_blob(tinyxml::XMLElement& e, bytes_view const Value)
SetAttribute(e, "value", base64::encode(Value));
}
-bool deserialise_value(std::string_view const Type, char const* Value, auto const& Setter)
+bool deserialise_value(std::string_view const Type, std::optional<std::string> const& Value, auto const& Setter)
{
if (Type == "qword"sv)
{
if (Value)
- Setter(strtoull(Value, nullptr, 16));
+ Setter(strtoull(Value->c_str(), nullptr, 16));
return true;
}
if (Type == "text"sv)
{
if (Value)
- Setter(encoding::utf8::get_chars(Value));
+ Setter(encoding::utf8::get_chars(*Value));
return true;
}
if (Type == "base64"sv)
{
if (Value)
- Setter(base64::decode(Value));
+ Setter(base64::decode(*Value));
return true;
}
if (Type == "hex"sv)
{
if (Value)
- Setter(HexStringToBlob(encoding::utf8::get_chars(Value)));
+ Setter(HexStringToBlob(encoding::utf8::get_chars(*Value)));
return true;
}
@@ -420,25 +420,25 @@ private:
SCOPED_ACTION(auto)(ScopedTransaction());
for(const auto& e: xml_enum(Representation.Root().FirstChildElement(GetKeyName()), "setting"))
{
- const auto key = e.Attribute("key");
+ const auto key = GetAttribute(e, "key");
if (!key)
continue;
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
- const auto type = e.Attribute("type");
+ const auto type = GetAttribute(e, "type");
if (!type)
continue;
- const auto value = e.Attribute("value");
+ const auto value = GetAttribute(e, "value");
if (!value)
continue;
- const auto Key = encoding::utf8::get_chars(key);
- const auto Name = encoding::utf8::get_chars(name);
- deserialise_value(type, value, [&](auto const& Value){ SetValue(Key, Name, Value); });
+ const auto Key = encoding::utf8::get_chars(*key);
+ const auto Name = encoding::utf8::get_chars(*name);
+ deserialise_value(*type, value, [&](auto const& Value){ SetValue(Key, Name, Value); });
}
}
@@ -526,9 +526,9 @@ protected:
serialise_blob(e, Blob);
}
- virtual bytes DeserializeBlob(const char* Type, const char* Value, const tinyxml::XMLElement& e) const
+ virtual bytes DeserializeBlob(std::string_view const Type, const std::optional<std::string_view> Value, const tinyxml::XMLElement& e) const
{
- return Value? HexStringToBlob(encoding::utf8::get_chars(Value)) : bytes{};
+ return Value? HexStringToBlob(encoding::utf8::get_chars(*Value)) : bytes{};
}
private:
@@ -772,33 +772,35 @@ private:
void Import(const key& root, const tinyxml::XMLElement& key)
{
- const auto KeyName = key.Attribute("name");
+ const auto KeyName = GetAttribute(key, "name");
if (!KeyName)
return;
- const auto Key = CreateKey(root, encoding::utf8::get_chars(KeyName));
+ const auto Key = CreateKey(root, encoding::utf8::get_chars(*KeyName));
- if (const auto KeyDescription = key.Attribute("description"))
- SetKeyDescription(Key, encoding::utf8::get_chars(KeyDescription));
+ if (const auto KeyDescription = GetAttribute(key, "description"))
+ SetKeyDescription(Key, encoding::utf8::get_chars(*KeyDescription));
for (const auto& e: xml_enum(key, "value"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
- const auto type = e.Attribute("type");
+ const auto type = GetAttribute(e, "type");
if (!type)
continue;
- const auto value = e.Attribute("value");
+ const auto value = GetAttribute(e, "value");
- const auto Name = encoding::utf8::get_chars(name);
+ const auto Name = encoding::utf8::get_chars(*name);
- if (!deserialise_value(type, value, [&](auto const& Value){ SetValue(Key, Name, Value); }))
+ if (!deserialise_value(*type, value, [&](auto const& Value){ SetValue(Key, Name, Value); }))
{
+ const auto Value = value? std::optional<std::string_view>{ *value } : std::nullopt;
+
// custom types, value is optional
- SetValue(Key, Name, DeserializeBlob(type, value, e));
+ SetValue(Key, Name, DeserializeBlob(*type, Value, e));
}
}
@@ -873,14 +875,16 @@ void color_to_xml(bytes_view const Blob, tinyxml::XMLElement& e)
}
-FarColor deserialize_color(function_ref<char const* (char const* Name)> const Getter, FarColor const& Default)
+FarColor deserialize_color(function_ref<std::optional<std::string> (char const* Name)> const Getter, FarColor const& Default)
{
const auto process_color = [&](char const* const Name, COLORREF& Color)
{
if (const auto Value = Getter(Name))
{
+ const auto StrValue = Value->c_str();
+
char* EndPtr;
- if (const auto Result = std::strtoul(Value, &EndPtr, 16); EndPtr != Value)
+ if (const auto Result = std::strtoul(StrValue, &EndPtr, 16); EndPtr != StrValue)
Color = Result;
}
};
@@ -893,7 +897,7 @@ FarColor deserialize_color(function_ref<char const* (char const* Name)> const Ge
if (const auto flags = Getter("flags"))
{
- const auto FlagsStr = encoding::utf8::get_chars(flags);
+ const auto FlagsStr = encoding::utf8::get_chars(*flags);
Color.Flags = colors::ColorStringToFlags(FlagsStr) | StringToFlags(FlagsStr, LegacyColorFlagNames);
}
@@ -905,7 +909,7 @@ namespace
FarColor color_from_xml(tinyxml::XMLElement const& e)
{
- return deserialize_color([&](char const* const AttributeName){ return e.Attribute(AttributeName); }, {});
+ return deserialize_color([&](char const* const AttributeName){ return GetAttribute(e, AttributeName); }, {});
}
class HighlightHierarchicalConfigDb final: public HierarchicalConfigDb
@@ -938,7 +942,7 @@ private:
return HierarchicalConfigDb::SerializeBlob(Name, Blob, e);
}
- bytes DeserializeBlob(const char* Type, const char* Value, const tinyxml::XMLElement& e) const override
+ bytes DeserializeBlob(std::string_view const Type, const std::optional<std::string_view> Value, const tinyxml::XMLElement& e) const override
{
if(Type == "color"sv)
return bytes(view_bytes(color_from_xml(e)));
@@ -1010,12 +1014,12 @@ private:
SCOPED_ACTION(auto)(ScopedTransaction());
for (const auto& e: xml_enum(Representation.Root().FirstChildElement("colors"), "object"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
- const auto Name = encoding::utf8::get_chars(name);
+ const auto Name = encoding::utf8::get_chars(*name);
if (const auto Color = color_from_xml(e); Color != FarColor{})
{
@@ -1241,20 +1245,20 @@ private:
primary_key id{};
for (const auto& e: xml_enum(base, "filetype"))
{
- const auto mask = e.Attribute("mask");
- const auto description = e.Attribute("description");
+ const auto mask = GetAttribute(e, "mask");
+ const auto description = GetAttribute(e, "description");
if (!mask)
continue;
- const auto Mask = encoding::utf8::get_chars(mask);
- const auto Description = encoding::utf8::get_chars(NullToEmpty(description));
+ const auto Mask = encoding::utf8::get_chars(*mask);
+ const auto Description = description? encoding::utf8::get_chars(*description) : string{};
id = AddType(id, Mask, Description);
for (const auto& se: xml_enum(e, "command"))
{
- const auto command = se.Attribute("command");
+ const auto command = GetAttribute(se, "command");
if (!command)
continue;
@@ -1266,7 +1270,7 @@ private:
if (se.QueryIntAttribute("enabled", &enabled) != tinyxml::XML_SUCCESS)
continue;
- SetCommand(id, type, encoding::utf8::get_chars(command), enabled != 0);
+ SetCommand(id, type, encoding::utf8::get_chars(*command), enabled != 0);
}
}
@@ -1727,38 +1731,38 @@ private:
SCOPED_ACTION(auto)(ScopedTransaction());
for (const auto& e: xml_enum(Representation.Root().FirstChildElement("pluginhotkeys"), "plugin"))
{
- const auto key = e.Attribute("key");
+ const auto key = GetAttribute(e, "key");
if (!key)
continue;
- const auto Key = encoding::utf8::get_chars(key);
+ const auto Key = encoding::utf8::get_chars(*key);
for (const auto& se: xml_enum(e, "hotkey"))
{
- const auto stype = se.Attribute("menu");
+ const auto stype = GetAttribute(se, "menu");
if (!stype)
continue;
- const auto UuidStr = se.Attribute("guid");
+ const auto UuidStr = GetAttribute(se, "guid");
if (!UuidStr)
continue;
- const auto Uuid = uuid::try_parse(encoding::utf8::get_chars(UuidStr));
+ const auto Uuid = uuid::try_parse(encoding::utf8::get_chars(*UuidStr));
if (!Uuid)
continue;
- const auto hotkey = se.Attribute("hotkey");
+ const auto hotkey = GetAttribute(se, "hotkey");
const auto ProcessHotkey = [&](hotkey_type const Type)
{
- if (hotkey && *hotkey)
- SetHotkey(Key, *Uuid, Type, encoding::utf8::get_chars(hotkey));
+ if (hotkey && !hotkey->empty())
+ SetHotkey(Key, *Uuid, Type, encoding::utf8::get_chars(*hotkey));
else
DelHotkey(Key, *Uuid, Type);
};
- std::string_view const TypeStr(stype);
+ std::string_view const TypeStr(*stype);
if (TypeStr == "drive"sv)
ProcessHotkey(hotkey_type::drive_menu);
@@ -2326,7 +2330,7 @@ private:
if (e.QueryIntAttribute("kind", &kind) != tinyxml::XML_SUCCESS)
continue;
- const auto key = e.Attribute("key");
+ const auto key = GetAttribute(e, "key");
if (!key)
continue;
@@ -2340,26 +2344,26 @@ private:
const auto lock = e.IntAttribute("lock");
const auto time = e.Unsigned64Attribute("time");
- const auto guid = e.Attribute("guid");
- const auto file = e.Attribute("file");
+ const auto guid = GetAttribute(e, "guid");
+ const auto file = GetAttribute(e, "file");
const auto data = GetAttribute(e, "data");
AddInternal(
kind,
- encoding::utf8::get_chars(key),
+ encoding::utf8::get_chars(*key),
type,
lock != 0,
encoding::utf8::get_chars(*name),
os::chrono::nt_clock::from_hectonanoseconds(time),
- encoding::utf8::get_chars(NullToEmpty(guid)),
- encoding::utf8::get_chars(NullToEmpty(file)),
+ guid? encoding::utf8::get_chars(*guid) : L""sv,
+ file? encoding::utf8::get_chars(*file) : L""sv,
data? encoding::utf8::get_chars(*data) : L""sv
);
}
for (const auto& e: xml_enum(historyRoot.FirstChildElement("editorpositions"), "position"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
@@ -2370,14 +2374,14 @@ private:
const auto leftpos = e.IntAttribute("leftpos");
const auto codepage = e.IntAttribute("codepage");
- ExecuteStatement(stmtSetEditorPos, encoding::utf8::get_chars(name), time, line, linepos, screenline, leftpos, codepage);
+ ExecuteStatement(stmtSetEditorPos, encoding::utf8::get_chars(*name), time, line, linepos, screenline, leftpos, codepage);
}
const auto stmtGetEditorPositionId = create_stmt("SELECT id FROM editorposition_history WHERE name=?1;"sv);
for (const auto& e: xml_enum(historyRoot.FirstChildElement("editorbookmarks"), "bookmark"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
@@ -2401,13 +2405,13 @@ private:
if (e.QueryIntAttribute("leftpos", &leftpos) != tinyxml::XML_SUCCESS)
continue;
- if (auto_statement const Stmt(&stmtGetEditorPositionId); Stmt->Bind(encoding::utf8::get_chars(name)).Step())
+ if (auto_statement const Stmt(&stmtGetEditorPositionId); Stmt->Bind(encoding::utf8::get_chars(*name)).Step())
ExecuteStatement(stmtSetEditorBookmark, Stmt->GetColInt64(0), num, line, linepos, screenline, leftpos);
}
for (const auto& e: xml_enum(historyRoot.FirstChildElement("viewerpositions"), "position"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
@@ -2417,14 +2421,14 @@ private:
const auto hex = e.IntAttribute("hex");
const auto codepage = e.IntAttribute("codepage");
- ExecuteStatement(stmtSetViewerPos, encoding::utf8::get_chars(name), time, filepos, leftpos, hex, codepage);
+ ExecuteStatement(stmtSetViewerPos, encoding::utf8::get_chars(*name), time, filepos, leftpos, hex, codepage);
}
const auto stmtGetViewerPositionId = create_stmt("SELECT id FROM viewerposition_history WHERE name=?1;"sv);
for (const auto& e: xml_enum(historyRoot.FirstChildElement("viewerbookmarks"), "bookmark"))
{
- const auto name = e.Attribute("name");
+ const auto name = GetAttribute(e, "name");
if (!name)
continue;
@@ -2440,7 +2444,7 @@ private:
if (e.QueryInt64Attribute("leftpos", &leftpos) != tinyxml::XML_SUCCESS)
continue;
- if (auto_statement const Stmt(&stmtGetViewerPositionId); Stmt->Bind(encoding::utf8::get_chars(name)).Step())
+ if (auto_statement const Stmt(&stmtGetViewerPositionId); Stmt->Bind(encoding::utf8::get_chars(*name)).Step())
ExecuteStatement(stmtSetViewerBookmark, Stmt->GetColInt64(0), num, filepos, leftpos);
}
}
@@ -2608,8 +2612,8 @@ void config_provider::TryImportDatabase(representable& p, const char* NodeName,
{
for (const auto& i: xml_enum(root.FirstChildElement("pluginsconfig"), "plugin"))
{
- const auto Uuid = i.Attribute("guid");
- if (Uuid && !std::strcmp(Uuid, NodeName))
+ const auto Uuid = GetAttribute(i, "guid");
+ if (Uuid && *Uuid == NodeName)
{
m_TemplateSource->SetRoot(&const_cast<tinyxml::XMLElement&>(i));
p.Import(*m_TemplateSource);
@@ -2904,11 +2908,11 @@ void config_provider::Import(string_view const File)
{
for (const auto& plugin: xml_enum(root.FirstChildElement(Config.Name), "plugin"))
{
- const auto UuidStr = plugin.Attribute("guid");
+ const auto UuidStr = GetAttribute(plugin, "guid");
if (!UuidStr)
continue;
- if (const auto Uuid = encoding::utf8::get_chars(UuidStr); is_uuid(Uuid))
+ if (const auto Uuid = encoding::utf8::get_chars(*UuidStr); is_uuid(Uuid))
{
Representation.SetRoot(&const_cast<tinyxml::XMLElement&>(plugin));
CreatePluginsConfig(Uuid, Config.IsLocal)->Import(Representation);
diff --git a/far/configdb.hpp b/far/configdb.hpp
index d92a9d916..582458b98 100644
--- a/far/configdb.hpp
+++ b/far/configdb.hpp
@@ -589,6 +589,6 @@ private:
[[nodiscard]]
config_provider& ConfigProvider();
-FarColor deserialize_color(function_ref<char const*(char const* Name)> Getter, FarColor const& Default);
+FarColor deserialize_color(function_ref<std::optional<std::string> (char const* Name)> Getter, FarColor const& Default);
#endif // CONFIGDB_HPP_552309E5_DEA6_42FD_BD7B_0F59C839FE62
diff --git a/far/vbuild.m4 b/far/vbuild.m4
index b12244baf..938caac80 100644
--- a/far/vbuild.m4
+++ b/far/vbuild.m4
@@ -1 +1 @@
-6656
+6657