392 lines
9.1 KiB
C++
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";
|
|||
|
}
|