gctl/lib/utility/get_option.cpp
2024-09-10 15:45:07 +08:00

392 lines
9.1 KiB
C++

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#include "get_option.h"
void gctl::parse_key_value(std::string in_str, std::string separator, std::string &key,
std::string &value)
{
if (in_str.empty())
{
throw runtime_error("Empty string. From parse_key_value(...)");
}
// 程序寻找参数对中的分隔符并以此为标准初步分割参数名称和值
int pos = in_str.find(separator);
if (pos == in_str.npos)
{
throw runtime_error("Invalid string: " + in_str + ". From parse_key_value(...)");
}
key = in_str.substr(0, pos);
value = in_str.substr(pos+1, in_str.length());
// 去除字符串开头与尾部的空白字符 包括空格与制表符
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
if (value.empty())
{
throw runtime_error("No value found for the key: " + key + ". From parse_key_value(...)");
}
return;
}
gctl::text_option::text_option()
{
group = -1;
mandatory = false;
name = value = "NullValue";
}
void gctl::text_option::set(std::string n, bool m)
{
name = n;
mandatory = m;
return;
}
void gctl::text_option::set_group(int g)
{
group = g;
return;
}
gctl::getoption::~getoption()
{
clear();
}
void gctl::getoption::clear()
{
options_.clear();
}
void gctl::getoption::add_option(std::string opt_name, bool manda, int gp)
{
text_option tmp_p;
tmp_p.set(opt_name, manda);
tmp_p.set_group(gp);
options_.push_back(tmp_p);
return;
}
void gctl::getoption::add_options(std::initializer_list<std::string> opt_name, std::initializer_list<bool> opt_manda)
{
if (opt_name.size() != opt_manda.size())
{
throw gctl::runtime_error("Unequal initialization lists. From gctl::getoption::init_options(...)");
}
text_option tmp_p;
std::initializer_list<std::string>::iterator s_iter = opt_name.begin();
std::initializer_list<bool>::iterator b_iter = opt_manda.begin();
for (size_t i = 0; i < opt_name.size(); i++)
{
tmp_p.set(*s_iter, *b_iter);
s_iter++;
b_iter++;
options_.push_back(tmp_p);
}
return;
}
void gctl::getoption::set_group(int gp, std::initializer_list<std::string> opt_name)
{
if (gp == -1)
{
throw std::runtime_error("group tag can't be -1. From gctl::getoption::set_groups(...)");
}
std::initializer_list<std::string>::iterator s_iter;
for (size_t i = 0; i < options_.size(); i++)
{
for (s_iter = opt_name.begin(); s_iter != opt_name.end(); ++s_iter)
{
if (*s_iter == options_[i].name)
{
options_[i].group = gp;
break;
}
}
}
group_idx_.push_back(gp);
return;
}
void gctl::getoption::read_options(std::string filename, std::string separator,
std::string conntector, char annotate)
{
std::ifstream infile;
open_matched_infile(infile, filename, ".txt,.log,.opt,.job,.default");
bool all_blank;
std::string str;
while(std::getline(infile, str))
{
if (str.empty() || str[0] == annotate) continue;
all_blank = true;
for (size_t i = 0; i < str.size(); i++)
{
if (str[i] != ' ')
{
all_blank = false;
break;
}
}
if (all_blank) continue;
std::string key, value;
parse_key_value(str, separator, key, value);
for (size_t i = 0; i < options_.size(); i++)
{
if (options_[i].name == key)
{
if (options_[i].value == "NullValue") options_[i].value = value;
else options_[i].value += conntector + value;
break;
}
}
}
infile.close();
return;
}
void gctl::getoption::read_options(const std::vector<std::string> &str_vec,
std::string separator, std::string conntector, char annotate)
{
bool all_blank;
std::string str;
for (int i = 0; i < str_vec.size(); i++)
{
str = str_vec[i];
if (str.empty() || str[0] == annotate) continue;
all_blank = true;
for (size_t i = 0; i < str.size(); i++)
{
if (str[i] != ' ')
{
all_blank = false;
break;
}
}
if (all_blank) continue;
std::string key, value;
parse_key_value(str, separator, key, value);
for (size_t i = 0; i < options_.size(); i++)
{
if (options_[i].name == key)
{
if (options_[i].value == "NullValue") options_[i].value = value;
else options_[i].value += conntector + value;
break;
}
}
}
return;
}
void gctl::getoption::read_options(const gctl::array<std::string> &str_vec,
std::string separator, std::string conntector, char annotate)
{
bool all_blank;
std::string str;
for (int i = 0; i < str_vec.size(); i++)
{
str = str_vec[i];
if (str.empty() || str[0] == annotate) continue;
all_blank = true;
for (size_t i = 0; i < str.size(); i++)
{
if (str[i] != ' ')
{
all_blank = false;
break;
}
}
if (all_blank) continue;
std::string key, value;
parse_key_value(str, separator, key, value);
for (size_t i = 0; i < options_.size(); i++)
{
if (options_[i].name == key)
{
if (options_[i].value == "NullValue") options_[i].value = value;
else options_[i].value += conntector + value;
break;
}
}
}
return;
}
void gctl::getoption::check_mandatory()
{
bool err = false;
std::string err_str;
for (size_t i = 0; i < options_.size(); i++)
{
// Not in a group, is mandatory and is not set
if (options_[i].group == -1 && options_[i].mandatory && options_[i].value == "NullValue")
{
err_str = "Mandatory option not set: " + options_[i].name;
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
err = true;
}
}
if (err)
{
throw gctl::runtime_error("Fail to pass the mandatory test. From gctl::getoption::check_mandatory()");
}
return;
}
void gctl::getoption::check_group(int gp)
{
bool err = true;
for (size_t i = 0; i < options_.size(); i++)
{
// In the given group and is set
if (options_[i].group == gp && options_[i].value != "NullValue")
{
err = false;
break;
}
}
if (err)
{
GCTL_ShowWhatError("At least one of the following options must be set:", GCTL_ERROR_ERROR, 0, 0, 0);
for (size_t i = 0; i < options_.size(); i++)
{
if (options_[i].group == gp) std::cerr << options_[i].name << "\n";
}
throw gctl::runtime_error("Fail to pass the group test. From gctl::getoption::check_group(...)");
}
return;
}
void gctl::getoption::check_groups()
{
for (size_t i = 0; i < group_idx_.size(); i++)
{
check_group(group_idx_[i]);
}
return;
}
void gctl::getoption::show_options(std::ostream& outstream, bool show_all)
{
for (size_t i = 0; i < options_.size(); i++)
{
if (options_[i].value != "NullValue")
{
outstream << options_[i].name << ":\t" << options_[i].value << std::endl;
}
else if (show_all)
{
outstream << options_[i].name << ":\t[Not set]" << std::endl;
}
}
outstream << "======================" << std::endl;
return;
}
bool gctl::getoption::has_value(std::string key, char delimiter)
{
std::vector<std::string> tmp_keys;
// 分割待匹配的字符串
parse_string_to_vector(key, delimiter, tmp_keys);
for (size_t o = 0; o < options_.size(); o++)
{
for (size_t i = 0; i < tmp_keys.size(); i++)
{
if (tmp_keys[i] == options_[o].name)
{
if (options_[o].value != "NullValue")
{
return true;
}
}
}
}
return false;
}
std::string gctl::getoption::get_value(std::string key, char delimiter)
{
std::vector<std::string> tmp_keys;
// 分割待匹配的字符串
parse_string_to_vector(key, delimiter, tmp_keys);
for (size_t o = 0; o < options_.size(); o++)
{
for (size_t i = 0; i < tmp_keys.size(); i++)
{
if (tmp_keys[i] == options_[o].name)
{
return options_[o].value;
}
}
}
// 全部没找到
throw runtime_error("Option not recored: " + key + ". From getoption::get_value(...)");
return "null";
}