gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
ArgParser can throw exception instead of exit(1) (#332)
0 3 0
default
3 files changed with 72 insertions and 7 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
... ...
@@ -56,27 +56,36 @@
56 56
  // Bundle -gr* options into a group
57 57
  ap.optionGroup("gr", "gra")
58 58
    .optionGroup("gr", "grb")
59 59
    .optionGroup("gr", "grc");
60 60
  // Set the group mandatory
61 61
  ap.mandatoryGroup("gr");
62 62
  // Set the options of the group exclusive (only one option can be given)
63 63
  ap.onlyOneGroup("gr");
64 64
  // Add non-parsed arguments (e.g. input files)
65 65
  ap.other("infile", "The input file.")
66 66
    .other("...");
67 67

	
68
  // Throw an exception when problems occurs. The default behavior is to
69
  // exit(1) on these cases, but this makes Valgrind falsely warn
70
  // about memory leaks.
71
  ap.throwOnProblems();
72
  
68 73
  // Perform the parsing process
69 74
  // (in case of any error it terminates the program)
70
  ap.parse();
75
  // The try {} construct is necessary only if the ap.trowOnProblems()
76
  // setting is in use.
77
  try {
78
    ap.parse();
79
  } catch (ArgParserException &) { return 1; }
71 80

	
72 81
  // Check each option if it has been given and print its value
73 82
  std::cout << "Parameters of '" << ap.commandName() << "':\n";
74 83

	
75 84
  std::cout << "  Value of -n: " << i << std::endl;
76 85
  if(ap.given("val")) std::cout << "  Value of -val: " << d << std::endl;
77 86
  if(ap.given("val2")) {
78 87
    d = ap["val2"];
79 88
    std::cout << "  Value of -val2: " << d << std::endl;
80 89
  }
81 90
  if(ap.given("name")) std::cout << "  Value of -name: " << s << std::endl;
82 91
  if(ap.given("f")) std::cout << "  -f is given\n";
Ignore white space 6 line context
... ...
@@ -11,32 +11,41 @@
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#include <lemon/arg_parser.h>
20 20

	
21 21
namespace lemon {
22 22

	
23
  void ArgParser::_terminate(ArgParserException::Reason reason) const
24
  {
25
    if(_exit_on_problems)
26
      exit(1);
27
    else throw(ArgParserException(reason));
28
  }
29
  
30
  
23 31
  void ArgParser::_showHelp(void *p)
24 32
  {
25 33
    (static_cast<ArgParser*>(p))->showHelp();
26
    exit(1);
34
    (static_cast<ArgParser*>(p))->_terminate(ArgParserException::HELP);
27 35
  }
28 36

	
29 37
  ArgParser::ArgParser(int argc, const char * const *argv)
30
    :_argc(argc), _argv(argv), _command_name(argv[0]) {
38
    :_argc(argc), _argv(argv), _command_name(argv[0]),
39
    _exit_on_problems(true) {
31 40
    funcOption("-help","Print a short help message",_showHelp,this);
32 41
    synonym("help","-help");
33 42
    synonym("h","-help");
34 43
  }
35 44

	
36 45
  ArgParser::~ArgParser()
37 46
  {
38 47
    for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
39 48
      if(i->second.self_delete)
40 49
        switch(i->second.type) {
41 50
        case BOOL:
42 51
          delete i->second.bool_p;
... ...
@@ -333,34 +342,34 @@
333 342
        pos+=cstr.str().size();
334 343
      }
335 344
    std::cerr << std::endl;
336 345
  }
337 346

	
338 347
  void ArgParser::showHelp() const
339 348
  {
340 349
    shortHelp();
341 350
    std::cerr << "Where:\n";
342 351
    for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
343 352
        i!=_others_help.end();++i) showHelp(i);
344 353
    for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
345
    exit(1);
354
    _terminate(ArgParserException::HELP);
346 355
  }
347 356

	
348 357

	
349 358
  void ArgParser::unknownOpt(std::string arg) const
350 359
  {
351 360
    std::cerr << "\nUnknown option: " << arg << "\n";
352 361
    std::cerr << "\nType '" << _command_name <<
353 362
      " --help' to obtain a short summary on the usage.\n\n";
354
    exit(1);
363
    _terminate(ArgParserException::UNKNOWN_OPT);
355 364
  }
356 365

	
357 366
  void ArgParser::requiresValue(std::string arg, OptType t) const
358 367
  {
359 368
    std::cerr << "Argument '" << arg << "' requires a";
360 369
    switch(t) {
361 370
    case STRING:
362 371
      std::cerr << " string";
363 372
      break;
364 373
    case INTEGER:
365 374
      std::cerr << "n integer";
366 375
      break;
... ...
@@ -405,25 +414,25 @@
405 414
          if(i->second.only_one&&set>1) {
406 415
            std::cerr << _command_name <<
407 416
              ": At most one of the following arguments can be given.\n";
408 417
            ok=false;
409 418
            for(GroupData::Opts::const_iterator o=i->second.opts.begin();
410 419
                o!=i->second.opts.end();++o)
411 420
              showHelp(_opts.find(*o));
412 421
          }
413 422
        }
414 423
    if(!ok) {
415 424
      std::cerr << "\nType '" << _command_name <<
416 425
        " --help' to obtain a short summary on the usage.\n\n";
417
      exit(1);
426
      _terminate(ArgParserException::INVALID_OPT);
418 427
    }
419 428
  }
420 429

	
421 430
  ArgParser &ArgParser::parse()
422 431
  {
423 432
    for(int ar=1; ar<_argc; ++ar) {
424 433
      std::string arg(_argv[ar]);
425 434
      if (arg[0] != '-' || arg.size() == 1) {
426 435
        _file_args.push_back(arg);
427 436
      }
428 437
      else {
429 438
        Opts::iterator i = _opts.find(arg.substr(1));
Ignore white space 24 line context
... ...
@@ -25,24 +25,62 @@
25 25
#include <string>
26 26
#include <iostream>
27 27
#include <sstream>
28 28
#include <algorithm>
29 29
#include <lemon/assert.h>
30 30

	
31 31
///\ingroup misc
32 32
///\file
33 33
///\brief A tool to parse command line arguments.
34 34

	
35 35
namespace lemon {
36 36

	
37
  ///Exception used by ArgParser
38
  class ArgParserException : public Exception {
39
  public:
40
    enum Reason {
41
      HELP,         /// <tt>--help</tt> option was given
42
      UNKNOWN_OPT,  /// Unknown option was given
43
      INVALID_OPT   /// Invalid combination of options
44
    };
45
    
46
  private:
47
    Reason _reason;
48
    
49
  public:
50
    ///Constructor
51
    ArgParserException(Reason r) throw() : _reason(r) {}
52
    ///Virtual destructor
53
    virtual ~ArgParserException() throw() {}
54
    ///A short description of the exception
55
    virtual const char* what() const throw() {
56
      switch(_reason)
57
        {
58
        case HELP:
59
          return "lemon::ArgParseException: ask for help";
60
          break;
61
        case UNKNOWN_OPT:
62
          return "lemon::ArgParseException: unknown option";
63
          break;
64
        case INVALID_OPT:
65
          return "lemon::ArgParseException: invalid combination of options";
66
          break;
67
        }
68
      return "";
69
    }
70
    ///Return the reason for the failure
71
    Reason reason() const {return _reason; }
72
  };
73

	
74

	
37 75
  ///Command line arguments parser
38 76

	
39 77
  ///\ingroup misc
40 78
  ///Command line arguments parser.
41 79
  ///
42 80
  ///For a complete example see the \ref arg_parser_demo.cc demo file.
43 81
  class ArgParser {
44 82

	
45 83
    static void _showHelp(void *p);
46 84
  protected:
47 85

	
48 86
    int _argc;
... ...
@@ -94,37 +132,41 @@
94 132
    struct OtherArg
95 133
    {
96 134
      std::string name;
97 135
      std::string help;
98 136
      OtherArg(std::string n, std::string h) :name(n), help(h) {}
99 137

	
100 138
    };
101 139

	
102 140
    std::vector<OtherArg> _others_help;
103 141
    std::vector<std::string> _file_args;
104 142
    std::string _command_name;
105 143

	
106

	
144
    
107 145
  private:
108 146
    //Bind a function to an option.
109 147

	
110 148
    //\param name The name of the option. The leading '-' must be omitted.
111 149
    //\param help A help string.
112 150
    //\retval func The function to be called when the option is given. It
113 151
    //  must be of type "void f(void *)"
114 152
    //\param data Data to be passed to \c func
115 153
    ArgParser &funcOption(const std::string &name,
116 154
                    const std::string &help,
117 155
                    void (*func)(void *),void *data);
118 156

	
157
    bool _exit_on_problems;
158
    
159
    void _terminate(ArgParserException::Reason reason) const;
160

	
119 161
  public:
120 162

	
121 163
    ///Constructor
122 164
    ArgParser(int argc, const char * const *argv);
123 165

	
124 166
    ~ArgParser();
125 167

	
126 168
    ///\name Options
127 169
    ///
128 170

	
129 171
    ///@{
130 172

	
... ...
@@ -371,16 +413,21 @@
371 413
    ///\sa RefType
372 414
    RefType operator[](const std::string &n) const
373 415
    {
374 416
      return RefType(*this, n);
375 417
    }
376 418

	
377 419
    ///Give back the non-option type arguments.
378 420

	
379 421
    ///Give back a reference to a vector consisting of the program arguments
380 422
    ///not starting with a '-' character.
381 423
    const std::vector<std::string> &files() const { return _file_args; }
382 424

	
425
    ///Throw instead of exit in case of problems
426
    void throwOnProblems() 
427
    {
428
      _exit_on_problems=false;
429
    }
383 430
  };
384 431
}
385 432

	
386 433
#endif // LEMON_ARG_PARSER_H
0 comments (0 inline)