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

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

Merged 14.1-update-dev1@1312.

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