easy-iso

Iso-surface extraction from volume data
git clone https://git.0xfab.ch/easy-iso.git
Log | Files | Refs | Submodules | README | LICENSE

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 };