source: 3DVCSoftware/branches/HTM-DEV-0.3-dev0/source/Lib/TAppCommon/program_options_lite.h @ 495

Last change on this file since 495 was 495, checked in by tech, 11 years ago

Fixed several bugs and mismatches.

  • Property svn:eol-style set to native
File size: 12.4 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-2013, ITU/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 ITU/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#include <iostream>
34#include <sstream>
35#include <string>
36#include <list>
37#include <map>
38#include  "../TLibCommon/TypeDef.h"
39
40#if H_MV
41#include <vector>
42#include <errno.h>
43#include <cstring>
44#ifdef WIN32
45#define strdup _strdup
46#endif
47#endif
48//! \ingroup TAppCommon
49//! \{
50
51
52namespace df
53{
54  namespace program_options_lite
55  {
56    struct Options;
57   
58    struct ParseFailure : public std::exception
59    {
60      ParseFailure(std::string arg0, std::string val0) throw()
61      : arg(arg0), val(val0)
62      {}
63
64      ~ParseFailure() throw() {};
65
66      std::string arg;
67      std::string val;
68
69      const char* what() const throw() { return "Option Parse Failure"; }
70    };
71
72    void doHelp(std::ostream& out, Options& opts, unsigned columns = 80);
73    unsigned parseGNU(Options& opts, unsigned argc, const char* argv[]);
74    unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[]);
75    std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[]);
76    void scanLine(Options& opts, std::string& line);
77    void scanFile(Options& opts, std::istream& in);
78    void setDefaults(Options& opts);
79    void parseConfigFile(Options& opts, const std::string& filename);
80    bool storePair(Options& opts, const std::string& name, const std::string& value);
81   
82    /** OptionBase: Virtual base class for storing information relating to a
83     * specific option This base class describes common elements.  Type specific
84     * information should be stored in a derived class. */
85    struct OptionBase
86    {
87#if H_MV     
88      OptionBase(const std::string& name, const std::string& desc, bool duplicate = false)
89        : opt_string(name), opt_desc(desc), opt_duplicate(duplicate)
90#else
91      OptionBase(const std::string& name, const std::string& desc)
92      : opt_string(name), opt_desc(desc)
93#endif
94      {};
95     
96      virtual ~OptionBase() {}
97     
98      /* parse argument arg, to obtain a value for the option */
99      virtual void parse(const std::string& arg) = 0;
100      /* set the argument to the default value */
101      virtual void setDefault() = 0;
102     
103      std::string opt_string;
104      std::string opt_desc;
105#if H_MV
106      bool        opt_duplicate; 
107#endif
108    };
109   
110    /** Type specific option storage */
111    template<typename T>
112    struct Option : public OptionBase
113    {
114#if H_MV
115      Option(const std::string& name, T& storage, T default_val, const std::string& desc, bool duplicate = false)
116        : OptionBase(name, desc, duplicate), opt_storage(storage), opt_default_val(default_val)
117#else
118      Option(const std::string& name, T& storage, T default_val, const std::string& desc)
119      : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val)
120#endif
121      {}
122     
123      void parse(const std::string& arg);
124     
125      void setDefault()
126      {
127        opt_storage = opt_default_val;
128      }
129     
130      T& opt_storage;
131      T opt_default_val;
132    };
133   
134    /* Generic parsing */
135    template<typename T>
136    inline void
137    Option<T>::parse(const std::string& arg)
138    {
139      std::istringstream arg_ss (arg,std::istringstream::in);
140      arg_ss.exceptions(std::ios::failbit);
141      try
142      {
143        arg_ss >> opt_storage;
144      }
145      catch (...)
146      {
147        throw ParseFailure(opt_string, arg);
148      }
149    }
150   
151    /* string parsing is specialized -- copy the whole string, not just the
152     * first word */
153    template<>
154    inline void
155    Option<std::string>::parse(const std::string& arg)
156    {
157      opt_storage = arg;
158    }
159
160#if H_MV   
161    template<>
162    inline void
163      Option<char*>::parse(const std::string& arg)
164    {
165      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
166    }
167
168    template<>
169    inline void
170      Option< std::vector<char*> >::parse(const std::string& arg)
171    {
172      opt_storage.clear(); 
173
174      char* pcStart = (char*) arg.data();     
175      char* pcEnd = strtok (pcStart," ");
176
177      while (pcEnd != NULL)
178      {
179        size_t uiStringLength = pcEnd - pcStart;
180        char* pcNewStr = (char*) malloc( uiStringLength + 1 );
181        strncpy( pcNewStr, pcStart, uiStringLength); 
182        pcNewStr[uiStringLength] = '\0'; 
183        pcStart = pcEnd+1; 
184        pcEnd = strtok (NULL, " ,.-");
185        opt_storage.push_back( pcNewStr ); 
186      }     
187    }
188
189
190    template<>   
191    inline void
192      Option< std::vector<double> >::parse(const std::string& arg)
193    {
194      char* pcNextStart = (char*) arg.data();
195      char* pcEnd = pcNextStart + arg.length();
196
197      char* pcOldStart = 0; 
198
199      size_t iIdx = 0; 
200
201      while (pcNextStart < pcEnd)
202      {
203        errno = 0; 
204
205        if ( iIdx < opt_storage.size() )
206        {
207          opt_storage[iIdx] = strtod(pcNextStart, &pcNextStart);
208        }
209        else
210        {
211          opt_storage.push_back( strtod(pcNextStart, &pcNextStart)) ;
212        }
213        iIdx++; 
214
215        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
216        {
217          std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
218          exit(EXIT_FAILURE);   
219        };   
220        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
221        pcOldStart = pcNextStart; 
222
223      }
224    }
225
226    template<>
227    inline void
228      Option< std::vector<int> >::parse(const std::string& arg)
229    {
230      opt_storage.clear();
231
232
233      char* pcNextStart = (char*) arg.data();
234      char* pcEnd = pcNextStart + arg.length();
235
236      char* pcOldStart = 0; 
237
238      size_t iIdx = 0; 
239
240
241      while (pcNextStart < pcEnd)
242      {
243
244        if ( iIdx < opt_storage.size() )
245        {
246          opt_storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
247        }
248        else
249        {
250          opt_storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
251        }
252        iIdx++; 
253        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
254        {
255          std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
256          exit(EXIT_FAILURE);
257        };   
258        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
259        pcOldStart = pcNextStart;
260      }
261    }
262
263
264    template<>
265    inline void
266      Option< std::vector<bool> >::parse(const std::string& arg)
267    {
268      char* pcNextStart = (char*) arg.data();
269      char* pcEnd = pcNextStart + arg.length();
270
271      char* pcOldStart = 0; 
272
273      size_t iIdx = 0; 
274
275      while (pcNextStart < pcEnd)
276      {
277        if ( iIdx < opt_storage.size() )
278        {
279          opt_storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
280        }
281        else
282        {
283          opt_storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
284        }
285        iIdx++; 
286
287        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
288        {
289          std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
290          exit(EXIT_FAILURE);
291        };   
292        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
293        pcOldStart = pcNextStart;
294      }
295    }
296#endif
297    /** Option class for argument handling using a user provided function */
298    struct OptionFunc : public OptionBase
299    {
300      typedef void (Func)(Options&, const std::string&);
301     
302      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
303      : OptionBase(name, desc), parent(parent_), func(func_)
304      {}
305     
306      void parse(const std::string& arg)
307      {
308        func(parent, arg);
309      }
310     
311      void setDefault()
312      {
313        return;
314      }
315     
316    private:
317      Options& parent;
318      void (*func)(Options&, const std::string&);
319    };
320   
321    class OptionSpecific;
322    struct Options
323    {
324      ~Options();
325     
326      OptionSpecific addOptions();
327     
328      struct Names
329      {
330        Names() : opt(0) {};
331        ~Names()
332        {
333          if (opt)
334            delete opt;
335        }
336        std::list<std::string> opt_long;
337        std::list<std::string> opt_short;
338        OptionBase* opt;
339      };
340
341      void addOption(OptionBase *opt);
342     
343      typedef std::list<Names*> NamesPtrList;
344      NamesPtrList opt_list;
345     
346      typedef std::map<std::string, NamesPtrList> NamesMap;
347      NamesMap opt_long_map;
348      NamesMap opt_short_map;
349    };
350   
351    /* Class with templated overloaded operator(), for use by Options::addOptions() */
352    class OptionSpecific
353    {
354    public:
355      OptionSpecific(Options& parent_) : parent(parent_) {}
356     
357      /**
358       * Add option described by name to the parent Options list,
359       *   with storage for the option's value
360       *   with default_val as the default value
361       *   with desc as an optional help description
362       */
363      template<typename T>
364      OptionSpecific&
365      operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "")
366      {
367        parent.addOption(new Option<T>(name, storage, default_val, desc));
368        return *this;
369      }
370     
371#if H_MV
372      template<typename T>
373      OptionSpecific&
374        operator()(const std::string& name, std::vector<T>& storage, T default_val, unsigned uiMaxNum, const std::string& desc = "" )
375      {
376        std::string cNameBuffer;
377        std::string cDescBuffer;
378
379        cNameBuffer.resize( name.size() + 10 );
380        cDescBuffer.resize( desc.size() + 10 );
381
382        storage.resize(uiMaxNum);
383        for ( unsigned int uiK = 0; uiK < uiMaxNum; uiK++ )
384        {
385          Bool duplicate = (uiK != 0); 
386          // isn't there are sprintf function for string??
387          sprintf((char*) cNameBuffer.c_str(),name.c_str(),uiK,uiK);
388
389          if ( !duplicate )
390          {         
391            sprintf((char*) cDescBuffer.c_str(),desc.c_str(),uiK,uiK);
392          }
393
394          cNameBuffer.resize( std::strlen(cNameBuffer.c_str()) ); 
395          cDescBuffer.resize( std::strlen(cDescBuffer.c_str()) ); 
396         
397
398          parent.addOption(new Option<T>( cNameBuffer, (storage[uiK]), default_val, cDescBuffer, duplicate ));
399        }
400
401        return *this;
402      }
403#endif
404      /**
405       * Add option described by name to the parent Options list,
406       *   with desc as an optional help description
407       * instead of storing the value somewhere, a function of type
408       * OptionFunc::Func is called.  It is upto this function to correctly
409       * handle evaluating the option's value.
410       */
411      OptionSpecific&
412      operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
413      {
414        parent.addOption(new OptionFunc(name, parent, func, desc));
415        return *this;
416      }
417    private:
418      Options& parent;
419    };
420   
421  }; /* namespace: program_options_lite */
422}; /* namespace: df */
423
424//! \}
Note: See TracBrowser for help on using the repository browser.