Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_args 5 #define tools_args 6 7 #ifdef TOOLS_MEM 8 #include "mem" 9 #include "S_STRING" 10 #endif 11 12 #include "sout" 13 #include "strip" 14 #include "words" 15 #include "sto" 16 #include "forit" 17 #include "mnmx" 18 //#include "squote" 19 20 #include <ostream> 21 22 namespace tools { 23 24 class args { 25 #ifdef TOOLS_MEM 26 public: 27 TOOLS_SCLASS(tools::args) 28 #endif 29 public: 30 typedef std::pair<std::string,std::string> arg; 31 public: 32 args(){ 33 #ifdef TOOLS_MEM 34 mem::increment(s_class().c_str()); 35 #endif 36 } 37 args(int a_argc,char* a_argv[]){ 38 #ifdef TOOLS_MEM 39 mem::increment(s_class().c_str()); 40 #endif 41 for(int index=0;index<a_argc;index++) { 42 std::string _s(a_argv[index]); 43 std::string::size_type pos = _s.find('='); 44 if(pos==std::string::npos) { 45 m_args.push_back(arg(_s,"")); 46 } else { 47 std::string key = _s.substr(0,pos); 48 pos++; 49 std::string value = _s.substr(pos,_s.size()-pos); 50 m_args.push_back(arg(key,value)); 51 } 52 } 53 } 54 args(const std::vector<std::string>& a_args,bool a_strip = false){ 55 #ifdef TOOLS_MEM 56 mem::increment(s_class().c_str()); 57 #endif 58 add(a_args,a_strip); 59 } 60 args(const std::vector<arg>& a_args):m_args(a_args){ 61 #ifdef TOOLS_MEM 62 mem::increment(s_class().c_str()); 63 #endif 64 } 65 args(const std::string& a_args,const std::string& a_sep,bool a_strip){ 66 #ifdef TOOLS_MEM 67 mem::increment(s_class().c_str()); 68 #endif 69 std::vector<std::string> _args; 70 words(a_args,a_sep,false,_args); 71 add(_args,a_strip); 72 } 73 virtual ~args(){ 74 #ifdef TOOLS_MEM 75 mem::decrement(s_class().c_str()); 76 #endif 77 } 78 public: 79 args(const args& a_from):m_args(a_from.m_args){ 80 #ifdef TOOLS_MEM 81 mem::increment(s_class().c_str()); 82 #endif 83 } 84 args& operator=(const args& a_from){ 85 m_args = a_from.m_args; 86 return *this; 87 } 88 public: 89 const std::vector<arg>& get_args() const {return m_args;} 90 //std::vector<arg>& get_args() {return m_args;} 91 92 bool is_arg(const std::string& a_string) const { 93 tools_vforcit(arg,m_args,it) { 94 if((*it).first==a_string) return true; 95 } 96 return false; 97 } 98 bool is_empty() const {return m_args.size()?false:true;} 99 size_t size() const {return m_args.size();} 100 size_t number() const {return m_args.size();} //back comp. 101 bool find(const std::string& a_key,std::string& a_value,const std::string& a_def = std::string()) const { 102 tools_vforcit(arg,m_args,it) { 103 if((*it).first==a_key) { 104 a_value = (*it).second; 105 return true; 106 } 107 } 108 a_value = a_def; 109 return false; 110 } 111 #ifdef TOOLS_DEPRECATED 112 std::vector<std::string> find(const std::string& a_key) const { 113 std::vector<std::string> vals; 114 tools_vforcit(arg,m_args,it) { 115 if((*it).first==a_key) vals.push_back((*it).second); 116 } 117 return vals; 118 } 119 #endif 120 void find(const std::string& a_key,std::vector<std::string>& a_vals,bool a_clear=true) const { 121 if(a_clear) a_vals.clear(); 122 tools_vforcit(arg,m_args,it) { 123 if((*it).first==a_key) a_vals.push_back((*it).second); 124 } 125 } 126 127 bool find(const std::string& a_string,bool& a_value,const bool& a_def = false) const { 128 std::string _s; 129 if(!find(a_string,_s)) {a_value = a_def;return false;} 130 return to(_s,a_value,a_def); 131 } 132 template <class aT> 133 bool find(const std::string& a_string,aT& a_value,const aT& a_def = aT()) const { 134 std::string _s; 135 if(!find(a_string,_s)) {a_value = a_def;return false;} 136 return to<aT>(_s,a_value,a_def); 137 } 138 139 #ifdef TOOLS_DEPRECATED 140 std::vector<std::string> tovector() const { 141 // Return a vector of string <name=value> 142 std::vector<std::string> vec; 143 tools_vforcit(arg,m_args,it) { 144 std::string _s; 145 if((*it).second.empty()) { 146 _s = (*it).first; 147 } else { 148 _s = (*it).first; 149 _s += "="; 150 _s += (*it).second; 151 } 152 vec.push_back(_s); 153 } 154 return vec; 155 } 156 #endif 157 void to_vector(std::vector<std::string>& a_vec) const { 158 // Return a vector of string <name=value> 159 a_vec.clear(); 160 std::string _s; 161 tools_vforcit(arg,m_args,it) { 162 _s = (*it).first; 163 if((*it).second.size()) { 164 _s += "="; 165 _s += (*it).second; 166 } 167 a_vec.push_back(_s); 168 } 169 } 170 171 bool add(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){ 172 if(a_override) { 173 tools_vforit(arg,m_args,it) { 174 if((*it).first==a_key) { 175 (*it).second = a_value; 176 return true; 177 } 178 } 179 } 180 if(a_key.empty()) return false; 181 m_args.push_back(arg(a_key,a_value)); 182 return true; 183 } 184 185 bool insert_begin(const std::string& a_key,const std::string& a_value = std::string(),bool a_override = true){ 186 if(a_override) { 187 tools_vforit(arg,m_args,it) { 188 if((*it).first==a_key) { 189 (*it).second = a_value; 190 return true; 191 } 192 } 193 } 194 if(a_key.empty()) return false; 195 m_args.insert(m_args.begin(),arg(a_key,a_value)); 196 return true; 197 } 198 199 void add(const std::vector<std::string>& a_args,bool a_strip = false) { 200 tools_vforcit(std::string,a_args,it) { 201 const std::string& sarg = *it; 202 std::string::size_type pos = sarg.find('='); 203 if(pos==std::string::npos) { 204 if(a_strip) { 205 std::string left = sarg; 206 strip(left,both,' '); 207 m_args.push_back(arg(left,"")); 208 } else { 209 m_args.push_back(arg(sarg,"")); 210 } 211 } else { 212 std::string left = sarg.substr(0,pos); 213 std::string right = sarg.substr((pos+1),sarg.size()-(pos+1)); 214 if(a_strip) { 215 strip(left,both,' '); 216 strip(right,both,' '); 217 } 218 m_args.push_back(arg(left,right)); 219 } 220 } 221 } 222 223 void add_keyvals(const std::vector<std::string>& a_args,bool a_strip = false) { 224 //a_args must contain an even number of strings. 225 size_t sz_half = a_args.size()/2; 226 if((2*sz_half)!=a_args.size()) return; 227 for(std::vector<std::string>::const_iterator it = a_args.begin();it!=a_args.end();it+=2) { 228 if(a_strip) { 229 std::string key = *it; 230 strip(key,both,' '); 231 std::string val = *(it+1); 232 strip(val,both,' '); 233 m_args.push_back(arg(key,val)); 234 } else { 235 m_args.push_back(arg(*it,*(it+1))); 236 } 237 } 238 } 239 240 void add(const std::vector<arg>& a_args){ 241 tools_vforcit(arg,a_args,it) m_args.push_back(*it); 242 } 243 244 void add(const args& a_from){ 245 tools_vforcit(arg,a_from.m_args,it) m_args.push_back(*it); 246 } 247 248 249 int remove(const std::string& a_key){ 250 size_t nbeg = m_args.size(); 251 for(std::vector<arg>::iterator it = m_args.begin();it!=m_args.end();) { 252 if(a_key==(*it).first) { 253 it = m_args.erase(it); 254 } else { 255 ++it; 256 } 257 } 258 return int(nbeg) - int(m_args.size()); 259 } 260 261 void remove_first(){if(m_args.size()) m_args.erase(m_args.begin());} 262 void remove_last(){if(m_args.size()) m_args.erase(m_args.end()-1);} 263 264 bool last(std::string& a_key,std::string& a_value) const { 265 a_key.clear(); 266 a_value.clear(); 267 if(m_args.empty()) return false; 268 a_key = m_args.back().first; 269 a_value = m_args.back().second; 270 return true; 271 } 272 273 bool prog_name(std::string& a_value) const { 274 if(m_args.empty()) {a_value.clear();return false;} 275 if(m_args[0].second.size()) {a_value.clear();return false;} 276 a_value = m_args[0].first; 277 return true; 278 } 279 280 bool file(std::string& a_file) const { 281 std::string slast; 282 std::string _s; 283 if((m_args.size()>1) //first arg is the program name ! 284 && last(slast,_s) 285 && (slast.find('-')!=0) 286 && (_s.empty()) ) { 287 a_file = slast; //Last argument is not an option. 288 return true; 289 } else { 290 a_file.clear(); 291 return false; 292 } 293 } 294 295 bool file(std::string& a_file,bool a_remove) { 296 std::string slast; 297 std::string _s; 298 if((m_args.size()>1) //first arg is the program name ! 299 && last(slast,_s) 300 && (slast.find('-')!=0) 301 && (_s.empty()) ) { 302 a_file = slast; //Last argument is not an option. 303 if(a_remove) m_args.erase(m_args.end()-1); 304 return true; 305 } else { 306 a_file.clear(); 307 return false; 308 } 309 } 310 311 void not_hyphens(std::vector<std::string>& a_not_hyphens,bool a_skip_first = false) const { 312 a_not_hyphens.clear(); 313 // Get the serie of trailing args not beginning with '-' 314 // and without a value (not of the form [-]xxx=yyy). 315 // Note that an argument like that in between arguments 316 // is NOT taken into account. 317 if(m_args.empty()) return; 318 std::vector<arg>::const_iterator it = m_args.begin(); 319 if(a_skip_first) it++; 320 for(;it!=m_args.end();++it) { 321 if( ((*it).first.find('-')==0) || (*it).second.size() ) { 322 a_not_hyphens.clear(); 323 } else { 324 a_not_hyphens.push_back((*it).first); 325 } 326 } 327 } 328 329 void files(std::vector<std::string>& a_files,bool a_skip_first = true) const { //true and not false as in the upper. 330 return not_hyphens(a_files,a_skip_first); 331 } 332 333 bool first_not_hyphen(std::string& a_first,bool a_skip_first = false) const { 334 std::vector<std::string> _ss; 335 not_hyphens(_ss,a_skip_first); 336 if(_ss.empty()) {a_first.clear();return false;} 337 a_first = _ss[0]; 338 return true; 339 } 340 341 //bool first_of_files(std::string& a_file,bool a_skip_first) const {return first_of_hyphen(a_file,a_skip_first);} 342 343 bool argcv(int& a_argc,char**& a_argv) const { 344 // If using with : 345 // int argc; 346 // char** argv; 347 // args.argcv(argc,argv); 348 // you can delete with : 349 // args::delete_argcv(argc,argv); 350 if(m_args.empty()) {a_argc = 0;a_argv = 0;return true;} 351 typedef char* _cstr_t; 352 _cstr_t* av = new _cstr_t[m_args.size()+1]; 353 if(!av) {a_argc = 0;a_argv = 0;return false;} 354 a_argv = av; 355 for(std::vector<arg>::const_iterator it = m_args.begin();it!=m_args.end();++it,av++) { 356 std::string::size_type lf = (*it).first.length(); 357 std::string::size_type ls = (*it).second.length(); 358 std::string::size_type sz = lf; 359 if(ls) sz += 1 + ls; 360 char* p = new char[sz+1]; 361 if(!p) {a_argc = 0;a_argv = 0;return false;} //some delete are lacking. 362 *av = p; 363 {char* pf = (char*)(*it).first.c_str(); 364 for(std::string::size_type i=0;i<lf;i++,p++,pf++) {*p = *pf;} 365 *p = 0;} 366 if(ls) {*p = '=';p++;} 367 {char* ps = (char*)(*it).second.c_str(); 368 for(std::string::size_type i=0;i<ls;i++,p++,ps++) {*p = *ps;} 369 *p = 0;} 370 } 371 *(a_argv+m_args.size()) = 0; 372 a_argc = (int)m_args.size(); 373 return true; 374 } 375 static void delete_argcv(int& a_argc,char**& a_argv) { 376 for(int index=0;index<a_argc;index++) delete [] a_argv[index]; 377 delete [] a_argv; 378 a_argc = 0; 379 a_argv = 0; 380 } 381 382 bool known_options(const std::vector<std::string>& a_knowns) const { 383 tools_vforcit(arg,m_args,it) { 384 if((*it).first.find('-')==0) { //find '-' at first pos. 385 bool found = false; 386 tools_vforcit(std::string,a_knowns,it2) { 387 if((*it).first==(*it2)) { 388 found = true; 389 break; 390 } 391 } 392 if(!found) return false; //one option not in a_knowns. 393 } 394 } 395 return true; //all options are in a_knowns. 396 } 397 398 bool known_options(const std::string& a_known) const { 399 tools_vforcit(arg,m_args,it) { 400 if((*it).first.find('-')==0) { //find '-' at first pos. 401 if((*it).first!=a_known) return false; //one option not a_known. 402 } 403 } 404 return true; //all options are a_known. 405 } 406 407 //void remove_string_delimiters_in_keys() { 408 // tools_vforit(arg,m_args,it) { 409 // if(!rm_quotes((*it).first)) rm_double_quotes((*it).first); 410 // } 411 //} 412 413 //void remove_string_delimiters_in_values() { 414 // tools_vforit(arg,m_args,it) { 415 // if(!rm_quotes((*it).second)) rm_double_quotes((*it).second); 416 // } 417 //} 418 419 void files_at_end(bool a_skip_first = true) { 420 // reorder to have "file" arguments at end. 421 if(m_args.empty()) return; 422 std::vector<arg> _args; 423 if(a_skip_first) _args.push_back(*(m_args.begin())); 424 //first pass : 425 {std::vector<arg>::const_iterator it = m_args.begin(); 426 if(a_skip_first) it++; 427 for(;it!=m_args.end();++it) { 428 if( ((*it).first.find('-')==0) || (*it).second.size() ) { 429 _args.push_back(*it); 430 } 431 }} 432 //second pass : 433 {std::vector<arg>::const_iterator it = m_args.begin(); 434 if(a_skip_first) it++; 435 for(;it!=m_args.end();++it) { 436 if( ((*it).first.find('-')==0) || (*it).second.size() ) { 437 } else { 438 _args.push_back(*it); 439 } 440 }} 441 m_args = _args; 442 } 443 444 //NOTE : print is a Python keyword. 445 void dump(std::ostream& a_out,const std::string& a_comment = std::string(),const std::string& a_prefix = std::string()) const { 446 if(a_comment.size()) a_out << a_comment << std::endl; 447 tools_vforcit(arg,m_args,it) { 448 a_out << a_prefix << "key = " << sout((*it).first) << ", value = " << sout((*it).second) << std::endl; 449 } 450 } 451 452 public: //backcomp (for Panoramix). 453 bool isAnArgument(const std::string& a_key) const {return is_arg(a_key);} 454 protected: 455 std::vector<arg> m_args; 456 }; 457 458 inline bool check_args(const std::vector<std::string>& a_args,unsigned int a_number,std::ostream& a_out){ 459 if(a_args.size()==a_number) return true; 460 a_out << "bad argument number." 461 << " Given " << (unsigned int)a_args.size() 462 << " whilst " << a_number << " expected." 463 << std::endl; 464 return false; 465 } 466 467 inline bool check_min(const std::vector<std::string>& a_args,unsigned int a_number,std::string& a_last,std::ostream& a_out){ 468 if(a_args.size()>=a_number) { 469 if(a_number==0) { 470 if(a_args.empty()) { 471 a_last.clear(); 472 } else { 473 a_last = a_args[0]; 474 for(size_t index=1;index<a_args.size();index++) a_last += " " + a_args[index]; 475 } 476 } else { 477 a_last = a_args[a_number-1]; 478 for(size_t index=a_number;index<a_args.size();index++) a_last += " " + a_args[index]; 479 } 480 return true; 481 } 482 a_out << "bad argument number." 483 << " Given " << (unsigned int)a_args.size() 484 << " whilst at least " << a_number << " expected." 485 << std::endl; 486 return false; 487 } 488 489 inline bool check_min_args(const std::vector<std::string>& aArgs,unsigned int a_number,std::ostream& a_out){ 490 if(aArgs.size()>=a_number) return true; 491 a_out << "bad argument number." 492 << " Given " << (unsigned int)aArgs.size() 493 << " whilst at least " << a_number << " expected." 494 << std::endl; 495 return false; 496 } 497 498 inline bool check_or_args(const std::vector<std::string>& aArgs,unsigned int a_1,unsigned int a_2,std::ostream& a_out){ 499 if((aArgs.size()==a_1)||(aArgs.size()==a_2)) return true; 500 a_out << "bad argument number." 501 << " Given " << (unsigned int)aArgs.size() 502 << " whilst " << a_1 << " or " << a_2 << " expected." 503 << std::endl; 504 return false; 505 } 506 507 inline std::vector<std::string> to(int a_argc,char** a_argv) { 508 std::vector<std::string> v; 509 for(int index=0;index<a_argc;index++) v.push_back(a_argv[index]); 510 return v; 511 } 512 513 } 514 515 #endif