// 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 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){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif add(a_args); } 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 = false){ 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;} 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 = "") const { tools_vforcit(arg,m_args,it) { if((*it).first==a_key) { a_value = (*it).second; return true; } } a_value = a_def; return false; } 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; } 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); } 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; } bool add(const std::string& a_key,const std::string& a_value = "",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; } void add(const std::vector& a_args,bool a_strip = false) { tools_vforcit(std::string,a_args,it) { std::vector ws; words((*it),"=",false,ws); if(ws.size()==1) { if(a_strip) strip(ws[0],both,' '); m_args.push_back(arg(ws[0],"")); } else if(ws.size()>=2) { if(a_strip) { strip(ws[0],both,' '); strip(ws[1],both,' '); } m_args.push_back(arg(ws[0],ws[1])); } } } 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); } 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; } } void files(std::vector& a_files,bool a_skip_first = true) const { a_files.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_files.clear(); } else { a_files.push_back((*it).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_opts) const { tools_vforcit(arg,m_args,it) { if((*it).first.find('-')==0) { //find '-' at first pos. bool found = false; tools_vforcit(std::string,a_opts,it2) { if((*it).first==(*it2)) { found = true; break; } } if(!found) return false; } } return true; } 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 = "",const std::string& a_prefix = "") 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