]> git.tdb.fi Git - libs/core.git/commitdiff
Make help message printing automatic
authorMikko Rasa <tdb@tdb.fi>
Wed, 25 May 2011 18:35:59 +0000 (21:35 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 25 May 2011 18:35:59 +0000 (21:35 +0300)
Start making more use of std exception classes

source/core/application.cpp
source/core/application.h
source/core/getopt.cpp
source/core/getopt.h

index 139f94f2d88054d745ad9119b562dd7ec174d596..a60f605cbf03162a3e22d9ec3e1939f8472a68dd 100644 (file)
@@ -8,12 +8,9 @@ Distributed under the LGPL
 #include <signal.h>
 #include <iostream>
 #include <typeinfo>
-#include "../debug/backtrace.h"
 #include "../debug/demangle.h"
-#include "../time/units.h"
-#include "../time/utils.h"
 #include "application.h"
-#include "except.h"
+#include "getopt.h"
 
 using namespace std;
 
@@ -29,7 +26,8 @@ Application::Application():
 
 /**
 Constructs an instance of the registered application class and runs it.  If the
-application throws a UsageError, the static usage() function is called.
+application throws a usage_error, a help message is printed.  The GetOpt class
+will throw such exceptions automatically in error conditions.
 
 This function can only be called once.  The global main() function provided by
 the library normally does it automatically at program startup.
@@ -58,9 +56,10 @@ int Application::run(int argc, char **argv, void *data)
                {
                        app_ = starter_->create_app(argc, argv);
                }
-               catch(const UsageError &e)
+               catch(const usage_error &e)
                {
-                       starter_->usage(e.what(), argv[0], e.get_brief());
+                       cerr<<e.what()<<'\n';
+                       cerr<<e.help()<<'\n';
                        return 1;
                }
 
@@ -81,36 +80,12 @@ int Application::run(int argc, char **argv, void *data)
                cerr<<"An uncaught exception occurred.\n";
                cerr<<"  type:   "<<Debug::demangle(typeid(e).name())<<'\n';
                cerr<<"  what(): "<<e.what()<<'\n';
-
-               const Exception *exc = dynamic_cast<const Exception *>(&e);
-               if(exc && !exc->get_backtrace().get_frames().empty())
-               {
-                       cerr<<"  backtrace:\n";
-                       const list<Debug::Backtrace::StackFrame> &frames = exc->get_backtrace().get_frames();
-                       for(list<Debug::Backtrace::StackFrame>::const_iterator i=frames.begin(); i!=frames.end(); ++i)
-                               cerr<<"    "<<*i<<'\n';
-               }
 #endif
 
                return 124;
        }
 }
 
-/**
-Prints a message describing the usage of the application.  The default version
-will blame the programmer for being lazy.
-
-@param   reason  Why the function was called
-@param   argv0   The value of argv[0], to be used in the message
-@param   brief   Whether to print a brief or long usage message
-*/
-void Application::usage(const char *reason, const char *, bool)
-{
-       if(reason)
-               cerr<<"UsageError: "<<reason<<'\n';
-       cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
-}
-
 /**
 Default main loop.  Calls tick() repeatedly until exit() is called.  A custom
 main loop should monitor the done member variable and return exit_code.
@@ -153,7 +128,7 @@ void Application::sighandler_(int s)
 Application::Starter::Starter()
 {
        if(starter_)
-               throw InvalidState("Can't create more than one Starter instance");
+               throw logic_error("Can't create more than one Starter instance");
 
        starter_ = this;
 }
index b51ac3c446e8e87028623ea0db5751871cacc874..4ae8c5614250819ec6aa28ed83c7cc6461f7ee69 100644 (file)
@@ -25,7 +25,6 @@ protected:
                virtual ~Starter() { }
 
                virtual Application *create_app(int, char **) = 0;
-               virtual void usage(const char *, const char *, bool) = 0;
        };
 
        bool done;
@@ -44,7 +43,6 @@ public:
        virtual ~Application() { }
 
        static int run(int, char **, void * =0);
-       static void usage(const char *, const char *, bool);
        static void *get_data() { return data_; }
 
 protected:
@@ -66,7 +64,6 @@ private:
        {
        public:
                Application *create_app(int argc, char **argv) { return new T(argc, argv); }
-               void usage(const char *r, const char *a, bool b) { T::usage(r, a, b); }
        };
 
        static Starter starter_;
index 74f14761c8636c19c7612cd27972ae5ac683832d..9b8b84cdee323bc1c83f2ebb35dd69915b2f9a00 100644 (file)
@@ -11,6 +11,12 @@ using namespace std;
 
 namespace Msp {
 
+GetOpt::GetOpt():
+       help(false)
+{
+       add_option("help", help, NO_ARG).set_help("Displays this help");
+}
+
 GetOpt::~GetOpt()
 {
        for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
@@ -22,7 +28,7 @@ GetOpt::OptBase &GetOpt::get_option(char s)
        for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
                if((*i)->get_short()==s)
                        return **i;
-       throw UsageError(string("Unknown option -")+s);
+       throw usage_error(string("Unknown option -")+s);
 }
 
 GetOpt::OptBase &GetOpt::get_option(const string &l)
@@ -30,32 +36,42 @@ GetOpt::OptBase &GetOpt::get_option(const string &l)
        for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
                if((*i)->get_long()==l)
                        return **i;
-       throw UsageError(string("Unknown option --")+l);
+       throw usage_error(string("Unknown option --")+l);
 }
 
 void GetOpt::operator()(unsigned argc, const char *const *argv)
 {
-       unsigned i = 1;
-       for(; i<argc;)
+       try
        {
-               if(argv[i][0]=='-')
+               unsigned i = 1;
+               for(; i<argc;)
                {
-                       if(argv[i][1]=='-')
+                       if(argv[i][0]=='-')
                        {
-                               if(!argv[i][2])
-                                       break;
-
-                               i += process_long(argv+i);
+                               if(argv[i][1]=='-')
+                               {
+                                       if(!argv[i][2])
+                                               break;
+
+                                       i += process_long(argv+i);
+                               }
+                               else
+                                       i += process_short(argv+i);
                        }
                        else
-                               i += process_short(argv+i);
+                               args.push_back(argv[i++]);
                }
-               else
-                       args.push_back(argv[i++]);
+               
+               for(; i<argc; ++i)
+                       args.push_back(argv[i]);
        }
-       
-       for(; i<argc; ++i)
-               args.push_back(argv[i]);
+       catch(const usage_error &e)
+       {
+               throw usage_error(e.what(), "Usage: "+generate_usage(argv[0]));
+       }
+
+       if(help)
+               throw usage_error(string("Help for ")+argv[0]+":", generate_help());
 }
 
 unsigned GetOpt::process_long(const char *const *argp)
@@ -75,7 +91,7 @@ unsigned GetOpt::process_long(const char *const *argp)
        else if(opt.get_arg_type()==REQUIRED_ARG)
        {
                if(!argp[1])
-                       throw UsageError("Premature end of arguments");
+                       throw usage_error("--"+string(arg)+" requires an argument");
 
                // Process the next argument as option argument
                opt.process(argp[1]);
@@ -106,7 +122,7 @@ unsigned GetOpt::process_short(const char *const *argp)
                else if(opt.get_arg_type()==REQUIRED_ARG)
                {
                        if(!argp[1])
-                               throw UsageError("Premature end of arguments");
+                               throw usage_error("-"+string(1, *arg)+" requires an argument");
                        
                        // Use the next argument as option argument
                        opt.process(argp[1]);
@@ -226,7 +242,7 @@ GetOpt::OptBase &GetOpt::OptBase::set_help(const string &h, const string &m)
 void GetOpt::OptBase::process()
 {
        if(arg_type==REQUIRED_ARG)
-               throw UsageError("--"+lng+" requires an argument");
+               throw usage_error("--"+lng+" requires an argument");
        ++seen_count;
 
        store();
@@ -235,7 +251,7 @@ void GetOpt::OptBase::process()
 void GetOpt::OptBase::process(const string &arg)
 {
        if(arg_type==NO_ARG)
-               throw UsageError("--"+lng+" takes no argument");
+               throw usage_error("--"+lng+" takes no argument");
        ++seen_count;
 
        store(arg);
index 8e0f49a3fb9d12c83d986289e6cf69d5fc10cee9..d45e888692ea9f96d2947180f19de75f6652eabb 100644 (file)
@@ -8,13 +8,27 @@ Distributed under the LGPL
 #ifndef MSP_CORE_GETOPT_H_
 #define MSP_CORE_GETOPT_H_
 
+#include <list>
 #include <sstream>
+#include <stdexcept>
 #include <string>
 #include <vector>
-#include "except.h"
 
 namespace Msp {
 
+class usage_error: public std::runtime_error
+{
+private:
+       std::string help_;
+
+public:
+       usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), help_(h) { }
+       ~usage_error() throw() { }
+
+       const char *help() const throw() { return help_.c_str(); }
+};
+
+
 class GetOpt
 {
 public:
@@ -69,7 +83,7 @@ private:
                        std::istringstream ss(a);
                        ss>>tmp;
                        if(ss.fail())
-                               throw UsageError("Invalid argument for --"+lng);
+                               throw usage_error("Invalid argument for --"+lng);
 
                        data = tmp;
                }
@@ -82,7 +96,7 @@ private:
        {
        public:
                ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d)
-               { if(arg_type!=REQUIRED_ARG) throw Exception("ListOption with arg_type!=REQUIRED makes no sense"); }
+               { if(arg_type!=REQUIRED_ARG) throw std::invalid_argument("ListOption arg_type!=REQUIRED"); }
 
                virtual void store() { }
 
@@ -92,7 +106,7 @@ private:
                        std::istringstream ss(a);
                        ss>>tmp;
                        if(ss.fail())
-                               throw UsageError("Invalid argument for --"+lng);
+                               throw usage_error("Invalid argument for --"+lng);
 
                        data.push_back(tmp);
                }
@@ -100,10 +114,12 @@ private:
                T &data;
        };
 
+       bool help;
        std::list<OptBase *> opts;
        std::vector<std::string> args;
 
 public:
+       GetOpt();
        ~GetOpt();
 
        const std::vector<std::string> &get_args() const { return args; }