source: 3DVCSoftware/trunk/source/Lib/TAppCommon/program_options_lite.h @ 1417

Last change on this file since 1417 was 1413, checked in by tech, 7 years ago

Merged HTM-16.2-dev@1412

File size: 17.6 KB
RevLine 
[56]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
[1313]4 * granted under this license.
[56]5 *
[1413]6 * Copyright (c) 2010-2017, ITU/ISO/IEC
[56]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>
[1313]38#include  "../TLibCommon/CommonDef.h"
39#if NH_MV
[608]40#include <vector>
[56]41#include <errno.h>
42#include <cstring>
43
44#ifdef WIN32
45#define strdup _strdup
46#endif
[608]47#endif
[1313]48
49
50#ifndef __PROGRAM_OPTIONS_LITE__
51#define __PROGRAM_OPTIONS_LITE__
52
[56]53//! \ingroup TAppCommon
54//! \{
55
56
57namespace df
58{
59  namespace program_options_lite
60  {
61    struct Options;
[1313]62
[608]63    struct ParseFailure : public std::exception
64    {
65      ParseFailure(std::string arg0, std::string val0) throw()
66      : arg(arg0), val(val0)
67      {}
68
69      ~ParseFailure() throw() {};
70
71      std::string arg;
72      std::string val;
73
74      const char* what() const throw() { return "Option Parse Failure"; }
75    };
76
[1313]77    struct ErrorReporter
78    {
[1386]79#if NH_MV
[1356]80      ErrorReporter() : is_errored(0), output_on_unknow_parameter(true)  {}
81#else
[1313]82      ErrorReporter() : is_errored(0) {}
[1356]83#endif
[1313]84      virtual ~ErrorReporter() {}
85      virtual std::ostream& error(const std::string& where);
86      virtual std::ostream& warn(const std::string& where);
87      bool is_errored;
[1386]88#if NH_MV
[1356]89      bool output_on_unknow_parameter;
90#endif
[1313]91    };
92
93    extern ErrorReporter default_error_reporter;
94
[56]95    void doHelp(std::ostream& out, Options& opts, unsigned columns = 80);
[1313]96    std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[], ErrorReporter& error_reporter = default_error_reporter);
[56]97    void setDefaults(Options& opts);
[1313]98    void parseConfigFile(Options& opts, const std::string& filename, ErrorReporter& error_reporter = default_error_reporter);
99
[56]100    /** OptionBase: Virtual base class for storing information relating to a
101     * specific option This base class describes common elements.  Type specific
102     * information should be stored in a derived class. */
103    struct OptionBase
104    {
[1313]105#if NH_MV     
[1356]106      OptionBase(const std::string& name, const std::string& desc, bool duplicate = false, std::vector< int > maxdim = std::vector< int >(0) )
107        : opt_string(name), opt_desc(desc), opt_duplicate(duplicate), max_dim( maxdim )
108#else
[56]109      OptionBase(const std::string& name, const std::string& desc)
110      : opt_string(name), opt_desc(desc)
[608]111#endif
[56]112      {};
[1313]113
[56]114      virtual ~OptionBase() {}
[1313]115
[56]116      /* parse argument arg, to obtain a value for the option */
[1386]117#if NH_MV
[1356]118      virtual void parse(const std::string& arg, const std::vector<int>& idcs,  ErrorReporter&) = 0;
119     
120      bool   checkDim( std::vector< int > dims, ErrorReporter& err )
121      {     
122        bool doParsing = true; 
123        if ( dims.size() != max_dim.size() )
124        {
125            err.error(" ") << "Number of indices of `" <<  opt_string << "' not matching. Should be " << max_dim.size() << std::endl; 
126            doParsing = false; 
127        }
128
129        for (size_t i = 0 ; i < dims.size(); i++ )
130        {
131          if ( dims[i] >= max_dim[i] )
132          {
133            if (err.output_on_unknow_parameter )
134            {       
135              err.warn(" ") << "Index " << i  << " of  " <<  opt_string << " should be less than " << max_dim[i] << std::endl;             
136              doParsing = false; 
137            }
138          }
139        }
140        return doParsing; 
141      }
142
143      void   xParseVec( const std::string& arg, BoolAry1d& storage )
144      {       
145        char* pcNextStart = (char*) arg.data();
146        char* pcEnd = pcNextStart + arg.length();
147
148        char* pcOldStart = 0; 
149
150        size_t iIdx = 0; 
151
152        while (pcNextStart < pcEnd)
153        {
154          if ( iIdx < storage.size() )
155          {
156            storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
157          }
158          else
159          {
160            storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
161          }
162          iIdx++; 
163
164          if ( errno == ERANGE || (pcNextStart == pcOldStart) )
165          {
166            std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
167            exit(EXIT_FAILURE);
168          };   
169          while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
170          pcOldStart = pcNextStart;
171        }
172      }
173
174      void   xParseVec( const std::string& arg, IntAry1d& storage )
175      {       
176        storage.clear();
177
178        char* pcNextStart = (char*) arg.data();
179        char* pcEnd = pcNextStart + arg.length();
180
181        char* pcOldStart = 0; 
182
183        size_t iIdx = 0; 
184
185
186        while (pcNextStart < pcEnd)
187        {
188
189          if ( iIdx < storage.size() )
190          {
191            storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
192          }
193          else
194          {
195            storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
196          }
197          iIdx++; 
198          if ( errno == ERANGE || (pcNextStart == pcOldStart) )
199          {
200            std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
201            exit(EXIT_FAILURE);
202          };   
203          while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
204          pcOldStart = pcNextStart;
205        }     
206      }
207#else
[1313]208      virtual void parse(const std::string& arg, ErrorReporter&) = 0;
[1356]209#endif
[56]210      /* set the argument to the default value */
211      virtual void setDefault() = 0;
[1313]212
[56]213      std::string opt_string;
214      std::string opt_desc;
[1313]215#if NH_MV
[608]216      bool        opt_duplicate; 
[1356]217      std::vector<int> max_dim;
[608]218#endif
[56]219    };
[1313]220
[56]221    /** Type specific option storage */
222    template<typename T>
223    struct Option : public OptionBase
224    {
[1313]225#if NH_MV
[1356]226      Option(const std::string& name, T& storage, T default_val, const std::string& desc, bool duplicate = false, std::vector< int > maxdim = std::vector< int >(0) )
227        : OptionBase(name, desc, duplicate, maxdim), opt_storage(storage), opt_default_val(default_val)
228#else
[56]229      Option(const std::string& name, T& storage, T default_val, const std::string& desc)
230      : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val)
[608]231#endif
[56]232      {}
[1313]233
[1386]234#if NH_MV
[1356]235      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&);
236#else
[1313]237      void parse(const std::string& arg, ErrorReporter&);
[1356]238#endif
[1313]239
[56]240      void setDefault()
241      {
242        opt_storage = opt_default_val;
243      }
[1313]244
[56]245      T& opt_storage;
246      T opt_default_val;
247    };
[1313]248
[56]249    /* Generic parsing */
250    template<typename T>
251    inline void
[1386]252#if NH_MV
[1356]253    Option<T>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
254#else
[1313]255    Option<T>::parse(const std::string& arg, ErrorReporter&)
[1356]256#endif
[56]257    {
[1386]258#if NH_MV
[1356]259      assert( idcs.size() == 0 ); 
260#endif
261     
[56]262      std::istringstream arg_ss (arg,std::istringstream::in);
[608]263      arg_ss.exceptions(std::ios::failbit);
264      try
265      {
266        arg_ss >> opt_storage;
267      }
268      catch (...)
269      {
270        throw ParseFailure(opt_string, arg);
271      }
[56]272    }
[1313]273
[56]274    /* string parsing is specialized -- copy the whole string, not just the
275     * first word */
276    template<>
277    inline void
[1386]278#if NH_MV
[1356]279    Option<std::string>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
[1386]280    {
281      assert( idcs.size() == 0 ); 
282      opt_storage = arg;
283    }
[1356]284#else
[1313]285    Option<std::string>::parse(const std::string& arg, ErrorReporter&)
[56]286    {
287      opt_storage = arg;
288    }
[1386]289#endif
[608]290
[1313]291#if NH_MV   
[56]292    template<>
293    inline void
[1356]294      Option<char*>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
[56]295    {
[1356]296      assert( idcs.size() == 0 ); 
[56]297      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
298    }
299
300    template<>   
301    inline void
[1356]302      Option< std::vector<double> >::parse(const std::string& arg, const std::vector< int > & idcs, ErrorReporter&)
[56]303    {
[1356]304      assert( idcs.size() == 0 ); 
[56]305      char* pcNextStart = (char*) arg.data();
306      char* pcEnd = pcNextStart + arg.length();
307
308      char* pcOldStart = 0; 
309
310      size_t iIdx = 0; 
311
312      while (pcNextStart < pcEnd)
313      {
314        errno = 0; 
315
316        if ( iIdx < opt_storage.size() )
317        {
318          opt_storage[iIdx] = strtod(pcNextStart, &pcNextStart);
319        }
320        else
321        {
322          opt_storage.push_back( strtod(pcNextStart, &pcNextStart)) ;
323        }
324        iIdx++; 
325
326        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
327        {
328          std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
329          exit(EXIT_FAILURE);   
330        };   
331        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
332        pcOldStart = pcNextStart; 
333
334      }
335    }
336
[1356]337
[56]338    template<>
339    inline void
[1356]340      Option< IntAry1d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err)
341    {
342      xParseVec( arg, opt_storage );
343    };
344
345    template<>
346    inline void
347      Option< IntAry2d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
348    {
349      xParseVec( arg, opt_storage[ idcs[0] ] );
350    };
351
352    template<>
353    inline void
354      Option< IntAry3d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
355    {
356      xParseVec ( arg, opt_storage[ idcs[0] ][ idcs[1] ] );
357    };
[1386]358
[1356]359    template<>
360    inline void
361    Option< std::vector< std::vector<double> > >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
362    {
363        // xParseVec ( arg, opt_storage[ idcs[0] ] );
364        char* pcNextStart = (char*) arg.data();
365        char* pcEnd = pcNextStart + arg.length();
366
367        char* pcOldStart = 0; 
368
369        size_t iIdx = 0; 
370
371        while (pcNextStart < pcEnd)
372        {
373            errno = 0; 
374
375            if ( iIdx < opt_storage[idcs[0]].size() )
376            {
377                opt_storage[idcs[0]][iIdx] = strtod(pcNextStart, &pcNextStart);
378            }
379            else
380            {
381                opt_storage[idcs[0]].push_back( strtod(pcNextStart, &pcNextStart)) ;
382            }
383            iIdx++; 
384
385            if ( errno == ERANGE || (pcNextStart == pcOldStart) )
386            {
387                std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
388                exit(EXIT_FAILURE);   
389            };   
390            while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
391            pcOldStart = pcNextStart; 
[56]392        }
393    }
394
395
396    template<>
397    inline void
[1356]398      Option< StringAry1d  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
399    {
400
401      opt_storage[ idcs[ 0 ] ] = arg;
402    };
403
404    template<>
405    inline void
406      Option< StringAry2d  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
407    {
408
409      opt_storage[idcs[0]][idcs[1]] = arg;
410    };
411
412
413    template<>
414    inline void
415      Option< std::vector< char*>  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
416    {
417     
418      opt_storage[ idcs[ 0 ] ] = arg.empty() ? NULL : strdup(arg.c_str()) ;
419    };
420
421    template<>
422    inline void
423      Option< BoolAry1d >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err)
424    {     
425      xParseVec( arg, opt_storage );
426    };
427
428    template<>
429    inline void
430      Option< BoolAry2d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err)
431    {     
432      xParseVec( arg, opt_storage[ idcs[0] ] );
433    };
434
435    template<>
436    inline void
437      Option< BoolAry3d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err )
438    {     
439      xParseVec( arg, opt_storage[idcs[0]][idcs[1]] );
440    };
[608]441#endif
[56]442    /** Option class for argument handling using a user provided function */
443    struct OptionFunc : public OptionBase
444    {
[1313]445      typedef void (Func)(Options&, const std::string&, ErrorReporter&);
446
[56]447      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
448      : OptionBase(name, desc), parent(parent_), func(func_)
449      {}
[1313]450
[1386]451#if NH_MV
[1356]452      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& error_reporter)
453#else
[1313]454      void parse(const std::string& arg, ErrorReporter& error_reporter)
[1356]455#endif
[56]456      {
[1313]457        func(parent, arg, error_reporter);
[56]458      }
[1313]459
[56]460      void setDefault()
461      {
462        return;
463      }
[1313]464
[56]465    private:
466      Options& parent;
[1313]467      Func* func;
[56]468    };
[1313]469
[56]470    class OptionSpecific;
471    struct Options
472    {
473      ~Options();
[1313]474
[56]475      OptionSpecific addOptions();
[1313]476
[56]477      struct Names
478      {
479        Names() : opt(0) {};
480        ~Names()
481        {
482          if (opt)
[1313]483          {
[56]484            delete opt;
[1313]485          }
[56]486        }
487        std::list<std::string> opt_long;
488        std::list<std::string> opt_short;
489        OptionBase* opt;
490      };
491
492      void addOption(OptionBase *opt);
[1313]493
[56]494      typedef std::list<Names*> NamesPtrList;
495      NamesPtrList opt_list;
[1313]496
[56]497      typedef std::map<std::string, NamesPtrList> NamesMap;
498      NamesMap opt_long_map;
499      NamesMap opt_short_map;
500    };
[1313]501
[56]502    /* Class with templated overloaded operator(), for use by Options::addOptions() */
503    class OptionSpecific
504    {
505    public:
506      OptionSpecific(Options& parent_) : parent(parent_) {}
[1313]507
[56]508      /**
509       * Add option described by name to the parent Options list,
510       *   with storage for the option's value
511       *   with default_val as the default value
512       *   with desc as an optional help description
513       */
514      template<typename T>
515      OptionSpecific&
516      operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "")
517      {
518        parent.addOption(new Option<T>(name, storage, default_val, desc));
519        return *this;
520      }
[1313]521
522#if NH_MV
[56]523      template<typename T>
524      OptionSpecific&
525        operator()(const std::string& name, std::vector<T>& storage, T default_val, unsigned uiMaxNum, const std::string& desc = "" )
526      {
[1356]527        std::vector<T> defVal;
528        defVal.resize( uiMaxNum, default_val ); 
529        std::vector< int > maxSize; 
530        maxSize.push_back( uiMaxNum ); 
531        parent.addOption(new Option< std::vector<T> >( name, storage, defVal, desc, false, maxSize ));
532
533        return *this;
534      }
535
536      template<typename T>
537      OptionSpecific&
538        operator()(const std::string& name, std::vector< std::vector<T> >& storage, T default_val, unsigned uiMaxNumDim1, unsigned uiMaxNumDim2, const std::string& desc = "" )
539      {
540        std::vector< std::vector<T> > defVal;
541        defVal.resize(uiMaxNumDim1);
542        for ( unsigned int idxDim1 = 0; idxDim1 < uiMaxNumDim1; idxDim1++ )
543        {
544          defVal[ idxDim1 ].resize(uiMaxNumDim2, default_val );         
545        }
546
547        std::vector< int > maxSize; 
548        maxSize.push_back( uiMaxNumDim1 ); 
549        maxSize.push_back( uiMaxNumDim2 ); 
550
551        parent.addOption(new Option< std::vector< std::vector<T> > >( name, storage, defVal, desc, false, maxSize ));
552        return *this;
553      }
[608]554#endif
[56]555      /**
556       * Add option described by name to the parent Options list,
557       *   with desc as an optional help description
558       * instead of storing the value somewhere, a function of type
559       * OptionFunc::Func is called.  It is upto this function to correctly
560       * handle evaluating the option's value.
561       */
562      OptionSpecific&
563      operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
564      {
565        parent.addOption(new OptionFunc(name, parent, func, desc));
566        return *this;
567      }
568    private:
569      Options& parent;
570    };
571
[1313]572  } /* namespace: program_options_lite */
573} /* namespace: df */
574
[56]575//! \}
[1313]576
577#endif
Note: See TracBrowser for help on using the repository browser.