mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
ini parsing doesn't set options anymore, it returns a structure
moved a lot of stuff back to conf, didn't belong in ini
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
namespace mob
|
||||
{
|
||||
|
||||
|
||||
BOOL WINAPI signal_handler(DWORD) noexcept
|
||||
{
|
||||
gcx().debug(context::generic, "caught sigint");
|
||||
|
||||
+85
-15
@@ -228,6 +228,20 @@ std::vector<std::string> format_options()
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
fs::path find_in_path(std::string_view exe)
|
||||
{
|
||||
const std::wstring wexe = utf8_to_utf16(exe);
|
||||
|
||||
const std::size_t size = MAX_PATH;
|
||||
wchar_t buffer[size + 1] = {};
|
||||
|
||||
if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr))
|
||||
return buffer;
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
fs::path find_iscc()
|
||||
{
|
||||
const auto tasks = find_tasks("installer");
|
||||
@@ -436,20 +450,6 @@ fs::path find_third_party_directory()
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
fs::path find_in_path(std::string_view exe)
|
||||
{
|
||||
const std::wstring wexe = utf8_to_utf16(exe);
|
||||
|
||||
const std::size_t size = MAX_PATH;
|
||||
wchar_t buffer[size + 1] = {};
|
||||
|
||||
if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr))
|
||||
return buffer;
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
bool find_qmake(fs::path& check)
|
||||
{
|
||||
// try Qt/Qt5.14.2/msvc*/bin/qmake.exe
|
||||
@@ -691,6 +691,31 @@ void find_vcvars()
|
||||
}
|
||||
|
||||
|
||||
struct parsed_option
|
||||
{
|
||||
std::string task, section, key, value;
|
||||
};
|
||||
|
||||
parsed_option parse_option(const std::string& s)
|
||||
{
|
||||
// parses "task:section/key=value" where "task:" is optional
|
||||
static std::regex re(R"((?:(.+)\:)?(.+)/(.*)=(.*))");
|
||||
std::smatch m;
|
||||
|
||||
if (!std::regex_match(s, m, re))
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"bad option {}, must be [task:]section/key=value", s);
|
||||
}
|
||||
|
||||
return {
|
||||
trim_copy(m[1].str()),
|
||||
trim_copy(m[2].str()),
|
||||
trim_copy(m[3].str()),
|
||||
trim_copy(m[4].str())
|
||||
};
|
||||
}
|
||||
|
||||
void init_options(
|
||||
const std::vector<fs::path>& inis, const std::vector<std::string>& opts)
|
||||
{
|
||||
@@ -703,7 +728,52 @@ void init_options(
|
||||
{
|
||||
// Check if the prefix is set by this ini file:
|
||||
fs::path cprefix = add ? fs::path{} : conf().path().prefix();
|
||||
parse_ini(ini, add);
|
||||
const auto data = parse_ini(ini);
|
||||
|
||||
for (auto&& a : data.aliases)
|
||||
add_alias(a.first, a.second);
|
||||
|
||||
for (auto&& [section_string, kvs] : data.sections)
|
||||
{
|
||||
const auto col = section_string.find(":");
|
||||
std::string task, section;
|
||||
|
||||
if (col == std::string::npos)
|
||||
{
|
||||
section = section_string;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = section_string.substr(0, col);
|
||||
section = section_string.substr(col + 1);
|
||||
}
|
||||
|
||||
for (auto&& [k, v] : kvs)
|
||||
{
|
||||
if (task.empty())
|
||||
{
|
||||
if (add)
|
||||
details::add_string(section, k, v);
|
||||
else
|
||||
details::set_string(section, k, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task == "_override")
|
||||
{
|
||||
details::set_string_for_task("_override", section, k, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& tasks = find_tasks(task);
|
||||
MOB_ASSERT(!tasks.empty());
|
||||
|
||||
for (auto& t : tasks)
|
||||
details::set_string_for_task(t->name(), section, k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf().path().prefix() != cprefix)
|
||||
ini_prefix = ini;
|
||||
|
||||
+12
-24
@@ -3,23 +3,6 @@
|
||||
namespace mob
|
||||
{
|
||||
|
||||
std::vector<fs::path> find_inis(
|
||||
bool auto_detect, const std::vector<std::string>& from_cl,
|
||||
bool verbose);
|
||||
|
||||
void init_options(
|
||||
const std::vector<fs::path>& inis, const std::vector<std::string>& opts);
|
||||
|
||||
bool verify_options();
|
||||
void log_options();
|
||||
void dump_available_options();
|
||||
|
||||
fs::path find_in_path(std::string_view exe);
|
||||
fs::path find_root(bool verbose=false);
|
||||
fs::path find_in_root(const fs::path& file);
|
||||
fs::path make_temp_file();
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
std::string get_string(std::string_view section, std::string_view key);
|
||||
@@ -29,16 +12,21 @@ namespace details
|
||||
void set_string(
|
||||
std::string_view section, std::string_view key,
|
||||
std::string_view value);
|
||||
|
||||
void add_string(
|
||||
std::string_view section, std::string_view key, std::string_view value);
|
||||
|
||||
void set_string_for_task(
|
||||
std::string_view task_name, std::string_view section,
|
||||
std::string_view key, std::string_view value);
|
||||
}
|
||||
|
||||
|
||||
void init_options(
|
||||
const std::vector<fs::path>& inis, const std::vector<std::string>& opts);
|
||||
|
||||
bool verify_options();
|
||||
void log_options();
|
||||
void dump_available_options();
|
||||
|
||||
fs::path find_root(bool verbose=false);
|
||||
fs::path find_in_root(const fs::path& file);
|
||||
fs::path make_temp_file();
|
||||
|
||||
|
||||
template <class DefaultType>
|
||||
class conf_section
|
||||
{
|
||||
|
||||
+151
-152
@@ -9,175 +9,40 @@
|
||||
namespace mob
|
||||
{
|
||||
|
||||
std::string default_ini_filename()
|
||||
{
|
||||
return "mob.ini";
|
||||
}
|
||||
|
||||
parsed_option parse_option(const std::string& s)
|
||||
{
|
||||
// task:section/key=value
|
||||
// task: is optional
|
||||
std::regex re(R"((?:(.+)\:)?(.+)/(.*)=(.*))");
|
||||
std::smatch m;
|
||||
|
||||
if (!std::regex_match(s, m, re))
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"bad option {}, must be [task:]section/key=value", s);
|
||||
}
|
||||
|
||||
std::string task = trim_copy(m[1].str());
|
||||
std::string section = trim_copy(m[2].str());
|
||||
std::string key = trim_copy(m[3].str());
|
||||
std::string value = trim_copy(m[4].str());
|
||||
|
||||
return {task, section, key, value};
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class... Args>
|
||||
void ini_error(
|
||||
const fs::path& ini, std::size_t line, std::string_view f, Args&&... args)
|
||||
const ini_data& ini, std::size_t line, std::string_view f, Args&&... args)
|
||||
{
|
||||
gcx().bail_out(context::conf,
|
||||
"{}:{}: {}",
|
||||
path_to_utf8(ini), (line + 1),
|
||||
path_to_utf8(ini.path), (line + 1),
|
||||
fmt::format(f, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
std::vector<std::string> read_ini(const fs::path& ini)
|
||||
|
||||
ini_data::kv_map& ini_data::get_section(std::string_view name)
|
||||
{
|
||||
std::ifstream in(ini);
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
for (;;)
|
||||
for (auto itor=sections.begin(); itor!=sections.end(); ++itor)
|
||||
{
|
||||
std::string line;
|
||||
std::getline(in, line);
|
||||
trim(line);
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
|
||||
lines.push_back(std::move(line));
|
||||
if (itor->first == name)
|
||||
return itor->second;
|
||||
}
|
||||
|
||||
if (in.bad())
|
||||
gcx().bail_out(context::conf, "failed to read ini {}", ini);
|
||||
|
||||
return lines;
|
||||
sections.push_back({std::string(name), kv_map()});
|
||||
return sections.back().second;
|
||||
}
|
||||
|
||||
void parse_section(
|
||||
const fs::path& ini, std::size_t& i,
|
||||
const std::vector<std::string>& lines,
|
||||
std::string_view task, std::string_view section, bool add)
|
||||
void ini_data::set(std::string_view section, std::string key, std::string value)
|
||||
{
|
||||
++i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (i >= lines.size() || lines[i][0] == '[')
|
||||
break;
|
||||
|
||||
const auto& line = lines[i];
|
||||
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto sep = line.find("=");
|
||||
if (sep == std::string::npos)
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
|
||||
const std::string k = trim_copy(line.substr(0, sep));
|
||||
const std::string v = trim_copy(line.substr(sep + 1));
|
||||
|
||||
if (k.empty())
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
|
||||
if (section == "aliases")
|
||||
{
|
||||
add_alias(k, split_quoted(v, " "));
|
||||
}
|
||||
else if (task.empty())
|
||||
{
|
||||
if (add)
|
||||
details::add_string(section, k, v);
|
||||
else
|
||||
details::set_string(section, k, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task == "_override")
|
||||
{
|
||||
details::set_string_for_task("_override", section, k, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& tasks = find_tasks(task);
|
||||
|
||||
if (tasks.empty())
|
||||
ini_error(ini, i, "no task matching '{}' found", task);
|
||||
|
||||
for (auto& t : tasks)
|
||||
details::set_string_for_task(t->name(), section, k, v);
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
auto& s = get_section(section);
|
||||
s.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
void parse_ini(const fs::path& ini, bool add)
|
||||
|
||||
|
||||
std::string default_ini_filename()
|
||||
{
|
||||
gcx().debug(context::conf, "using ini at {}", ini);
|
||||
|
||||
const auto lines = read_ini(ini);
|
||||
std::size_t i = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (i >= lines.size())
|
||||
break;
|
||||
|
||||
const auto& line = lines[i];
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.starts_with("[") && line.ends_with("]"))
|
||||
{
|
||||
const std::string s = line.substr(1, line.size() - 2);
|
||||
|
||||
std::string task, section;
|
||||
|
||||
const auto col = s.find(":");
|
||||
|
||||
if (col == std::string::npos)
|
||||
{
|
||||
section = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = s.substr(0, col);
|
||||
section = s.substr(col + 1);
|
||||
}
|
||||
|
||||
parse_section(ini, i, lines, task, section, add);
|
||||
}
|
||||
else
|
||||
{
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
}
|
||||
}
|
||||
return "mob.ini";
|
||||
}
|
||||
|
||||
std::vector<fs::path> find_inis(
|
||||
@@ -260,7 +125,8 @@ std::vector<fs::path> find_inis(
|
||||
|
||||
auto cwd = fs::current_path();
|
||||
|
||||
while (!cwd.empty()) {
|
||||
while (!cwd.empty())
|
||||
{
|
||||
const auto in_cwd = cwd / default_ini_filename();
|
||||
if (fs::exists(in_cwd) && !fs::equivalent(in_cwd, master))
|
||||
{
|
||||
@@ -315,4 +181,137 @@ std::vector<fs::path> find_inis(
|
||||
return map(v, [&](auto&& p){ return p.second; });
|
||||
}
|
||||
|
||||
std::vector<std::string> read_ini(const fs::path& ini)
|
||||
{
|
||||
std::ifstream in(ini);
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::string line;
|
||||
std::getline(in, line);
|
||||
trim(line);
|
||||
|
||||
if (!in)
|
||||
break;
|
||||
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
|
||||
if (in.bad())
|
||||
gcx().bail_out(context::conf, "failed to read ini {}", ini);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
void parse_line(
|
||||
ini_data& ini, std::size_t i, const std::string& line,
|
||||
const std::string& task, const std::string& section)
|
||||
{
|
||||
const auto sep = line.find("=");
|
||||
if (sep == std::string::npos)
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
|
||||
const std::string k = trim_copy(line.substr(0, sep));
|
||||
const std::string v = trim_copy(line.substr(sep + 1));
|
||||
|
||||
if (k.empty())
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
|
||||
if (section == "aliases")
|
||||
{
|
||||
add_alias(k, split_quoted(v, " "));
|
||||
}
|
||||
else if (task.empty())
|
||||
{
|
||||
ini.set(section, k, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!valid_task_name(task))
|
||||
ini_error(ini, i, "no task matching '{}' found", task);
|
||||
|
||||
ini.set(task + ":" + section, k, v);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_section(
|
||||
ini_data& ini, std::size_t& i, const std::vector<std::string>& lines,
|
||||
const std::string& section_string)
|
||||
{
|
||||
std::string task, section;
|
||||
|
||||
const auto col = section_string.find(":");
|
||||
|
||||
if (col == std::string::npos)
|
||||
{
|
||||
section = section_string;
|
||||
}
|
||||
else
|
||||
{
|
||||
task = section_string.substr(0, col);
|
||||
section = section_string.substr(col + 1);
|
||||
}
|
||||
|
||||
|
||||
++i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (i >= lines.size() || lines[i][0] == '[')
|
||||
break;
|
||||
|
||||
const auto& line = lines[i];
|
||||
|
||||
// empty or comment
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_line(ini, i, line, task, section);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
ini_data parse_ini(const fs::path& path)
|
||||
{
|
||||
gcx().debug(context::conf, "using ini at {}", path);
|
||||
|
||||
ini_data ini;
|
||||
ini.path = path;
|
||||
|
||||
const auto lines = read_ini(path);
|
||||
std::size_t i = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (i >= lines.size())
|
||||
break;
|
||||
|
||||
const auto& line = lines[i];
|
||||
|
||||
// empty or comment
|
||||
if (line.empty() || line[0] == '#' || line[0] == ';')
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.starts_with("[") && line.ends_with("]"))
|
||||
{
|
||||
const std::string name = line.substr(1, line.size() - 2);
|
||||
parse_section(ini, i, lines, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ini_error(ini, i, "bad line '{}'", line);
|
||||
}
|
||||
}
|
||||
|
||||
return ini;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+19
-4
@@ -4,13 +4,28 @@ namespace mob
|
||||
{
|
||||
|
||||
std::string default_ini_filename();
|
||||
void parse_ini(const fs::path& ini, bool add);
|
||||
|
||||
struct parsed_option
|
||||
std::vector<fs::path> find_inis(
|
||||
bool auto_detect, const std::vector<std::string>& from_cl,
|
||||
bool verbose);
|
||||
|
||||
|
||||
struct ini_data
|
||||
{
|
||||
std::string task, section, key, value;
|
||||
using alias_patterns = std::vector<std::string>;
|
||||
using aliases_map = std::map<std::string, alias_patterns>;
|
||||
|
||||
using kv_map = std::map<std::string, std::string>;
|
||||
using sections_vector = std::vector<std::pair<std::string, kv_map>>;
|
||||
|
||||
fs::path path;
|
||||
aliases_map aliases;
|
||||
sections_vector sections;
|
||||
|
||||
kv_map& get_section(std::string_view name);
|
||||
void set(std::string_view section, std::string key, std::string value);
|
||||
};
|
||||
|
||||
parsed_option parse_option(const std::string& s);
|
||||
ini_data parse_ini(const fs::path& ini);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -141,6 +141,17 @@ task* find_one_task(std::string_view pattern, bool verbose)
|
||||
return tasks[0];
|
||||
}
|
||||
|
||||
bool valid_task_name(std::string_view pattern)
|
||||
{
|
||||
if (!find_tasks(pattern).empty())
|
||||
return true;
|
||||
|
||||
if (pattern == "_override")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void run_all_tasks()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -25,6 +25,7 @@ void run_all_tasks();
|
||||
bool is_super_task(const std::string& name);
|
||||
std::vector<task*> find_tasks(std::string_view pattern);
|
||||
task* find_one_task(std::string_view pattern, bool verbose=true);
|
||||
bool valid_task_name(std::string_view pattern);
|
||||
|
||||
std::vector<task*> get_all_tasks();
|
||||
std::vector<task*> get_top_level_tasks();
|
||||
|
||||
Reference in New Issue
Block a user