# HG changeset patch # User Alpar Juttner # Date 2010-02-14 19:23:55 # Node ID c2ff0a365245e31db53ee51bce5280d6d3061688 # Parent cc9e0c15d7477a877efb6ee9f299cff19b755314 ArgParser can throw exception instead of exit(1) (#332) diff --git a/demo/arg_parser_demo.cc b/demo/arg_parser_demo.cc --- a/demo/arg_parser_demo.cc +++ b/demo/arg_parser_demo.cc @@ -65,9 +65,18 @@ ap.other("infile", "The input file.") .other("..."); + // Throw an exception when problems occurs. The default behavior is to + // exit(1) on these cases, but this makes Valgrind falsely warn + // about memory leaks. + ap.throwOnProblems(); + // Perform the parsing process // (in case of any error it terminates the program) - ap.parse(); + // The try {} construct is necessary only if the ap.trowOnProblems() + // setting is in use. + try { + ap.parse(); + } catch (ArgParserException &) { return 1; } // Check each option if it has been given and print its value std::cout << "Parameters of '" << ap.commandName() << "':\n"; diff --git a/lemon/arg_parser.cc b/lemon/arg_parser.cc --- a/lemon/arg_parser.cc +++ b/lemon/arg_parser.cc @@ -20,14 +20,23 @@ namespace lemon { + void ArgParser::_terminate(ArgParserException::Reason reason) const + { + if(_exit_on_problems) + exit(1); + else throw(ArgParserException(reason)); + } + + void ArgParser::_showHelp(void *p) { (static_cast(p))->showHelp(); - exit(1); + (static_cast(p))->_terminate(ArgParserException::HELP); } ArgParser::ArgParser(int argc, const char * const *argv) - :_argc(argc), _argv(argv), _command_name(argv[0]) { + :_argc(argc), _argv(argv), _command_name(argv[0]), + _exit_on_problems(true) { funcOption("-help","Print a short help message",_showHelp,this); synonym("help","-help"); synonym("h","-help"); @@ -342,7 +351,7 @@ for(std::vector::const_iterator i=_others_help.begin(); i!=_others_help.end();++i) showHelp(i); for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i); - exit(1); + _terminate(ArgParserException::HELP); } @@ -351,7 +360,7 @@ std::cerr << "\nUnknown option: " << arg << "\n"; std::cerr << "\nType '" << _command_name << " --help' to obtain a short summary on the usage.\n\n"; - exit(1); + _terminate(ArgParserException::UNKNOWN_OPT); } void ArgParser::requiresValue(std::string arg, OptType t) const @@ -414,7 +423,7 @@ if(!ok) { std::cerr << "\nType '" << _command_name << " --help' to obtain a short summary on the usage.\n\n"; - exit(1); + _terminate(ArgParserException::INVALID_OPT); } } diff --git a/lemon/arg_parser.h b/lemon/arg_parser.h --- a/lemon/arg_parser.h +++ b/lemon/arg_parser.h @@ -34,6 +34,44 @@ namespace lemon { + ///Exception used by ArgParser + class ArgParserException : public Exception { + public: + enum Reason { + HELP, /// --help option was given + UNKNOWN_OPT, /// Unknown option was given + INVALID_OPT /// Invalid combination of options + }; + + private: + Reason _reason; + + public: + ///Constructor + ArgParserException(Reason r) throw() : _reason(r) {} + ///Virtual destructor + virtual ~ArgParserException() throw() {} + ///A short description of the exception + virtual const char* what() const throw() { + switch(_reason) + { + case HELP: + return "lemon::ArgParseException: ask for help"; + break; + case UNKNOWN_OPT: + return "lemon::ArgParseException: unknown option"; + break; + case INVALID_OPT: + return "lemon::ArgParseException: invalid combination of options"; + break; + } + return ""; + } + ///Return the reason for the failure + Reason reason() const {return _reason; } + }; + + ///Command line arguments parser ///\ingroup misc @@ -103,7 +141,7 @@ std::vector _file_args; std::string _command_name; - + private: //Bind a function to an option. @@ -116,6 +154,10 @@ const std::string &help, void (*func)(void *),void *data); + bool _exit_on_problems; + + void _terminate(ArgParserException::Reason reason) const; + public: ///Constructor @@ -380,6 +422,11 @@ ///not starting with a '-' character. const std::vector &files() const { return _file_args; } + ///Throw instead of exit in case of problems + void throwOnProblems() + { + _exit_on_problems=false; + } }; }