/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * 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 . * * 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 opt_name, std::initializer_list 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::iterator s_iter = opt_name.begin(); std::initializer_list::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 opt_name) { if (gp == -1) { throw std::runtime_error("group tag can't be -1. From gctl::getoption::set_groups(...)"); } std::initializer_list::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 &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 &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 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 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"; }