source: 3DVCSoftware/branches/0.1-poznan-univ/source/App/TAppCommon/program_options_lite.h

Last change on this file was 2, checked in by hhi, 13 years ago

inital import

  • Property svn:eol-style set to native
File size: 9.4 KB
Line 
1
2#include <iostream>
3#include <sstream>
4#include <string>
5#include <vector>
6#include <list>
7#include <map>
8#include <stdlib.h>
9#include <errno.h>
10#include <cstring>
11#include <math.h>
12
13
14#ifdef WIN32
15#define strdup _strdup
16#endif
17
18namespace df
19{
20  namespace program_options_lite
21  {
22    struct Options;
23   
24    void doHelp(std::ostream& out, Options& opts, unsigned columns = 80);
25    unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]);
26    unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]);
27    std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[]);
28    void scanLine(Options& opts, std::string& line);
29    void scanFile(Options& opts, std::istream& in);
30    void setDefaults(Options& opts);
31    void parseConfigFile(Options& opts, const std::string& filename);
32    bool storePair(Options& opts, const std::string& name, const std::string& value);
33   
34    /** OptionBase: Virtual base class for storing information relating to a
35     * specific option This base class describes common elements.  Type specific
36     * information should be stored in a derived class. */
37    struct OptionBase
38    {
39      OptionBase(const std::string& name, const std::string& desc)
40      : opt_string(name), opt_desc(desc)
41      {};
42     
43      virtual ~OptionBase() {}
44     
45      /* parse argument @arg, to obtain a value for the option */
46      virtual void parse(const std::string& arg) = 0;
47      /* set the argument to the default value */
48      virtual void setDefault() = 0;
49     
50      std::string opt_string;
51      std::string opt_desc;
52    };
53   
54    /** Type specific option storage */
55    template<typename T>
56    struct Option : public OptionBase
57    {
58      Option(const std::string& name, T& storage, T default_val, const std::string& desc)
59      : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val)
60      {}
61     
62      void parse(const std::string& arg);
63     
64      void setDefault()
65      {
66        opt_storage = opt_default_val;
67      }
68     
69      T& opt_storage;
70      T opt_default_val;
71    };
72   
73    /* Generic parsing */
74    template<typename T>
75    inline void
76    Option<T>::parse(const std::string& arg)
77    {
78      std::istringstream arg_ss (arg,std::istringstream::in);
79      arg_ss >> opt_storage;
80    }
81   
82    /* string parsing is specialized -- copy the whole string, not just the
83     * first word */
84    template<>
85    inline void
86    Option<std::string>::parse(const std::string& arg)
87    {
88      opt_storage = arg;
89    }
90   
91    template<>
92    inline void
93      Option<char*>::parse(const std::string& arg)
94    {
95      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
96    }
97
98    template<>
99    inline void
100      Option< std::vector<char*> >::parse(const std::string& arg)
101    {
102      opt_storage.clear(); 
103     
104      char* pcStart = (char*) arg.data();     
105      char* pcEnd = strtok (pcStart," ");
106
107      while (pcEnd != NULL)
108      {
109        size_t uiStringLength = pcEnd - pcStart;
110        char* pcNewStr = (char*) malloc( uiStringLength + 1 );
111        strncpy( pcNewStr, pcStart, uiStringLength); 
112        pcNewStr[uiStringLength] = '\0'; 
113        pcStart = pcEnd+1; 
114        pcEnd = strtok (NULL, " ,.-");
115        opt_storage.push_back( pcNewStr ); 
116      }     
117    }
118
119
120    template<>   
121    inline void
122      Option< std::vector<double> >::parse(const std::string& arg)
123    {
124      char* pcNextStart = (char*) arg.data();
125      char* pcEnd = pcNextStart + arg.length();
126
127      char* pcOldStart = 0; 
128
129      size_t iIdx = 0; 
130
131      while (pcNextStart < pcEnd)
132      {
133        errno = 0; 
134
135        if ( iIdx < opt_storage.size() )
136        {
137          opt_storage[iIdx] = strtod(pcNextStart, &pcNextStart);
138        }
139        else
140        {
141        opt_storage.push_back( strtod(pcNextStart, &pcNextStart)) ;
142        }
143        iIdx++; 
144
145        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
146        {
147          std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
148          exit(EXIT_FAILURE);   
149        };   
150        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
151        pcOldStart = pcNextStart; 
152
153      }
154    }
155
156    template<>
157    inline void
158      Option< std::vector<int> >::parse(const std::string& arg)
159    {
160      opt_storage.clear();
161
162
163      char* pcNextStart = (char*) arg.data();
164      char* pcEnd = pcNextStart + arg.length();
165
166      char* pcOldStart = 0; 
167
168      size_t iIdx = 0; 
169
170
171      while (pcNextStart < pcEnd)
172      {
173
174        if ( iIdx < opt_storage.size() )
175        {
176          opt_storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
177        }
178        else
179        {
180          opt_storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
181        }
182        iIdx++; 
183        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
184        {
185          std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
186          exit(EXIT_FAILURE);
187        };   
188        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
189        pcOldStart = pcNextStart;
190      }
191    }
192
193
194    template<>
195    inline void
196      Option< std::vector<bool> >::parse(const std::string& arg)
197    {
198      char* pcNextStart = (char*) arg.data();
199      char* pcEnd = pcNextStart + arg.length();
200
201      char* pcOldStart = 0; 
202
203      size_t iIdx = 0; 
204
205      while (pcNextStart < pcEnd)
206      {
207        if ( iIdx < opt_storage.size() )
208        {
209          opt_storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
210        }
211        else
212        {
213          opt_storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
214        }
215        iIdx++; 
216
217        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
218        {
219          std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
220          exit(EXIT_FAILURE);
221        };   
222        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
223        pcOldStart = pcNextStart;
224      }
225    }
226   
227    /** Option class for argument handling using a user provided function */
228    struct OptionFunc : public OptionBase
229    {
230      typedef void (Func)(Options&, const std::string&);
231     
232      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
233      : OptionBase(name, desc), parent(parent_), func(func_)
234      {}
235     
236      void parse(const std::string& arg)
237      {
238        func(parent, arg);
239      }
240     
241      void setDefault()
242      {
243        return;
244      }
245     
246    private:
247      Options& parent;
248      void (*func)(Options&, const std::string&);
249    };
250   
251    class OptionSpecific;
252    struct Options
253    {
254      ~Options();
255     
256      OptionSpecific addOptions();
257     
258      struct Names
259      {
260        Names() : opt(0) {};
261        ~Names()
262        {
263          if (opt)
264            delete opt;
265        }
266        std::list<std::string> opt_long;
267        std::list<std::string> opt_short;
268        OptionBase* opt;
269      };
270
271      void addOption(OptionBase *opt);
272     
273      typedef std::list<Names*> NamesPtrList;
274      NamesPtrList opt_list;
275     
276      typedef std::map<std::string, NamesPtrList> NamesMap;
277      NamesMap opt_long_map;
278      NamesMap opt_short_map;
279    };
280   
281    /* Class with templated overloaded operator(), for use by Options::addOptions() */
282    class OptionSpecific
283    {
284    public:
285      OptionSpecific(Options& parent_) : parent(parent_) {}
286     
287      /**
288       * Add option described by @name to the parent Options list,
289       *   with @storage for the option's value
290       *   with @default_val as the default value
291       *   with @desc as an optional help description
292       */
293      template<typename T>
294      OptionSpecific&
295      operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "")
296      {
297        parent.addOption(new Option<T>(name, storage, default_val, desc));
298        return *this;
299      }
300     
301      template<typename T>
302      OptionSpecific&
303        operator()(const std::string& name, std::vector<T>& storage, T default_val, unsigned uiMaxNum, const std::string& desc = "" )
304      {
305        std::string cNameBuffer;
306        std::string cDescriptionBuffer;
307
308        cNameBuffer       .resize( name.size() + 10 );
309        cDescriptionBuffer.resize( desc.size() + 10 );
310
311        storage.resize(uiMaxNum);
312        for ( unsigned int uiK = 0; uiK < uiMaxNum; uiK++ )
313        {
314          // isn't there are sprintf function for string??
315          sprintf((char*) cNameBuffer.c_str()       ,name.c_str(),uiK,uiK);
316          sprintf((char*) cDescriptionBuffer.c_str(),desc.c_str(),uiK,uiK);
317
318          parent.addOption(new Option<T>( cNameBuffer, (storage[uiK]), default_val, cDescriptionBuffer ));
319        }
320
321        return *this;
322      }
323
324     
325      /**
326       * Add option described by @name to the parent Options list,
327       *   with @desc as an optional help description
328       * instead of storing the value somewhere, a function of type
329       * OptionFunc::Func is called.  It is upto this function to correctly
330       * handle evaluating the option's value.
331       */
332      OptionSpecific&
333      operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
334      {
335        parent.addOption(new OptionFunc(name, parent, func, desc));
336        return *this;
337      }
338    private:
339      Options& parent;
340    };
341   
342  }; /* namespace: program_options_lite */
343}; /* namespace: df */
Note: See TracBrowser for help on using the repository browser.