]> 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 <signal.h>
 #include <iostream>
 #include <typeinfo>
-#include "../debug/backtrace.h"
 #include "../debug/demangle.h"
 #include "../debug/demangle.h"
-#include "../time/units.h"
-#include "../time/utils.h"
 #include "application.h"
 #include "application.h"
-#include "except.h"
+#include "getopt.h"
 
 using namespace std;
 
 
 using namespace std;
 
@@ -29,7 +26,8 @@ Application::Application():
 
 /**
 Constructs an instance of the registered application class and runs it.  If the
 
 /**
 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.
 
 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);
                }
                {
                        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;
                }
 
                        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';
                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;
        }
 }
 
 #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.
 /**
 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_)
 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;
 }
 
        starter_ = this;
 }
index b51ac3c446e8e87028623ea0db5751871cacc874..4ae8c5614250819ec6aa28ed83c7cc6461f7ee69 100644 (file)
@@ -25,7 +25,6 @@ protected:
                virtual ~Starter() { }
 
                virtual Application *create_app(int, char **) = 0;
                virtual ~Starter() { }
 
                virtual Application *create_app(int, char **) = 0;
-               virtual void usage(const char *, const char *, bool) = 0;
        };
 
        bool done;
        };
 
        bool done;
@@ -44,7 +43,6 @@ public:
        virtual ~Application() { }
 
        static int run(int, char **, void * =0);
        virtual ~Application() { }
 
        static int run(int, char **, void * =0);
-       static void usage(const char *, const char *, bool);
        static void *get_data() { return data_; }
 
 protected:
        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); }
        {
        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_;
        };
 
        static Starter starter_;
index 74f14761c8636c19c7612cd27972ae5ac683832d..9b8b84cdee323bc1c83f2ebb35dd69915b2f9a00 100644 (file)
@@ -11,6 +11,12 @@ using namespace std;
 
 namespace Msp {
 
 
 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)
 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;
        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)
 }
 
 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;
        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)
 {
 }
 
 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
                        }
                        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)
 }
 
 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])
        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]);
 
                // 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])
                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]);
                        
                        // 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)
 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();
        ++seen_count;
 
        store();
@@ -235,7 +251,7 @@ void GetOpt::OptBase::process()
 void GetOpt::OptBase::process(const string &arg)
 {
        if(arg_type==NO_ARG)
 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);
        ++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_
 
 #ifndef MSP_CORE_GETOPT_H_
 #define MSP_CORE_GETOPT_H_
 
+#include <list>
 #include <sstream>
 #include <sstream>
+#include <stdexcept>
 #include <string>
 #include <vector>
 #include <string>
 #include <vector>
-#include "except.h"
 
 namespace Msp {
 
 
 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:
 class GetOpt
 {
 public:
@@ -69,7 +83,7 @@ private:
                        std::istringstream ss(a);
                        ss>>tmp;
                        if(ss.fail())
                        std::istringstream ss(a);
                        ss>>tmp;
                        if(ss.fail())
-                               throw UsageError("Invalid argument for --"+lng);
+                               throw usage_error("Invalid argument for --"+lng);
 
                        data = tmp;
                }
 
                        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)
        {
        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() { }
 
 
                virtual void store() { }
 
@@ -92,7 +106,7 @@ private:
                        std::istringstream ss(a);
                        ss>>tmp;
                        if(ss.fail())
                        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);
                }
 
                        data.push_back(tmp);
                }
@@ -100,10 +114,12 @@ private:
                T &data;
        };
 
                T &data;
        };
 
+       bool help;
        std::list<OptBase *> opts;
        std::vector<std::string> args;
 
 public:
        std::list<OptBase *> opts;
        std::vector<std::string> args;
 
 public:
+       GetOpt();
        ~GetOpt();
 
        const std::vector<std::string> &get_args() const { return args; }
        ~GetOpt();
 
        const std::vector<std::string> &get_args() const { return args; }