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

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

Merged HTM-16.2-dev@1412

File size: 17.6 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-2017, 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/CommonDef.h"
39#if NH_MV
40#include <vector>
41#include <errno.h>
42#include <cstring>
43
44#ifdef WIN32
45#define strdup _strdup
46#endif
47#endif
48
49
50#ifndef __PROGRAM_OPTIONS_LITE__
51#define __PROGRAM_OPTIONS_LITE__
52
53//! \ingroup TAppCommon
54//! \{
55
56
57namespace df
58{
59  namespace program_options_lite
60  {
61    struct Options;
62
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
77    struct ErrorReporter
78    {
79#if NH_MV
80      ErrorReporter() : is_errored(0), output_on_unknow_parameter(true)  {}
81#else
82      ErrorReporter() : is_errored(0) {}
83#endif
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;
88#if NH_MV
89      bool output_on_unknow_parameter;
90#endif
91    };
92
93    extern ErrorReporter default_error_reporter;
94
95    void doHelp(std::ostream& out, Options& opts, unsigned columns = 80);
96    std::list<const char*> scanArgv(Options& opts, unsigned argc, const char* argv[], ErrorReporter& error_reporter = default_error_reporter);
97    void setDefaults(Options& opts);
98    void parseConfigFile(Options& opts, const std::string& filename, ErrorReporter& error_reporter = default_error_reporter);
99
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    {
105#if NH_MV     
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
109      OptionBase(const std::string& name, const std::string& desc)
110      : opt_string(name), opt_desc(desc)
111#endif
112      {};
113
114      virtual ~OptionBase() {}
115
116      /* parse argument arg, to obtain a value for the option */
117#if NH_MV
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
208      virtual void parse(const std::string& arg, ErrorReporter&) = 0;
209#endif
210      /* set the argument to the default value */
211      virtual void setDefault() = 0;
212
213      std::string opt_string;
214      std::string opt_desc;
215#if NH_MV
216      bool        opt_duplicate; 
217      std::vector<int> max_dim;
218#endif
219    };
220
221    /** Type specific option storage */
222    template<typename T>
223    struct Option : public OptionBase
224    {
225#if NH_MV
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
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)
231#endif
232      {}
233
234#if NH_MV
235      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&);
236#else
237      void parse(const std::string& arg, ErrorReporter&);
238#endif
239
240      void setDefault()
241      {
242        opt_storage = opt_default_val;
243      }
244
245      T& opt_storage;
246      T opt_default_val;
247    };
248
249    /* Generic parsing */
250    template<typename T>
251    inline void
252#if NH_MV
253    Option<T>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
254#else
255    Option<T>::parse(const std::string& arg, ErrorReporter&)
256#endif
257    {
258#if NH_MV
259      assert( idcs.size() == 0 ); 
260#endif
261     
262      std::istringstream arg_ss (arg,std::istringstream::in);
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      }
272    }
273
274    /* string parsing is specialized -- copy the whole string, not just the
275     * first word */
276    template<>
277    inline void
278#if NH_MV
279    Option<std::string>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
280    {
281      assert( idcs.size() == 0 ); 
282      opt_storage = arg;
283    }
284#else
285    Option<std::string>::parse(const std::string& arg, ErrorReporter&)
286    {
287      opt_storage = arg;
288    }
289#endif
290
291#if NH_MV   
292    template<>
293    inline void
294      Option<char*>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
295    {
296      assert( idcs.size() == 0 ); 
297      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
298    }
299
300    template<>   
301    inline void
302      Option< std::vector<double> >::parse(const std::string& arg, const std::vector< int > & idcs, ErrorReporter&)
303    {
304      assert( idcs.size() == 0 ); 
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
337
338    template<>
339    inline void
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    };
358
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; 
392        }
393    }
394
395
396    template<>
397    inline void
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    };
441#endif
442    /** Option class for argument handling using a user provided function */
443    struct OptionFunc : public OptionBase
444    {
445      typedef void (Func)(Options&, const std::string&, ErrorReporter&);
446
447      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
448      : OptionBase(name, desc), parent(parent_), func(func_)
449      {}
450
451#if NH_MV
452      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& error_reporter)
453#else
454      void parse(const std::string& arg, ErrorReporter& error_reporter)
455#endif
456      {
457        func(parent, arg, error_reporter);
458      }
459
460      void setDefault()
461      {
462        return;
463      }
464
465    private:
466      Options& parent;
467      Func* func;
468    };
469
470    class OptionSpecific;
471    struct Options
472    {
473      ~Options();
474
475      OptionSpecific addOptions();
476
477      struct Names
478      {
479        Names() : opt(0) {};
480        ~Names()
481        {
482          if (opt)
483          {
484            delete opt;
485          }
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);
493
494      typedef std::list<Names*> NamesPtrList;
495      NamesPtrList opt_list;
496
497      typedef std::map<std::string, NamesPtrList> NamesMap;
498      NamesMap opt_long_map;
499      NamesMap opt_short_map;
500    };
501
502    /* Class with templated overloaded operator(), for use by Options::addOptions() */
503    class OptionSpecific
504    {
505    public:
506      OptionSpecific(Options& parent_) : parent(parent_) {}
507
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      }
521
522#if NH_MV
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      {
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      }
554#endif
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
572  } /* namespace: program_options_lite */
573} /* namespace: df */
574
575//! \}
576
577#endif
Note: See TracBrowser for help on using the repository browser.