// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_args #define tools_args #ifdef TOOLS_MEM #include "mem" #include "S_STRING" #endif #include "sout" #include "strip" #include "words" #include "sto" #include "forit" #include "mnmx" //#include "squote" #include namespace tools { class args { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::args) #endif public: typedef std::pair arg; public: args(){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } args(int a_argc,char* a_argv[]){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif for(int index=0;index& a_args,bool a_strip = false){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif add(a_args,a_strip); } args(const std::vector& a_args):m_args(a_args){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } args(const std::string& a_args,const std::string& a_sep,bool a_strip){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif std::vector _args; words(a_args,a_sep,false,_args); add(_args,a_strip); } virtual ~args(){ #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } public: args(const args& a_from):m_args(a_from.m_args){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } args& operator=(const args& a_from){ m_args = a_from.m_args; return *this; } public: const std::vector& get_args() const {return m_args;} //std::vector& get_args() {return m_args;} bool is_arg(const std::string& a_string) const { tools_vforcit(arg,m_args,it) { if((*it).first==a_string) return true; } return false; } bool is_empty() const {return m_args.size()?false:true;} size_t size() const {return m_args.size();} size_t number() const {return m_args.size();} //back comp. bool find(const std::string& a_key,std::string& a_value,const std::string& a_def = std::string()) const { tools_vforcit(arg,m_args,it) { if((*it).first==a_key) { a_value = (*it).second; return true; } } a_value = a_def; return false; } #ifdef TOOLS_DEPRECATED std::vector find(const std::string& a_key) const { std::vector vals; tools_vforcit(arg,m_args,it) { if((*it).first==a_key) vals.push_back((*it).second); } return vals; } #endif void find(const std::string& a_key,std::vector& a_vals,bool a_clear=true) const { if(a_clear) a_vals.clear(); tools_vforcit(arg,m_args,it) { if((*it).first==a_key) a_vals.push_back((*it).second); } } bool find(const std::string& a_string,bool& a_value,const bool& a_def = false) const { std::string s; if(!find(a_string,s)) {a_value = a_def;return false;} return to(s,a_value,a_def); } template bool find(const std::string& a_string,aT& a_value,const aT& a_def = aT()) const { std::string _s; if(!find(a_string,_s)) {a_value = a_def;return false;} return to(_s,a_value,a_def); } #ifdef TOOLS_DEPRECATED std::vector tovector() const { // Return a vector of string std::vector vec; tools_vforcit(arg,m_args,it) { std::string s; if((*it).second.empty()) { s = (*it).first; } else { s = (*it).first; s += "="; s += (*it).second; } vec.push_back(s); } return vec; } #endif void to_vector(std::vector& a_vec) const { // Return a vector of string a_vec.clear(); std::string s; tools_vforcit(arg,m_args,it) { s = (*it).first; if((*it).second.size()) { s += "="; s += (*it).second; } a_vec.push_back(s); } } bool add(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){ if(a_override) { tools_vforit(arg,m_args,it) { if((*it).first==a_key) { (*it).second = a_value; return true; } } } if(a_key.empty()) return false; m_args.push_back(arg(a_key,a_value)); return true; } bool insert_begin(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){ if(a_override) { tools_vforit(arg,m_args,it) { if((*it).first==a_key) { (*it).second = a_value; return true; } } } if(a_key.empty()) return false; m_args.insert(m_args.begin(),arg(a_key,a_value)); return true; } void add(const std::vector& a_args,bool a_strip = false) { tools_vforcit(std::string,a_args,it) { const std::string& sarg = *it; std::string::size_type pos = sarg.find('='); if(pos==std::string::npos) { if(a_strip) { std::string left = sarg; strip(left,both,' '); m_args.push_back(arg(left,"")); } else { m_args.push_back(arg(sarg,"")); } } else { std::string left = sarg.substr(0,pos); std::string right = sarg.substr((pos+1),sarg.size()-(pos+1)); if(a_strip) { strip(left,both,' '); strip(right,both,' '); } m_args.push_back(arg(left,right)); } } } void add_keyvals(const std::vector& a_args,bool a_strip = false) { //a_args must contain an even number of strings. size_t sz_half = a_args.size()/2; if((2*sz_half)!=a_args.size()) return; for(std::vector::const_iterator it = a_args.begin();it!=a_args.end();it+=2) { if(a_strip) { std::string key = *it; strip(key,both,' '); std::string val = *(it+1); strip(val,both,' '); m_args.push_back(arg(key,val)); } else { m_args.push_back(arg(*it,*(it+1))); } } } void add(const std::vector& a_args){ tools_vforcit(arg,a_args,it) m_args.push_back(*it); } void add(const args& a_from){ tools_vforcit(arg,a_from.m_args,it) m_args.push_back(*it); } int remove(const std::string& a_key){ size_t nbeg = m_args.size(); for(std::vector::iterator it = m_args.begin();it!=m_args.end();) { if(a_key==(*it).first) { it = m_args.erase(it); } else { ++it; } } return int(nbeg) - int(m_args.size()); } void remove_first(){m_args.erase(m_args.begin());} bool last(std::string& a_key,std::string& a_value) const { a_key.clear(); a_value.clear(); if(m_args.empty()) return false; a_key = m_args.back().first; a_value = m_args.back().second; return true; } bool prog_name(std::string& a_value) const { if(m_args.empty()) {a_value.clear();return false;} if(m_args[0].second.size()) {a_value.clear();return false;} a_value = m_args[0].first; return true; } bool file(std::string& a_file) const { std::string slast; std::string s; if((m_args.size()>1) //first arg is the program name ! && last(slast,s) && (slast.find('-')!=0) && (s.empty()) ) { a_file = slast; //Last argument is not an option. return true; } else { a_file.clear(); return false; } } bool file(std::string& a_file,bool a_remove) { std::string slast; std::string s; if((m_args.size()>1) //first arg is the program name ! && last(slast,s) && (slast.find('-')!=0) && (s.empty()) ) { a_file = slast; //Last argument is not an option. if(a_remove) m_args.erase(m_args.end()-1); return true; } else { a_file.clear(); return false; } } void not_hyphens(std::vector& a_not_hyphens,bool a_skip_first = false) const { a_not_hyphens.clear(); // Get the serie of trailing args not beginning with '-' // and without a value (not of the form [-]xxx=yyy). // Note that an argument like that in between arguments // is NOT taken into account. if(m_args.empty()) return; std::vector::const_iterator it = m_args.begin(); if(a_skip_first) it++; for(;it!=m_args.end();++it) { if( ((*it).first.find('-')==0) || (*it).second.size() ) { a_not_hyphens.clear(); } else { a_not_hyphens.push_back((*it).first); } } } void files(std::vector& a_files,bool a_skip_first = true) const { //true and not false as in the upper. return not_hyphens(a_files,a_skip_first); } bool first_not_hyphen(std::string& a_first,bool a_skip_first = false) const { std::vector _ss; not_hyphens(_ss,a_skip_first); if(_ss.empty()) {a_first.clear();return false;} a_first = _ss[0]; return true; } //bool first_of_files(std::string& a_file,bool a_skip_first) const {return first_of_hyphen(a_file,a_skip_first);} bool argcv(int& a_argc,char**& a_argv) const { // If using with : // int argc; // char** argv; // args.argcv(argc,argv); // you can delete with : // args::delete_argcv(argc,argv); if(m_args.empty()) {a_argc = 0;a_argv = 0;return true;} typedef char* _cstr_t; _cstr_t* av = new _cstr_t[m_args.size()+1]; if(!av) {a_argc = 0;a_argv = 0;return false;} a_argv = av; for(std::vector::const_iterator it = m_args.begin();it!=m_args.end();++it,av++) { std::string::size_type lf = (*it).first.length(); std::string::size_type ls = (*it).second.length(); std::string::size_type sz = lf; if(ls) sz += 1 + ls; char* p = new char[sz+1]; if(!p) {a_argc = 0;a_argv = 0;return false;} //some delete are lacking. *av = p; {char* pf = (char*)(*it).first.c_str(); for(std::string::size_type i=0;i& a_knowns) const { tools_vforcit(arg,m_args,it) { if((*it).first.find('-')==0) { //find '-' at first pos. bool found = false; tools_vforcit(std::string,a_knowns,it2) { if((*it).first==(*it2)) { found = true; break; } } if(!found) return false; //one option not in a_knowns. } } return true; //all options are in a_knowns. } bool known_options(const std::string& a_known) const { tools_vforcit(arg,m_args,it) { if((*it).first.find('-')==0) { //find '-' at first pos. if((*it).first!=a_known) return false; //one option not a_known. } } return true; //all options are a_known. } //void remove_string_delimiters_in_keys() { // tools_vforit(arg,m_args,it) { // if(!rm_quotes((*it).first)) rm_double_quotes((*it).first); // } //} //void remove_string_delimiters_in_values() { // tools_vforit(arg,m_args,it) { // if(!rm_quotes((*it).second)) rm_double_quotes((*it).second); // } //} void files_at_end(bool a_skip_first = true) { // reorder to have "file" arguments at end. if(m_args.empty()) return; std::vector _args; if(a_skip_first) _args.push_back(*(m_args.begin())); //first pass : {std::vector::const_iterator it = m_args.begin(); if(a_skip_first) it++; for(;it!=m_args.end();++it) { if( ((*it).first.find('-')==0) || (*it).second.size() ) { _args.push_back(*it); } }} //second pass : {std::vector::const_iterator it = m_args.begin(); if(a_skip_first) it++; for(;it!=m_args.end();++it) { if( ((*it).first.find('-')==0) || (*it).second.size() ) { } else { _args.push_back(*it); } }} m_args = _args; } //NOTE : print is a Python keyword. void dump(std::ostream& a_out,const std::string& a_comment = std::string(),const std::string& a_prefix = std::string()) const { if(a_comment.size()) a_out << a_comment << std::endl; tools_vforcit(arg,m_args,it) { a_out << a_prefix << "key = " << sout((*it).first) << ", value = " << sout((*it).second) << std::endl; } } public: //backcomp (for Panoramix). bool isAnArgument(const std::string& a_key) const {return is_arg(a_key);} protected: std::vector m_args; }; inline bool check_args(const std::vector& a_args,unsigned int a_number,std::ostream& a_out){ if(a_args.size()==a_number) return true; a_out << "bad argument number." << " Given " << (unsigned int)a_args.size() << " whilst " << a_number << " expected." << std::endl; return false; } inline bool check_min(const std::vector& a_args,unsigned int a_number,std::string& a_last,std::ostream& a_out){ if(a_args.size()>=a_number) { if(a_number==0) { if(a_args.empty()) { a_last.clear(); } else { a_last = a_args[0]; for(size_t index=1;index& aArgs,unsigned int a_number,std::ostream& a_out){ if(aArgs.size()>=a_number) return true; a_out << "bad argument number." << " Given " << (unsigned int)aArgs.size() << " whilst at least " << a_number << " expected." << std::endl; return false; } inline bool check_or_args(const std::vector& aArgs,unsigned int a_1,unsigned int a_2,std::ostream& a_out){ if((aArgs.size()==a_1)||(aArgs.size()==a_2)) return true; a_out << "bad argument number." << " Given " << (unsigned int)aArgs.size() << " whilst " << a_1 << " or " << a_2 << " expected." << std::endl; return false; } inline std::vector to(int a_argc,char** a_argv) { std::vector v; for(int index=0;index