#include "precomp.hpp" #include namespace cv { struct CommandLineParserParams { public: String help_message; String def_value; std::vector keys; int number; }; struct CommandLineParser::Impl { bool error; String error_message; String about_message; String path_to_app; String app_name; std::vector data; std::vector split_range_string(const String& str, char fs, char ss) const; std::vector split_string(const String& str, char symbol = ' ', bool create_empty_item = false) const; String cat_string(const String& str) const; void apply_params(const String& key, const String& value); void apply_params(int i, String value); void sort_params(); int refcount; }; static String get_type_name(int type) { if( type == Param::INT ) return "int"; if( type == Param::BOOLEAN ) return "bool"; if( type == Param::UNSIGNED_INT ) return "unsigned"; if( type == Param::UINT64 ) return "unsigned long long"; if( type == Param::FLOAT ) return "float"; if( type == Param::REAL ) return "double"; if( type == Param::STRING ) return "string"; return "unknown"; } static void from_str(const String& str, int type, void* dst) { std::stringstream ss(str.c_str()); if( type == Param::INT ) ss >> *(int*)dst; else if( type == Param::BOOLEAN ) { std::string temp; ss >> temp; *(bool*) dst = temp == "true"; } else if( type == Param::UNSIGNED_INT ) ss >> *(unsigned*)dst; else if( type == Param::UINT64 ) ss >> *(uint64*)dst; else if( type == Param::FLOAT ) ss >> *(float*)dst; else if( type == Param::REAL ) ss >> *(double*)dst; else if( type == Param::STRING ) *(String*)dst = str; else throw cv::Exception(CV_StsBadArg, "unknown/unsupported parameter type", "", __FILE__, __LINE__); if (ss.fail()) { String err_msg = "can not convert: [" + str + + "] to [" + get_type_name(type) + "]"; throw cv::Exception(CV_StsBadArg, err_msg, "", __FILE__, __LINE__); } } void CommandLineParser::getByName(const String& name, bool space_delete, int type, void* dst) const { try { for (size_t i = 0; i < impl->data.size(); i++) { for (size_t j = 0; j < impl->data[i].keys.size(); j++) { if (name.compare(impl->data[i].keys[j]) == 0) { String v = impl->data[i].def_value; if (space_delete) v = impl->cat_string(v); from_str(v, type, dst); return; } } } impl->error = true; impl->error_message = impl->error_message + "Unknown parameter " + name + "\n"; } catch (std::exception& e) { impl->error = true; impl->error_message = impl->error_message + "Exception: " + String(e.what()) + "\n"; } } void CommandLineParser::getByIndex(int index, bool space_delete, int type, void* dst) const { try { for (size_t i = 0; i < impl->data.size(); i++) { if (impl->data[i].number == index) { String v = impl->data[i].def_value; if (space_delete == true) v = impl->cat_string(v); from_str(v, type, dst); return; } } impl->error = true; impl->error_message = impl->error_message + "Unknown parameter #" + format("%d", index) + "\n"; } catch(std::exception & e) { impl->error = true; impl->error_message = impl->error_message + "Exception: " + String(e.what()) + "\n"; } } static bool cmp_params(const CommandLineParserParams & p1, const CommandLineParserParams & p2) { if (p1.number < p2.number) return true; if (p1.number > p2.number) return false; return p1.keys[0].compare(p2.keys[0]) < 0; } CommandLineParser::CommandLineParser(int argc, const char* const argv[], const String& keys) { impl = new Impl; impl->refcount = 1; // path to application size_t pos_s = String(argv[0]).find_last_of("/\\"); if (pos_s == String::npos) { impl->path_to_app = ""; impl->app_name = String(argv[0]); } else { impl->path_to_app = String(argv[0]).substr(0, pos_s); impl->app_name = String(argv[0]).substr(pos_s + 1, String(argv[0]).length() - pos_s); } impl->error = false; impl->error_message = ""; // parse keys std::vector k = impl->split_range_string(keys, '{', '}'); int jj = 0; for (size_t i = 0; i < k.size(); i++) { std::vector l = impl->split_string(k[i], '|', true); CommandLineParserParams p; p.keys = impl->split_string(l[0]); p.def_value = l[1]; p.help_message = impl->cat_string(l[2]); p.number = -1; if (p.keys.size() <= 0) { impl->error = true; impl->error_message = "Field KEYS could not be empty\n"; } else { if (p.keys[0][0] == '@') { p.number = jj; jj++; } impl->data.push_back(p); } } // parse argv jj = 0; for (int i = 1; i < argc; i++) { String s = String(argv[i]); if (s.find('=') != String::npos && s.find('=') < s.length()) { std::vector k_v = impl->split_string(s, '=', true); for (int h = 0; h < 2; h++) { if (k_v[0][0] == '-') k_v[0] = k_v[0].substr(1, k_v[0].length() -1); } impl->apply_params(k_v[0], k_v[1]); } else if (s.length() > 2 && s[0] == '-' && s[1] == '-') { impl->apply_params(s.substr(2), "true"); } else if (s.length() > 1 && s[0] == '-') { impl->apply_params(s.substr(1), "true"); } else { impl->apply_params(jj, s); jj++; } } impl->sort_params(); } CommandLineParser::~CommandLineParser() { if (CV_XADD(&impl->refcount, -1) == 1) delete impl; } CommandLineParser::CommandLineParser(const CommandLineParser& parser) { impl = parser.impl; CV_XADD(&impl->refcount, 1); } CommandLineParser& CommandLineParser::operator = (const CommandLineParser& parser) { if( this != &parser ) { if(CV_XADD(&impl->refcount, -1) == 1) delete impl; impl = parser.impl; CV_XADD(&impl->refcount, 1); } return *this; } void CommandLineParser::about(const String& message) { impl->about_message = message; } void CommandLineParser::Impl::apply_params(const String& key, const String& value) { for (size_t i = 0; i < data.size(); i++) { for (size_t k = 0; k < data[i].keys.size(); k++) { if (key.compare(data[i].keys[k]) == 0) { data[i].def_value = value; break; } } } } void CommandLineParser::Impl::apply_params(int i, String value) { for (size_t j = 0; j < data.size(); j++) { if (data[j].number == i) { data[j].def_value = value; break; } } } void CommandLineParser::Impl::sort_params() { for (size_t i = 0; i < data.size(); i++) { std::sort(data[i].keys.begin(), data[i].keys.end()); } std::sort (data.begin(), data.end(), cmp_params); } String CommandLineParser::Impl::cat_string(const String& str) const { int left = 0, right = (int)str.length(); while( left <= right && str[left] == ' ' ) left++; while( right > left && str[right-1] == ' ' ) right--; return left >= right ? String("") : str.substr(left, right-left); } String CommandLineParser::getPathToApplication() const { return impl->path_to_app; } bool CommandLineParser::has(const String& name) const { for (size_t i = 0; i < impl->data.size(); i++) { for (size_t j = 0; j < impl->data[i].keys.size(); j++) { if (name.compare(impl->data[i].keys[j]) == 0 && String("true").compare(impl->data[i].def_value) == 0) { return true; } } } return false; } bool CommandLineParser::check() const { return impl->error == false; } void CommandLineParser::printErrors() const { if (impl->error) { printf("\nERRORS:\n%s\n", impl->error_message.c_str()); fflush(stdout); } } void CommandLineParser::printMessage() const { if (impl->about_message != "") printf("%s\n", impl->about_message.c_str()); printf("Usage: %s [params] ", impl->app_name.c_str()); for (size_t i = 0; i < impl->data.size(); i++) { if (impl->data[i].number > -1) { String name = impl->data[i].keys[0].substr(1, impl->data[i].keys[0].length() - 1); printf("%s ", name.c_str()); } } printf("\n\n"); for (size_t i = 0; i < impl->data.size(); i++) { if (impl->data[i].number == -1) { printf("\t"); for (size_t j = 0; j < impl->data[i].keys.size(); j++) { String k = impl->data[i].keys[j]; if (k.length() > 1) { printf("--"); } else { printf("-"); } printf("%s", k.c_str()); if (j != impl->data[i].keys.size() - 1) { printf(", "); } } String dv = impl->cat_string(impl->data[i].def_value); if (dv.compare("") != 0) { printf(" (value:%s)", dv.c_str()); } printf("\n\t\t%s\n", impl->data[i].help_message.c_str()); } } printf("\n"); for (size_t i = 0; i < impl->data.size(); i++) { if (impl->data[i].number != -1) { printf("\t"); String k = impl->data[i].keys[0]; k = k.substr(1, k.length() - 1); printf("%s", k.c_str()); String dv = impl->cat_string(impl->data[i].def_value); if (dv.compare("") != 0) { printf(" (value:%s)", dv.c_str()); } printf("\n\t\t%s\n", impl->data[i].help_message.c_str()); } } } std::vector CommandLineParser::Impl::split_range_string(const String& _str, char fs, char ss) const { String str = _str; std::vector vec; String word = ""; bool begin = false; while (!str.empty()) { if (str[0] == fs) { if (begin == true) { throw cv::Exception(CV_StsParseError, String("error in split_range_string(") + str + String(", ") + String(1, fs) + String(", ") + String(1, ss) + String(")"), "", __FILE__, __LINE__ ); } begin = true; word = ""; str = str.substr(1, str.length() - 1); } if (str[0] == ss) { if (begin == false) { throw cv::Exception(CV_StsParseError, String("error in split_range_string(") + str + String(", ") + String(1, fs) + String(", ") + String(1, ss) + String(")"), "", __FILE__, __LINE__ ); } begin = false; vec.push_back(word); } if (begin == true) { word = word + str[0]; } str = str.substr(1, str.length() - 1); } if (begin == true) { throw cv::Exception(CV_StsParseError, String("error in split_range_string(") + str + String(", ") + String(1, fs) + String(", ") + String(1, ss) + String(")"), "", __FILE__, __LINE__ ); } return vec; } std::vector CommandLineParser::Impl::split_string(const String& _str, char symbol, bool create_empty_item) const { String str = _str; std::vector vec; String word = ""; while (!str.empty()) { if (str[0] == symbol) { if (!word.empty() || create_empty_item) { vec.push_back(word); word = ""; } } else { word = word + str[0]; } str = str.substr(1, str.length() - 1); } if (word != "" || create_empty_item) { vec.push_back(word); } return vec; } }