ode-toolbox

ODE integration tools
git clone https://git.0xfab.ch/ode-toolbox.git
Log | Files | Refs | README | LICENSE

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 */