M
Bitte die Diskussion nicht zu sehr abschweifen lassen
Wie gewünscht Poste ich mal den restlichen Code und eine genaue Erklärung meiner Intension.
Der Code ist dafür da, um eine Konfiguration aus zu lesen. Sie wird einmalig ausgelesen und dann nur noch drauf gelesen. Ziel ist es, dass das spätere abfragen der Konfiguration so schnell wie möglich geht. Das einmalige einlesen kann durch aus langsamer sein (darum auch regex). Es wird maximal die Konfiguration komplett neu eingelesen. Die Konfiguration kann wie folgt aussehen:
EDIT: Warum ich std::unordered_map<Block, BlockListNew> ConfigBlockNew; anstelle einer multimap genommen habe, kann ich persönlich gerade nicht sagen. Der Code ist schon älter und ich schreibe den gerade neu. Es gab bestimmt Gründe warum dem so war, die ich leider jetzt nicht mehr kenne ^^
key value
key2 value2
# Kommentar
// Auch ein Kommentar
/*
Mehrzeiliges Kommentar
Bla bla
*/
blockKeyABC BlockValue {
key value
key2 value, value2
}
blockKeyABC BlockValue2 {
}
blockKeyDEF Value {
}
key3 value3
Der Grund warum ich "Blöcke" erst in am ende des Block } hinzufüge, liegt darin das im block auch "ignore 1" stehen könnte und der block dann zwar ausgelesen wurde, jedoch nicht hinzugefügt werden soll. std::vector nutze ich, da die Reihenfolge genauso so wie in der Konfiguration angegeben wurde auch erhalten bleiben soll. Innerhalb eines Block soll/darf jeder key nur 1 mal vorkommen. Die BlockKey sind vorgeben, also es gibt eine Liste welche möglich sind, ungültige Blöcke werden einfach ignoriert.
int CConfig::parseConfigFile(const std::string &path)
{
std::ifstream fh(path);
if (!fh.is_open())
{
// Kann Datei nicht öffnen
return -1;
}
KeyValueMap config;
ConfigBlock blockConfigs;
ConfigBlockNew blocks;
bool inCommand = false;
Block blockType = Block::nothing;
std::unique_ptr<BlockElementNew> block_ptr;
std::string line;
std::smatch match;
int i = 0;
//
while (std::getline(fh, line))
{
i++;
// Prüfe auf UTF-8 BOM
if (i == 1 && line.size() >= 3)
{
if (line[0] == (char)0xEF && line[1] == (char)0xBB && line[2] == (char)0xBF)
{
// std::cout << "UTF8 detected!" << std::endl;
line.erase(0, 3);
}
}
if (block_ptr) {
std::cout << "block_ptr is true" << std::endl;
} else {
std::cout << "block_ptr is false" << std::endl;
}
// Lösche Zeilenumbruch am ende
// Lösche Tab und leerzeichen am Anfang und Ende
Misc::trim(line);
// Wenn Zeile leer ist
if (line.size() == 0)
{
continue;
}
// Überspringe # und //
if (line[0] == '#' || (line.size() >= 2 && line.substr(0,2) == "//"))
{
continue;
}
if (!inCommand && line.size() >= 2 && line.substr(0,2) == "/*")
{
// Block Kommentar Anfang
inCommand = true;
continue;
}
if (inCommand && std::regex_search(line, std::regex("\\*/$")))
{
// Block Kommentar Ende
inCommand = false;
continue;
}
if (inCommand)
{
// Block Kommentar Zeile
continue;
}
// Beginne Block
if (!block_ptr && std::regex_search(line, match, std::regex("(\\w+?)\\s+(.*?)\\s*\\{$")))
{
// Suche zu dem Schlüssel (string) den enum-class Wert
// Dabei ignoriere Groß- und Kleinschreibung des Schlüssel
auto const enumKey = BlockNameMap.find(match[1]);
if (enumKey == BlockNameMap.end())
{
std::cout << "Unbekannter Blockname [" << match[1] << "]" << std::endl;
// Schlüssel nicht gefunden, Warnung ausgeben
continue;
}
blockType = enumKey->second;
std::cout << "Starte Block [" << match[1] << "]" << std::endl;
// ConfigBlock::iterator it = blockConfigs.find(enumKey->second); // enumKey->second = CConfig::Block
/*
// Suche nach Blockgruppe
if (it == blockConfigs.end())
{
// Blockgruppe gibt es in der map noch nicht, erstelle diesen
std::cout << "BlockConfig nicht gefunden, neue erstellen" << std::endl;
std::pair<ConfigBlock::iterator, bool> result = blockConfigs.insert(ConfigBlock::value_type(enumKey->second, {}));
// std::pair<ConfigBlockNew::iterator, bool> result2 = blockConfigsNew.insert(ConfigBlockNew::value_type(enumKey->second, {}));
if (result.second == false)
{
// Hinzufügen fehlgeschlagen
// std::cout << "Hinzufügen der BlockConfig fehlgeschlagen" << std::endl;
return i;
}
it = result.first;
//it2 = result2.first;
}
*/
// match[2] = BlockValue1, BlockValue2
// Zerlege match[2] in vector
auto identity = Misc::split(match[2].str(), ',');
// Die einzelnen Einträge trimmen
Misc::trim(identity);
block_ptr = std::make_unique<BlockElementNew>(identity);
}
else if (block_ptr && line == "}")
{
// Block Ende
std::cout << "Beende Block " << std::endl;
// Suche nach dem Block-Typ (enumClass)
ConfigBlockNew::iterator it = blocks.find(blockType);
// Wenn Typ nicht gefunden wurde, füge ihn hinzu
if (it == blocks.end())
{
// Blockgruppe gibt es in der map noch nicht, erstelle diesen
std::cout << "Block-Config nicht gefunden, erstellen." << std::endl;
// BlockListNew tmp = BlockListNew (block_ptr);
//auto result = blocks.insert(std::make_pair(blockType, BlockListNew{std::move(block_ptr)}));
// auto result = blocks.emplace();
// ConfigBlockNew blocks
//auto result = blocks.emplace(ConfigBlockNew::value_type(blockType, { } ));
// BlockListNew liste = { std::move(block_ptr) };
// auto result = blocks.emplace(std::make_pair(blockType, BlockListNew::value_type({ std::make_unique<BlockElementNew>(std::move(block_ptr)) }) ));
//auto result = blocks.emplace(blockType, BlockListNew::value_type(std::make_unique<BlockElementNew>()));
// auto result = blocks.insert(blockType, BlockListNew::value_type(std::move(block_ptr)) );
/*
if (result.second == false)
{
// Hinzufügen fehlgeschlagen
std::cout << "Hinzufügen der Block-Config fehlgeschlagen" << std::endl;
return false;
}
else {
std::cout << "Hinzüfügen der neuen Blockliste erfolgreich" << std::endl;
}
*/
// std::move(block_ptr)
}
else {
// Block in die Hash-Map verschieben
it->second.push_back(std::move(block_ptr));
}
// Pointer zurücksetzten
block_ptr.reset();
}
else
{
// TODO:
// Umsetzen von
// : key = value
if (!std::regex_match(line, match, std::regex("^(\\w+?)\\s+(.*)")))
{
// Zeilen mit einem Key aber keinem Wert (ignorieren)
// std::cout << "Schlüssel ohne Wert: [" << line << "]" << std::endl;
continue;
}
// Gerade in Block-Element
if (block_ptr)
{
std::cout << "In Block Element" << std::endl;
// std::transform(match[1].str().begin(), match[1].str().end(), match[1].str().begin(), ::tolower);
// Suche zu dem Schlüssel (string) den enum-class Wert
// Dabei ignoriere Groß- und Kleinschreibung des Schlüssel
auto const enumKey = KeyNameMap.find(match[1]);
if (enumKey == KeyNameMap.end())
{
// Schlüssel nicht gefunden, Warnung ausgeben
std::cout << "Unbekannter Blockschlüssel [" << match[1] << "]" << std::endl;
continue;
}
switch (enumKey->second)
{
// irrelevant
default: {
//std::unique_ptr<ValueType> p = std::make_unique<ValueTypeString>(match[2]);
//block->condition3.insert(KeyValueMap3::value_type(enumKey->second, std::move(p)));
//block->condition.insert(KeyValueMap::value_type(enumKey->second, match[2]));
}
}
}
else
{
// std::cout << "Config Element" << std::endl;
auto const enumKey = KeyNameMap.find(match[1]);
if (enumKey == KeyNameMap.end())
{
// Schlüssel nicht gefunden, Warnung ausgeben
// std::cout << "Unbekannter Schlüssel [" << match[1] << "]" << std::endl;
continue;
}
config.insert(KeyValueMap::value_type(enumKey->second, match[2]));
//block[enumKey->second] = match[2].str();
// config[match[1].str()] = { match[1], match[2] };
}
}
}
if (block_ptr)
{
// Ein Config-Block wurde nicht geschlossen!
std::cout << "Ein Config-Block wurde nicht geschlossen!" << std::endl;
return -2;
}
if (fh.bad())
{
// Wenn irgendwas während des Dateilesen schief geht
return -1;
}
return 0;
}