Path: blob/master/modules/core/src/command_line_parser.cpp
16337 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.3#include "precomp.hpp"4#include <sstream>56namespace cv7{89namespace {10static const char* noneValue = "<none>";1112static String cat_string(const String& str)13{14int left = 0, right = (int)str.length();15while( left < right && str[left] == ' ' )16left++;17while( right > left && str[right-1] == ' ' )18right--;19return left >= right ? String("") : str.substr(left, right-left);20}21}2223struct CommandLineParserParams24{25public:26String help_message;27String def_value;28std::vector<String> keys;29int number;30};313233struct CommandLineParser::Impl34{35bool error;36String error_message;37String about_message;3839String path_to_app;40String app_name;4142std::vector<CommandLineParserParams> data;4344std::vector<String> split_range_string(const String& str, char fs, char ss) const;45std::vector<String> split_string(const String& str, char symbol = ' ', bool create_empty_item = false) const;4647void apply_params(const String& key, const String& value);48void apply_params(int i, String value);4950void sort_params();51int refcount;52};535455static const char* get_type_name(Param type)56{57if( type == Param::INT )58return "int";59if( type == Param::BOOLEAN )60return "bool";61if( type == Param::UNSIGNED_INT )62return "unsigned";63if( type == Param::UINT64 )64return "unsigned long long";65if( type == Param::FLOAT )66return "float";67if( type == Param::REAL )68return "double";69if( type == Param::STRING )70return "string";71return "unknown";72}7374static bool parse_bool(std::string str)75{76std::transform(str.begin(), str.end(), str.begin(), details::char_tolower);77std::istringstream is(str);78bool b;79is >> (str.size() > 1 ? std::boolalpha : std::noboolalpha) >> b;80return b;81}8283static void from_str(const String& str, Param type, void* dst)84{85std::stringstream ss(str.c_str());86if( type == Param::INT )87ss >> *(int*)dst;88else if( type == Param::BOOLEAN )89{90std::string temp;91ss >> temp;92*(bool*) dst = parse_bool(temp);93}94else if( type == Param::UNSIGNED_INT )95ss >> *(unsigned*)dst;96else if( type == Param::UINT64 )97ss >> *(uint64*)dst;98else if( type == Param::FLOAT )99ss >> *(float*)dst;100else if( type == Param::REAL )101ss >> *(double*)dst;102else if( type == Param::STRING )103*(String*)dst = str;104else if( type == Param::SCALAR)105{106Scalar& scalar = *(Scalar*)dst;107for (int i = 0; i < 4 && !ss.eof(); ++i)108ss >> scalar[i];109}110else111CV_Error(Error::StsBadArg, "unknown/unsupported parameter type");112113if (ss.fail())114{115CV_Error_(Error::StsBadArg, ("can not convert: [%s] to [%s]", str.c_str(), get_type_name(type)));116}117}118119void CommandLineParser::getByName(const String& name, bool space_delete, Param type, void* dst) const120{121CV_TRY122{123for (size_t i = 0; i < impl->data.size(); i++)124{125for (size_t j = 0; j < impl->data[i].keys.size(); j++)126{127if (name == impl->data[i].keys[j])128{129String v = impl->data[i].def_value;130if (space_delete)131v = cat_string(v);132133// the key was neither specified nor has a default value134if((v.empty() && type != Param::STRING) || v == noneValue) {135impl->error = true;136impl->error_message = impl->error_message + "Missing parameter: '" + name + "'\n";137return;138}139140from_str(v, type, dst);141return;142}143}144}145}146CV_CATCH (Exception, e)147{148impl->error = true;149impl->error_message = impl->error_message + "Parameter '"+ name + "': " + e.err + "\n";150return;151}152CV_Error_(Error::StsBadArg, ("undeclared key '%s' requested", name.c_str()));153}154155156void CommandLineParser::getByIndex(int index, bool space_delete, Param type, void* dst) const157{158CV_TRY159{160for (size_t i = 0; i < impl->data.size(); i++)161{162if (impl->data[i].number == index)163{164String v = impl->data[i].def_value;165if (space_delete == true) v = cat_string(v);166167// the key was neither specified nor has a default value168if((v.empty() && type != Param::STRING) || v == noneValue) {169impl->error = true;170impl->error_message = impl->error_message + format("Missing parameter #%d\n", index);171return;172}173from_str(v, type, dst);174return;175}176}177}178CV_CATCH(Exception, e)179{180impl->error = true;181impl->error_message = impl->error_message + format("Parameter #%d: ", index) + e.err + "\n";182return;183}184CV_Error_(Error::StsBadArg, ("undeclared position %d requested", index));185}186187static bool cmp_params(const CommandLineParserParams & p1, const CommandLineParserParams & p2)188{189if (p1.number < p2.number)190return true;191192if (p1.number > p2.number)193return false;194195return p1.keys[0].compare(p2.keys[0]) < 0;196}197198CommandLineParser::CommandLineParser(int argc, const char* const argv[], const String& keys)199{200impl = new Impl;201impl->refcount = 1;202203// path to application204size_t pos_s = String(argv[0]).find_last_of("/\\");205if (pos_s == String::npos)206{207impl->path_to_app = "";208impl->app_name = String(argv[0]);209}210else211{212impl->path_to_app = String(argv[0]).substr(0, pos_s);213impl->app_name = String(argv[0]).substr(pos_s + 1, String(argv[0]).length() - pos_s);214}215216impl->error = false;217impl->error_message = "";218219// parse keys220std::vector<String> k = impl->split_range_string(keys, '{', '}');221222int jj = 0;223for (size_t i = 0; i < k.size(); i++)224{225std::vector<String> l = impl->split_string(k[i], '|', true);226CommandLineParserParams p;227p.keys = impl->split_string(l[0]);228p.def_value = l[1];229p.help_message = cat_string(l[2]);230p.number = -1;231if (p.keys.size() <= 0)232{233impl->error = true;234impl->error_message = "Field KEYS could not be empty\n";235}236else237{238if (p.keys[0][0] == '@')239{240p.number = jj;241jj++;242}243244impl->data.push_back(p);245}246}247248// parse argv249jj = 0;250for (int i = 1; i < argc; i++)251{252String s(argv[i]);253bool hasSingleDash = s.length() > 1 && s[0] == '-';254255if (hasSingleDash)256{257bool hasDoubleDash = s.length() > 2 && s[1] == '-';258String key = s.substr(hasDoubleDash ? 2 : 1);259String value = "true";260size_t equalsPos = key.find('=');261262if(equalsPos != String::npos) {263value = key.substr(equalsPos + 1);264key = key.substr(0, equalsPos);265}266impl->apply_params(key, value);267}268else269{270impl->apply_params(jj, s);271jj++;272}273}274275impl->sort_params();276}277278CommandLineParser::~CommandLineParser()279{280if (CV_XADD(&impl->refcount, -1) == 1)281delete impl;282}283284CommandLineParser::CommandLineParser(const CommandLineParser& parser)285{286impl = parser.impl;287CV_XADD(&impl->refcount, 1);288}289290CommandLineParser& CommandLineParser::operator = (const CommandLineParser& parser)291{292if( this != &parser )293{294CV_XADD(&parser.impl->refcount, 1);295if(CV_XADD(&impl->refcount, -1) == 1)296delete impl;297impl = parser.impl;298}299return *this;300}301302void CommandLineParser::about(const String& message)303{304impl->about_message = message;305}306307void CommandLineParser::Impl::apply_params(const String& key, const String& value)308{309for (size_t i = 0; i < data.size(); i++)310{311for (size_t k = 0; k < data[i].keys.size(); k++)312{313if (key.compare(data[i].keys[k]) == 0)314{315data[i].def_value = value;316break;317}318}319}320}321322void CommandLineParser::Impl::apply_params(int i, String value)323{324for (size_t j = 0; j < data.size(); j++)325{326if (data[j].number == i)327{328data[j].def_value = value;329break;330}331}332}333334void CommandLineParser::Impl::sort_params()335{336for (size_t i = 0; i < data.size(); i++)337{338std::sort(data[i].keys.begin(), data[i].keys.end());339}340341std::sort (data.begin(), data.end(), cmp_params);342}343344String CommandLineParser::getPathToApplication() const345{346return impl->path_to_app;347}348349bool CommandLineParser::has(const String& name) const350{351for (size_t i = 0; i < impl->data.size(); i++)352{353for (size_t j = 0; j < impl->data[i].keys.size(); j++)354{355if (name == impl->data[i].keys[j])356{357const String v = cat_string(impl->data[i].def_value);358return !v.empty() && v != noneValue;359}360}361}362363CV_Error_(Error::StsBadArg, ("undeclared key '%s' requested", name.c_str()));364}365366bool CommandLineParser::check() const367{368return impl->error == false;369}370371void CommandLineParser::printErrors() const372{373if (impl->error)374{375printf("\nERRORS:\n%s\n", impl->error_message.c_str());376fflush(stdout);377}378}379380void CommandLineParser::printMessage() const381{382if (impl->about_message != "")383printf("%s\n", impl->about_message.c_str());384385printf("Usage: %s [params] ", impl->app_name.c_str());386387for (size_t i = 0; i < impl->data.size(); i++)388{389if (impl->data[i].number > -1)390{391String name = impl->data[i].keys[0].substr(1, impl->data[i].keys[0].length() - 1);392printf("%s ", name.c_str());393}394}395396printf("\n\n");397398for (size_t i = 0; i < impl->data.size(); i++)399{400if (impl->data[i].number == -1)401{402printf("\t");403for (size_t j = 0; j < impl->data[i].keys.size(); j++)404{405String k = impl->data[i].keys[j];406if (k.length() > 1)407{408printf("--");409}410else411{412printf("-");413}414printf("%s", k.c_str());415416if (j != impl->data[i].keys.size() - 1)417{418printf(", ");419}420}421String dv = cat_string(impl->data[i].def_value);422if (dv.compare("") != 0)423{424printf(" (value:%s)", dv.c_str());425}426printf("\n\t\t%s\n", impl->data[i].help_message.c_str());427}428}429printf("\n");430431for (size_t i = 0; i < impl->data.size(); i++)432{433if (impl->data[i].number != -1)434{435printf("\t");436String k = impl->data[i].keys[0];437k = k.substr(1, k.length() - 1);438439printf("%s", k.c_str());440441String dv = cat_string(impl->data[i].def_value);442if (dv.compare("") != 0)443{444printf(" (value:%s)", dv.c_str());445}446printf("\n\t\t%s\n", impl->data[i].help_message.c_str());447}448}449}450451std::vector<String> CommandLineParser::Impl::split_range_string(const String& _str, char fs, char ss) const452{453String str = _str;454std::vector<String> vec;455String word = "";456bool begin = false;457while (!str.empty())458{459if (str[0] == fs)460{461if (begin == true)462{463CV_THROW (cv::Exception(CV_StsParseError,464String("error in split_range_string(")465+ str466+ String(", ")467+ String(1, fs)468+ String(", ")469+ String(1, ss)470+ String(")"),471"", __FILE__, __LINE__472));473}474begin = true;475word = "";476str = str.substr(1, str.length() - 1);477}478479if (str[0] == ss)480{481if (begin == false)482{483CV_THROW (cv::Exception(CV_StsParseError,484String("error in split_range_string(")485+ str486+ String(", ")487+ String(1, fs)488+ String(", ")489+ String(1, ss)490+ String(")"),491"", __FILE__, __LINE__492));493}494begin = false;495vec.push_back(word);496}497498if (begin == true)499{500word = word + str[0];501}502str = str.substr(1, str.length() - 1);503}504505if (begin == true)506{507CV_THROW (cv::Exception(CV_StsParseError,508String("error in split_range_string(")509+ str510+ String(", ")511+ String(1, fs)512+ String(", ")513+ String(1, ss)514+ String(")"),515"", __FILE__, __LINE__516));517}518return vec;519}520521std::vector<String> CommandLineParser::Impl::split_string(const String& _str, char symbol, bool create_empty_item) const522{523String str = _str;524std::vector<String> vec;525String word = "";526527while (!str.empty())528{529if (str[0] == symbol)530{531if (!word.empty() || create_empty_item)532{533vec.push_back(word);534word = "";535}536}537else538{539word = word + str[0];540}541str = str.substr(1, str.length() - 1);542}543544if (word != "" || create_empty_item)545{546vec.push_back(word);547}548549return vec;550}551552}553554555