source: 3DVCSoftware/branches/0.3-poznan-univ/source/App/TAppCommon/program_options_lite.h @ 45

Last change on this file since 45 was 5, checked in by hhi, 13 years ago

Clean version with cfg-files

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1/* The copyright in this software is being made available under the BSD
2 * License, included below. This software may be subject to other third party
3 * and contributor rights, including patent rights, and no such rights are
4 * granted under this license.
5 *
6 * Copyright (c) 2010-2011, ISO/IEC
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above copyright notice,
15 *    this list of conditions and the following disclaimer in the documentation
16 *    and/or other materials provided with the distribution.
17 *  * Neither the name of the ISO/IEC nor the names of its contributors may
18 *    be used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35#include <iostream>
36#include <sstream>
37#include <string>
38#include <vector>
39#include <list>
40#include <map>
41#include <stdlib.h>
42#include <errno.h>
43#include <cstring>
44#include <math.h>
45
46
47#ifdef WIN32
48#define strdup _strdup
49#endif
50
51namespace df
52{
53  namespace program_options_lite
54  {
55    struct Options;
56   
57    void doHelp(std::ostream& out, Options& opts, unsigned columns = 80);
58    unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]);
59    unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]);
60    std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[]);
61    void scanLine(Options& opts, std::string& line);
62    void scanFile(Options& opts, std::istream& in);
63    void setDefaults(Options& opts);
64    void parseConfigFile(Options& opts, const std::string& filename);
65    bool storePair(Options& opts, const std::string& name, const std::string& value);
66   
67    /** OptionBase: Virtual base class for storing information relating to a
68     * specific option This base class describes common elements.  Type specific
69     * information should be stored in a derived class. */
70    struct OptionBase
71    {
72      OptionBase(const std::string& name, const std::string& desc)
73      : opt_string(name), opt_desc(desc)
74      {};
75     
76      virtual ~OptionBase() {}
77     
78      /* parse argument @arg, to obtain a value for the option */
79      virtual void parse(const std::string& arg) = 0;
80      /* set the argument to the default value */
81      virtual void setDefault() = 0;
82     
83      std::string opt_string;
84      std::string opt_desc;
85    };
86   
87    /** Type specific option storage */
88    template<typename T>
89    struct Option : public OptionBase
90    {
91      Option(const std::string& name, T& storage, T default_val, const std::string& desc)
92      : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val)
93      {}
94     
95      void parse(const std::string& arg);
96     
97      void setDefault()
98      {
99        opt_storage = opt_default_val;
100      }
101     
102      T& opt_storage;
103      T opt_default_val;
104    };
105   
106    /* Generic parsing */
107    template<typename T>
108    inline void
109    Option<T>::parse(const std::string& arg)
110    {
111      std::istringstream arg_ss (arg,std::istringstream::in);
112      arg_ss >> opt_storage;
113    }
114   
115    /* string parsing is specialized -- copy the whole string, not just the
116     * first word */
117    template<>
118    inline void
119    Option<std::string>::parse(const std::string& arg)
120    {
121      opt_storage = arg;
122    }
123   
124    template<>
125    inline void
126      Option<char*>::parse(const std::string& arg)
127    {
128      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
129    }
130
131    template<>
132    inline void
133      Option< std::vector<char*> >::parse(const std::string& arg)
134    {
135      opt_storage.clear(); 
136     
137      char* pcStart = (char*) arg.data();     
138      char* pcEnd = strtok (pcStart," ");
139
140      while (pcEnd != NULL)
141      {
142        size_t uiStringLength = pcEnd - pcStart;
143        char* pcNewStr = (char*) malloc( uiStringLength + 1 );
144        strncpy( pcNewStr, pcStart, uiStringLength); 
145        pcNewStr[uiStringLength] = '\0'; 
146        pcStart = pcEnd+1; 
147        pcEnd = strtok (NULL, " ,.-");
148        opt_storage.push_back( pcNewStr ); 
149      }     
150    }
151
152
153    template<>   
154    inline void
155      Option< std::vector<double> >::parse(const std::string& arg)
156    {
157      char* pcNextStart = (char*) arg.data();
158      char* pcEnd = pcNextStart + arg.length();
159
160      char* pcOldStart = 0; 
161
162      size_t iIdx = 0; 
163
164      while (pcNextStart < pcEnd)
165      {
166        errno = 0; 
167
168        if ( iIdx < opt_storage.size() )
169        {
170          opt_storage[iIdx] = strtod(pcNextStart, &pcNextStart);
171        }
172        else
173        {
174        opt_storage.push_back( strtod(pcNextStart, &pcNextStart)) ;
175        }
176        iIdx++; 
177
178        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
179        {
180          std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
181          exit(EXIT_FAILURE);   
182        };   
183        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
184        pcOldStart = pcNextStart; 
185
186      }
187    }
188
189    template<>
190    inline void
191      Option< std::vector<int> >::parse(const std::string& arg)
192    {
193      opt_storage.clear();
194
195
196      char* pcNextStart = (char*) arg.data();
197      char* pcEnd = pcNextStart + arg.length();
198
199      char* pcOldStart = 0; 
200
201      size_t iIdx = 0; 
202
203
204      while (pcNextStart < pcEnd)
205      {
206
207        if ( iIdx < opt_storage.size() )
208        {
209          opt_storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
210        }
211        else
212        {
213          opt_storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
214        }
215        iIdx++; 
216        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
217        {
218          std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
219          exit(EXIT_FAILURE);
220        };   
221        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
222        pcOldStart = pcNextStart;
223      }
224    }
225
226
227    template<>
228    inline void
229      Option< std::vector<bool> >::parse(const std::string& arg)
230    {
231      char* pcNextStart = (char*) arg.data();
232      char* pcEnd = pcNextStart + arg.length();
233
234      char* pcOldStart = 0; 
235
236      size_t iIdx = 0; 
237
238      while (pcNextStart < pcEnd)
239      {
240        if ( iIdx < opt_storage.size() )
241        {
242          opt_storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
243        }
244        else
245        {
246          opt_storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
247        }
248        iIdx++; 
249
250        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
251        {
252          std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
253          exit(EXIT_FAILURE);
254        };   
255        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
256        pcOldStart = pcNextStart;
257      }
258    }
259   
260    /** Option class for argument handling using a user provided function */
261    struct OptionFunc : public OptionBase
262    {
263      typedef void (Func)(Options&, const std::string&);
264     
265      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
266      : OptionBase(name, desc), parent(parent_), func(func_)
267      {}
268     
269      void parse(const std::string& arg)
270      {
271        func(parent, arg);
272      }
273     
274      void setDefault()
275      {
276        return;
277      }
278     
279    private:
280      Options& parent;
281      void (*func)(Options&, const std::string&);
282    };
283   
284    class OptionSpecific;
285    struct Options
286    {
287      ~Options();
288     
289      OptionSpecific addOptions();
290     
291      struct Names
292      {
293        Names() : opt(0) {};
294        ~Names()
295        {
296          if (opt)
297            delete opt;
298        }
299        std::list<std::string> opt_long;
300        std::list<std::string> opt_short;
301        OptionBase* opt;
302      };
303
304      void addOption(OptionBase *opt);
305     
306      typedef std::list<Names*> NamesPtrList;
307      NamesPtrList opt_list;
308     
309      typedef std::map<std::string, NamesPtrList> NamesMap;
310      NamesMap opt_long_map;
311      NamesMap opt_short_map;
312    };
313   
314    /* Class with templated overloaded operator(), for use by Options::addOptions() */
315    class OptionSpecific
316    {
317    public:
318      OptionSpecific(Options& parent_) : parent(parent_) {}
319     
320      /**
321       * Add option described by @name to the parent Options list,
322       *   with @storage for the option's value
323       *   with @default_val as the default value
324       *   with @desc as an optional help description
325       */
326      template<typename T>
327      OptionSpecific&
328      operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "")
329      {
330        parent.addOption(new Option<T>(name, storage, default_val, desc));
331        return *this;
332      }
333     
334      template<typename T>
335      OptionSpecific&
336        operator()(const std::string& name, std::vector<T>& storage, T default_val, unsigned uiMaxNum, const std::string& desc = "" )
337      {
338        std::string cNameBuffer;
339        std::string cDescriptionBuffer;
340
341        cNameBuffer       .resize( name.size() + 10 );
342        cDescriptionBuffer.resize( desc.size() + 10 );
343
344        storage.resize(uiMaxNum);
345        for ( unsigned int uiK = 0; uiK < uiMaxNum; uiK++ )
346        {
347          // isn't there are sprintf function for string??
348          sprintf((char*) cNameBuffer.c_str()       ,name.c_str(),uiK,uiK);
349          sprintf((char*) cDescriptionBuffer.c_str(),desc.c_str(),uiK,uiK);
350
351          parent.addOption(new Option<T>( cNameBuffer, (storage[uiK]), default_val, cDescriptionBuffer ));
352        }
353
354        return *this;
355      }
356
357     
358      /**
359       * Add option described by @name to the parent Options list,
360       *   with @desc as an optional help description
361       * instead of storing the value somewhere, a function of type
362       * OptionFunc::Func is called.  It is upto this function to correctly
363       * handle evaluating the option's value.
364       */
365      OptionSpecific&
366      operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
367      {
368        parent.addOption(new OptionFunc(name, parent, func, desc));
369        return *this;
370      }
371    private:
372      Options& parent;
373    };
374   
375  }; /* namespace: program_options_lite */
376}; /* namespace: df */
Note: See TracBrowser for help on using the repository browser.