#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;
/**
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.
{
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;
}
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.
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;
}
virtual ~Starter() { }
virtual Application *create_app(int, char **) = 0;
- virtual void usage(const char *, const char *, bool) = 0;
};
bool done;
virtual ~Application() { }
static int run(int, char **, void * =0);
- static void usage(const char *, const char *, bool);
static void *get_data() { return data_; }
protected:
{
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_;
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)
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)
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)
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]);
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]);
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();
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);
#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:
std::istringstream ss(a);
ss>>tmp;
if(ss.fail())
- throw UsageError("Invalid argument for --"+lng);
+ throw usage_error("Invalid argument for --"+lng);
data = tmp;
}
{
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() { }
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);
}
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; }