ArgumentParser.h (11324B)
1 /* 2 * ArgumentParser.h 3 * Cubism 4 * 5 * This argument parser assumes that all arguments are optional ie, each of the argument names is preceded by a '-' 6 * all arguments are however NOT optional to avoid a mess with default values and returned values when not found! 7 * 8 * More converter could be required: 9 * add as needed 10 * TypeName as{TypeName}() in Value 11 * 12 * Created by Christian Conti on 6/7/10. 13 * Copyright 2010 ETH Zurich. All rights reserved. 14 * 15 */ 16 17 #pragma once 18 #include <cstdio> 19 #include <cstdlib> 20 #include <cstring> 21 #include <map> 22 #include <vector> 23 #include <string> 24 #include <iostream> 25 #include <sstream> 26 #include <iomanip> 27 #include <fstream> 28 #include <limits> 29 30 31 using namespace std; 32 33 class Value 34 { 35 private: 36 string content; 37 38 public: 39 40 Value() : content("") {} 41 42 Value(string content_) : content(content_) { /*printf("%s\n",content.c_str());*/ } 43 44 double asDouble(double def=0) 45 { 46 if (content == "") 47 { 48 ostringstream sbuf; 49 sbuf << def; 50 content = sbuf.str(); 51 } 52 return (double) atof(content.c_str()); 53 } 54 55 int asInt(int def=0) 56 { 57 if (content == "") 58 { 59 ostringstream sbuf; 60 sbuf << def; 61 content = sbuf.str(); 62 } 63 return atoi(content.c_str()); 64 } 65 66 bool asBool(bool def=false) 67 { 68 if (content == "") 69 { 70 if (def) content = "true"; 71 else content = "false"; 72 } 73 if (content == "0") return false; 74 if (content == "false") return false; 75 76 return true; 77 } 78 79 string asString(string def="") 80 { 81 if (content == "") content = def; 82 83 return content; 84 } 85 }; 86 87 class CommandlineParser 88 { 89 private: 90 const int iArgC; 91 const char** vArgV; 92 bool bStrictMode, bVerbose; 93 94 protected: 95 map<string,Value> mapArguments; 96 97 public: 98 99 Value& operator()(const string arg) 100 { 101 if (bStrictMode) 102 { 103 map<string,Value>::const_iterator it = mapArguments.find(arg); 104 105 if (it == mapArguments.end()) 106 { 107 printf("Runtime option NOT SPECIFIED! ABORTING! name: %s\n",arg.data()); 108 abort(); 109 } 110 } 111 112 if (bVerbose) printf("%s is %s\n", arg.data(), mapArguments[arg].asString().data()); 113 return mapArguments[arg]; 114 } 115 116 bool check(const string arg) const 117 { 118 return mapArguments.find(arg) != mapArguments.end(); 119 } 120 121 CommandlineParser(const int argc, const char ** argv) : mapArguments(), iArgC(argc), vArgV(argv), bStrictMode(false), bVerbose(true) 122 { 123 for (int i=1; i<argc; i++) 124 if (argv[i][0] == '-') 125 { 126 string values = ""; 127 int itemCount = 0; 128 129 for (int j=i+1; j<argc; j++) 130 { 131 const bool leadingDash = (argv[j][0] == '-'); 132 const char c = argv[j][1]; 133 const bool firstNumeric = ((c >= '0' && c <= '9') || c == 0) ? true : false; 134 if (leadingDash && !firstNumeric) 135 break; 136 else 137 { 138 if (strcmp(values.c_str(), "")) 139 values += ' '; 140 141 values += argv[j]; 142 itemCount++; 143 } 144 } 145 146 if (itemCount == 0) 147 values = "true"; 148 149 mapArguments[argv[i]] = Value(values); 150 i += itemCount; 151 } 152 153 mute(); 154 //printf("found %ld arguments of %d\n",mapArguments.size(),argc); 155 } 156 157 int getargc() const { return iArgC; } 158 159 const char** getargv() const { return vArgV; } 160 161 void set_strict_mode() 162 { 163 bStrictMode = true; 164 } 165 166 void unset_strict_mode() 167 { 168 bStrictMode = false; 169 } 170 171 void mute() 172 { 173 bVerbose = false; 174 } 175 176 void loud() 177 { 178 bVerbose = true; 179 } 180 181 void save_options(string path=".") 182 { 183 string options; 184 for(map<string,Value>::iterator it=mapArguments.begin(); it!=mapArguments.end(); it++) 185 { 186 options+= it->first + " " + it->second.asString() + " "; 187 } 188 string filepath = (path + "/" + string("argumentparser.log")); 189 FILE * f = fopen(filepath.data(), "a"); 190 if (f == NULL) 191 { 192 printf("impossible to write %s.\n", filepath.data()); 193 return; 194 } 195 fprintf(f, "%s\n", options.data()); 196 fclose(f); 197 } 198 199 void print_args() 200 { 201 for(map<string,Value>::iterator it=mapArguments.begin(); it!=mapArguments.end(); it++) 202 { 203 std::cout.width(50); 204 std::cout.fill('.'); 205 std::cout << std::left << it->first; 206 std::cout << ": " << it->second.asString() << std::endl; 207 } 208 } 209 }; 210 211 212 class ArgumentParser: public CommandlineParser 213 { 214 typedef std::map<std::string, Value> ArgMap; 215 typedef std::map<std::string, Value*> pArgMap; 216 typedef std::map<std::string, ArgMap* > FileMap; 217 218 const char commentStart; 219 220 // keep a reference form option origin 221 ArgMap from_commandline; 222 FileMap from_files; 223 pArgMap from_code; 224 225 // helper 226 void _ignoreComments(std::istream& stream, const char commentChar) 227 { 228 stream >> std::ws; 229 int nextchar = stream.peek(); 230 while (nextchar == commentChar) 231 { 232 stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 233 stream >> std::ws; 234 nextchar = stream.peek(); 235 } 236 } 237 238 bool _existKey(std::string& key) const 239 { 240 const std::string og_key = key; 241 bool bExist = true; 242 243 // look for both possible keys (i.e. with leading "-" and without) 244 ArgMap::const_iterator it = mapArguments.find(key); 245 if (it == mapArguments.end()) 246 { 247 if (key[0] == '-') key = key.erase(0, 1); 248 else key = "-" + key; 249 it = mapArguments.find(key); 250 if (it == mapArguments.end()) 251 { 252 key = og_key; 253 bExist = false; 254 } 255 } 256 return bExist; 257 } 258 259 inline std::string _stripKey(std::string key) const 260 { 261 if (key[0] == '-') key = key.erase(0, 1); 262 return key; 263 } 264 265 266 public: 267 ArgumentParser(const int _argc, const char ** _argv): 268 CommandlineParser(_argc, _argv), commentStart('#') 269 { 270 from_commandline = mapArguments; 271 } 272 273 virtual ~ArgumentParser() 274 { 275 for (FileMap::iterator it = from_files.begin(); it != from_files.end(); it++) 276 delete it->second; 277 } 278 279 void readFile(const std::string filepath) 280 { 281 from_files[filepath] = new ArgMap; 282 ArgMap& myFMap = *(from_files[filepath]); 283 284 std::ifstream confFile(filepath.c_str()); 285 if (confFile.is_open()) 286 { 287 // read (key value) pairs from input file, ignore comments 288 // beginning with "#" 289 _ignoreComments(confFile, commentStart); 290 while (!confFile.eof()) 291 { 292 std::string line, key, val; 293 std::getline(confFile, line); 294 std::istringstream lineStream(line); 295 lineStream >> key; 296 lineStream >> val; 297 _ignoreComments(lineStream, commentStart); 298 while(!lineStream.eof()) 299 { 300 std::string multiVal; 301 lineStream >> multiVal; 302 val += (" " + multiVal); 303 _ignoreComments(lineStream, commentStart); 304 } 305 if (_existKey(key)) continue; 306 307 std::pair<string, Value> item(key, Value(val)); 308 mapArguments.insert(item); // add to parent container 309 myFMap.insert(item); // add to private container 310 311 _ignoreComments(confFile, commentStart); 312 } 313 } 314 } 315 316 Value& operator()(std::string key) 317 { 318 const bool bDefaultInCode = !_existKey(key); 319 Value& retval = CommandlineParser::operator()(key); 320 if (bDefaultInCode) from_code[key] = &retval; 321 return retval; 322 } 323 324 inline bool check(std::string key) const { return _existKey(key); } 325 inline bool exist(std::string key) const { return _existKey(key); } 326 327 void print_args() 328 { 329 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 330 std::cout << "* Summary:" << std::endl; 331 std::cout << "* Parameter read from command line: " << from_commandline.size() << std::endl; 332 size_t nFiles = 0; 333 size_t nFileParameter = 0; 334 for (FileMap::const_iterator it=from_files.begin(); it!=from_files.end(); ++it) 335 { 336 if (it->second->size() > 0) 337 { 338 ++nFiles; 339 nFileParameter += it->second->size(); 340 } 341 } 342 std::cout << "* Parameter read from " << std::setw(3) << std::right << nFiles << " file(s): " << nFileParameter << std::endl; 343 std::cout << "* Parameter read from defaults in code: " << from_code.size() << std::endl; 344 std::cout << "* Total number of parameter read from all sources: " << mapArguments.size() << std::endl; 345 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 346 347 // command line given arguments 348 if (!from_commandline.empty()) 349 { 350 std::cout << "* Command Line:" << std::endl; 351 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 352 for(ArgMap::iterator it=from_commandline.begin(); it!=from_commandline.end(); it++) 353 { 354 std::cout.width(50); 355 std::cout.fill('.'); 356 std::cout << std::left << _stripKey(it->first); 357 std::cout << ": " << it->second.asString() << std::endl; 358 } 359 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 360 } 361 362 // options read from input files 363 if (!from_files.empty()) 364 { 365 for (FileMap::iterator itFile=from_files.begin(); itFile!=from_files.end(); itFile++) 366 { 367 if (!itFile->second->empty()) 368 { 369 std::cout << "* File: " << itFile->first << std::endl; 370 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 371 ArgMap& fileArgs = *(itFile->second); 372 for(ArgMap::iterator it=fileArgs.begin(); it!=fileArgs.end(); it++) 373 { 374 std::cout.width(50); 375 std::cout.fill('.'); 376 std::cout << std::left << _stripKey(it->first); 377 std::cout << ": " << it->second.asString() << std::endl; 378 } 379 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 380 } 381 } 382 } 383 384 // defaults defined in code 385 if (!from_code.empty()) 386 { 387 std::cout << "* Defined in Code:" << std::endl; 388 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 389 for(pArgMap::iterator it=from_code.begin(); it!=from_code.end(); it++) 390 { 391 std::cout.width(50); 392 std::cout.fill('.'); 393 std::cout << std::left << _stripKey(it->first); 394 std::cout << ": " << it->second->asString() << std::endl; 395 } 396 std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; 397 } 398 } 399 };