# HG changeset patch
# User Alpar Juttner <alpar@cs.elte.hu>
# Date 1267381381 -3600
# Node ID 81f7e910060b8e4d7957f36ac3fc14559a6df724
# Parent  aa8c9008b3de9bb247ce81ad736a53c0d96f7b5b# Parent  c2ff0a365245e31db53ee51bce5280d6d3061688
Merge #332

diff -r aa8c9008b3de -r 81f7e910060b demo/arg_parser_demo.cc
--- a/demo/arg_parser_demo.cc	Fri Feb 26 23:53:09 2010 +0100
+++ b/demo/arg_parser_demo.cc	Sun Feb 28 19:23:01 2010 +0100
@@ -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 -r aa8c9008b3de -r 81f7e910060b lemon/arg_parser.cc
--- a/lemon/arg_parser.cc	Fri Feb 26 23:53:09 2010 +0100
+++ b/lemon/arg_parser.cc	Sun Feb 28 19:23:01 2010 +0100
@@ -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<ArgParser*>(p))->showHelp();
-    exit(1);
+    (static_cast<ArgParser*>(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<OtherArg>::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 -r aa8c9008b3de -r 81f7e910060b lemon/arg_parser.h
--- a/lemon/arg_parser.h	Fri Feb 26 23:53:09 2010 +0100
+++ b/lemon/arg_parser.h	Sun Feb 28 19:23:01 2010 +0100
@@ -34,6 +34,44 @@
 
 namespace lemon {
 
+  ///Exception used by ArgParser
+  class ArgParserException : public Exception {
+  public:
+    enum Reason {
+      HELP,         /// <tt>--help</tt> 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<std::string> _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<std::string> &files() const { return _file_args; }
 
+    ///Throw instead of exit in case of problems
+    void throwOnProblems() 
+    {
+      _exit_on_problems=false;
+    }
   };
 }