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