Improve readability of usage message

Former-commit-id: 7919b8e95e57518ee5dd60c6de8b6524a1749998
This commit is contained in:
poljvd 2014-12-17 16:43:14 +01:00
parent b74036b61d
commit 6248489aed

View File

@ -17,6 +17,9 @@
#include "getoptpp.h" #include "getoptpp.h"
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#include <cstdio>
#include <string>
#include <sys/ioctl.h>
using namespace std; using namespace std;
@ -34,107 +37,124 @@ OptionsParser::OptionsParser(const char* programDesc) : fprogramDesc(programDesc
OptionsParser::~OptionsParser() {} OptionsParser::~OptionsParser() {}
ParameterSet& OptionsParser::getParameters() { ParameterSet& OptionsParser::getParameters() {
return parameters; return parameters;
} }
void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error) void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error)
{ {
argv0 = argv[0]; argv0 = argv[0];
if(argc == 1) return; if(argc == 1) return;
vector<string> v(&argv[1], &argv[argc]); vector<string> v(&argv[1], &argv[argc]);
ParserState state(/* *this,*/ v); ParserState state(/* *this,*/ v);
for(; !state.end(); state.advance()) { for(; !state.end(); state.advance()) {
std::list<Parameter*>::iterator i; std::list<Parameter*>::iterator i;
for(i = parameters.parameters.begin(); for(i = parameters.parameters.begin();
i != parameters.parameters.end(); i++) i != parameters.parameters.end(); i++)
{ {
int n = 0; int n = 0;
try try
{ {
n = (*i)->receive(state); n = (*i)->receive(state);
} }
catch(Parameter::ExpectedArgument &) catch(Parameter::ExpectedArgument &)
{ {
throw Parameter::ExpectedArgument(state.get() + ": expected an argument"); throw Parameter::ExpectedArgument(state.get() + ": expected an argument");
} }
catch(Parameter::UnexpectedArgument &) catch(Parameter::UnexpectedArgument &)
{ {
throw Parameter::UnexpectedArgument(state.get() + ": did not expect an argument"); throw Parameter::UnexpectedArgument(state.get() + ": did not expect an argument");
} }
catch(Switchable::SwitchingError &) catch(Switchable::SwitchingError &)
{ {
throw Parameter::ParameterRejected(state.get() + ": parameter already set"); throw Parameter::ParameterRejected(state.get() + ": parameter already set");
} }
catch(Parameter::ParameterRejected & pr) { catch(Parameter::ParameterRejected & pr) {
std::string what = pr.what(); std::string what = pr.what();
if(what.length()) if(what.length())
{ {
throw Parameter::ParameterRejected(state.get() + ": " + what); throw Parameter::ParameterRejected(state.get() + ": " + what);
} }
throw Parameter::ParameterRejected(state.get() + " (unspecified error)"); throw Parameter::ParameterRejected(state.get() + " (unspecified error)");
} }
for (int j = 1; j < n; ++j) for (int j = 1; j < n; ++j)
{ {
state.advance(); state.advance();
} }
if(n != 0) if(n != 0)
{ {
break; break;
} }
} }
if(i == parameters.parameters.end()) { if(i == parameters.parameters.end()) {
std::string file = state.get(); std::string file = state.get();
if(file == "--") { if(file == "--") {
state.advance(); state.advance();
break; break;
} }
else if(file.at(0) == '-') else if(file.at(0) == '-')
throw Parameter::ParameterRejected(string("Bad parameter: ") + file); throw Parameter::ParameterRejected(string("Bad parameter: ") + file);
else files.push_back(state.get()); else files.push_back(state.get());
} }
} }
if(!state.end()) for(; !state.end(); state.advance()) { if(!state.end()) for(; !state.end(); state.advance()) {
files.push_back(state.get()); files.push_back(state.get());
} }
} }
void OptionsParser::usage() const { void OptionsParser::usage() const {
cerr << fprogramDesc << endl; cerr << fprogramDesc << endl;
cerr << "Build time: " << __DATE__ << " " << __TIME__ << endl << endl; cerr << "Build time: " << __DATE__ << " " << __TIME__ << endl << endl;
cerr << "Usage: " << programName() << " [OPTIONS]" << endl << endl; cerr << "Usage: " << programName() << " [OPTIONS]" << endl << endl;
cerr << "Parameters: " << endl; cerr << "Parameters: " << endl;
std::list<Parameter*>::const_iterator i; int totalWidth = 80;
for(i = parameters.parameters.begin(); int usageWidth = 33;
i != parameters.parameters.end(); i++)
{
cerr.width(33);
cerr << std::left << " " + (*i)->usageLine();
cerr.width(40); // read total width from the terminal
cerr << std::left << (*i)->description() << endl; struct winsize w;
if (ioctl(0, TIOCGWINSZ, &w) == 0)
{
if (w.ws_col > totalWidth)
totalWidth = w.ws_col;
}
} std::list<Parameter*>::const_iterator i;
for(i = parameters.parameters.begin();
i != parameters.parameters.end(); i++)
{
cerr.width(usageWidth);
cerr << std::left << " " + (*i)->usageLine();
std::string description = (*i)->description();
while (int(description.length()) > (totalWidth - usageWidth))
{
size_t pos = description.find_last_of(' ', totalWidth - usageWidth);
cerr << description.substr(0, pos) << std::endl << std::string(usageWidth - 1, ' ');
description = description.substr(pos);
}
cerr << description << endl;
}
} }
const vector<string>& OptionsParser::getFiles() const { const vector<string>& OptionsParser::getFiles() const {
return files; return files;
} }
const string& OptionsParser::programName() const { const string& OptionsParser::programName() const {
return argv0; return argv0;
} }
/* /*
@ -144,15 +164,15 @@ const string& OptionsParser::programName() const {
*/ */
ParameterSet::ParameterSet(const ParameterSet& ps) { ParameterSet::ParameterSet(const ParameterSet& ps) {
throw new runtime_error("ParameterSet not copyable"); throw new runtime_error("ParameterSet not copyable");
} }
ParameterSet::~ParameterSet() { ParameterSet::~ParameterSet() {
for(std::list<Parameter*>::iterator i = parameters.begin(); for(std::list<Parameter*>::iterator i = parameters.begin();
i != parameters.end(); i++) i != parameters.end(); i++)
{ {
delete *i; delete *i;
} }
} }
@ -161,18 +181,18 @@ ParameterSet::~ParameterSet() {
*/ */
Parameter& ParameterSet::operator[](char c) const { Parameter& ParameterSet::operator[](char c) const {
for(std::list<Parameter*>::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { for(std::list<Parameter*>::const_iterator i = parameters.begin(); i!= parameters.end(); i++) {
if((*i)->shortOption() == c) return *(*i); if((*i)->shortOption() == c) return *(*i);
} }
throw out_of_range("ParameterSet["+string(&c)+string("]")); throw out_of_range("ParameterSet["+string(&c)+string("]"));
} }
Parameter& ParameterSet::operator[](const string& param) const { Parameter& ParameterSet::operator[](const string& param) const {
for(std::list<Parameter*>::const_iterator i = parameters.begin(); i!= parameters.end(); i++) { for(std::list<Parameter*>::const_iterator i = parameters.begin(); i!= parameters.end(); i++) {
if((*i)->longOption() == param) return *(*i); if((*i)->longOption() == param) return *(*i);
} }
throw out_of_range("ParameterSet["+param+"]"); throw out_of_range("ParameterSet["+param+"]");
} }
@ -186,29 +206,29 @@ Parameter& ParameterSet::operator[](const string& param) const {
ParserState::ParserState(/*OptionsParser &opts, */vector<string>& args) : ParserState::ParserState(/*OptionsParser &opts, */vector<string>& args) :
/*opts(opts),*/ arguments(args), iterator(args.begin()) /*opts(opts),*/ arguments(args), iterator(args.begin())
{ {
} }
const string ParserState::peek() const { const string ParserState::peek() const {
vector<string>::const_iterator next = iterator+1; vector<string>::const_iterator next = iterator+1;
if(next != arguments.end()) return *next; if(next != arguments.end()) return *next;
else return ""; else return "";
} }
const string ParserState::get() const { const string ParserState::get() const {
if(!end()) return *iterator; if(!end()) return *iterator;
else return ""; else return "";
} }
void ParserState::advance() { void ParserState::advance() {
iterator++; iterator++;
} }
bool ParserState::end() const { bool ParserState::end() const {
return iterator == arguments.end(); return iterator == arguments.end();
} }
@ -222,7 +242,7 @@ bool ParserState::end() const {
Parameter::Parameter(char shortOption, const std::string & longOption, const std::string & description) : Parameter::Parameter(char shortOption, const std::string & longOption, const std::string & description) :
fshortOption(shortOption), flongOption(longOption), fdescription(description) fshortOption(shortOption), flongOption(longOption), fdescription(description)
{ {
} }
@ -250,22 +270,22 @@ MultiSwitchable::~MultiSwitchable() {}
void UniquelySwitchable::set() throw (Switchable::SwitchingError) { void UniquelySwitchable::set() throw (Switchable::SwitchingError) {
if(UniquelySwitchable::isSet()) throw Switchable::SwitchingError(); if(UniquelySwitchable::isSet()) throw Switchable::SwitchingError();
fset = true; fset = true;
} }
UniquelySwitchable::~UniquelySwitchable() {} UniquelySwitchable::~UniquelySwitchable() {}
PresettableUniquelySwitchable::~PresettableUniquelySwitchable() {} PresettableUniquelySwitchable::~PresettableUniquelySwitchable() {}
bool PresettableUniquelySwitchable::isSet() const { bool PresettableUniquelySwitchable::isSet() const {
return UniquelySwitchable::isSet() || fpreset.isSet(); return UniquelySwitchable::isSet() || fpreset.isSet();
} }
void PresettableUniquelySwitchable::set() throw (Switchable::SwitchingError) void PresettableUniquelySwitchable::set() throw (Switchable::SwitchingError)
{ {
UniquelySwitchable::set(); UniquelySwitchable::set();
} }
void PresettableUniquelySwitchable::preset() { void PresettableUniquelySwitchable::preset() {
fpreset.set(); fpreset.set();
} }
/* /*
@ -279,58 +299,58 @@ void PresettableUniquelySwitchable::preset() {
template<> template<>
PODParameter<string>::PODParameter(char shortOption, const char *longOption, PODParameter<string>::PODParameter(char shortOption, const char *longOption,
const char* description) : CommonParameter<PresettableUniquelySwitchable>(shortOption, longOption, description) { const char* description) : CommonParameter<PresettableUniquelySwitchable>(shortOption, longOption, description) {
} }
template<> template<>
int PODParameter<int>::validate(const string &s) throw(Parameter::ParameterRejected) int PODParameter<int>::validate(const string &s) throw(Parameter::ParameterRejected)
{ {
// This is sadly necessary for strto*-functions to operate on // This is sadly necessary for strto*-functions to operate on
// const char*. The function doesn't write to the memory, though, // const char*. The function doesn't write to the memory, though,
// so it's quite safe. // so it's quite safe.
char* cstr = const_cast<char*>(s.c_str()); char* cstr = const_cast<char*>(s.c_str());
if(*cstr == '\0') throw ParameterRejected("No argument given"); if(*cstr == '\0') throw ParameterRejected("No argument given");
long l = strtol(cstr, &cstr, 10); long l = strtol(cstr, &cstr, 10);
if(*cstr != '\0') throw ParameterRejected("Expected int"); if(*cstr != '\0') throw ParameterRejected("Expected int");
if(l > INT_MAX || l < INT_MIN) { if(l > INT_MAX || l < INT_MIN) {
throw ParameterRejected("Expected int"); throw ParameterRejected("Expected int");
} }
return l; return l;
} }
template<> template<>
long PODParameter<long>::validate(const string &s) throw(Parameter::ParameterRejected) long PODParameter<long>::validate(const string &s) throw(Parameter::ParameterRejected)
{ {
char* cstr = const_cast<char*>(s.c_str()); char* cstr = const_cast<char*>(s.c_str());
if(*cstr == '\0') throw ParameterRejected("No argument given"); if(*cstr == '\0') throw ParameterRejected("No argument given");
long l = strtol(cstr, &cstr, 10); long l = strtol(cstr, &cstr, 10);
if(*cstr != '\0') throw ParameterRejected("Expected long"); if(*cstr != '\0') throw ParameterRejected("Expected long");
return l; return l;
} }
template<> template<>
double PODParameter<double>::validate(const string &s) throw(Parameter::ParameterRejected) double PODParameter<double>::validate(const string &s) throw(Parameter::ParameterRejected)
{ {
char* cstr = const_cast<char*>(s.c_str()); char* cstr = const_cast<char*>(s.c_str());
if(*cstr == '\0') throw ParameterRejected("No argument given"); if(*cstr == '\0') throw ParameterRejected("No argument given");
double d = strtod(cstr, &cstr); double d = strtod(cstr, &cstr);
if(*cstr != '\0') throw ParameterRejected("Expected double"); if(*cstr != '\0') throw ParameterRejected("Expected double");
return d; return d;
} }
template<> template<>
string PODParameter<string>::validate(const string &s) throw(Parameter::ParameterRejected) string PODParameter<string>::validate(const string &s) throw(Parameter::ParameterRejected)
{ {
return s; return s;
} }