Avoid sscanf for parsing config lines

This commit is contained in:
Chris Robinson
2019-12-14 17:26:58 -08:00
parent ac7a5dcbfa
commit ad9584acc3
+38 -37
View File
@@ -224,35 +224,28 @@ void LoadConfigFromFile(std::istream &f)
continue;
}
auto cmtpos = buffer.find('#');
if(cmtpos != std::string::npos)
buffer.resize(cmtpos);
while(!buffer.empty() && std::isspace(buffer.back()))
buffer.pop_back();
if(buffer.empty()) continue;
auto cmtpos = std::min(buffer.find('#'), buffer.size());
while(cmtpos > 0 && std::isspace(buffer[cmtpos-1]))
--cmtpos;
if(!cmtpos) continue;
buffer.erase(cmtpos);
const char *line{&buffer[0]};
char key[256]{};
char value[256]{};
if(std::sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
std::sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
std::sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
auto sep = buffer.find('=');
if(sep == std::string::npos)
{
/* sscanf doesn't handle '' or "" as empty values, so clip it
* manually. */
if(std::strcmp(value, "\"\"") == 0 || std::strcmp(value, "''") == 0)
value[0] = 0;
}
else if(std::sscanf(line, "%255[^=] %255[=]", key, value) == 2)
{
/* Special case for 'key =' */
value[0] = 0;
}
else
{
ERR(" config parse error: malformed option line: \"%s\"\n\n", line);
ERR(" config parse error: malformed option line: \"%s\"\n", buffer.c_str());
continue;
}
auto keyend = sep++;
while(keyend > 0 && std::isspace(buffer[keyend-1]))
--keyend;
if(!keyend)
{
ERR(" config parse error: malformed option line: \"%s\"\n", buffer.c_str());
continue;
}
while(sep < buffer.size() && std::isspace(buffer[sep]))
sep++;
std::string fullKey;
if(!curSection.empty())
@@ -260,26 +253,34 @@ void LoadConfigFromFile(std::istream &f)
fullKey += curSection;
fullKey += '/';
}
fullKey += key;
while(!fullKey.empty() && std::isspace(fullKey.back()))
fullKey.pop_back();
fullKey += buffer.substr(0u, keyend);
TRACE(" found '%s' = '%s'\n", fullKey.c_str(), value);
std::string value{(sep < buffer.size()) ? buffer.substr(sep) : std::string{}};
if(value.size() > 1)
{
if((value.front() == '"' && value.back() == '"')
|| (value.front() == '\'' && value.back() == '\''))
{
value.pop_back();
value.erase(value.begin());
}
}
TRACE(" found '%s' = '%s'\n", fullKey.c_str(), value.c_str());
/* Check if we already have this option set */
auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(),
[&fullKey](const ConfigEntry &entry) -> bool
{ return entry.key == fullKey; }
);
auto find_key = [&fullKey](const ConfigEntry &entry) -> bool
{ return entry.key == fullKey; };
auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), find_key);
if(ent != ConfOpts.end())
{
if(value[0])
ent->value = expdup(value);
if(!value.empty())
ent->value = expdup(value.c_str());
else
ConfOpts.erase(ent);
}
else if(value[0])
ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)});
else if(!value.empty())
ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value.c_str())});
}
ConfOpts.shrink_to_fit();
}