source: 3DVCSoftware/branches/HTM-15.2-dev/source/Lib/TAppCommon/program_options_lite.h @ 1362

Last change on this file since 1362 was 1362, checked in by tech, 9 years ago

Align macros

File size: 21.9 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-2015, 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_SEI
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_SEI
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#if NH_MV_SEI     
107      OptionBase(const std::string& name, const std::string& desc, bool duplicate = false, std::vector< int > maxdim = std::vector< int >(0) )
108        : opt_string(name), opt_desc(desc), opt_duplicate(duplicate), max_dim( maxdim )
109#else
110      OptionBase(const std::string& name, const std::string& desc, bool duplicate = false)
111        : opt_string(name), opt_desc(desc), opt_duplicate(duplicate)
112#endif
113#else
114      OptionBase(const std::string& name, const std::string& desc)
115      : opt_string(name), opt_desc(desc)
116#endif
117      {};
118
119      virtual ~OptionBase() {}
120
121      /* parse argument arg, to obtain a value for the option */
122#if NH_MV_SEI
123      virtual void parse(const std::string& arg, const std::vector<int>& idcs,  ErrorReporter&) = 0;
124     
125      bool   checkDim( std::vector< int > dims, ErrorReporter& err )
126      {     
127        bool doParsing = true; 
128        if ( dims.size() != max_dim.size() )
129        {
130            err.error(" ") << "Number of indices of `" <<  opt_string << "' not matching. Should be " << max_dim.size() << std::endl; 
131            doParsing = false; 
132        }
133
134        for (size_t i = 0 ; i < dims.size(); i++ )
135        {
136          if ( dims[i] >= max_dim[i] )
137          {
138            if (err.output_on_unknow_parameter )
139            {       
140              err.warn(" ") << "Index " << i  << " of  " <<  opt_string << " should be less than " << max_dim[i] << std::endl;             
141              doParsing = false; 
142            }
143          }
144        }
145        return doParsing; 
146      }
147
148      void   xParseVec( const std::string& arg, BoolAry1d& storage )
149      {       
150        char* pcNextStart = (char*) arg.data();
151        char* pcEnd = pcNextStart + arg.length();
152
153        char* pcOldStart = 0; 
154
155        size_t iIdx = 0; 
156
157        while (pcNextStart < pcEnd)
158        {
159          if ( iIdx < storage.size() )
160          {
161            storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
162          }
163          else
164          {
165            storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
166          }
167          iIdx++; 
168
169          if ( errno == ERANGE || (pcNextStart == pcOldStart) )
170          {
171            std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
172            exit(EXIT_FAILURE);
173          };   
174          while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
175          pcOldStart = pcNextStart;
176        }
177      }
178
179      void   xParseVec( const std::string& arg, IntAry1d& storage )
180      {       
181        storage.clear();
182
183        char* pcNextStart = (char*) arg.data();
184        char* pcEnd = pcNextStart + arg.length();
185
186        char* pcOldStart = 0; 
187
188        size_t iIdx = 0; 
189
190
191        while (pcNextStart < pcEnd)
192        {
193
194          if ( iIdx < storage.size() )
195          {
196            storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
197          }
198          else
199          {
200            storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
201          }
202          iIdx++; 
203          if ( errno == ERANGE || (pcNextStart == pcOldStart) )
204          {
205            std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
206            exit(EXIT_FAILURE);
207          };   
208          while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
209          pcOldStart = pcNextStart;
210        }     
211      }
212#else
213      virtual void parse(const std::string& arg, ErrorReporter&) = 0;
214#endif
215      /* set the argument to the default value */
216      virtual void setDefault() = 0;
217
218      std::string opt_string;
219      std::string opt_desc;
220#if NH_MV
221      bool        opt_duplicate; 
222#if NH_MV_SEI
223      std::vector<int> max_dim;
224#endif
225#endif
226    };
227
228    /** Type specific option storage */
229    template<typename T>
230    struct Option : public OptionBase
231    {
232#if NH_MV
233#if NH_MV_SEI
234      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) )
235        : OptionBase(name, desc, duplicate, maxdim), opt_storage(storage), opt_default_val(default_val)
236#else
237      Option(const std::string& name, T& storage, T default_val, const std::string& desc, bool duplicate = false)
238        : OptionBase(name, desc, duplicate), opt_storage(storage), opt_default_val(default_val)
239#endif
240#else
241      Option(const std::string& name, T& storage, T default_val, const std::string& desc)
242      : OptionBase(name, desc), opt_storage(storage), opt_default_val(default_val)
243#endif
244      {}
245
246#if NH_MV_SEI
247      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&);
248#else
249      void parse(const std::string& arg, ErrorReporter&);
250#endif
251
252      void setDefault()
253      {
254        opt_storage = opt_default_val;
255      }
256
257      T& opt_storage;
258      T opt_default_val;
259    };
260
261    /* Generic parsing */
262    template<typename T>
263    inline void
264#if NH_MV_SEI
265    Option<T>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
266#else
267    Option<T>::parse(const std::string& arg, ErrorReporter&)
268#endif
269    {
270#if NH_MV_SEI
271      assert( idcs.size() == 0 ); 
272#endif
273     
274      std::istringstream arg_ss (arg,std::istringstream::in);
275      arg_ss.exceptions(std::ios::failbit);
276      try
277      {
278        arg_ss >> opt_storage;
279      }
280      catch (...)
281      {
282        throw ParseFailure(opt_string, arg);
283      }
284    }
285
286    /* string parsing is specialized -- copy the whole string, not just the
287     * first word */
288    template<>
289    inline void
290#if NH_MV_SEI
291    Option<std::string>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
292#else
293    Option<std::string>::parse(const std::string& arg, ErrorReporter&)
294#endif
295    {
296#if NH_MV_SEI
297      assert( idcs.size() == 0 ); 
298#endif
299      opt_storage = arg;
300    }
301
302#if NH_MV   
303    template<>
304    inline void
305#if NH_MV_SEI
306      Option<char*>::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter&)
307#else
308      Option<char*>::parse(const std::string& arg, ErrorReporter&)
309#endif
310    {
311#if NH_MV_SEI
312      assert( idcs.size() == 0 ); 
313#endif
314      opt_storage = arg.empty() ? NULL : strdup(arg.c_str()) ;
315    }
316
317#if !NH_MV_SEI
318
319    template<>
320    inline void
321      Option< std::vector<char*> >::parse(const std::string& arg, ErrorReporter&)
322    {
323      opt_storage.clear(); 
324
325      char* pcStart = (char*) arg.data();     
326      char* pcEnd = strtok (pcStart," ");
327
328      while (pcEnd != NULL)
329      {
330        size_t uiStringLength = pcEnd - pcStart;
331        char* pcNewStr = (char*) malloc( uiStringLength + 1 );
332        strncpy( pcNewStr, pcStart, uiStringLength); 
333        pcNewStr[uiStringLength] = '\0'; 
334        pcStart = pcEnd+1; 
335        pcEnd = strtok (NULL, " ,.-");
336        opt_storage.push_back( pcNewStr ); 
337      }     
338    }
339#endif
340
341    template<>   
342    inline void
343#if NH_MV_SEI
344      Option< std::vector<double> >::parse(const std::string& arg, const std::vector< int > & idcs, ErrorReporter&)
345#else
346      Option< std::vector<double> >::parse(const std::string& arg, ErrorReporter&)
347#endif
348    {
349#if NH_MV_SEI
350      assert( idcs.size() == 0 ); 
351#endif
352      char* pcNextStart = (char*) arg.data();
353      char* pcEnd = pcNextStart + arg.length();
354
355      char* pcOldStart = 0; 
356
357      size_t iIdx = 0; 
358
359      while (pcNextStart < pcEnd)
360      {
361        errno = 0; 
362
363        if ( iIdx < opt_storage.size() )
364        {
365          opt_storage[iIdx] = strtod(pcNextStart, &pcNextStart);
366        }
367        else
368        {
369          opt_storage.push_back( strtod(pcNextStart, &pcNextStart)) ;
370        }
371        iIdx++; 
372
373        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
374        {
375          std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
376          exit(EXIT_FAILURE);   
377        };   
378        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
379        pcOldStart = pcNextStart; 
380
381      }
382    }
383
384
385#if NH_MV_SEI
386    template<>
387    inline void
388      Option< IntAry1d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err)
389    {
390      xParseVec( arg, opt_storage );
391    };
392
393    template<>
394    inline void
395      Option< IntAry2d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
396    {
397      xParseVec( arg, opt_storage[ idcs[0] ] );
398    };
399
400    template<>
401    inline void
402      Option< IntAry3d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
403    {
404      xParseVec ( arg, opt_storage[ idcs[0] ][ idcs[1] ] );
405    };
406#if SEI_DRI_F0169
407    template<>
408    inline void
409    Option< std::vector< std::vector<double> > >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter&)
410    {
411        // xParseVec ( arg, opt_storage[ idcs[0] ] );
412        char* pcNextStart = (char*) arg.data();
413        char* pcEnd = pcNextStart + arg.length();
414
415        char* pcOldStart = 0; 
416
417        size_t iIdx = 0; 
418
419        while (pcNextStart < pcEnd)
420        {
421            errno = 0; 
422
423            if ( iIdx < opt_storage[idcs[0]].size() )
424            {
425                opt_storage[idcs[0]][iIdx] = strtod(pcNextStart, &pcNextStart);
426            }
427            else
428            {
429                opt_storage[idcs[0]].push_back( strtod(pcNextStart, &pcNextStart)) ;
430            }
431            iIdx++; 
432
433            if ( errno == ERANGE || (pcNextStart == pcOldStart) )
434            {
435                std::cerr << "Error Parsing Doubles: `" << arg << "'" << std::endl;
436                exit(EXIT_FAILURE);   
437            };   
438            while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
439            pcOldStart = pcNextStart; 
440
441        }       
442
443
444    }
445#endif
446#else
447    template<>
448    inline void
449      Option< std::vector<int> >::parse(const std::string& arg, ErrorReporter&)
450    {
451      opt_storage.clear();
452
453
454      char* pcNextStart = (char*) arg.data();
455      char* pcEnd = pcNextStart + arg.length();
456
457      char* pcOldStart = 0; 
458
459      size_t iIdx = 0; 
460
461
462      while (pcNextStart < pcEnd)
463      {
464
465        if ( iIdx < opt_storage.size() )
466        {
467          opt_storage[iIdx] = (int) strtol(pcNextStart, &pcNextStart,10);
468        }
469        else
470        {
471          opt_storage.push_back( (int) strtol(pcNextStart, &pcNextStart,10)) ;
472        }
473        iIdx++; 
474        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
475        {
476          std::cerr << "Error Parsing Integers: `" << arg << "'" << std::endl;
477          exit(EXIT_FAILURE);
478        };   
479        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
480        pcOldStart = pcNextStart;
481      }
482    }
483#endif
484
485#if NH_MV_SEI
486
487    template<>
488    inline void
489      Option< StringAry1d  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
490    {
491
492      opt_storage[ idcs[ 0 ] ] = arg;
493    };
494
495    template<>
496    inline void
497      Option< StringAry2d  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
498    {
499
500      opt_storage[idcs[0]][idcs[1]] = arg;
501    };
502
503
504    template<>
505    inline void
506      Option< std::vector< char*>  >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err )
507    {
508     
509      opt_storage[ idcs[ 0 ] ] = arg.empty() ? NULL : strdup(arg.c_str()) ;
510    };
511
512    template<>
513    inline void
514      Option< BoolAry1d >::parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& err)
515    {     
516      xParseVec( arg, opt_storage );
517    };
518
519    template<>
520    inline void
521      Option< BoolAry2d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err)
522    {     
523      xParseVec( arg, opt_storage[ idcs[0] ] );
524    };
525
526    template<>
527    inline void
528      Option< BoolAry3d >::parse(const std::string& arg, const IntAry1d& idcs, ErrorReporter& err )
529    {     
530      xParseVec( arg, opt_storage[idcs[0]][idcs[1]] );
531    };
532#else
533    template<>
534    inline void
535      Option< std::vector<bool> >::parse(const std::string& arg, ErrorReporter&)
536    {
537      char* pcNextStart = (char*) arg.data();
538      char* pcEnd = pcNextStart + arg.length();
539
540      char* pcOldStart = 0; 
541
542      size_t iIdx = 0; 
543
544      while (pcNextStart < pcEnd)
545      {
546        if ( iIdx < opt_storage.size() )
547        {
548          opt_storage[iIdx] = (strtol(pcNextStart, &pcNextStart,10) != 0);
549        }
550        else
551        {
552          opt_storage.push_back(strtol(pcNextStart, &pcNextStart,10) != 0) ;
553        }
554        iIdx++; 
555
556        if ( errno == ERANGE || (pcNextStart == pcOldStart) )
557        {
558          std::cerr << "Error Parsing Bools: `" << arg << "'" << std::endl;
559          exit(EXIT_FAILURE);
560        };   
561        while( (pcNextStart < pcEnd) && ( *pcNextStart == ' ' || *pcNextStart == '\t' || *pcNextStart == '\r' ) ) pcNextStart++; 
562        pcOldStart = pcNextStart;
563      }
564    }
565#endif
566#endif
567    /** Option class for argument handling using a user provided function */
568    struct OptionFunc : public OptionBase
569    {
570      typedef void (Func)(Options&, const std::string&, ErrorReporter&);
571
572      OptionFunc(const std::string& name, Options& parent_, Func *func_, const std::string& desc)
573      : OptionBase(name, desc), parent(parent_), func(func_)
574      {}
575
576#if NH_MV_SEI
577      void parse(const std::string& arg, const std::vector<int>& idcs, ErrorReporter& error_reporter)
578#else
579      void parse(const std::string& arg, ErrorReporter& error_reporter)
580#endif
581      {
582        func(parent, arg, error_reporter);
583      }
584
585      void setDefault()
586      {
587        return;
588      }
589
590    private:
591      Options& parent;
592      Func* func;
593    };
594
595    class OptionSpecific;
596    struct Options
597    {
598      ~Options();
599
600      OptionSpecific addOptions();
601
602      struct Names
603      {
604        Names() : opt(0) {};
605        ~Names()
606        {
607          if (opt)
608          {
609            delete opt;
610          }
611        }
612        std::list<std::string> opt_long;
613        std::list<std::string> opt_short;
614        OptionBase* opt;
615      };
616
617      void addOption(OptionBase *opt);
618
619      typedef std::list<Names*> NamesPtrList;
620      NamesPtrList opt_list;
621
622      typedef std::map<std::string, NamesPtrList> NamesMap;
623      NamesMap opt_long_map;
624      NamesMap opt_short_map;
625    };
626
627    /* Class with templated overloaded operator(), for use by Options::addOptions() */
628    class OptionSpecific
629    {
630    public:
631      OptionSpecific(Options& parent_) : parent(parent_) {}
632
633      /**
634       * Add option described by name to the parent Options list,
635       *   with storage for the option's value
636       *   with default_val as the default value
637       *   with desc as an optional help description
638       */
639      template<typename T>
640      OptionSpecific&
641      operator()(const std::string& name, T& storage, T default_val, const std::string& desc = "")
642      {
643        parent.addOption(new Option<T>(name, storage, default_val, desc));
644        return *this;
645      }
646
647#if NH_MV
648      template<typename T>
649      OptionSpecific&
650        operator()(const std::string& name, std::vector<T>& storage, T default_val, unsigned uiMaxNum, const std::string& desc = "" )
651      {
652#if NH_MV_SEI
653        std::vector<T> defVal;
654        defVal.resize( uiMaxNum, default_val ); 
655        std::vector< int > maxSize; 
656        maxSize.push_back( uiMaxNum ); 
657        parent.addOption(new Option< std::vector<T> >( name, storage, defVal, desc, false, maxSize ));
658
659        return *this;
660      }
661
662      template<typename T>
663      OptionSpecific&
664        operator()(const std::string& name, std::vector< std::vector<T> >& storage, T default_val, unsigned uiMaxNumDim1, unsigned uiMaxNumDim2, const std::string& desc = "" )
665      {
666        std::vector< std::vector<T> > defVal;
667        defVal.resize(uiMaxNumDim1);
668        for ( unsigned int idxDim1 = 0; idxDim1 < uiMaxNumDim1; idxDim1++ )
669        {
670          defVal[ idxDim1 ].resize(uiMaxNumDim2, default_val );         
671        }
672
673        std::vector< int > maxSize; 
674        maxSize.push_back( uiMaxNumDim1 ); 
675        maxSize.push_back( uiMaxNumDim2 ); 
676
677        parent.addOption(new Option< std::vector< std::vector<T> > >( name, storage, defVal, desc, false, maxSize ));
678        return *this;
679      }
680#else
681        std::string cNameBuffer;
682        std::string cDescBuffer;
683
684        storage.resize(uiMaxNum);
685        for ( unsigned int uiK = 0; uiK < uiMaxNum; uiK++ )
686        {
687          cNameBuffer       .resize( name.size() + 10 );
688          cDescBuffer.resize( desc.size() + 10 );
689
690          Bool duplicate = (uiK != 0); 
691          // isn't there are sprintf function for string??
692          sprintf((char*) cNameBuffer.c_str()       ,name.c_str(),uiK,uiK);
693
694          if ( !duplicate )
695          {         
696            sprintf((char*) cDescBuffer.c_str(),desc.c_str(),uiK,uiK);
697          }
698
699          cNameBuffer.resize( std::strlen(cNameBuffer.c_str()) ); 
700          cDescBuffer.resize( std::strlen(cDescBuffer.c_str()) ); 
701         
702
703          parent.addOption(new Option<T>( cNameBuffer, (storage[uiK]), default_val, cDescBuffer, duplicate ));
704        }
705
706        return *this;
707      }
708#endif
709#endif
710      /**
711       * Add option described by name to the parent Options list,
712       *   with desc as an optional help description
713       * instead of storing the value somewhere, a function of type
714       * OptionFunc::Func is called.  It is upto this function to correctly
715       * handle evaluating the option's value.
716       */
717      OptionSpecific&
718      operator()(const std::string& name, OptionFunc::Func *func, const std::string& desc = "")
719      {
720        parent.addOption(new OptionFunc(name, parent, func, desc));
721        return *this;
722      }
723    private:
724      Options& parent;
725    };
726
727  } /* namespace: program_options_lite */
728} /* namespace: df */
729
730//! \}
731
732#endif
Note: See TracBrowser for help on using the repository browser.