Add error handling for loading base configurations and preference settings

This commit is contained in:
Tindy X
2020-01-01 13:25:44 +08:00
parent b1f373ee58
commit 09c14e0222
2 changed files with 89 additions and 30 deletions

View File

@@ -9,6 +9,15 @@
#include "misc.h"
#define INIREADER_EXCEPTION_NONE 0
#define INIREADER_EXCEPTION_EMPTY -1
#define INIREADER_EXCEPTION_DUPLICATE -2
#define INIREADER_EXCEPTION_OUTOFBOUND -3
#define INIREADER_EXCEPTION_NOTEXIST -4
#define INIREADER_EXCEPTION_NOTPARSED -5
#define __SAVE_ERROR_AND_RETURN(x) {last_error = x; return last_error;}
typedef std::map<std::string, std::multimap<std::string, std::string>> ini_data_struct;
typedef std::multimap<std::string, std::string> string_multimap;
typedef std::vector<std::string> string_array;
@@ -34,6 +43,10 @@ private:
std::string isolated_items_section;
//error flags
int last_error = INIREADER_EXCEPTION_NONE;
unsigned int last_error_index = 0;
bool chkIgnore(std::string section)
{
bool excluded = false, included = false;
@@ -86,6 +99,33 @@ public:
~INIReader() = default;
std::string GetErrorString(int error)
{
switch(error)
{
case INIREADER_EXCEPTION_EMPTY:
return "Empty document";
case INIREADER_EXCEPTION_DUPLICATE:
return "Duplicate section";
case INIREADER_EXCEPTION_NOTEXIST:
return "Target does not exist";
case INIREADER_EXCEPTION_OUTOFBOUND:
return "Item exists outside of any section";
case INIREADER_EXCEPTION_NOTPARSED:
return "Parse error";
default:
return "Undefined";
}
}
std::string GetLastError()
{
if(parsed)
return GetErrorString(last_error);
else
return "line " + std::__cxx11::to_string(last_error_index) + ": " + GetErrorString(last_error);
}
/**
* @brief Exclude a section with the given name.
*/
@@ -137,7 +177,7 @@ public:
int Parse(std::string content) //parse content into mapped data
{
if(!content.size()) //empty content
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_EMPTY);
//remove UTF-8 BOM
if(content.compare(0, 3, "\xEF\xBB\xBF") == 0)
@@ -157,8 +197,10 @@ public:
if(store_isolated_line)
curSection = isolated_items_section; //items before any section define will be store in this section
strStrm<<content;
last_error_index = 0; //reset error index
while(getline(strStrm, strLine, delimiter)) //get one line of content
{
last_error_index++;
lineSize = strLine.size();
if(!lineSize || strLine[0] == ';' || strLine[0] == '#') //empty lines and comments are ignored
continue;
@@ -172,7 +214,7 @@ public:
if(inExcludedSection) //this section is excluded
continue;
if(!curSection.size()) //not in any section
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_OUTOFBOUND);
itemName = trim(strLine.substr(0, strLine.find("=")));
itemVal = trim(strLine.substr(strLine.find("=") + 1));
itemGroup.emplace(itemName, itemVal); //insert to current section
@@ -195,7 +237,7 @@ public:
ini_content.erase(curSection); //remove the old section
}
else
return -1; //not allowed, stop
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
}
ini_content.emplace(curSection, itemGroup); //insert previous section to content map
read_sections.emplace_back(curSection); //add to read sections list
@@ -223,13 +265,13 @@ public:
ini_content.erase(curSection); //remove the old section
}
else
return -1; //not allowed, stop
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
}
ini_content.emplace(curSection, itemGroup); //insert this section to content map
read_sections.emplace_back(curSection); //add to read sections list
}
parsed = true;
return 0; //all done
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); //all done
}
/**
@@ -238,7 +280,7 @@ public:
int ParseFile(std::string filePath)
{
if(!fileExist(filePath))
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
return Parse(fileGet(filePath, false));
}
@@ -280,10 +322,10 @@ public:
int EnterSection(std::string section)
{
if(!SectionExist(section))
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
current_section = cached_section = section;
cached_section_content = ini_content.at(section);
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
/**
@@ -356,7 +398,7 @@ public:
unsigned int ItemCount(std::string section)
{
if(!parsed || !SectionExist(section))
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTPARSED);
return ini_content.at(section).size();
}
@@ -376,7 +418,7 @@ public:
int GetItems(std::string section, string_multimap &data)
{
if(!parsed || !SectionExist(section))
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
if(cached_section != section)
{
@@ -385,7 +427,7 @@ public:
}
data = cached_section_content;
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
/**
@@ -402,12 +444,12 @@ public:
int GetAll(std::string section, std::string itemName, string_array &results) //retrieve item(s) with the same itemName prefix
{
if(!parsed)
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTPARSED);
string_multimap mapTemp;
if(GetItems(section, mapTemp) != 0)
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
for(auto &x : mapTemp)
{
@@ -415,7 +457,7 @@ public:
results.emplace_back(x.second);
}
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
/**
@@ -539,7 +581,7 @@ public:
int Set(std::string section, std::string itemName, std::string itemVal)
{
if(!section.size())
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
if(!parsed)
parsed = true;
@@ -556,7 +598,7 @@ public:
ini_content.insert(std::pair<std::string, std::multimap<std::string, std::string>>(section, mapTemp));
}
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
/**
@@ -565,7 +607,7 @@ public:
int Set(std::string itemName, std::string itemVal)
{
if(!current_section.size())
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
return Set(current_section, itemName, itemVal);
}
@@ -640,7 +682,7 @@ public:
int RenameSection(std::string oldName, std::string newName)
{
if(!SectionExist(oldName) || SectionExist(newName))
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE);
/*
auto nodeHandler = ini_content.extract(oldName);
nodeHandler.key() = newName;
@@ -648,7 +690,7 @@ public:
*/
ini_content[newName] = std::move(ini_content[oldName]);
ini_content.erase(oldName);
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
/**
@@ -658,7 +700,7 @@ public:
{
int retVal;
if(!SectionExist(section))
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
retVal = ini_content.at(section).erase(itemName);
if(retVal && cached_section == section)
@@ -690,11 +732,11 @@ public:
{
cached_section_content = mapTemp;
}
return 0;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE);
}
else
{
return -1;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST);
}
}

View File

@@ -134,15 +134,21 @@ void readConf()
{
guarded_mutex guard(on_configuring);
std::cerr<<"Reading preference settings..."<<std::endl;
INIReader ini;
ini.allow_dup_section_titles = true;
//ini.do_utf8_to_gbk = true;
int retVal = ini.ParseFile(pref_path);
if(retVal != INIREADER_EXCEPTION_NONE)
{
std::cerr<<"Unable to load preference settings. Reason: "<<ini.GetLastError()<<"\n";
return;
}
eraseElements(def_exclude_remarks);
eraseElements(def_include_remarks);
eraseElements(clash_extra_group);
eraseElements(rulesets);
string_array emojis_temp, renames_temp;
INIReader ini;
ini.allow_dup_section_titles = true;
//ini.do_utf8_to_gbk = true;
ini.ParseFile(pref_path);
ini.EnterSection("common");
if(ini.ItemExist("api_mode"))
@@ -250,20 +256,31 @@ void readConf()
void generateBase()
{
std::string base_content;
int retVal = 0;
std::cerr<<"Generating base content for Clash/R...\n";
if(fileExist(clash_rule_base))
base_content = fileGet(clash_rule_base, false);
else
base_content = webGet(clash_rule_base, getSystemProxy());
clash_base = YAML::Load(base_content);
rulesetToClash(clash_base, ruleset_content_array);
try
{
clash_base = YAML::Load(base_content);
rulesetToClash(clash_base, ruleset_content_array);
}
catch (YAML::Exception &e)
{
std::cerr<<"Unable to load Clash base content. Reason: "<<e.msg<<"\n";
}
std::cerr<<"Generating base content for Mellow...\n";
if(fileExist(mellow_rule_base))
base_content = fileGet(mellow_rule_base, false);
else
base_content = webGet(mellow_rule_base, getSystemProxy());
mellow_base.Parse(base_content);
rulesetToSurge(mellow_base, ruleset_content_array, 2);
retVal = mellow_base.Parse(base_content);
if(retVal != INIREADER_EXCEPTION_NONE)
std::cerr<<"Unable to load Mellow base content. Reason: "<<mellow_base.GetLastError()<<"\n";
else
rulesetToSurge(mellow_base, ruleset_content_array, 2);
}
std::string subconverter(RESPONSE_CALLBACK_ARGS)